Check import opt-in before processing source headers
This commit is contained in:
@@ -218,7 +218,13 @@ Required remediation:
|
|||||||
|
|
||||||
### 4. Preserve import opt-in before stripping source directives (P2)
|
### 4. Preserve import opt-in before stripping source directives (P2)
|
||||||
|
|
||||||
Status: open.
|
Status: complete. Directive opt-in is now checked on the original document
|
||||||
|
before source-version processing. The shared acquisition boundary covers main
|
||||||
|
and direct underlay sources. The public regression failed for both enabled
|
||||||
|
modes and roles before the fix and now verifies `import.disabled`, source-local
|
||||||
|
attribution, and no partial result. Focused source-version/directive/import
|
||||||
|
tests and the everyday check passed on `go1.26.9 linux/amd64`; existing enabled
|
||||||
|
import and selected-overlay tests remain green.
|
||||||
|
|
||||||
Affected: `assembleBaseInputTrackedForRole` in
|
Affected: `assembleBaseInputTrackedForRole` in
|
||||||
[load_input.go](../../internal/engine/load_input.go), lines 54–87, and
|
[load_input.go](../../internal/engine/load_input.go), lines 54–87, and
|
||||||
|
|||||||
@@ -78,6 +78,41 @@ func TestFacadeSourceVersionEvidenceRedactsCollidingShapes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFacadeSourceVersionModesPreserveImportOptIn(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
for _, mode := range []configkit.SourceVersionMode{configkit.SourceVersionModeIfPresent, configkit.SourceVersionModeRequired} {
|
||||||
|
for _, underlay := range []bool{false, true} {
|
||||||
|
bad := configkit.Bytes("disabled-imports", []byte("version: accepted\nconfigkit: {imports: [{path: missing.yml}]}\nvalue: visible\n"))
|
||||||
|
definition := configkit.Definition[map[string]any]{Version: &configkit.VersionRule{
|
||||||
|
Path: configkit.Keys("version"), Check: func(configkit.Version, *configkit.Validation) error { return nil },
|
||||||
|
}}
|
||||||
|
var err error
|
||||||
|
var resultPresent bool
|
||||||
|
wantSource := "source-1"
|
||||||
|
if underlay {
|
||||||
|
loaded, loadErr := configkit.LoadLayered(configkit.Input{Source: configkit.Bytes("main", []byte("version: main\n"))}, configkit.LayeredOptions[map[string]any]{
|
||||||
|
Definition: definition, SourceVersionMode: mode,
|
||||||
|
Underlays: []configkit.Underlay{{Inputs: []configkit.Input{{Source: bad}}}},
|
||||||
|
})
|
||||||
|
err, resultPresent, wantSource = loadErr, loaded != nil, "source-2"
|
||||||
|
} else {
|
||||||
|
loaded, loadErr := configkit.Load(bad, configkit.Options[map[string]any]{Definition: definition, SourceVersionMode: mode})
|
||||||
|
err, resultPresent = loadErr, loaded != nil
|
||||||
|
}
|
||||||
|
var failure *configkit.LoadError
|
||||||
|
if resultPresent || !errors.As(err, &failure) {
|
||||||
|
t.Errorf("mode=%v underlay=%v: import opt-in did not fail safely", mode, underlay)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
diagnostics := failure.Diagnostics()
|
||||||
|
if len(diagnostics) != 1 || diagnostics[0].Code != configkit.CodeImportDisabled || diagnostics[0].Path.String() != "/configkit" ||
|
||||||
|
diagnostics[0].Primary == nil || diagnostics[0].Primary.SourceID != wantSource {
|
||||||
|
t.Errorf("mode=%v underlay=%v: diagnostics=%#v", mode, underlay, diagnostics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (reader *sourceVersionModeReader) Read(data []byte) (int, error) {
|
func (reader *sourceVersionModeReader) Read(data []byte) (int, error) {
|
||||||
reader.reads++
|
reader.reads++
|
||||||
return reader.Reader.Read(data)
|
return reader.Reader.Read(data)
|
||||||
|
|||||||
@@ -51,6 +51,11 @@ func assembleBaseInputTrackedForRole[T any](source Source, options Options[T], d
|
|||||||
}
|
}
|
||||||
return input, diagnostics
|
return input, diagnostics
|
||||||
}
|
}
|
||||||
|
if !options.Imports && parsed.document != nil {
|
||||||
|
if diagnostics := disabledDirectiveDiagnostics(parsed.document, Path{}); len(diagnostics) != 0 {
|
||||||
|
return input, diagnostics
|
||||||
|
}
|
||||||
|
}
|
||||||
var versionProcessing *sourceVersionProcessingResult
|
var versionProcessing *sourceVersionProcessingResult
|
||||||
if versionState != nil && versionState.mode != sourceVersionModeDefault {
|
if versionState != nil && versionState.mode != sourceVersionModeDefault {
|
||||||
var sourceID string
|
var sourceID string
|
||||||
@@ -84,9 +89,6 @@ func assembleBaseInputTrackedForRole[T any](source Source, options Options[T], d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !options.Imports && input.document != nil {
|
if !options.Imports && input.document != nil {
|
||||||
if diagnostics := disabledDirectiveDiagnostics(input.document, Path{}); len(diagnostics) != 0 {
|
|
||||||
return input, diagnostics
|
|
||||||
}
|
|
||||||
_, placed, err := placeDocument(input.document, destination, input.document.Location, parseLimits.document.Depth, parseLimits.document.Nodes)
|
_, placed, err := placeDocument(input.document, destination, input.document.Location, parseLimits.document.Depth, parseLimits.document.Nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return input, []Diagnostic{sourceDiagnostic(CodeSourceLimitExceeded, parsed.source.ID, "configuration exceeds the source depth or node limit after destination placement")}
|
return input, []Diagnostic{sourceDiagnostic(CodeSourceLimitExceeded, parsed.source.ID, "configuration exceeds the source depth or node limit after destination placement")}
|
||||||
|
|||||||
Reference in New Issue
Block a user