package configkit_test import ( "bytes" "errors" "fmt" "os" "path/filepath" "strings" "testing" "testing/fstest" configkit "gitea.maximumdirect.net/eric/ConfigKit" ) func TestFacadeSourceVersionEvidenceFollowsAssembledSequenceRanges(t *testing.T) { t.Parallel() for _, grouped := range []bool{false, true} { index := 0 if grouped { index = 1 } for _, sensitivePath := range []string{"", fmt.Sprintf("/records/%d/version", index), fmt.Sprintf("/records/%d", index)} { t.Run(fmt.Sprintf("grouped=%t/secret=%s", grouped, sensitivePath), func(t *testing.T) { definition := configkit.Definition[map[string]any]{ SequenceIdentities: []configkit.SequenceIdentity{configkit.SequenceIdentityAt(configkit.Keys("records"), "id")}, Version: &configkit.VersionRule{Path: configkit.Keys("records").Index(0).Key("version"), Check: func(configkit.Version, *configkit.Validation) error { return nil }}, Secret: func(path configkit.Path) bool { return sensitivePath != "" && path.String() == sensitivePath }, } first := "records: [{id: first, version: first-version}]\n" child := "records: [{id: child, version: PRIVATE-VERSION-CANARY}]\n" var result *configkit.Result[map[string]any] var err error if grouped { result, err = configkit.LoadLayered(configkit.Input{Source: configkit.Bytes("main", []byte(first))}, configkit.LayeredOptions[map[string]any]{ Definition: definition, SourceVersionMode: configkit.SourceVersionModeRequired, Underlays: []configkit.Underlay{{Inputs: []configkit.Input{ {Source: configkit.Bytes("first", []byte(first))}, {Source: configkit.Bytes("child", []byte(child))}, }}}, }) } else { filesystem := configkit.NewFilesystem("versions", fstest.MapFS{ "main.yml": {Data: []byte("configkit: {imports: [{path: child.yml}]}\n" + first)}, "child.yml": {Data: []byte(child)}, }) result, err = configkit.Load(filesystem.File("main.yml"), configkit.Options[map[string]any]{ Definition: definition, Imports: true, SourceVersionMode: configkit.SourceVersionModeRequired, }) } if err != nil { t.Fatal(err) } if !grouped { records, ok := result.Config["records"].([]any) if !ok || len(records) != 2 { t.Fatalf("scheduled records = %#v", result.Config["records"]) } firstRecord, ok := records[0].(map[string]any) if !ok || firstRecord["id"] != "child" { t.Fatalf("scheduled records = %#v", result.Config["records"]) } } sources := result.Sources() check := sources[len(sources)-1].VersionCheck if check == nil || check.Path.String() != "/records/0/version" || check.Location == nil || check.Location.SourceID != sources[len(sources)-1].ID { t.Fatalf("source-local evidence changed: %#v", check) } if sensitivePath != "" { if !check.Redacted || check.Version.Text != "" { t.Fatal("shifted version evidence was disclosed") } } else if check.Redacted || check.Version.Text != "PRIVATE-VERSION-CANARY" { t.Fatal("unclassified version evidence was lost") } }) } } } func TestFacadeSourceVersionOwnershipAcceptsContextualIndexes(t *testing.T) { t.Parallel() parsed, err := configkit.ParsePath("/records/0/version") if err != nil { t.Fatal(err) } for _, grouped := range []bool{false, true} { for _, path := range []configkit.Path{configkit.Keys("records").Index(0).Key("version"), parsed} { definition := configkit.Definition[map[string]any]{ SequenceIdentities: []configkit.SequenceIdentity{configkit.SequenceIdentityAt(configkit.Keys("records"), "id")}, Version: &configkit.VersionRule{Path: path, Check: func(configkit.Version, *configkit.Validation) error { return nil }}, } first := "records: [{id: first, version: first}]\n" child := "records: [{id: child, version: child}]\n" var result *configkit.Result[map[string]any] if grouped { result, err = configkit.LoadLayered(configkit.Input{Source: configkit.Bytes("main", []byte(first))}, configkit.LayeredOptions[map[string]any]{ Definition: definition, SourceVersionMode: configkit.SourceVersionModeRequired, Underlays: []configkit.Underlay{{Inputs: []configkit.Input{{Source: configkit.Bytes("lower", []byte(child))}}}}, }) } else { filesystem := configkit.NewFilesystem("versions", fstest.MapFS{"main.yml": {Data: []byte("configkit: {imports: [{path: child.yml}]}\n" + first)}, "child.yml": {Data: []byte(child)}}) result, err = configkit.Load(filesystem.File("main.yml"), configkit.Options[map[string]any]{Definition: definition, SourceVersionMode: configkit.SourceVersionModeRequired, Imports: true}) } if err != nil || result == nil { t.Fatalf("grouped=%t path=%#v: %v", grouped, path, err) } if len(result.Config["records"].([]any)) != 2 { t.Fatal("version path changed composition") } } } } func TestFacadeItemMainKeepsDefaultVersionOwnership(t *testing.T) { t.Parallel() for _, layered := range []bool{false, true} { for _, protected := range []bool{true, false} { body, helper := "id: main\n", "version: imported-version\n" if !protected { body += "version: main-version\n" helper = "other: {version: permitted}\n" } filesystem := configkit.NewFilesystem("item-main", fstest.MapFS{ "main.yml": {Data: []byte(body + "configkit: {imports: [{path: helper.yml}]}\n")}, "helper.yml": {Data: []byte(helper)}, }) checks := 0 definition := configkit.Definition[map[string]any]{Version: &configkit.VersionRule{ Path: configkit.Keys("records").Index(0).Key("version"), Check: func(version configkit.Version, _ *configkit.Validation) error { checks++ if version.Text != "main-version" { t.Error("helper supplied main version") } return nil }, }} var err error if layered { _, err = configkit.LoadLayered[map[string]any](configkit.Input{Source: filesystem.File("main.yml"), Imports: true, Destination: configkit.Keys("records"), PlacementMode: configkit.PlacementModeSequenceItem}, configkit.LayeredOptions[map[string]any]{Definition: definition}) } else { _, err = configkit.Load(filesystem.File("main.yml"), configkit.Options[map[string]any]{Definition: definition, Imports: true, Destination: configkit.Keys("records"), PlacementMode: configkit.PlacementModeSequenceItem}) } if protected { loadError, ok := err.(*configkit.LoadError) if !ok || len(loadError.Diagnostics()) != 1 || loadError.Diagnostics()[0].Code != configkit.CodeImportVersion || loadError.Diagnostics()[0].Path.String() != "/records/0/version" || checks != 0 { t.Fatalf("layered=%t ownership error = %v, checks=%d", layered, err, checks) } } else if err != nil || checks != 1 { t.Fatalf("unrelated helper version rejected: %v, checks=%d", err, checks) } } } } type sourceVersionModeReader struct { *strings.Reader reads int } func TestFacadeSourceVersionEvidenceRedactsCollidingShapes(t *testing.T) { t.Parallel() type header struct { Version string `yaml:"version"` } type secretHeader struct { Version string `yaml:"version" configkit:"secret"` } type configuration struct { Meta map[string]header `yaml:"meta"` Data struct { Meta map[string]secretHeader `yaml:"meta"` } `yaml:"data"` } path, err := configkit.ParsePath("/meta/0/version") if err != nil { t.Fatal(err) } for _, reverse := range []bool{false, true} { groups := []configkit.Underlay{ {Inputs: []configkit.Input{{ Source: configkit.Bytes("mapping", []byte("meta: {\"0\": {version: PRIVATE-HEADER-CANARY}}\n")), Destination: configkit.Keys("data"), }}}, {Inputs: []configkit.Input{{ Source: configkit.Bytes("sequence", []byte("meta: [{version: another-header}]\n")), Destination: configkit.Keys("data"), }}}, } if reverse { groups[0], groups[1] = groups[1], groups[0] } loaded, err := configkit.LoadLayered(configkit.Input{ Source: configkit.Bytes("main", []byte("meta: {\"0\": {version: main}}\ndata: {meta: null}\n")), }, configkit.LayeredOptions[configuration]{ Definition: configkit.Definition[configuration]{Version: &configkit.VersionRule{ Path: path, Check: func(configkit.Version, *configkit.Validation) error { return nil }, }}, SourceVersionMode: configkit.SourceVersionModeRequired, Underlays: groups, }) if err != nil { t.Fatal(err) } if loaded.Config.Meta["0"].Version != "main" || loaded.Config.Data.Meta != nil { t.Fatalf("reverse=%v: final payload changed: %#v", reverse, loaded.Config) } foundMapping := false for _, source := range loaded.Sources() { if source.Label != "mapping" { continue } foundMapping = true if check := source.VersionCheck; check == nil || !check.Version.Present || !check.Redacted || check.Version.Text != "" { t.Errorf("reverse=%v: schema-tagged header was not redacted", reverse) } } if !foundMapping { t.Fatal("missing mapping source record") } } } 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 TestFacadeSourceVersionAbsenceKeepsCompleteEvidencePath(t *testing.T) { t.Parallel() for _, test := range []struct { name, main, underlay string path configkit.Path }{ {"missing member", "meta: {version: main}\n", "{}\n", configkit.Keys("meta", "version")}, {"scalar obstruction", "meta: {version: main}\n", "meta: false\n", configkit.Keys("meta", "version")}, {"unavailable index", "meta: [null, null, null, {version: main}]\n", "meta: []\n", configkit.Keys("meta").Index(3).Key("version")}, } { for _, mode := range []configkit.SourceVersionMode{configkit.SourceVersionModeIfPresent, configkit.SourceVersionModeRequired} { var callbackEvidence *configkit.SourceVersionCheck loaded, err := configkit.LoadLayered(configkit.Input{Source: configkit.Bytes("main", []byte(test.main))}, configkit.LayeredOptions[map[string]any]{ SourceVersionMode: mode, Definition: configkit.Definition[map[string]any]{ Version: &configkit.VersionRule{Path: test.path, Check: func(configkit.Version, *configkit.Validation) error { return nil }}, Resolve: func(_ *map[string]any, resolution *configkit.Resolution) error { source, found := resolution.Source("source-2") if !found { t.Fatal("missing callback source") } callbackEvidence = source.VersionCheck return nil }, }, Underlays: []configkit.Underlay{{Inputs: []configkit.Input{{ Source: configkit.Bytes("underlay", []byte(test.underlay)), Destination: configkit.Keys("under"), }}}}, }) var evidence *configkit.SourceVersionCheck if mode == configkit.SourceVersionModeRequired { var failure *configkit.LoadError if loaded != nil || !errors.As(err, &failure) { t.Fatalf("%s: required omission did not fail", test.name) } diagnostics := failure.Diagnostics() if len(diagnostics) != 1 || diagnostics[0].Code != configkit.CodeVersionError || diagnostics[0].Path.String() != test.path.String() { t.Fatalf("%s: required diagnostics=%#v", test.name, diagnostics) } evidence = failure.Sources()[1].VersionCheck } else { if err != nil { t.Fatalf("%s: %v", test.name, err) } evidence = loaded.Sources()[1].VersionCheck if callbackEvidence == nil || callbackEvidence.Path.String() != test.path.String() { t.Errorf("%s: callback path is incomplete", test.name) } } if evidence == nil || evidence.Version.Present || evidence.Path.String() != test.path.String() || evidence.Location == nil || evidence.Location.SourceID != "source-2" || evidence.Location.Line != 1 { t.Errorf("%s mode=%v: absence evidence=%#v", test.name, mode, evidence) } } } } func TestFacadeSourceVersionMissingHeaderDoesNotOverlapControl(t *testing.T) { t.Parallel() for _, test := range []struct { name string mode configkit.SourceVersionMode control string wantCode configkit.Code }{ {"optional omission", configkit.SourceVersionModeIfPresent, "base", ""}, {"required omission", configkit.SourceVersionModeRequired, "base", configkit.CodeVersionError}, {"invalid control", configkit.SourceVersionModeIfPresent, "true", configkit.CodeInheritanceInvalid}, } { t.Run(test.name, func(t *testing.T) { main := configkit.Bytes("main", []byte("{}\n")) if test.mode == configkit.SourceVersionModeRequired { main = configkit.NoSource() } checks := 0 path := configkit.Keys("entries", "child", "extends", "version") loaded, err := configkit.LoadLayered(configkit.Input{Source: main, Destination: configkit.Keys("main")}, configkit.LayeredOptions[map[string]any]{ SourceVersionMode: test.mode, Definition: configkit.Definition[map[string]any]{Version: &configkit.VersionRule{ Path: path, Check: func(version configkit.Version, _ *configkit.Validation) error { checks++ if version.Present { t.Error("checker received a nonexistent declaration") } return nil }, }}, Underlays: []configkit.Underlay{{Inputs: []configkit.Input{{ Source: configkit.Bytes("underlay", []byte("entries:\n base: {value: good}\n child: {extends: "+test.control+"}\n")), Destination: configkit.Keys("under"), }}}}, }) if checks != 1 { t.Errorf("checker ran %d times, want absent main only", checks) } if test.wantCode != "" { var failure *configkit.LoadError if loaded != nil || !errors.As(err, &failure) { t.Fatal("invalid input did not fail safely") } if diagnostics := failure.Diagnostics(); len(diagnostics) != 1 || diagnostics[0].Code != test.wantCode { t.Fatalf("diagnostics=%#v", diagnostics) } return } if err != nil { t.Fatal(err) } child := loaded.Config["under"].(map[string]any)["entries"].(map[string]any)["child"].(map[string]any) if child["value"] != "good" { t.Fatal("valid sibling inheritance was not applied") } check := loaded.Sources()[1].VersionCheck if check == nil || check.Version.Present || check.Path.String() != path.String() { t.Fatal("optional omission evidence was not retained") } }) } } func (reader *sourceVersionModeReader) Read(data []byte) (int, error) { reader.reads++ return reader.Reader.Read(data) } func TestFacadeSourceVersionModesAcrossOrdinaryAndLayeredLoads(t *testing.T) { t.Parallel() var checked []configkit.Version definition := configkit.Definition[map[string]any]{Version: &configkit.VersionRule{ Path: configkit.Keys("meta", "version"), Check: func(version configkit.Version, _ *configkit.Validation) error { checked = append(checked, version) return nil }, }} ordinary, err := configkit.Load(configkit.Bytes("ordinary", []byte("meta: {version: ordinary-v}\n")), configkit.Options[map[string]any]{ Definition: definition, SourceVersionMode: configkit.SourceVersionModeIfPresent, }) if err != nil || ordinary == nil { t.Fatalf("ordinary enabled load = %#v, %v", ordinary, err) } if got := ordinary.Config["meta"].(map[string]any)["version"]; got != "ordinary-v" { t.Fatalf("main declaration was not retained: %#v", ordinary.Config) } directory := t.TempDir() mainPath := filepath.Join(directory, "main.yml") if err := os.WriteFile(mainPath, []byte("meta: {version: main-v}\n"), 0o600); err != nil { t.Fatal(err) } layered, err := configkit.LoadLayered(configkit.Input{Source: configkit.File(mainPath)}, configkit.LayeredOptions[map[string]any]{ Definition: definition, SourceVersionMode: configkit.SourceVersionModeRequired, Underlays: []configkit.Underlay{{Inputs: []configkit.Input{{ Source: configkit.Mapping("underlay", map[string]any{ "meta": map[string]any{"version": "underlay-v"}, "fallback": "present", }), Destination: configkit.Keys("defaults"), }}}}, }) if err != nil || layered == nil { t.Fatalf("layered enabled load = %#v, %v", layered, err) } defaults, ok := layered.Config["defaults"].(map[string]any) if !ok || defaults["fallback"] != "present" { t.Fatalf("layered underlay payload = %#v", layered.Config["defaults"]) } if meta, ok := defaults["meta"].(map[string]any); !ok || len(meta) != 0 { t.Fatalf("accepted underlay declaration was not consumed: %#v", defaults["meta"]) } if len(checked) != 3 { t.Fatalf("checker calls across separate mode uses = %#v", checked) } for _, want := range []string{"ordinary-v", "main-v", "underlay-v"} { found := false for _, version := range checked { found = found || version.Present && version.Text == want } if !found { t.Errorf("checked versions %#v do not include %q", checked, want) } } } func TestFacadeSourceVersionModeZeroPreservesDefaultBehavior(t *testing.T) { t.Parallel() checks := 0 result, err := configkit.Load(configkit.Bytes("default", []byte("version: v1\n")), configkit.Options[map[string]any]{ Definition: configkit.Definition[map[string]any]{Version: &configkit.VersionRule{ Path: configkit.Keys("version"), Check: func(version configkit.Version, _ *configkit.Validation) error { checks++ if version != (configkit.Version{Present: true, Text: "v1"}) { t.Errorf("default version = %#v", version) } return nil }, }}, }) if err != nil || result == nil || result.Config["version"] != "v1" || checks != 1 { t.Fatalf("zero-mode load = %#v, %v; checks = %d", result, err, checks) } } func TestFacadeSourceVersionModeValidationPrecedesSourceReads(t *testing.T) { t.Parallel() validDefinition := configkit.Definition[map[string]any]{Version: &configkit.VersionRule{ Path: configkit.Keys("version"), Check: func(configkit.Version, *configkit.Validation) error { return nil }, }} for _, test := range []struct { name string mode configkit.SourceVersionMode def configkit.Definition[map[string]any] layered bool }{ {name: "unknown ordinary mode", mode: configkit.SourceVersionMode(255), def: validDefinition}, {name: "ordinary mode requires checker", mode: configkit.SourceVersionModeIfPresent}, {name: "unknown layered mode", mode: configkit.SourceVersionMode(255), def: validDefinition, layered: true}, {name: "layered mode requires checker", mode: configkit.SourceVersionModeRequired, layered: true}, } { t.Run(test.name, func(t *testing.T) { reader := &sourceVersionModeReader{Reader: strings.NewReader("version: v1\n")} source := configkit.Reader("version.yml", reader) var err error if test.layered { _, err = configkit.LoadLayered(configkit.Input{Source: source}, configkit.LayeredOptions[map[string]any]{ Definition: test.def, SourceVersionMode: test.mode, }) } else { _, err = configkit.Load(source, configkit.Options[map[string]any]{ Definition: test.def, SourceVersionMode: test.mode, }) } var loadError *configkit.LoadError if !errors.As(err, &loadError) || len(loadError.Diagnostics()) != 1 || loadError.Diagnostics()[0].Code != configkit.CodeOptionsInvalid { t.Fatalf("invalid mode error = %#v", err) } if reader.reads != 0 { t.Fatalf("invalid options read source %d times", reader.reads) } }) } } func TestFacadeSourceVersionDefinitionCanBeReusedWithDifferentModes(t *testing.T) { t.Parallel() checks := 0 definition := configkit.Definition[map[string]any]{Version: &configkit.VersionRule{ Path: configkit.Keys("version"), Check: func(version configkit.Version, _ *configkit.Validation) error { checks++ if version.Present { t.Errorf("missing declaration reached checker as %#v", version) } return nil }, }} source := configkit.Bytes("reused", []byte("value: retained\n")) ifPresent, err := configkit.Load(source, configkit.Options[map[string]any]{ Definition: definition, SourceVersionMode: configkit.SourceVersionModeIfPresent, }) if err != nil || ifPresent == nil || checks != 1 { t.Fatalf("if-present load = %#v, %v; checks = %d", ifPresent, err, checks) } required, err := configkit.Load(source, configkit.Options[map[string]any]{ Definition: definition, SourceVersionMode: configkit.SourceVersionModeRequired, }) var loadError *configkit.LoadError if required != nil || !errors.As(err, &loadError) || len(loadError.Diagnostics()) != 1 || loadError.Diagnostics()[0].Code != configkit.CodeVersionError { t.Fatalf("required load = %#v, %v", required, err) } if checks != 1 { t.Fatalf("required absence reached checker: calls = %d", checks) } } func TestFacadeSourceVersionEvidenceIsSanitizedAndDetached(t *testing.T) { t.Parallel() const canary = "PRIVATE-SOURCE-VERSION-CANARY" directory := t.TempDir() path := filepath.Join(directory, "main.yml") if err := os.WriteFile(path, []byte("version: "+canary+"\nvalue: visible\n"), 0o600); err != nil { t.Fatal(err) } var callbackSource configkit.SourceInfo var callbackContext configkit.ResourceContext definition := configkit.Definition[map[string]any]{ Version: &configkit.VersionRule{Path: configkit.Keys("version"), Check: func(configkit.Version, *configkit.Validation) error { return nil }}, Secret: func(candidate configkit.Path) bool { return candidate.String() == "/service/version" }, Resolve: func(_ *map[string]any, resolution *configkit.Resolution) error { var found bool callbackSource, found = resolution.Source("source-1") if !found { t.Fatal("resolution callback could not query the acquired source") } if callbackSource.VersionCheck == nil || !callbackSource.VersionCheck.Redacted || callbackSource.VersionCheck.Version.Text != "" { t.Fatalf("callback source did not conservatively redact evidence: %#v", callbackSource.VersionCheck) } callbackContext, found = resolution.SourceContext("source-1") if !found || callbackContext.FS == nil || callbackContext.BaseDir != "." { t.Fatalf("callback source context = %#v, found=%v", callbackContext, found) } return nil }, } loaded, err := configkit.LoadLayered(configkit.Input{Source: configkit.File(path), Destination: configkit.Keys("service")}, configkit.LayeredOptions[map[string]any]{ Definition: definition, SourceVersionMode: configkit.SourceVersionModeIfPresent, }) if err != nil || loaded == nil { t.Fatalf("LoadLayered = %#v, %v", loaded, err) } if callbackSource.VersionCheck == nil || !callbackSource.VersionCheck.Redacted || callbackSource.VersionCheck.Version.Text != "" { t.Fatalf("callback evidence lost its conservative snapshot: %#v", callbackSource.VersionCheck) } callbackSource.VersionCheck.Path = configkit.Keys("mutated-callback") callbackSource.VersionCheck.Version.Text = canary callbackSource.VersionCheck.Location.Line = 98 finalSources := loaded.Sources() if len(finalSources) != 1 || finalSources[0].Path != path || finalSources[0].VersionCheck == nil { t.Fatalf("final sources = %#v", finalSources) } check := finalSources[0].VersionCheck if check.Path.String() != "/version" || check.Version != (configkit.Version{Present: true}) || !check.Redacted || check.Location == nil || check.Location.SourceID != finalSources[0].ID || check.Location.Line != 1 { t.Fatalf("final classified evidence = %#v", check) } if err := os.Remove(path); err != nil { t.Fatal(err) } if callbackContext.FS == nil || callbackContext.BaseDir != "." { t.Fatalf("resource metadata changed after removing the source: %#v", callbackContext) } check.Path = configkit.Keys("mutated") check.Location.Line = 99 check.Redacted = false check.Version.Text = "mutated" repeated := loaded.Sources() if len(repeated) != 1 || repeated[0].VersionCheck.Path.String() != "/version" || repeated[0].VersionCheck.Location.Line != 1 || !repeated[0].VersionCheck.Redacted || repeated[0].VersionCheck.Version.Text != "" { t.Fatalf("source evidence was aliased or re-read after source removal: %#v", repeated) } publicText := "PUBLIC-SOURCE-VERSION" var publicCallback configkit.SourceInfo public, err := configkit.Load(configkit.Bytes("public", []byte("version: "+publicText+"\n")), configkit.Options[map[string]any]{ SourceVersionMode: configkit.SourceVersionModeIfPresent, Definition: configkit.Definition[map[string]any]{ Version: definition.Version, Resolve: func(_ *map[string]any, resolution *configkit.Resolution) error { publicCallback, _ = resolution.Source("source-1") return nil }, }, }) if err != nil || public == nil || len(public.Sources()) != 1 || public.Sources()[0].VersionCheck == nil { t.Fatalf("unclassified source evidence = %#v, %v", public, err) } if got := public.Sources()[0].VersionCheck; got.Redacted || got.Version.Text != publicText || !got.Version.Present { t.Fatalf("unclassified evidence = %#v", got) } if publicCallback.VersionCheck == nil || !publicCallback.VersionCheck.Redacted || publicCallback.VersionCheck.Version.Text != "" { t.Fatalf("unclassified callback evidence was not initially conservative: %#v", publicCallback.VersionCheck) } } func TestFacadeSourceVersionEvidenceOnFailedLoadsAndSyntheticSources(t *testing.T) { t.Parallel() definition := configkit.Definition[map[string]any]{Version: &configkit.VersionRule{ Path: configkit.Keys("version"), Check: func(configkit.Version, *configkit.Validation) error { return nil }, }} t.Run("early import acquisition failure", func(t *testing.T) { const canary = "EARLY-ACQUISITION-SOURCE-VERSION-CANARY" checked := 0 earlyDefinition := configkit.Definition[map[string]any]{Version: &configkit.VersionRule{ Path: configkit.Keys("version"), Check: func(configkit.Version, *configkit.Validation) error { checked++; return nil }, }} path := filepath.Join(t.TempDir(), "main.yml") contents := "version: " + canary + "\nconfigkit:\n imports:\n - path: missing.yml\n required: true\n" if err := os.WriteFile(path, []byte(contents), 0o600); err != nil { t.Fatal(err) } _, err := configkit.LoadLayered(configkit.Input{Source: configkit.File(path), Imports: true}, configkit.LayeredOptions[map[string]any]{ Definition: earlyDefinition, SourceVersionMode: configkit.SourceVersionModeIfPresent, }) var failure *configkit.LoadError if !errors.As(err, &failure) || len(failure.Sources()) != 1 { t.Fatalf("early acquisition failure sources = %#v, error %v", failure, err) } if checked != 1 { t.Fatalf("main declaration checker calls = %d; error %v", checked, err) } check := failure.Sources()[0].VersionCheck if check == nil || !check.Redacted || !check.Version.Present || check.Version.Text != "" { t.Fatalf("early acquisition evidence was not conservatively redacted: %#v; sources %#v", check, failure.Sources()) } if strings.Contains(err.Error(), canary) { t.Fatalf("early acquisition failure disclosed source-version canary: %v", err) } }) _, err := configkit.Load(configkit.Bytes("malformed", []byte("version: true\n")), configkit.Options[map[string]any]{ Definition: definition, SourceVersionMode: configkit.SourceVersionModeIfPresent, }) var loadError *configkit.LoadError if !errors.As(err, &loadError) { t.Fatalf("malformed version error = %v", err) } sources := loadError.Sources() if len(sources) != 1 || sources[0].VersionCheck == nil || !sources[0].VersionCheck.Redacted || !sources[0].VersionCheck.Version.Present || sources[0].VersionCheck.Version.Text != "" || sources[0].VersionCheck.Path.String() != "/version" { t.Fatalf("failed-load source evidence = %#v", sources) } sources[0].VersionCheck.Path = configkit.Keys("mutated-error") sources[0].VersionCheck.Version.Text = "mutated" sources[0].VersionCheck.Location.Line = 99 if again := loadError.Sources()[0].VersionCheck; again.Path.String() != "/version" || again.Version.Text != "" || again.Location.Line == 99 { t.Fatalf("LoadError source evidence was aliased: %#v", again) } for _, test := range []struct { name string def configkit.Definition[map[string]any] canary string }{ { name: "resolver failure", canary: "RESOLVER-SOURCE-VERSION-CANARY", def: configkit.Definition[map[string]any]{Version: definition.Version, Resolve: func(*map[string]any, *configkit.Resolution) error { return errors.New("resolver failed") }}, }, { name: "validator failure", canary: "VALIDATOR-SOURCE-VERSION-CANARY", def: configkit.Definition[map[string]any]{Version: definition.Version, Validate: func(_ *map[string]any, validation *configkit.Validation) { validation.Error(configkit.Keys("value"), "invalid value") }}, }, } { t.Run(test.name, func(t *testing.T) { _, err := configkit.Load(configkit.Bytes("late-failure", []byte("version: "+test.canary+"\nvalue: configured\n")), configkit.Options[map[string]any]{ Definition: test.def, SourceVersionMode: configkit.SourceVersionModeIfPresent, }) var failure *configkit.LoadError if !errors.As(err, &failure) || len(failure.Sources()) != 1 { t.Fatalf("late failure sources = %#v, error %v", failure, err) } if strings.Contains(err.Error(), test.canary) { t.Fatalf("late failure disclosed source-version canary: %v", err) } check := failure.Sources()[0].VersionCheck if check == nil || !check.Redacted || !check.Version.Present || check.Version.Text != "" { t.Fatalf("late-failure evidence was not conservatively redacted: %#v", check) } }) } defaultResult, err := configkit.Load(configkit.Bytes("default", []byte("version: 7\n")), configkit.Options[map[string]any]{}) if err != nil || defaultResult == nil || len(defaultResult.Sources()) != 1 || defaultResult.Sources()[0].VersionCheck != nil { t.Fatalf("default source version check = %#v, %v", defaultResult, err) } withCLI, err := configkit.Load(configkit.Bytes("main", []byte("version: 8\nvalue: old\n")), configkit.Options[map[string]any]{ Definition: definition, SourceVersionMode: configkit.SourceVersionModeIfPresent, Overrides: []configkit.Override{{Path: configkit.Keys("value"), Value: "new", Flag: "--value"}}, }) if err != nil || withCLI == nil { t.Fatalf("enabled load with CLI source = %#v, %v", withCLI, err) } sawCLI := false for _, source := range withCLI.Sources() { if source.Kind == configkit.SourceKindCLI && source.VersionCheck != nil { t.Fatalf("synthetic CLI source acquired declaration evidence: %#v", source) } sawCLI = sawCLI || source.Kind == configkit.SourceKindCLI } if !sawCLI { t.Fatalf("CLI source record missing: %#v", withCLI.Sources()) } } func TestFacadeSourceVersionEvidencePreservesAbsenceAndNull(t *testing.T) { t.Parallel() var checked []configkit.Version loaded, err := configkit.LoadLayered(configkit.Input{Source: configkit.Bytes("main", []byte("version: 17\n"))}, configkit.LayeredOptions[map[string]any]{ SourceVersionMode: configkit.SourceVersionModeIfPresent, Definition: configkit.Definition[map[string]any]{Version: &configkit.VersionRule{ Path: configkit.Keys("version"), Check: func(version configkit.Version, _ *configkit.Validation) error { checked = append(checked, version) return nil }, }}, Underlays: []configkit.Underlay{{Inputs: []configkit.Input{ {Source: configkit.Bytes("absent", []byte("value: visible\n")), Destination: configkit.Keys("absent")}, {Source: configkit.Bytes("null", []byte("version: null\nvalue: visible\n")), Destination: configkit.Keys("nullable")}, }}}, }) if err != nil || loaded == nil { t.Fatalf("LoadLayered = %#v, %v", loaded, err) } if len(checked) != 2 || !checked[0].Present || checked[0].Text != "17" || !checked[1].Present || !checked[1].Null { t.Fatalf("checker calls = %#v; absent contribution must skip while null is checked", checked) } sources := loaded.Sources() if len(sources) != 3 || sources[1].VersionCheck == nil || sources[2].VersionCheck == nil { t.Fatalf("source version evidence = %#v", sources) } absent := sources[1].VersionCheck if absent.Version.Present || absent.Path.String() != "/version" || absent.Location == nil || absent.Redacted { t.Fatalf("optional omission evidence = %#v", absent) } null := sources[2].VersionCheck if !null.Version.Present || !null.Version.Null || null.Version.Text != "" || null.Path.String() != "/version" { t.Fatalf("null declaration evidence = %#v", null) } } func TestFacadeSourceVersionLifecycleKeepsConsumedHeadersOutOfPayloadHistory(t *testing.T) { type serviceConfig struct { Version uint64 `yaml:"version"` Count int `yaml:"count"` Enabled bool `yaml:"enabled"` Nullable *string `yaml:"nullable"` Revision string `yaml:"revision"` Defaulted string `yaml:"defaulted"` Resolved string `yaml:"resolved"` Credential configkit.Secret `yaml:"credential"` } type configuration struct { Service serviceConfig `yaml:"service"` } t.Setenv("CONFIGKIT_LIFECYCLE_SECRET", "lifecycle-secret-value") var checked []configkit.Version var validationCalls int definition := configkit.Definition[configuration]{ Defaults: func() configuration { return configuration{Service: serviceConfig{Defaulted: "from defaults"}} }, Version: &configkit.VersionRule{ Path: configkit.Keys("version"), Check: func(version configkit.Version, _ *configkit.Validation) error { checked = append(checked, version) return nil }, }, Resolve: func(current *configuration, resolution *configkit.Resolution) error { current.Service.Resolved = "resolved once" resolution.Record(configkit.Keys("service", "resolved"), configkit.ChangeNormalization, "derive resolved value") return nil }, Validate: func(current *configuration, validation *configkit.Validation) { validationCalls++ if current.Service.Version != 9007199254740993 || current.Service.Count != 0 || current.Service.Enabled || current.Service.Nullable != nil || current.Service.Revision != "ordinary-payload" || current.Service.Defaulted != "from defaults" || current.Service.Resolved != "resolved once" || current.Service.Credential.Value() != "lifecycle-secret-value" { validation.Error(configkit.Keys("service"), "assembled values did not survive source declaration processing") } }, } load := func(header string) *configkit.Result[configuration] { t.Helper() result, err := configkit.LoadLayered(configkit.Input{ Source: configkit.Bytes("main", []byte("version: 9007199254740993\n")), Destination: configkit.Keys("service"), }, configkit.LayeredOptions[configuration]{ Definition: definition, SourceVersionMode: configkit.SourceVersionModeIfPresent, Underlays: []configkit.Underlay{{Inputs: []configkit.Input{{ Source: configkit.Bytes("underlay", []byte("version: "+header+"\ncount: 0\nenabled: false\nnullable: null\nrevision: ordinary-payload\ncredential: CONFIGKIT_LIFECYCLE_SECRET\n")), Destination: configkit.Keys("service"), }}}}, }) if err != nil || result == nil { var failure *configkit.LoadError var diagnostics []configkit.Diagnostic if errors.As(err, &failure) { diagnostics = failure.Diagnostics() } t.Fatalf("LoadLayered(%q) = %#v, %v; diagnostics %#v", header, result, err, diagnostics) } return result } first := load("underlay-release-a") second := load("underlay-release-b") if len(checked) != 4 || checked[0].Text != "9007199254740993" || checked[1].Text != "underlay-release-a" || checked[2].Text != "9007199254740993" || checked[3].Text != "underlay-release-b" { t.Fatalf("source declarations checked = %#v", checked) } if validationCalls != 2 || first.Config.Service != second.Config.Service { t.Fatalf("final configs or validation count = %#v, %#v, %d", first.Config, second.Config, validationCalls) } if differences, err := configkit.Diff(first, second); err != nil || len(differences) != 0 { t.Fatalf("different consumed declarations created effective differences: %#v, %v", differences, err) } var firstEffective, secondEffective bytes.Buffer if err := first.WriteEffective(&firstEffective); err != nil { t.Fatal(err) } if err := second.WriteEffective(&secondEffective); err != nil { t.Fatal(err) } if firstEffective.String() != secondEffective.String() || strings.Contains(firstEffective.String(), "underlay-release") { t.Fatalf("consumed declarations affected effective rendering:\n%s\n%s", firstEffective.String(), secondEffective.String()) } sourcesA, sourcesB := first.Sources(), second.Sources() if len(sourcesA) != 2 || len(sourcesB) != 2 || sourcesA[1].VersionCheck == nil || sourcesB[1].VersionCheck == nil || sourcesA[1].VersionCheck.Version.Text != "underlay-release-a" || sourcesB[1].VersionCheck.Version.Text != "underlay-release-b" { t.Fatalf("sanitized evidence did not retain distinct accepted declarations: %#v / %#v", sourcesA, sourcesB) } versionExplanation, found := first.Explain(configkit.Keys("service", "version")) if !found { t.Fatal("retained main version missing from effective explanation") } underlayID := sourcesA[1].ID for _, location := range versionExplanation.Origin.Locations { if location.SourceID == underlayID { t.Fatalf("consumed underlay declaration entered effective origin: %#v", versionExplanation.Origin) } } for _, change := range versionExplanation.History { for _, location := range change.Origin.Locations { if location.SourceID == underlayID { t.Fatalf("consumed underlay declaration entered effective history: %#v", versionExplanation.History) } } } }