Validate search filesystem context after selection
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Configuration Discovery Review Findings
|
||||
|
||||
Status: five open findings. Implementation has not been changed by these reviews.
|
||||
Status: finding 1 complete; findings 2–5 remain open.
|
||||
|
||||
Reviewed commit: `e50fee2`, including the discovery implementation commits after
|
||||
`424c897`. The review compared the implementation with the
|
||||
@@ -10,7 +10,13 @@ configuration and architecture contracts.
|
||||
|
||||
## 1. Defer Absence-Only Context Requirements Until The Search Outcome Is Known
|
||||
|
||||
Priority: P2. Status: open.
|
||||
Priority: P2. Status: complete.
|
||||
|
||||
**Completed:** search prevalidation now defers absence-only root requirements
|
||||
until selection. Ordinary, layered-main, and underlay regression cases compare
|
||||
searched files with explicit files under an empty context and retain errors for
|
||||
absent inputs. The regression failed before the fix. Focused context/absence
|
||||
tests and `./scripts/check.sh` passed with Go 1.26.10 on Linux.
|
||||
|
||||
**Location:** [filesystem.go](../../internal/engine/filesystem.go), lines 77–123,
|
||||
and the outcome-specific validation in
|
||||
|
||||
@@ -204,6 +204,53 @@ func TestSearchContextCompatibilityUsesSelectedOutcome(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchEmptyContextUsesSelectedOutcome(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
root := t.TempDir()
|
||||
selected := writeImportFile(t, root, "selected.yml", "value: selected\n")
|
||||
missing := filepath.Join(root, "missing.yml")
|
||||
context := &FilesystemContext{}
|
||||
for _, entry := range []struct {
|
||||
name string
|
||||
load func(Source) (*Loaded[discoveryLoadConfig], error)
|
||||
}{
|
||||
{"ordinary", func(source Source) (*Loaded[discoveryLoadConfig], error) {
|
||||
return Load(source, testSecretBinding(), Options[discoveryLoadConfig]{Imports: true, Filesystem: context})
|
||||
}},
|
||||
{"layered main", func(source Source) (*Loaded[discoveryLoadConfig], error) {
|
||||
return LoadLayered(Input{Source: source, Imports: true, Filesystem: context}, testSecretBinding(), LayeredOptions[discoveryLoadConfig]{})
|
||||
}},
|
||||
{"underlay", func(source Source) (*Loaded[discoveryLoadConfig], error) {
|
||||
return LoadLayered(Input{Source: NoSource()}, testSecretBinding(), LayeredOptions[discoveryLoadConfig]{
|
||||
Underlays: []Underlay{{Inputs: []Input{{Source: source, Imports: true, Filesystem: context}}}},
|
||||
})
|
||||
}},
|
||||
} {
|
||||
t.Run(entry.name, func(t *testing.T) {
|
||||
explicit, err := entry.load(File(selected))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
searched, err := entry.load(SearchConfig("", Paths(missing, selected)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assertEquivalentDiscoveryLoads(t, searched.Config, searched.Inspection, explicit.Config, explicit.Inspection, Keys("value"))
|
||||
if searched.Config.Value != "selected" {
|
||||
t.Fatalf("selected value = %q", searched.Config.Value)
|
||||
}
|
||||
for _, source := range []Source{NoSource(), SearchConfig("", Paths(missing))} {
|
||||
result, err := entry.load(source)
|
||||
var failure *LoadError
|
||||
if result != nil || !errors.As(err, &failure) || len(failure.Diagnostics()) != 1 || failure.Diagnostics()[0].Code != CodeOptionsInvalid {
|
||||
t.Fatalf("absent input with empty context = %#v, %v", result, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchSourceObservesFileChangesBetweenLoads(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -79,7 +79,14 @@ func filesystemOptionDiagnostics(source Source, context *FilesystemContext) []Di
|
||||
case sourceNone:
|
||||
return absentFilesystemOptionDiagnostics(context)
|
||||
case sourceSearch:
|
||||
return absentFilesystemOptionDiagnostics(context)
|
||||
if context.FS != nil {
|
||||
return absentFilesystemOptionDiagnostics(context)
|
||||
}
|
||||
// A selected host file can derive its root; absence requires an
|
||||
// explicit root. Check that compatibility only after selection.
|
||||
if context.BaseDir != "" && !filepath.IsAbs(context.BaseDir) {
|
||||
return []Diagnostic{optionDiagnostic(CodeOptionsInvalid, "filesystem base directory must be an absolute host path")}
|
||||
}
|
||||
case sourceFile:
|
||||
if context.FS != nil {
|
||||
return []Diagnostic{optionDiagnostic(CodeOptionsInvalid, "host file sources cannot use a native filesystem context")}
|
||||
|
||||
Reference in New Issue
Block a user