package engine import ( "errors" "path/filepath" "reflect" "testing" "gitea.maximumdirect.net/eric/ConfigKit/internal/document" ) func TestSourceVersionAbsentPathKeepsUnresolvedSegmentIntent(t *testing.T) { t.Parallel() for _, test := range []struct { name string body string path string want []pathSegment }{ {"missing member", "{}\n", "/meta/version", []pathSegment{{kind: pathSegmentKey, key: "meta"}, {kind: pathSegmentParsed, key: "version"}}}, {"scalar obstruction", "meta: false\n", "/meta/version", []pathSegment{{kind: pathSegmentKey, key: "meta"}, {kind: pathSegmentParsed, key: "version"}}}, {"unavailable index", "meta: []\n", "/meta/3/version", []pathSegment{{kind: pathSegmentKey, key: "meta"}, {kind: pathSegmentIndex, index: 3}, {kind: pathSegmentParsed, key: "version"}}}, } { t.Run(test.name, func(t *testing.T) { path, err := ParsePath(test.path) if err != nil { t.Fatal(err) } resolved := resolveSourceVersionPath(sourceVersionTestDocument(t, test.body), path) if resolved.present || !reflect.DeepEqual(resolved.resolvedPath.segments, test.want) { t.Fatalf("absent path = %#v, want %#v", resolved.resolvedPath, test.want) } if !reflect.DeepEqual(path.segments, mustParseSourceVersionPath(t, test.path).segments) { t.Fatal("lookup mutated the requested path") } }) } } func TestFragmentVersionClaimUsesAssignedSequenceProjection(t *testing.T) { t.Parallel() fragment := sourceVersionTestDocument(t, "items: [{version: v1}]\n") rangeForPeer := []sequenceRange{{sourceIndex: 1, path: Keys("items"), start: 1, end: 2}} if node := fragmentVersionClaimProjected(fragment, &VersionRule{Path: Keys("items").Index(0).Key("version")}, 1, rangeForPeer); node != nil { t.Fatalf("peer append claimed main index 0: %#v", node) } if node := fragmentVersionClaimProjected(fragment, &VersionRule{Path: Keys("items").Index(1).Key("version")}, 1, rangeForPeer); node == nil || node.Text != "v1" { t.Fatalf("assigned peer index 1 claim = %#v, want its version node", node) } mappedRange := []sequenceRange{{ sourceIndex: 1, path: Keys("items"), start: 0, end: 3, items: []sequenceItemProjection{{inputIndex: 0, outputIndex: 2}}, }} if node := fragmentVersionClaimProjected(fragment, &VersionRule{Path: Keys("items").Index(0).Key("version")}, 1, mappedRange); node != nil { t.Fatalf("unassigned mapped peer index claimed a version: %#v", node) } if node := fragmentVersionClaimProjected(fragment, &VersionRule{Path: Keys("items").Index(2).Key("version")}, 1, mappedRange); node == nil || node.Text != "v1" { t.Fatalf("mapped peer index 2 claim = %#v, want its version node", node) } nested := sourceVersionTestDocument(t, "items: [{nested: [{version: nested-v}]}]\n") nestedRanges := []sequenceRange{ {sourceIndex: 1, path: Keys("items"), start: 1, end: 2}, {sourceIndex: 1, path: Keys("items").Index(0).Key("nested"), start: 2, end: 3}, } if node := fragmentVersionClaimProjected(nested, &VersionRule{Path: Keys("items").Index(1).Key("nested").Index(2).Key("version")}, 1, nestedRanges); node == nil || node.Text != "nested-v" { t.Fatalf("nested assigned claim = %#v, want nested version", node) } ancestor := sourceVersionTestDocument(t, "items: {version: replacement}\n") if node := fragmentVersionClaim(ancestor, &VersionRule{Path: Keys("items").Index(0).Key("version")}); node == nil || node.Kind != document.Mapping { t.Fatalf("destructive sequence ancestor claim = %#v, want mapping node", node) } effective := effectiveSourceVersionRuleForPlacement(&VersionRule{Path: Keys("version")}, Keys("catalog", "entries"), sourceVersionModeRequired, placementModeSequenceItem) if got, want := effective.Path.String(), "/catalog/entries/0/version"; got != want { t.Fatalf("item effective version path = %q, want %q", got, want) } defaultRule := effectiveSourceVersionRuleForPlacement(&VersionRule{Path: Keys("version")}, Keys("catalog", "entries"), sourceVersionModeDefault, placementModeSequenceItem) if got, want := defaultRule.Path.String(), "/version"; got != want { t.Fatalf("default effective version path = %q, want %q", got, want) } } type sourceVersionMountedService struct { Version string `yaml:"version"` } type sourceVersionMountedConfig struct { Service sourceVersionMountedService `yaml:"service"` } type sourceVersionNullConfig struct { Version *string `yaml:"version"` } type sourceVersionImportGroup struct { Name string `yaml:"name"` } type sourceVersionImportConfig struct { Service struct { Version string `yaml:"version"` Groups map[string]sourceVersionImportGroup `yaml:"groups"` } `yaml:"service"` } func sourceVersionTestDocument(t *testing.T, input string) *document.Node { t.Helper() parsed, diagnostics := parseSource(Bytes("source-version.yml", []byte(input)), "source-version", defaultParseLimits()) if len(diagnostics) != 0 { t.Fatalf("parse diagnostics = %#v", diagnostics) } return parsed.document } func requireSourceVersionDiagnostic(t *testing.T, diagnostics []Diagnostic, code Code, path string) Diagnostic { t.Helper() for _, diagnostic := range diagnostics { if diagnostic.Code == code && diagnostic.Path.String() == path { return diagnostic } } t.Fatalf("diagnostics = %#v, want %s at %q", diagnostics, code, path) return Diagnostic{} } func TestSourceVersionExtractionPreservesVersionVocabulary(t *testing.T) { t.Parallel() tests := []struct { name string input string want Version }{ {name: "string", input: "version: \"app.v7\"\n", want: Version{Present: true, Text: "app.v7"}}, {name: "integer", input: "version: 123456789012345678901234567890\n", want: Version{Present: true, Text: "123456789012345678901234567890"}}, {name: "null", input: "version: null\n", want: Version{Present: true, Null: true}}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { t.Parallel() root := sourceVersionTestDocument(t, test.input) var checked Version rule := &VersionRule{Path: Keys("version"), Check: func(version Version, _ *Validation) error { checked = version return nil }} result := processSourceVersion(root, rule, sourceVersionContribution, Keys("collections", "weather"), sourceVersionModeIfPresent) if len(result.diagnostics) != 0 || !result.evidence.checked || result.evidence.version != test.want || checked != test.want { t.Fatalf("result = %#v, checked = %#v", result, checked) } if _, found := documentAtPath(result.payload, rule.Path); found { t.Fatal("accepted non-main version remained in the payload") } if node, found := documentAtPath(root, rule.Path); !found || node == nil { t.Fatal("source document was mutated while consuming its version") } if result.evidence.destination.String() != "/collections/weather" { t.Fatalf("evidence destination = %q", result.evidence.destination.String()) } }) } } func TestSourceVersionExtractionHandlesMissingAndMalformedValues(t *testing.T) { t.Parallel() tests := []struct { name string input string path Path mode sourceVersionMode role sourceVersionRole wantCode Code wantPresent bool wantCallback bool wantAbsence sourceVersionPathAbsence }{ { name: "missing mapping member is optional absence", input: "settings: {}\n", path: Keys("settings", "version"), mode: sourceVersionModeIfPresent, role: sourceVersionContribution, wantPresent: false, wantAbsence: sourceVersionMemberMissing, }, { name: "missing below scalar is optional absence", input: "settings: scalar\n", path: Keys("settings", "version"), mode: sourceVersionModeIfPresent, role: sourceVersionContribution, wantPresent: false, wantAbsence: sourceVersionPathObstructed, }, { name: "required absence reports nearest location", input: "settings: scalar\n", path: Keys("settings", "version"), mode: sourceVersionModeRequired, role: sourceVersionContribution, wantCode: CodeVersionError, wantAbsence: sourceVersionPathObstructed, }, { name: "unavailable sequence index is absence", input: "versions: [1]\n", path: Keys("versions").Index(3), mode: sourceVersionModeRequired, role: sourceVersionContribution, wantCode: CodeVersionError, wantAbsence: sourceVersionIndexUnavailable, }, { name: "required actual main absence", input: "name: demo\n", path: Keys("version"), mode: sourceVersionModeRequired, role: sourceVersionMain, wantCode: CodeVersionError, wantAbsence: sourceVersionMemberMissing, }, { name: "main optional absence invokes checker", input: "name: demo\n", path: Keys("version"), mode: sourceVersionModeIfPresent, role: sourceVersionMain, wantCallback: true, wantAbsence: sourceVersionMemberMissing, }, {name: "boolean", input: "version: true\n", path: Keys("version"), mode: sourceVersionModeIfPresent, role: sourceVersionContribution, wantCode: CodeVersionType, wantPresent: true}, {name: "fraction", input: "version: 4.5\n", path: Keys("version"), mode: sourceVersionModeIfPresent, role: sourceVersionContribution, wantCode: CodeVersionType, wantPresent: true}, {name: "mapping", input: "version: {}\n", path: Keys("version"), mode: sourceVersionModeIfPresent, role: sourceVersionContribution, wantCode: CodeVersionType, wantPresent: true}, {name: "sequence", input: "version: []\n", path: Keys("version"), mode: sourceVersionModeIfPresent, role: sourceVersionContribution, wantCode: CodeVersionType, wantPresent: true}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { t.Parallel() root := sourceVersionTestDocument(t, test.input) called := false rule := &VersionRule{Path: test.path, Check: func(Version, *Validation) error { called = true return nil }} result := processSourceVersion(root, rule, test.role, Path{}, test.mode) if called != test.wantCallback { t.Fatalf("checker called = %v, want %v", called, test.wantCallback) } if test.wantCode != "" { diagnostic := requireSourceVersionDiagnostic(t, result.diagnostics, test.wantCode, test.path.String()) if result.payload != nil { t.Fatalf("failed processing returned payload %#v", result.payload) } if diagnostic.Primary == nil || diagnostic.Primary.SourceID != "source-version" || diagnostic.Primary.Line != 1 { t.Fatalf("diagnostic location = %#v", diagnostic.Primary) } } else if len(result.diagnostics) != 0 { t.Fatalf("diagnostics = %#v", result.diagnostics) } if result.evidence == nil || result.evidence.version.Present != test.wantPresent { t.Fatalf("evidence = %#v", result.evidence) } if result.evidence.absence != test.wantAbsence { t.Fatalf("absence cause = %v, want %v", result.evidence.absence, test.wantAbsence) } if test.wantCode == CodeVersionType && (!result.evidence.redacted || result.evidence.version.Text != "") { t.Fatalf("malformed value was retained: %#v", result.evidence) } if !test.wantCallback && result.evidence.checked { t.Fatalf("evidence incorrectly records a callback: %#v", result.evidence) } }) } } func TestSourceVersionExtractionConsumesOnlySelectedNodes(t *testing.T) { t.Parallel() destination := Keys("collections", "weather") root := sourceVersionTestDocument(t, "settings:\n version: 8\n") originalSettings, _ := documentAtPath(root, Keys("settings")) result := processSourceVersion(root, &VersionRule{ Path: Keys("settings", "version"), Check: func(Version, *Validation) error { return nil }, }, sourceVersionContribution, destination, sourceVersionModeIfPresent) settings, found := documentAtPath(result.payload, Keys("settings")) if len(result.diagnostics) != 0 || !found || settings.Kind != document.Mapping || len(settings.Mapping) != 0 { t.Fatalf("payload = %#v, diagnostics = %#v", result.payload, result.diagnostics) } if settings.Location != originalSettings.Location { t.Fatalf("authored ancestor location changed: got %#v, want %#v", settings.Location, originalSettings.Location) } if original, found := documentAtPath(root, Keys("settings", "version")); !found || original.Text != "8" { t.Fatalf("original source changed: %#v, found %v", original, found) } if len(result.evidence.ancestors) != 3 || result.evidence.ancestors[1].kind != document.Mapping { t.Fatalf("ancestor shape = %#v", result.evidence.ancestors) } sequenceRoot := sourceVersionTestDocument(t, "versions: [5, 7, 9]\n") originalVersions, _ := documentAtPath(sequenceRoot, Keys("versions")) originalLastLocation := originalVersions.Sequence[2].Location sequencePath, err := ParsePath("/versions/1") if err != nil { t.Fatal(err) } sequenceResult := processSourceVersion(sequenceRoot, &VersionRule{ Path: sequencePath, Check: func(version Version, _ *Validation) error { if version.Text != "7" { t.Fatalf("checked version = %#v", version) } return nil }, }, sourceVersionContribution, Path{}, sourceVersionModeRequired) versions, found := documentAtPath(sequenceResult.payload, Keys("versions")) if len(sequenceResult.diagnostics) != 0 || !found || versions.Kind != document.Sequence || len(versions.Sequence) != 2 || versions.Sequence[0].Text != "5" || versions.Sequence[1].Text != "9" { t.Fatalf("sequence payload = %#v, diagnostics = %#v", sequenceResult.payload, sequenceResult.diagnostics) } if versions.Sequence[1].Location != originalLastLocation { t.Fatalf("remaining sequence location changed: got %#v, want %#v", versions.Sequence[1].Location, originalLastLocation) } if len(sequenceResult.evidence.resolvedPath.segments) != 2 || sequenceResult.evidence.resolvedPath.segments[1].kind != pathSegmentIndex || sequenceResult.evidence.resolvedPath.segments[1].index != 1 { t.Fatalf("original sequence path = %#v", sequenceResult.evidence.resolvedPath) } itemRoot := sourceVersionTestDocument(t, "items:\n - name: first\n - version: 12\n") itemResult := processSourceVersion(itemRoot, &VersionRule{ Path: Keys("items").Index(1).Key("version"), Check: func(Version, *Validation) error { return nil }, }, sourceVersionContribution, Path{}, sourceVersionModeIfPresent) items, found := documentAtPath(itemResult.payload, Keys("items")) if len(itemResult.diagnostics) != 0 || !found || len(items.Sequence) != 2 || items.Sequence[1].Kind != document.Mapping || len(items.Sequence[1].Mapping) != 0 { t.Fatalf("sequence mapping payload = %#v, diagnostics = %#v", itemResult.payload, itemResult.diagnostics) } emptySequenceRoot := sourceVersionTestDocument(t, "versions: [7]\n") emptySequenceResult := processSourceVersion(emptySequenceRoot, &VersionRule{ Path: Keys("versions").Index(0), Check: func(Version, *Validation) error { return nil }, }, sourceVersionContribution, Path{}, sourceVersionModeIfPresent) emptySequence, found := documentAtPath(emptySequenceResult.payload, Keys("versions")) if len(emptySequenceResult.diagnostics) != 0 || !found || emptySequence.Kind != document.Sequence || len(emptySequence.Sequence) != 0 { t.Fatalf("empty sequence payload = %#v, diagnostics = %#v", emptySequenceResult.payload, emptySequenceResult.diagnostics) } } func TestSourceVersionExtractionResolvesContextualPathSegments(t *testing.T) { t.Parallel() tests := []struct { name string input string path Path wantRemainingPath bool wantRemainingText string }{ {name: "literal numeric mapping key", input: "versions:\n \"0\": 3\n other: 4\n", path: Keys("versions", "0")}, {name: "parsed numeric mapping key", input: "versions:\n \"0\": 3\n other: 4\n", path: mustParseSourceVersionPath(t, "/versions/0")}, {name: "parsed sequence index", input: "versions: [3, 4]\n", path: mustParseSourceVersionPath(t, "/versions/0"), wantRemainingPath: true, wantRemainingText: "4"}, {name: "explicit sequence index", input: "versions: [3, 4]\n", path: Keys("versions").Index(0), wantRemainingPath: true, wantRemainingText: "4"}, {name: "escaped mapping key", input: "a/b:\n version: 3\n", path: mustParseSourceVersionPath(t, "/a~1b/version")}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { t.Parallel() root := sourceVersionTestDocument(t, test.input) result := processSourceVersion(root, &VersionRule{ Path: test.path, Check: func(version Version, _ *Validation) error { if version.Text != "3" { t.Errorf("checked version = %#v", version) } return nil }, }, sourceVersionContribution, Path{}, sourceVersionModeIfPresent) if len(result.diagnostics) != 0 { t.Fatalf("diagnostics = %#v", result.diagnostics) } remaining, found := documentAtPath(result.payload, test.path) if found != test.wantRemainingPath || found && remaining.Text != test.wantRemainingText { t.Fatalf("remaining selected path = %#v, found = %v", remaining, found) } if !result.evidence.version.Present || result.evidence.version.Text != "3" { t.Fatalf("evidence = %#v", result.evidence) } }) } } func TestSourceVersionExtractionRejectsStructuralOverlap(t *testing.T) { t.Parallel() tests := []struct { name string input string path Path wantCode Code }{ { name: "inside import declaration", input: "configkit:\n imports:\n - path: child.yml\n", path: Keys("configkit", "imports").Index(0).Key("path"), wantCode: CodeVersionError, }, { name: "extends control", input: "settings:\n extends: parent\n", path: Keys("settings", "extends"), wantCode: CodeVersionError, }, { name: "invalid extends subtree", input: "settings:\n extends:\n version: 1\n", path: Keys("settings", "extends", "version"), wantCode: CodeVersionError, }, { name: "malformed directive cannot be consumed", input: "configkit:\n imports: true\n", path: Keys("configkit", "imports"), wantCode: CodeImportInvalid, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { t.Parallel() root := sourceVersionTestDocument(t, test.input) called := false result := processSourceVersion(root, &VersionRule{Path: test.path, Check: func(Version, *Validation) error { called = true return nil }}, sourceVersionContribution, Path{}, sourceVersionModeIfPresent) diagnostic := requireSourceVersionDiagnostic(t, result.diagnostics, test.wantCode, test.path.String()) if called || result.payload != nil { t.Fatalf("invalid overlap produced payload %#v or called checker %v", result.payload, called) } if test.wantCode == CodeVersionError && (result.evidence == nil || !result.evidence.redacted || result.evidence.version.Text != "") { t.Fatalf("overlap evidence was not conservatively redacted: %#v", result.evidence) } if diagnostic.Primary == nil || diagnostic.Primary.SourceID != "source-version" { t.Fatalf("diagnostic location = %#v", diagnostic.Primary) } }) } unrelatedRoot := sourceVersionTestDocument(t, "configkit:\n imports:\n - path: child.yml\nmetadata:\n version: 4\n") unrelatedResult := processSourceVersion(unrelatedRoot, &VersionRule{ Path: Keys("metadata", "version"), Check: func(Version, *Validation) error { return nil }, }, sourceVersionContribution, Path{}, sourceVersionModeIfPresent) metadata, found := documentAtPath(unrelatedResult.payload, Keys("metadata")) if len(unrelatedResult.diagnostics) != 0 || !found || len(metadata.Mapping) != 0 || len(unrelatedResult.imports) != 1 { t.Fatalf("unrelated directive result = %#v", unrelatedResult) } ordinaryRoot := sourceVersionTestDocument(t, "extends_version: 4\n") ordinaryResult := processSourceVersion(ordinaryRoot, &VersionRule{ Path: Keys("extends_version"), Check: func(Version, *Validation) error { return nil }, }, sourceVersionContribution, Path{}, sourceVersionModeIfPresent) if len(ordinaryResult.diagnostics) != 0 || ordinaryResult.payload == nil { t.Fatalf("ordinary extends_version key was rejected: %#v", ordinaryResult) } } func TestSourceVersionDefaultModeDoesNotCheckOrConsume(t *testing.T) { t.Parallel() root := sourceVersionTestDocument(t, "version: 2\n") called := false result := processSourceVersion(root, &VersionRule{Path: Keys("version"), Check: func(Version, *Validation) error { called = true return nil }}, sourceVersionContribution, Path{}, sourceVersionModeDefault) if len(result.diagnostics) != 0 || called || result.evidence != nil { t.Fatalf("default result = %#v, checker called = %v", result, called) } if node, found := documentAtPath(result.payload, Keys("version")); !found || node.Text != "2" { t.Fatalf("default payload = %#v", result.payload) } } func TestSourceVersionNoSourceMainRetainsAbsentCallback(t *testing.T) { t.Parallel() for _, test := range []struct { name string mode sourceVersionMode }{ {name: "if present", mode: sourceVersionModeIfPresent}, {name: "required", mode: sourceVersionModeRequired}, } { t.Run(test.name, func(t *testing.T) { t.Parallel() called := false result := processSourceVersion(nil, &VersionRule{ Path: Keys("version"), Check: func(version Version, _ *Validation) error { called = true if version != (Version{}) { t.Errorf("NoSource version = %#v", version) } return nil }, }, sourceVersionMain, Path{}, test.mode) if !called || len(result.diagnostics) != 0 || result.evidence != nil || result.payload != nil { t.Fatalf("NoSource result = %#v, callback called = %v", result, called) } }) } } func TestSourceVersionLoadChecksMountedMainLocallyAndProtectsEffectivePath(t *testing.T) { t.Parallel() checks := 0 definition := Definition[sourceVersionMountedConfig]{Version: &VersionRule{ Path: Keys("version"), Check: func(version Version, validation *Validation) error { checks++ if !version.Present || version.Null || version.Text != "9007199254740993" { return errors.New("unexpected source-local version") } validation.Warning(Path{}, "advisory") return nil }, }} main := Input{Source: Bytes("main.yml", []byte("version: 9007199254740993\n")), Destination: Keys("service")} loaded, err := LoadLayered(main, testSecretBinding(), LayeredOptions[sourceVersionMountedConfig]{ Definition: definition, SourceVersionMode: sourceVersionModeRequired, }) if err != nil || loaded == nil { t.Fatalf("mounted main load = %#v, %v", loaded, err) } if loaded.Config.Service.Version != "9007199254740993" || checks != 1 { t.Fatalf("mounted main config/callbacks = %#v, %d", loaded.Config, checks) } warnings := testLoaded(loaded).Diagnostics() if len(warnings) != 1 || warnings[0].Code != CodeVersionWarning || warnings[0].Severity != SeverityWarning { t.Fatalf("mounted main warnings = %#v", warnings) } checks = 0 _, err = LoadLayered(main, testSecretBinding(), LayeredOptions[sourceVersionMountedConfig]{ Definition: definition, SourceVersionMode: sourceVersionModeRequired, Overrides: []Override{{Path: Keys("service").Key("version"), Value: "4", Flag: "--version"}}, }) var loadErr *LoadError if !errors.As(err, &loadErr) { t.Fatalf("mounted protected override error = %T %v, want *LoadError", err, err) } requireSourceVersionDiagnostic(t, loadErr.Diagnostics(), CodeOverrideVersion, "/service/version") if checks != 1 { t.Fatalf("mounted protected override callbacks = %d, want 1", checks) } } func TestSourceVersionItemPlacementKeepsLocalChecksAndProtectsProjectedPath(t *testing.T) { t.Parallel() for _, test := range []struct { name string load func(Definition[map[string]any]) error }{ { name: "ordinary", load: func(definition Definition[map[string]any]) error { _, err := Load(Mapping("main", map[string]any{"version": "v1", "name": "ordinary"}), testSecretBinding(), Options[map[string]any]{ Definition: definition, SourceVersionMode: sourceVersionModeRequired, destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem, Overrides: []Override{{Path: Keys("catalog", "entries"), Value: []any{}, Flag: "--entries"}}, }) return err }, }, { name: "layered", load: func(definition Definition[map[string]any]) error { _, err := LoadLayered(Input{Source: Mapping("main", map[string]any{"version": "v1", "name": "layered"}), Destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem}, testSecretBinding(), LayeredOptions[map[string]any]{ Definition: definition, SourceVersionMode: sourceVersionModeRequired, Overrides: []Override{{Path: Keys("catalog", "entries"), Value: []any{}, Flag: "--entries"}}, }) return err }, }, } { t.Run(test.name, func(t *testing.T) { t.Parallel() checks := 0 definition := Definition[map[string]any]{Version: &VersionRule{ Path: Keys("version"), Check: func(version Version, _ *Validation) error { checks++ if !version.Present || version.Text != "v1" { t.Errorf("source-local version = %#v, want v1", version) } return nil }, }} err := test.load(definition) var loadErr *LoadError if !errors.As(err, &loadErr) { t.Fatalf("item placement override error = %T %v, want *LoadError", err, err) } requireSourceVersionDiagnostic(t, loadErr.Diagnostics(), CodeOverrideVersion, "/catalog/entries") if checks != 1 { t.Fatalf("source-version checker called %d times, want once", checks) } }) } } func TestSourceVersionItemEvidenceUsesProjectedSensitivityPath(t *testing.T) { t.Parallel() const canary = "PROJECTED-VERSION-EVIDENCE-CANARY" secretPath := Keys("catalog", "entries").Index(0).Key("version") loaded, err := Load(Mapping("main", map[string]any{"version": canary}), testSecretBinding(), Options[map[string]any]{ Definition: Definition[map[string]any]{ Version: &VersionRule{Path: Keys("version"), Check: func(Version, *Validation) error { return nil }}, Secret: func(path Path) bool { return path.String() == secretPath.String() }, }, SourceVersionMode: sourceVersionModeRequired, destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem, }) if err != nil { t.Fatalf("item source-version load: %v", err) } sources := loaded.Inspection.Sources() if len(sources) != 1 || sources[0].VersionCheck == nil || !sources[0].VersionCheck.Redacted || sources[0].VersionCheck.Version.Text != "" { t.Fatalf("projected source-version evidence was not redacted: %#v", sources) } } func TestSourceVersionLoadChecksNullAndNoSourceMain(t *testing.T) { t.Parallel() t.Run("required actual main absence fails before the checker", func(t *testing.T) { t.Parallel() checks := 0 _, err := Load(Bytes("main.yml", []byte("other: value\n")), testSecretBinding(), Options[sourceVersionNullConfig]{ SourceVersionMode: sourceVersionModeRequired, Definition: Definition[sourceVersionNullConfig]{Version: &VersionRule{ Path: Keys("version"), Check: func(Version, *Validation) error { checks++; return nil }, }}, }) var loadErr *LoadError if !errors.As(err, &loadErr) { t.Fatalf("missing required main version = %T %v, want *LoadError", err, err) } requireSourceVersionDiagnostic(t, loadErr.Diagnostics(), CodeVersionError, "/version") if checks != 0 { t.Fatalf("missing required main invoked checker %d times", checks) } }) t.Run("required null is passed to the checker", func(t *testing.T) { t.Parallel() checks := 0 loaded, err := Load(Bytes("main.yml", []byte("version: null\n")), testSecretBinding(), Options[sourceVersionNullConfig]{ SourceVersionMode: sourceVersionModeRequired, Definition: Definition[sourceVersionNullConfig]{Version: &VersionRule{ Path: Keys("version"), Check: func(version Version, _ *Validation) error { checks++ if !version.Present || !version.Null || version.Text != "" { return errors.New("unexpected null version") } return nil }, }}, }) if err != nil || loaded == nil || checks != 1 || loaded.Config.Version != nil { t.Fatalf("required null load = %#v, callbacks %d, %v", loaded, checks, err) } }) for _, mode := range []sourceVersionMode{sourceVersionModeIfPresent, sourceVersionModeRequired} { mode := mode t.Run(map[sourceVersionMode]string{sourceVersionModeIfPresent: "if-present", sourceVersionModeRequired: "required"}[mode], func(t *testing.T) { t.Parallel() checks := 0 loaded, err := Load(NoSource(), testSecretBinding(), Options[sourceVersionNullConfig]{ SourceVersionMode: mode, Definition: Definition[sourceVersionNullConfig]{Version: &VersionRule{ Path: Keys("version"), Check: func(version Version, _ *Validation) error { checks++ if version.Present || version.Null { return errors.New("NoSource should report absence") } return nil }, }}, }) if err != nil || loaded == nil || checks != 1 || len(testLoaded(loaded).Sources()) != 0 { t.Fatalf("NoSource load = %#v, callbacks %d, %v", loaded, checks, err) } }) } } func TestSourceVersionLoadReportsMountedMainErrorsAtLocalPath(t *testing.T) { t.Parallel() checks := 0 _, err := LoadLayered(Input{ Source: Bytes("main.yml", []byte("version: 5\n")), Destination: Keys("service"), }, testSecretBinding(), LayeredOptions[sourceVersionMountedConfig]{ SourceVersionMode: sourceVersionModeRequired, Definition: Definition[sourceVersionMountedConfig]{Version: &VersionRule{ Path: Keys("version"), Check: func(Version, *Validation) error { checks++; return errors.New("rejected") }, }}, }) var loadErr *LoadError if !errors.As(err, &loadErr) { t.Fatalf("mounted main rejection = %T %v, want *LoadError", err, err) } requireSourceVersionDiagnostic(t, loadErr.Diagnostics(), CodeVersionHookFailed, "/version") if checks != 1 { t.Fatalf("mounted main checker calls = %d, want 1", checks) } } func TestSourceVersionLoadChecksMainBeforeLayeredAcquisition(t *testing.T) { t.Parallel() checks := 0 _, err := LoadLayered(Input{Source: Bytes("main.yml", []byte("version: 5\n"))}, testSecretBinding(), LayeredOptions[sourceVersionNullConfig]{ SourceVersionMode: sourceVersionModeIfPresent, Definition: Definition[sourceVersionNullConfig]{Version: &VersionRule{ Path: Keys("version"), Check: func(Version, *Validation) error { checks++; return errors.New("rejected") }, }}, Underlays: []Underlay{{Inputs: []Input{{Source: Bytes("unread.yml", []byte("[malformed"))}}}}, }) var loadErr *LoadError if !errors.As(err, &loadErr) { t.Fatalf("main rejection = %T %v, want *LoadError", err, err) } requireSourceVersionDiagnostic(t, loadErr.Diagnostics(), CodeVersionHookFailed, "/version") if checks != 1 { t.Fatalf("main checker calls = %d, want 1", checks) } } func TestSourceVersionEnabledBuildsSchemaBeforeMainCallback(t *testing.T) { t.Parallel() checks := 0 _, err := Load(Bytes("main.yml", []byte("version: 5\n")), testSecretBinding(), Options[int]{ SourceVersionMode: sourceVersionModeIfPresent, Definition: Definition[int]{Version: &VersionRule{ Path: Keys("version"), Check: func(Version, *Validation) error { checks++; return nil }, }}, }) if err == nil || checks != 0 { t.Fatalf("invalid schema load = %v, checker calls %d; want schema failure before callback", err, checks) } } func TestSourceVersionLoadRejectsOptionsBeforeReadingMain(t *testing.T) { t.Parallel() checkerCalls := 0 definition := Definition[sourceVersionNullConfig]{Version: &VersionRule{ Path: Keys("version"), Check: func(Version, *Validation) error { checkerCalls++; return nil }, }} _, err := Load(Bytes("malformed.yml", []byte("[not valid")), testSecretBinding(), Options[sourceVersionNullConfig]{ Definition: definition, SourceVersionMode: sourceVersionMode(255), }) var loadErr *LoadError if !errors.As(err, &loadErr) { t.Fatalf("invalid-mode error = %T %v, want *LoadError", err, err) } requireSourceVersionDiagnostic(t, loadErr.Diagnostics(), CodeOptionsInvalid, "") if checkerCalls != 0 { t.Fatalf("invalid mode invoked checker %d times", checkerCalls) } _, err = Load(Bytes("malformed.yml", []byte("[not valid")), testSecretBinding(), Options[sourceVersionNullConfig]{SourceVersionMode: sourceVersionModeRequired}) if !errors.As(err, &loadErr) { t.Fatalf("missing-rule error = %T %v, want *LoadError", err, err) } requireSourceVersionDiagnostic(t, loadErr.Diagnostics(), CodeOptionsInvalid, "") _, err = LoadLayered(Input{Source: Bytes("malformed.yml", []byte("[not valid"))}, testSecretBinding(), LayeredOptions[sourceVersionNullConfig]{ SourceVersionMode: sourceVersionModeRequired, }) if !errors.As(err, &loadErr) { t.Fatalf("layered missing-rule error = %T %v, want *LoadError", err, err) } requireSourceVersionDiagnostic(t, loadErr.Diagnostics(), CodeOptionsInvalid, "") } func TestSourceVersionImportsCheckNestedAndGlobSourcesBeforeComposition(t *testing.T) { t.Parallel() directory := t.TempDir() mainPath := writeImportFile(t, directory, "main.yml", `version: main configkit: imports: - glob: fragments/*.yml destination: [groups] `) firstPath := writeImportFile(t, directory, "fragments/a.yml", `version: first configkit: imports: - path: nested/child.yml destination: [nested] a: {name: A} `) nestedPath := writeImportFile(t, directory, "fragments/nested/child.yml", "version: nested\nname: N\n") secondPath := writeImportFile(t, directory, "fragments/b.yml", "version: second\nb: {name: B}\n") checked := make(map[string]int) loaded, err := LoadLayered(Input{ Source: File(mainPath), Imports: true, Destination: Keys("service"), }, testSecretBinding(), LayeredOptions[sourceVersionImportConfig]{ SourceVersionMode: sourceVersionModeRequired, Definition: Definition[sourceVersionImportConfig]{Version: &VersionRule{ Path: Keys("version"), Check: func(version Version, validation *Validation) error { checked[version.Text]++ validation.Warning(Path{}, "accepted") return nil }, }}, }) if err != nil || loaded == nil { var loadErr *LoadError if errors.As(err, &loadErr) { t.Fatalf("source-local import load = %#v, diagnostics %#v", loaded, loadErr.Diagnostics()) } t.Fatalf("source-local import load = %#v, %v", loaded, err) } if loaded.Config.Service.Version != "main" || loaded.Config.Service.Groups["a"].Name != "A" || loaded.Config.Service.Groups["b"].Name != "B" || loaded.Config.Service.Groups["nested"].Name != "N" { t.Fatalf("mounted source-local imports = %#v", loaded.Config.Service) } if len(checked) != 4 || checked["main"] != 1 || checked["first"] != 1 || checked["nested"] != 1 || checked["second"] != 1 { t.Fatalf("checked declarations = %#v, want each independent source once", checked) } warnings := testLoaded(loaded).Diagnostics() if len(warnings) != 4 { t.Fatalf("accepted source warnings = %#v, want one per checked source", warnings) } for _, warning := range warnings { if warning.Code != CodeVersionWarning || warning.Severity != SeverityWarning { t.Fatalf("accepted source warning = %#v", warning) } } wantDestinations := map[string]string{ canonicalTestPath(t, mainPath): "/service", canonicalTestPath(t, firstPath): "/service/groups", canonicalTestPath(t, secondPath): "/service/groups", canonicalTestPath(t, nestedPath): "/service/groups/nested", } for _, source := range testLoaded(loaded).Sources() { want, found := wantDestinations[source.Path] if !found || source.Destination.String() != want { t.Errorf("source %q destination = %q, want %q", source.Path, source.Destination.String(), want) } delete(wantDestinations, source.Path) } if len(wantDestinations) != 0 { t.Errorf("sources not retained: %#v", wantDestinations) } } func TestSourceVersionImportsRejectHiddenAndMissingDeclarations(t *testing.T) { t.Parallel() t.Run("rejected child is not hidden by the main declaration", func(t *testing.T) { t.Parallel() directory := t.TempDir() mainPath := writeImportFile(t, directory, "main.yml", "version: main\nconfigkit: {imports: [{path: child.yml}]}\n") writeImportFile(t, directory, "child.yml", "version: rejected\n") checks := 0 _, err := Load(File(mainPath), testSecretBinding(), Options[sourceVersionNullConfig]{ Imports: true, SourceVersionMode: sourceVersionModeIfPresent, Definition: Definition[sourceVersionNullConfig]{Version: &VersionRule{ Path: Keys("version"), Check: func(version Version, _ *Validation) error { checks++ if version.Text == "rejected" { return errors.New("rejected") } return nil }, }}, }) var loadErr *LoadError if !errors.As(err, &loadErr) { t.Fatalf("rejected child error = %T %v, want *LoadError", err, err) } diagnostic := requireSourceVersionDiagnostic(t, loadErr.Diagnostics(), CodeVersionHookFailed, "/version") if diagnostic.Primary == nil || diagnostic.Primary.SourceID != "source-2" || checks != 2 { t.Fatalf("rejected child diagnostic/callbacks = %#v, %d", diagnostic, checks) } }) t.Run("required child omission reports its nearest source location", func(t *testing.T) { t.Parallel() directory := t.TempDir() mainPath := writeImportFile(t, directory, "main.yml", "version: main\nconfigkit: {imports: [{path: child.yml}]}\n") writeImportFile(t, directory, "child.yml", "name: child\n") checks := 0 _, err := Load(File(mainPath), testSecretBinding(), Options[sourceVersionNullConfig]{ Imports: true, SourceVersionMode: sourceVersionModeRequired, Definition: Definition[sourceVersionNullConfig]{Version: &VersionRule{ Path: Keys("version"), Check: func(Version, *Validation) error { checks++; return nil }, }}, }) var loadErr *LoadError if !errors.As(err, &loadErr) { t.Fatalf("required child omission = %T %v, want *LoadError", err, err) } diagnostic := requireSourceVersionDiagnostic(t, loadErr.Diagnostics(), CodeVersionError, "/version") if diagnostic.Primary == nil || diagnostic.Primary.SourceID != "source-2" || diagnostic.Primary.Line != 1 || checks != 1 { t.Fatalf("required omission diagnostic/callbacks = %#v, %d", diagnostic, checks) } }) t.Run("optional missing child remains absent", func(t *testing.T) { t.Parallel() directory := t.TempDir() mainPath := writeImportFile(t, directory, "main.yml", `version: main configkit: imports: - path: missing.yml `) checks := 0 loaded, err := Load(File(mainPath), testSecretBinding(), Options[sourceVersionNullConfig]{ Imports: true, SourceVersionMode: sourceVersionModeRequired, Definition: Definition[sourceVersionNullConfig]{Version: &VersionRule{ Path: Keys("version"), Check: func(Version, *Validation) error { checks++; return nil }, }}, }) if err != nil || loaded == nil || checks != 1 || len(testLoaded(loaded).Sources()) != 1 { t.Fatalf("optional missing source = %#v, checks %d, %v", loaded, checks, err) } }) } func TestSourceVersionUnderlaysCheckDistinctMountedDeclarations(t *testing.T) { t.Parallel() var checked []string definition := Definition[map[string]any]{Version: &VersionRule{ Path: Keys("meta", "version"), Check: func(version Version, validation *Validation) error { checked = append(checked, version.Text) if version.Text == "peer-a" || version.Text == "peer-c" { validation.Warning(Path{}, "accepted with advisory") } return nil }, }} main := Input{ Source: Bytes("main", []byte("meta: {version: main-v}\nservice: primary\n")), Destination: Keys("service"), } first := Input{ Source: Bytes("peer-a", []byte("meta:\n version: peer-a\nvalues: {first: one}\n")), Destination: Keys("defaults", "first"), } second := Input{ Source: Bytes("peer-b", []byte("meta:\n version: peer-b\nvalues: {second: two}\n")), Destination: Keys("defaults", "second"), } third := Input{ Source: Bytes("peer-c", []byte("meta:\n version: peer-c\nvalues: {third: three}\n")), Destination: Keys("defaults", "third"), } loaded, err := LoadLayered(main, testSecretBinding(), LayeredOptions[map[string]any]{ Definition: definition, SourceVersionMode: sourceVersionModeRequired, Underlays: []Underlay{{Inputs: []Input{first, second}}, {Inputs: []Input{third}}}, }) if err != nil { t.Fatalf("LoadLayered: %v", err) } if len(checked) != 4 { t.Fatalf("checked declarations = %#v, want main and all underlays", checked) } for _, want := range []string{"main-v", "peer-a", "peer-b", "peer-c"} { found := false for _, got := range checked { found = found || got == want } if !found { t.Errorf("checked declarations %#v do not include %q", checked, want) } } if len(loaded.Inspection.Diagnostics()) != 2 || loaded.Inspection.Diagnostics()[0].Code != CodeVersionWarning || loaded.Inspection.Diagnostics()[1].Code != CodeVersionWarning { t.Fatalf("accepted underlay warning was not retained: %#v", loaded.Inspection.Diagnostics()) } sources := loaded.Inspection.Sources() if len(sources) != 4 || sources[1].Layer != LayerUnderlay || sources[1].UnderlayIndex != 1 || sources[2].Layer != LayerUnderlay || sources[2].UnderlayIndex != 1 || sources[3].Layer != LayerUnderlay || sources[3].UnderlayIndex != 2 { t.Fatalf("underlay source records = %#v", sources) } defaults, ok := loaded.Config["defaults"].(map[string]any) if !ok { t.Fatalf("defaults = %#v", loaded.Config["defaults"]) } firstValue, ok := defaults["first"].(map[string]any) if !ok || firstValue["values"] == nil { t.Fatalf("first mounted contribution = %#v", defaults["first"]) } if meta, ok := firstValue["meta"].(map[string]any); !ok || len(meta) != 0 { t.Fatalf("consumed nested declaration did not preserve its empty ancestor: %#v", firstValue["meta"]) } } func TestSourceVersionUnderlaysRejectDeclarationsHiddenByMain(t *testing.T) { t.Parallel() var checked []string loaded, err := LoadLayered(Input{Source: Bytes("main", []byte("meta: {version: main-v}\nservice: primary\n"))}, testSecretBinding(), LayeredOptions[map[string]any]{ Definition: Definition[map[string]any]{Version: &VersionRule{ Path: Keys("meta", "version"), Check: func(version Version, _ *Validation) error { checked = append(checked, version.Text) if version.Text == "rejected-peer" { return errors.New("peer declaration is not accepted") } return nil }, }}, SourceVersionMode: sourceVersionModeIfPresent, Underlays: []Underlay{{Inputs: []Input{{Source: Bytes("underlay", []byte("meta: {version: rejected-peer}\nservice: shadowed\n"))}}}}, }) if err == nil || loaded != nil { t.Fatalf("LoadLayered = %#v, %v, want hidden underlay rejection", loaded, err) } loadErr, ok := err.(*LoadError) if !ok || len(loadErr.Diagnostics()) != 1 || loadErr.Diagnostics()[0].Code != CodeVersionHookFailed { t.Fatalf("underlay rejection diagnostics = %#v", err) } if len(checked) != 2 || checked[0] != "main-v" || checked[1] != "rejected-peer" { t.Fatalf("checked declarations = %#v", checked) } } func TestSourceVersionUnderlaysRequireActualHeadersButSkipAbsentSources(t *testing.T) { t.Parallel() newOptions := func(underlays []Underlay) LayeredOptions[map[string]any] { return LayeredOptions[map[string]any]{ Definition: Definition[map[string]any]{Version: &VersionRule{ Path: Keys("meta", "version"), Check: func(Version, *Validation) error { return nil }, }}, SourceVersionMode: sourceVersionModeRequired, Underlays: underlays, } } main := Input{Source: Bytes("main", []byte("meta: {version: main-v}\n"))} t.Run("required absence", func(t *testing.T) { loaded, err := LoadLayered(main, testSecretBinding(), newOptions([]Underlay{{Inputs: []Input{{Source: Bytes("missing", []byte("value: present\n"))}}}})) if err == nil || loaded != nil { t.Fatalf("LoadLayered = %#v, %v, want missing underlay declaration", loaded, err) } loadErr, ok := err.(*LoadError) if !ok || len(loadErr.Diagnostics()) != 1 || loadErr.Diagnostics()[0].Code != CodeVersionError { t.Fatalf("missing underlay diagnostics = %#v", err) } }) t.Run("empty group and NoSource", func(t *testing.T) { loaded, err := LoadLayered(main, testSecretBinding(), newOptions([]Underlay{{}, {Inputs: []Input{{Source: NoSource()}}}})) if err != nil { t.Fatalf("LoadLayered with absent contributions: %v", err) } if sources := loaded.Inspection.Sources(); len(sources) != 1 { t.Fatalf("empty groups and NoSource created source records: %#v", sources) } }) } func TestSourceVersionUnderlayImportsKeepLocalHeadersAndMountedDestinations(t *testing.T) { t.Parallel() directory := t.TempDir() underlayPath := writeImportFile(t, directory, "underlay.yml", `meta: {version: peer-root} configkit: imports: - path: nested.yml destination: [nested] root: retained `) writeImportFile(t, directory, "nested.yml", "meta: {version: peer-nested}\nname: nested\n") var checked []string loaded, err := LoadLayered(Input{ Source: Bytes("main", []byte("meta: {version: main-v}\n")), Destination: Keys("service"), }, testSecretBinding(), LayeredOptions[map[string]any]{ Definition: Definition[map[string]any]{Version: &VersionRule{ Path: Keys("meta", "version"), Check: func(version Version, _ *Validation) error { checked = append(checked, version.Text) return nil }, }}, SourceVersionMode: sourceVersionModeRequired, Underlays: []Underlay{{Inputs: []Input{{ Source: File(underlayPath), Imports: true, Destination: Keys("defaults"), }}}}, }) if err != nil { t.Fatalf("LoadLayered: %v", err) } if len(checked) != 3 { t.Fatalf("checked source declarations = %#v", checked) } for _, want := range []string{"main-v", "peer-root", "peer-nested"} { found := false for _, got := range checked { found = found || got == want } if !found { t.Errorf("checked source declarations %#v do not include %q", checked, want) } } sources := loaded.Inspection.Sources() if len(sources) != 3 || sources[1].Path != filepath.Clean(underlayPath) || sources[2].Destination.String() != "/defaults/nested" { t.Fatalf("underlay and nested import records = %#v", sources) } if sources[1].Layer != LayerUnderlay || sources[1].UnderlayIndex != 1 || sources[2].Layer != LayerUnderlay || sources[2].UnderlayIndex != 1 { t.Fatalf("underlay and nested import tiers = %#v", sources) } defaults, ok := loaded.Config["defaults"].(map[string]any) if !ok || defaults["root"] != "retained" { t.Fatalf("mounted underlay root = %#v", loaded.Config["defaults"]) } nested, ok := defaults["nested"].(map[string]any) if !ok || nested["name"] != "nested" { t.Fatalf("mounted nested import = %#v", defaults["nested"]) } } func TestSourceVersionUnderlaysProtectRemainingMountedPayload(t *testing.T) { t.Parallel() loaded, err := LoadLayered(Input{ Source: Bytes("main", []byte("meta: {version: main-v}\n")), Destination: Keys("service"), }, testSecretBinding(), LayeredOptions[map[string]any]{ Definition: Definition[map[string]any]{Version: &VersionRule{ Path: Keys("meta", "version"), Check: func(Version, *Validation) error { return nil }, }}, SourceVersionMode: sourceVersionModeRequired, Underlays: []Underlay{{Inputs: []Input{{Source: Bytes("underlay", []byte( "meta: {version: accepted}\nservice: {meta: {version: payload}}\n", ))}}}}, }) if err == nil || loaded != nil { t.Fatalf("LoadLayered = %#v, %v, want protected remaining payload rejection", loaded, err) } loadErr, ok := err.(*LoadError) if !ok || len(loadErr.Diagnostics()) != 1 || loadErr.Diagnostics()[0].Code != CodeUnderlayVersion { t.Fatalf("remaining payload diagnostics = %#v", err) } } func TestSourceVersionEvidencePropagatesThroughRecordedResolutionDependency(t *testing.T) { t.Parallel() type credentials struct { Password string `yaml:"password"` Public string `yaml:"public"` } type configuration struct { Credentials credentials `yaml:"credentials"` Derived string `yaml:"derived"` } load := func(header string) *Loaded[configuration] { t.Helper() loaded, err := LoadLayered(Input{ Source: Bytes("main", []byte("credentials: {password: main-value}\n")), }, testSecretBinding(), LayeredOptions[configuration]{ SourceVersionMode: sourceVersionModeIfPresent, Underlays: []Underlay{{Inputs: []Input{{Source: Bytes("underlay", []byte( "credentials:\n version: "+header+"\n public: visible-neighbor\n", ))}}}}, Definition: Definition[configuration]{ Version: &VersionRule{ Path: Keys("credentials", "version"), Check: func(Version, *Validation) error { return nil }, }, Secret: func(path Path) bool { return path.String() == "/credentials/version" }, Resolve: func(value *configuration, resolution *Resolution) error { value.Derived = value.Credentials.Password resolution.Record(Keys("derived"), ChangeNormalization, "derive from credentials", Keys("credentials")) return nil }, }, }) if err != nil || loaded == nil { t.Fatalf("LoadLayered with header %q = %#v, %v", header, loaded, err) } return loaded } left, right := load("202"), load("303") if left.Config.Derived != "main-value" || right.Config.Derived != "main-value" { t.Fatalf("derived values = %q, %q", left.Config.Derived, right.Config.Derived) } if !left.Inspection.secrets["/derived"] || !right.Inspection.secrets["/derived"] { t.Fatalf("evidence did not activate recorded dependency closure: left=%#v right=%#v", left.Inspection.secrets, right.Inspection.secrets) } derived, found := left.Inspection.Explain(Keys("derived")) if !found || !derived.Effective.Redacted { t.Fatalf("derived explanation was not redacted: %#v, found=%v", derived, found) } public, found := left.Inspection.Explain(Keys("credentials", "public")) if !found || public.Effective.Redacted || public.Effective.YAML != "visible-neighbor\n" { t.Fatalf("neighboring payload = %#v, found=%v", public, found) } headerPath := Keys("credentials", "version") if _, found := left.Inspection.Explain(headerPath); found { t.Fatal("consumed declaration created an effective or historical explanation path") } if _, found := left.Inspection.Metadata().Lookup(headerPath); found { t.Fatal("consumed declaration created a metadata path") } if differences, err := Diff(left.Inspection, right.Inspection); err != nil || len(differences) != 0 { t.Fatalf("different consumed headers changed effective diff: %#v, %v", differences, err) } } func TestSourceVersionSelectedOverlayConsumesHeaderAndRetainsWarning(t *testing.T) { t.Parallel() directory := t.TempDir() mainPath := writeImportFile(t, directory, "main.yml", "schema: {version: main-v}\nsettings: {kept: base}\nitems: [{id: base}]\n") overlayPath := writeImportFile(t, directory, "overlays/testing.yml", `schema: {version: overlay-v} configkit: sequences: - destination: [items] key: id mode: append settings: {changed: overlay} items: [{id: overlay}] `) var checked []string loaded, err := Load(File(mainPath), testSecretBinding(), Options[map[string]any]{ Overlay: "testing", SourceVersionMode: sourceVersionModeRequired, Definition: Definition[map[string]any]{Version: &VersionRule{ Path: Keys("schema", "version"), Check: func(version Version, validation *Validation) error { checked = append(checked, version.Text) if version.Text == "overlay-v" { validation.Warning(Path{}, "overlay accepted with advisory") } return nil }, }}, }) if err != nil { t.Fatalf("Load: %v", err) } if len(checked) != 2 || checked[0] != "main-v" || checked[1] != "overlay-v" { t.Fatalf("checked source declarations = %#v", checked) } if loaded.Config["schema"].(map[string]any)["version"] != "main-v" || loaded.Config["settings"].(map[string]any)["changed"] != "overlay" { t.Fatalf("overlay payload = %#v", loaded.Config) } if _, found := loaded.Config["configkit"]; found || len(loaded.Config["items"].([]any)) != 2 { t.Fatalf("overlay declarations or collection values = %#v", loaded.Config) } diagnostics := loaded.Inspection.Diagnostics() if len(diagnostics) != 1 || diagnostics[0].Code != CodeVersionWarning { t.Fatalf("overlay warning was not retained: %#v", diagnostics) } sources := loaded.Inspection.Sources() if len(sources) != 2 || sources[1].Path != filepath.Clean(overlayPath) || sources[1].Layer != LayerOverlay { t.Fatalf("overlay source records = %#v", sources) } } func TestSourceVersionSelectedOverlayRequiresAndChecksItsDeclaration(t *testing.T) { t.Parallel() t.Run("required absence", func(t *testing.T) { directory := t.TempDir() mainPath := writeImportFile(t, directory, "main.yml", "schema: {version: main-v}\n") writeImportFile(t, directory, "overlays/testing.yml", "settings: {changed: overlay}\n") loaded, err := Load(File(mainPath), testSecretBinding(), Options[map[string]any]{ Overlay: "testing", SourceVersionMode: sourceVersionModeRequired, Definition: Definition[map[string]any]{Version: &VersionRule{ Path: Keys("schema", "version"), Check: func(Version, *Validation) error { return nil }, }}, }) if err == nil || loaded != nil { t.Fatalf("Load = %#v, %v, want required overlay declaration error", loaded, err) } loadErr, ok := err.(*LoadError) if !ok || len(loadErr.Diagnostics()) != 1 || loadErr.Diagnostics()[0].Code != CodeVersionError { t.Fatalf("missing overlay diagnostics = %#v", err) } }) t.Run("checker rejection", func(t *testing.T) { directory := t.TempDir() mainPath := writeImportFile(t, directory, "main.yml", "schema: {version: main-v}\n") writeImportFile(t, directory, "overlays/testing.yml", "schema: {version: rejected-overlay}\nsettings: {changed: hidden}\n") var checked []string loaded, err := Load(File(mainPath), testSecretBinding(), Options[map[string]any]{ Overlay: "testing", SourceVersionMode: sourceVersionModeIfPresent, Definition: Definition[map[string]any]{Version: &VersionRule{ Path: Keys("schema", "version"), Check: func(version Version, _ *Validation) error { checked = append(checked, version.Text) if version.Text == "rejected-overlay" { return errors.New("overlay rejected") } return nil }, }}, }) if err == nil || loaded != nil { t.Fatalf("Load = %#v, %v, want overlay rejection", loaded, err) } loadErr, ok := err.(*LoadError) if !ok || len(loadErr.Diagnostics()) != 1 || loadErr.Diagnostics()[0].Code != CodeVersionHookFailed { t.Fatalf("overlay rejection diagnostics = %#v", err) } if len(checked) != 2 || checked[0] != "main-v" || checked[1] != "rejected-overlay" { t.Fatalf("checked source declarations = %#v", checked) } }) t.Run("structural validation precedes declaration processing", func(t *testing.T) { directory := t.TempDir() mainPath := writeImportFile(t, directory, "main.yml", "schema: {version: main-v}\n") writeImportFile(t, directory, "overlays/testing.yml", "configkit: {imports: true}\nschema: {version: overlay-v}\n") checks := 0 loaded, err := Load(File(mainPath), testSecretBinding(), Options[map[string]any]{ Overlay: "testing", SourceVersionMode: sourceVersionModeRequired, Definition: Definition[map[string]any]{Version: &VersionRule{ Path: Keys("schema", "version"), Check: func(Version, *Validation) error { checks++; return nil }, }}, }) if err == nil || loaded != nil { t.Fatalf("Load = %#v, %v, want structural overlay rejection", loaded, err) } loadErr, ok := err.(*LoadError) if !ok || len(loadErr.Diagnostics()) != 1 || loadErr.Diagnostics()[0].Code != CodeOverlayDirective { t.Fatalf("structural overlay diagnostics = %#v", err) } if checks != 1 { t.Fatalf("version checker calls = %d, want main only", checks) } }) } func TestSourceVersionOverlayLeavesCLIOverridesHeaderFree(t *testing.T) { t.Parallel() checks := 0 loaded, err := Load(Bytes("main", []byte("schema: {version: main-v}\nsettings: {base: value}\n")), testSecretBinding(), Options[map[string]any]{ SourceVersionMode: sourceVersionModeRequired, Definition: Definition[map[string]any]{Version: &VersionRule{ Path: Keys("schema", "version"), Check: func(Version, *Validation) error { checks++ return nil }, }}, Overrides: []Override{{Path: Keys("settings", "cli"), Value: "supplied", Flag: "--settings.cli"}}, }) if err != nil { t.Fatalf("Load with CLI override: %v", err) } if checks != 1 || loaded.Config["settings"].(map[string]any)["cli"] != "supplied" { t.Fatalf("checker count/configuration = %d, %#v", checks, loaded.Config) } } func TestSourceVersionOverlayProtectsMountedMainAndPreservesSequenceCoordinates(t *testing.T) { t.Parallel() t.Run("mounted main ownership", func(t *testing.T) { directory := t.TempDir() mainPath := writeImportFile(t, directory, "main.yml", "meta: {version: main-v}\n") writeImportFile(t, directory, "overlays/testing.yml", "meta: {version: overlay-v}\nservice: {meta: {version: payload}}\n") _, err := LoadLayered(Input{Source: File(mainPath), Destination: Keys("service")}, testSecretBinding(), LayeredOptions[map[string]any]{ Overlay: "testing", OverlayFilesystem: &FilesystemContext{BaseDir: directory, Root: directory}, SourceVersionMode: sourceVersionModeRequired, Definition: Definition[map[string]any]{Version: &VersionRule{ Path: Keys("meta", "version"), Check: func(Version, *Validation) error { return nil }, }}, }) loadErr, ok := err.(*LoadError) if !ok || len(loadErr.Diagnostics()) != 1 || loadErr.Diagnostics()[0].Code != CodeOverlayVersion { t.Fatalf("mounted overlay ownership error = %#v", err) } }) t.Run("sequence location remains source-local after deletion", func(t *testing.T) { directory := t.TempDir() mainPath := writeImportFile(t, directory, "main.yml", "base: true\n") writeImportFile(t, directory, "overlays/testing.yml", "versions:\n - before\n - overlay-version\n - after\n") main, diagnostics := parseSource(File(mainPath), "source-main", defaultParseLimits()) if len(diagnostics) != 0 { t.Fatalf("parse main: %#v", diagnostics) } localRule := &VersionRule{Path: Keys("versions").Index(1), Check: func(version Version, _ *Validation) error { if version.Text != "overlay-version" { t.Errorf("checked version = %#v", version) } return nil }} effectiveRule := effectiveSourceVersionRule(localRule, Keys("service"), sourceVersionModeRequired) state := &sourceVersionState{localRule: localRule, effectiveRule: effectiveRule, mode: sourceVersionModeRequired} base, compositionDiagnostics := composeDocuments(&document.Node{Kind: document.Mapping}) if len(compositionDiagnostics) != 0 { t.Fatalf("compose base: %#v", compositionDiagnostics) } assembly := newAssemblyAccumulator(base) _, diagnostics = loadSelectedOverlayIntoWithVersion( File(mainPath), nil, main, assembly, sourceInfos(main.source), "testing", effectiveRule, defaultImportLimits(), state, ) if len(diagnostics) != 0 { t.Fatalf("load selected overlay: %#v", diagnostics) } if len(state.evidence) != 1 || state.evidence[0].resolvedPath.String() != "/versions/1" || state.evidence[0].location == nil || state.evidence[0].location.Line != 3 { t.Fatalf("sequence evidence lost original coordinates: %#v", state.evidence) } versions, found := documentAtPath(assembly.current.root, Keys("versions")) if !found || versions.Kind != document.Sequence || len(versions.Sequence) != 2 || versions.Sequence[0].Text != "before" || versions.Sequence[1].Text != "after" { t.Fatalf("remaining overlay sequence = %#v", versions) } }) } func TestSourceVersionImportAccountingIncludesConsumedHeaderNodes(t *testing.T) { t.Parallel() directory := t.TempDir() mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: child.yml}]}\n") childPath := writeImportFile(t, directory, "child.yml", "version: accepted\nname: child\n") main := parseImportMain(t, mainPath) child, diagnostics := parseSource(File(childPath), "source-child", defaultParseLimits()) if len(diagnostics) != 0 { t.Fatalf("child parse diagnostics = %#v", diagnostics) } rule := &VersionRule{Path: Keys("version"), Check: func(Version, *Validation) error { return nil }} state := &sourceVersionState{localRule: rule, effectiveRule: rule, mode: sourceVersionModeRequired} wantNodes := countInputNodes(main.document) + countInputNodes(child.document) wantBytes := main.bytes + child.bytes limits := defaultImportLimits() limits.bytes = wantBytes limits.nodes = wantNodes accounting := &importAccounting{} composed, sources, foundDiagnostics := loadImportedDocumentsTrackedWithVersion( File(mainPath), nil, main, Path{}, rule, limits, accounting, nil, nil, state, ) if len(foundDiagnostics) != 0 || composed == nil || len(sources) != 2 || accounting.nodes != wantNodes || accounting.bytes != wantBytes { t.Fatalf("exact raw byte/node accounting = %#v, %d/%d, want %d/%d, %#v", composed, accounting.bytes, accounting.nodes, wantBytes, wantNodes, foundDiagnostics) } if len(state.evidence) != 1 || state.evidence[0].sourceID != "source-2" || !state.evidence[0].checked || state.evidence[0].version.Text != "accepted" { t.Fatalf("acquired child evidence = %#v", state.evidence) } if _, present := documentAtPath(composed.root, Keys("version")); present { t.Fatalf("consumed child header remains in application document: %#v", composed.root) } below := defaultImportLimits() below.nodes = wantNodes - 1 accounting = &importAccounting{} composed, _, foundDiagnostics = loadImportedDocumentsTrackedWithVersion( File(mainPath), nil, main, Path{}, rule, below, accounting, nil, nil, &sourceVersionState{localRule: rule, effectiveRule: rule, mode: sourceVersionModeRequired}, ) if composed != nil || len(foundDiagnostics) != 1 || foundDiagnostics[0].Code != CodeImportLimitExceeded { t.Fatalf("raw header nodes were not charged: %#v, %#v", composed, foundDiagnostics) } below = defaultImportLimits() below.bytes = wantBytes - 1 accounting = &importAccounting{} composed, _, foundDiagnostics = loadImportedDocumentsTrackedWithVersion( File(mainPath), nil, main, Path{}, rule, below, accounting, nil, nil, &sourceVersionState{localRule: rule, effectiveRule: rule, mode: sourceVersionModeRequired}, ) if composed != nil || len(foundDiagnostics) != 1 || foundDiagnostics[0].Code != CodeImportLimitExceeded { t.Fatalf("raw header bytes were not charged: %#v, %#v", composed, foundDiagnostics) } } func mustParseSourceVersionPath(t *testing.T, input string) Path { t.Helper() path, err := ParsePath(input) if err != nil { t.Fatal(err) } return path }