Resolve Windows rooted search paths with Go

This commit is contained in:
2026-10-24 19:24:30 +00:00
parent 2fedb0307f
commit 0369111d30
3 changed files with 84 additions and 5 deletions

View File

@@ -1,6 +1,6 @@
# Configuration Discovery Review Findings
Status: findings 1–4 complete; finding 5 remains open.
Status: complete. All five findings have been addressed in separate commits.
Reviewed commit: `e50fee2`, including the discovery implementation commits after
`424c897`. The review compared the implementation with the
@@ -185,7 +185,15 @@ code, not a new Windows support promise or native-platform release gate.
## 5. Preserve Drive-Root-Relative Windows Path Meaning
Priority: P3. Status: open. Algorithmic audit: correctness finding.
Priority: P3. Status: complete. Algorithmic audit: correctness finding.
**Completed:** drive-root-relative Windows paths now use `filepath.Abs` alongside
drive-relative paths, preserving native host interpretation. Windows regression
tests compare candidates and loaded files with explicit `File` for relative,
drive-root-relative (both separators), drive-relative, and absolute paths, through
both `Paths` and `SearchDirectory`. Existing Unix path/short-circuit tests and
`./scripts/check.sh` passed. The Windows engine test binary cross-compiled; no
native Windows execution or new release gate was introduced.
**Location:** [discovery.go](../../internal/engine/discovery.go),
`absoluteCandidate`, lines 380–391; also used for literal directory searches.
@@ -257,8 +265,8 @@ ordinary file acquisition. It did not benchmark or reopen those choices.
No unplanned quadratic algorithm or other actionable asymptotic regression was
identified. Findings 4 and 5 record the additional ordinary correctness issues
found while examining those algorithms; findings 1–3 were carried forward from
the earlier review. Existing configuration-tree algorithms outside the discovery changes
were not re-audited as new feature work.
the earlier review. Existing configuration-tree algorithms outside the discovery
changes were not re-audited as new feature work.
## Review Validation
@@ -278,3 +286,13 @@ were not re-audited as new feature work.
helper regression overlay described in finding 4. It collected no timing or
allocation measurements. Findings 4 and 5 are platform-specific correctness
findings, not claims of a native Windows validation run.
## Completed Remediation Validation
All five fixes include focused regression coverage and per-issue completion
markers above. The final `./scripts/check.sh` and `go test -race ./...` passed
with Go 1.26.10 on Linux. The Windows engine tests also cross-compiled with
`GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go test -c`, with the binary kept outside
the repository. No native Windows or macOS run was performed or made a gate.
The implementation preserves the public API, candidate ordering, optional
absence, and existing composition/version/ownership contracts.

View File

@@ -370,7 +370,9 @@ func (iterator *searchCandidateIterator) absoluteCandidate(path string) (string,
if filepath.IsAbs(path) {
return filepath.Clean(path), nil
}
if filepath.VolumeName(path) != "" {
// Drive-relative and drive-root-relative Windows paths need native
// resolution; joining a rooted path to the whole working directory changes it.
if filepath.VolumeName(path) != "" || runtime.GOOS == "windows" && len(path) > 0 && os.IsPathSeparator(path[0]) {
return filepath.Abs(path)
}
working, err := iterator.helpers.workingDir()

View File

@@ -4,6 +4,8 @@ package engine
import (
"errors"
"path/filepath"
"strings"
"testing"
)
@@ -30,3 +32,60 @@ func TestWindowsSearchRejectsReservedComponentsBeforeAcquisition(t *testing.T) {
}
}
}
func TestWindowsSearchPathsMatchHostAbsoluteResolution(t *testing.T) {
root := t.TempDir()
file := writeImportFile(t, root, "settings/config.yml", "value: selected\n")
working := t.TempDir()
t.Chdir(working)
relative, err := filepath.Rel(working, file)
if err != nil {
t.Fatal(err)
}
volume := filepath.VolumeName(file)
rooted := strings.TrimPrefix(file, volume)
for _, entry := range []struct {
name string
path string
}{
{"relative", relative},
{"drive root relative", rooted},
{"slash root relative", filepath.ToSlash(rooted)},
{"drive relative", volume + relative},
{"absolute", file},
} {
t.Run(entry.name, func(t *testing.T) {
want, err := filepath.Abs(entry.path)
if err != nil {
t.Fatal(err)
}
explicit, err := testLoad[discoveryLoadConfig](File(entry.path))
if err != nil {
t.Fatal(err)
}
for _, search := range []Search{
Paths(entry.path),
SearchDirectory(filepath.Dir(entry.path), DirectorySearchOptions{
Filenames: []FilenameGroup{CustomFilenames(filepath.Base(entry.path))},
}),
} {
iterator, diagnostics := newSearchCandidateIterator(search, "", discoveryDirectoryHelpers{})
if len(diagnostics) != 0 {
t.Fatal(diagnostics)
}
candidate, ok, err := iterator.next()
if err != nil || !ok || candidate != want {
t.Fatalf("candidate = %q, %v, %v; want %q", candidate, ok, err, want)
}
result, err := testLoad[discoveryLoadConfig](SearchConfig("", search))
if err != nil || result.Config.Value != explicit.Config.Value {
t.Fatalf("searched path = %#v, %v; explicit value %q", result, err, explicit.Config.Value)
}
sources := result.Sources()
if len(sources) != 1 || sources[0].Path != explicit.Sources()[0].Path {
t.Fatalf("searched source = %#v; explicit source %#v", sources, explicit.Sources())
}
}
})
}
}