package configkit_test import ( "bytes" "os" "path/filepath" "reflect" "strings" "testing" "testing/fstest" configkit "gitea.maximumdirect.net/eric/ConfigKit" ) func TestFacadeNoSourcePreservesAbsenceWithSequencePolicy(t *testing.T) { t.Parallel() for _, defaults := range []bool{false, true} { for _, registered := range []bool{false, true} { definition := configkit.Definition[map[string]any]{} if defaults { definition.Defaults = func() map[string]any { return map[string]any{"fallback": true} } } if registered { definition.SequenceCompositions = []configkit.SequenceComposition{{Path: configkit.Keys("records"), IdentityField: "id"}} } ordinary, err := configkit.Load(configkit.NoSource(), configkit.Options[map[string]any]{Definition: definition}) if err != nil { t.Fatal(err) } layered, err := configkit.LoadLayered[map[string]any](configkit.Input{Source: configkit.NoSource()}, configkit.LayeredOptions[map[string]any]{Definition: definition}) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(ordinary.Config, layered.Config) { t.Fatal("NoSource values differ between entry points") } for _, result := range []*configkit.Result[map[string]any]{ordinary, layered} { if len(result.Sources()) != 0 || result.Metadata().IsExplicit(configkit.Keys()) { t.Fatal("NoSource contributed an explicit root") } info, ok := result.Metadata().Lookup(configkit.Keys()) if !ok || info.Origin.Layer != configkit.LayerDefault { t.Fatalf("NoSource root origin = %#v, %t", info, ok) } } empty, err := configkit.Load(configkit.Mapping("empty", map[string]any{}), configkit.Options[map[string]any]{Definition: definition}) if err != nil || !empty.Metadata().IsExplicit(configkit.Keys()) { t.Fatal("real empty mapping lost its presence") } } } } func TestFacadeItemHelperHistoryPreservesTraversalOrder(t *testing.T) { t.Parallel() filesystem := configkit.NewFilesystem("history", fstest.MapFS{ "main.yml": {Data: []byte("records: [{id: authored}]\nconfigkit: {imports: [{path: one.yml, destination: [records], placement: sequence-item}, {path: two.yml, destination: [records], placement: sequence-item}]}\n")}, "one.yml": {Data: []byte("id: one\nconfigkit: {imports: [{path: helper-one.yml}, {path: child.yml, destination: [children], placement: sequence-item}]}\n")}, "two.yml": {Data: []byte("id: two\nconfigkit: {imports: [{path: helper-two.yml}]}\n")}, "helper-one.yml": {Data: []byte("text: first helper\n")}, "helper-two.yml": {Data: []byte("text: second helper\n")}, "child.yml": {Data: []byte("id: child\nconfigkit: {imports: [{path: child-helper.yml}]}\n")}, "child-helper.yml": {Data: []byte("text: nested helper\n")}, }) result, err := configkit.Load(filesystem.File("main.yml"), configkit.Options[map[string]any]{ Imports: true, Definition: configkit.Definition[map[string]any]{SequenceCompositions: []configkit.SequenceComposition{{Path: configkit.Keys("records"), IdentityField: "id"}}}, }) if err != nil { t.Fatal(err) } sourceOrder := make(map[string]int) sourceFiles := make(map[string]string) for index, source := range result.Sources() { sourceOrder[source.ID] = index sourceFiles[source.ID] = source.Path } for _, test := range []struct { path configkit.Path file, text string }{ {configkit.Keys("records").Index(1).Key("text"), "helper-one.yml", "first helper\n"}, {configkit.Keys("records").Index(2).Key("text"), "helper-two.yml", "second helper\n"}, {configkit.Keys("records").Index(1).Key("children").Index(0).Key("text"), "child-helper.yml", "nested helper\n"}, } { explanation, ok := result.Explain(test.path) if !ok || explanation.Effective.YAML != test.text || len(explanation.History) != 1 { t.Fatalf("helper history at %s = %#v", test.path.String(), explanation) } locations := explanation.History[0].Origin.Locations if len(locations) != 1 || sourceFiles[locations[0].SourceID] != test.file { t.Fatalf("helper origin at %s = %#v", test.path.String(), locations) } info, ok := result.Metadata().Lookup(test.path) if !ok || len(info.Origin.Locations) != 1 || info.Origin.Locations[0].SourceID != locations[0].SourceID { t.Fatal("metadata and explanation disagree") } } explanation, ok := result.Explain(configkit.Keys()) if !ok { t.Fatal("root explanation missing") } previous := -1 for _, change := range explanation.History { for _, location := range change.Origin.Locations { current := sourceOrder[location.SourceID] if current < previous { t.Fatalf("source %s replayed out of traversal order", location.SourceID) } previous = current } } } func TestFacadeRegisteredReplacementExplainsRemovedDescendants(t *testing.T) { t.Parallel() for _, test := range []struct { name string upper []any path configkit.Path }{ {"shorter", []any{map[string]any{"id": "main"}}, configkit.Keys("records").Index(1).Key("id")}, {"empty", []any{}, configkit.Keys("records").Index(0).Key("id")}, {"removed field", []any{map[string]any{"id": "main"}}, configkit.Keys("records").Index(0).Key("text")}, } { t.Run(test.name, func(t *testing.T) { result, err := configkit.LoadLayered[map[string]any](configkit.Input{Source: configkit.Mapping("main", map[string]any{"records": test.upper})}, configkit.LayeredOptions[map[string]any]{ Definition: configkit.Definition[map[string]any]{SequenceCompositions: []configkit.SequenceComposition{{Path: configkit.Keys("records"), IdentityField: "id"}}}, Underlays: []configkit.Underlay{{Inputs: []configkit.Input{{Source: configkit.Mapping("lower", map[string]any{"records": []any{map[string]any{"id": "one", "text": "old"}, map[string]any{"id": "two"}}})}}}}, }) if err != nil { t.Fatal(err) } explanation, ok := result.Explain(test.path) if !ok || explanation.Effective.Present || len(explanation.History) < 2 { t.Fatalf("removal not explained: %#v", explanation) } last := explanation.History[len(explanation.History)-1] if !last.Before.Present || last.After.Present || last.Origin.Layer != configkit.LayerBase || len(last.Origin.Locations) != 1 || last.Origin.Locations[0].SourceID != result.Sources()[0].ID { t.Fatalf("wrong removal transition/origin: %#v", last) } }) } } func TestFacadeSequencePlacementControlsAcrossLoadEntryPoints(t *testing.T) { definition := configkit.Definition[map[string]any]{ SequenceCompositions: []configkit.SequenceComposition{{Path: configkit.Keys("entries"), IdentityField: "id"}}, } ordinary, err := configkit.Load(configkit.Mapping("ordinary", map[string]any{"id": "one"}), configkit.Options[map[string]any]{ Definition: definition, Destination: configkit.Keys("entries"), PlacementMode: configkit.PlacementModeSequenceItem, }) if err != nil { t.Fatalf("ordinary item load: %v", err) } if got := ordinary.Config["entries"].([]any); len(got) != 1 || got[0].(map[string]any)["id"] != "one" { t.Fatalf("ordinary item placement = %#v", ordinary.Config) } if sources := ordinary.Sources(); len(sources) != 1 || sources[0].PlacementMode != configkit.PlacementModeSequenceItem || sources[0].Destination.String() != "/entries" || sources[0].DestinationUnresolved { t.Fatalf("ordinary item source = %#v", sources) } layered, err := configkit.LoadLayered[map[string]any](configkit.Input{Source: configkit.NoSource()}, configkit.LayeredOptions[map[string]any]{ Definition: definition, Underlays: []configkit.Underlay{{Inputs: []configkit.Input{ {Source: configkit.Mapping("first", map[string]any{"id": "first"}), Destination: configkit.Keys("entries"), PlacementMode: configkit.PlacementModeSequenceItem}, {Source: configkit.Mapping("second", map[string]any{"id": "second"}), Destination: configkit.Keys("entries"), PlacementMode: configkit.PlacementModeSequenceItem}, }}}, }) if err != nil { t.Fatalf("layered item load: %v", err) } items := layered.Config["entries"].([]any) if len(items) != 2 || items[0].(map[string]any)["id"] != "first" || items[1].(map[string]any)["id"] != "second" { t.Fatalf("layered item placement = %#v", layered.Config) } for _, source := range layered.Sources() { if source.PlacementMode != configkit.PlacementModeSequenceItem || source.Destination.String() != "/entries" || source.DestinationUnresolved { t.Errorf("layered item source = %#v", source) } } precedence, err := configkit.LoadLayered[map[string]any](configkit.Input{Source: configkit.Mapping("main", map[string]any{ "entries": []any{map[string]any{"id": "main"}}, })}, configkit.LayeredOptions[map[string]any]{ Definition: definition, Underlays: []configkit.Underlay{{Inputs: []configkit.Input{{ Source: configkit.Mapping("lower", map[string]any{"id": "lower"}), Destination: configkit.Keys("entries"), PlacementMode: configkit.PlacementModeSequenceItem, }}}}, }) if err != nil { t.Fatalf("registered sequence precedence load: %v", err) } if got := precedence.Config["entries"].([]any); len(got) != 1 || got[0].(map[string]any)["id"] != "main" { t.Fatalf("higher-priority list did not replace the lower sequence: %#v", precedence.Config) } for _, test := range []struct { name string load func(configkit.Source) error }{ {name: "ordinary", load: func(source configkit.Source) error { _, loadErr := configkit.Load(source, configkit.Options[map[string]any]{PlacementMode: configkit.PlacementMode(9)}) return loadErr }}, {name: "layered", load: func(source configkit.Source) error { _, loadErr := configkit.LoadLayered[map[string]any](configkit.Input{Source: source, PlacementMode: configkit.PlacementMode(9)}) return loadErr }}, } { t.Run(test.name, func(t *testing.T) { reader := &destinationCountingReader{} err := test.load(configkit.Reader("unread", reader)) loadError, ok := err.(*configkit.LoadError) if !ok || len(loadError.Diagnostics()) == 0 || loadError.Diagnostics()[0].Code != configkit.CodeOptionsInvalid || reader.reads != 0 { t.Fatalf("invalid placement result = %v, reads = %d", err, reader.reads) } }) } } func TestFacadeItemImportGlobComposesWithAuthoredSequence(t *testing.T) { directory := t.TempDir() mainPath := filepath.Join(directory, "main.yml") if err := os.WriteFile(mainPath, []byte(`configkit: imports: - glob: records/*.yml destination: [items] placement: sequence-item items: - id: authored name: authored item `), 0o600); err != nil { t.Fatal(err) } for name, id := range map[string]string{"b.yml": "imported-b", "a.yml": "imported-a"} { if err := os.MkdirAll(filepath.Join(directory, "records"), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(directory, "records", name), []byte("id: "+id+"\n"), 0o600); err != nil { t.Fatal(err) } } var callbackSources []configkit.SourceInfo var callbackContexts []configkit.ResourceContext result, err := configkit.Load(configkit.File(mainPath), configkit.Options[map[string]any]{ Imports: true, Definition: configkit.Definition[map[string]any]{ SequenceCompositions: []configkit.SequenceComposition{{Path: configkit.Keys("items"), IdentityField: "id"}}, Resolve: func(_ *map[string]any, resolution *configkit.Resolution) error { for _, id := range []string{"source-2", "source-3"} { source, ok := resolution.Source(id) if !ok { t.Errorf("resolver could not query %s", id) continue } context, found := resolution.SourceContext(id) if !found || context.FS == nil || context.BaseDir != "records" { t.Errorf("resolver context for %s = %#v, %v", id, context, found) } callbackSources = append(callbackSources, source) callbackContexts = append(callbackContexts, context) } return nil }, }, }) if err != nil { t.Fatalf("load item glob: %v", err) } items := result.Config["items"].([]any) wantIDs := []string{"authored", "imported-a", "imported-b"} for index, item := range items { if got := item.(map[string]any)["id"]; got != wantIDs[index] { t.Errorf("item %d ID = %#v, want %q", index, got, wantIDs[index]) } } if len(callbackSources) != 2 || len(callbackContexts) != 2 { t.Fatalf("callback snapshots = %#v, contexts %#v", callbackSources, callbackContexts) } for index, source := range callbackSources { if source.PlacementMode != configkit.PlacementModeSequenceItem || source.Destination.String() != "/items" || source.DestinationUnresolved { t.Errorf("callback source = %#v", source) } if callbackContexts[index].FS == nil || callbackContexts[index].BaseDir != "records" { t.Errorf("callback context = %#v", callbackContexts[index]) } } metadata := result.Metadata() for index := 1; index < len(wantIDs); index++ { path := configkit.Keys("items").Index(index).Key("id") info, ok := metadata.Lookup(path) if !ok || !info.Explicit || len(info.Origin.Locations) != 1 || info.Origin.Locations[0].SourceID != []string{"source-2", "source-3"}[index-1] { t.Errorf("shifted item origin at %s = %#v, %v", path.String(), info, ok) } } if got := result.Sources(); len(got) != 3 || got[1].Destination.String() != "/items" || got[1].DestinationUnresolved { t.Fatalf("final item sources = %#v", got) } } func TestFacadeItemDestinationFallbackEvidenceSurvivesFailures(t *testing.T) { directory := t.TempDir() mainPath := filepath.Join(directory, "main.yml") helperPath := filepath.Join(directory, "helper.yml") if err := os.WriteFile(mainPath, []byte("configkit: {imports: [{path: helper.yml, destination: [metadata]}]}\nid: main\n"), 0o600); err != nil { t.Fatal(err) } if err := os.WriteFile(helperPath, []byte("value: [unterminated\n"), 0o600); err != nil { t.Fatal(err) } _, err := configkit.Load(configkit.File(mainPath), configkit.Options[map[string]any]{ Imports: true, Destination: configkit.Keys("items"), PlacementMode: configkit.PlacementModeSequenceItem, }) loadError, ok := err.(*configkit.LoadError) if !ok { t.Fatalf("early failure = %v", err) } sources := loadError.Sources() if len(sources) != 2 || sources[0].Destination.String() != "/items" || sources[0].DestinationUnresolved || sources[0].PlacementMode != configkit.PlacementModeSequenceItem || sources[1].Destination.String() != "/items" || !sources[1].DestinationUnresolved || sources[1].PlacementMode != configkit.PlacementModeMapping { t.Fatalf("early source snapshots = %#v", sources) } if err := os.WriteFile(helperPath, []byte("value: invalid-for-typed-schema\n"), 0o600); err != nil { t.Fatal(err) } type item struct { ID string `yaml:"id"` Metadata struct { Value int `yaml:"value"` } `yaml:"metadata"` } type configuration struct { Items []item `yaml:"items"` } _, err = configkit.Load(configkit.File(mainPath), configkit.Options[configuration]{ Imports: true, Destination: configkit.Keys("items"), PlacementMode: configkit.PlacementModeSequenceItem, }) loadError, ok = err.(*configkit.LoadError) if !ok { t.Fatalf("post-placement failure = %v", err) } sources = loadError.Sources() if len(sources) != 2 || sources[0].Destination.String() != "/items" || sources[0].DestinationUnresolved || sources[1].Destination.String() != "/items/0/metadata" || sources[1].DestinationUnresolved { t.Fatalf("post-placement source snapshots = %#v", sources) } firstSnapshot := sources[1] sources[1].Destination = configkit.Keys("mutated") if again := loadError.Sources(); len(again) != 2 || again[1].Destination.String() != firstSnapshot.Destination.String() || again[1].DestinationUnresolved { t.Fatalf("failure source snapshots were aliased: %#v", again) } var callback configkit.SourceInfo _, err = configkit.Load(configkit.File(mainPath), configkit.Options[map[string]any]{ Imports: true, Destination: configkit.Keys("items"), PlacementMode: configkit.PlacementModeSequenceItem, Definition: configkit.Definition[map[string]any]{Resolve: func(_ *map[string]any, resolution *configkit.Resolution) error { callback, _ = resolution.Source("source-2") return nil }}, }) if err != nil { t.Fatalf("successful item load: %v", err) } if callback.Destination.String() != "/items/0/metadata" || callback.DestinationUnresolved || callback.PlacementMode != configkit.PlacementModeMapping { t.Fatalf("callback source snapshot = %#v", callback) } } func TestFacadeNestedItemFallbackUsesNearestResolvedContainer(t *testing.T) { directory := t.TempDir() mainPath := filepath.Join(directory, "main.yml") childPath := filepath.Join(directory, "child.yml") helperPath := filepath.Join(directory, "helper.yml") if err := os.WriteFile(mainPath, []byte("configkit: {imports: [{path: child.yml, destination: [children], placement: sequence-item}]}\nid: parent\n"), 0o600); err != nil { t.Fatal(err) } if err := os.WriteFile(childPath, []byte("configkit: {imports: [{path: helper.yml, destination: [metadata]}]}\nid: child\n"), 0o600); err != nil { t.Fatal(err) } if err := os.WriteFile(helperPath, []byte("value: [unterminated\n"), 0o600); err != nil { t.Fatal(err) } _, err := configkit.Load(configkit.File(mainPath), configkit.Options[map[string]any]{ Imports: true, Destination: configkit.Keys("groups"), PlacementMode: configkit.PlacementModeSequenceItem, }) loadError, ok := err.(*configkit.LoadError) if !ok { t.Fatalf("nested acquisition failure = %v", err) } sources := loadError.Sources() if len(sources) != 3 { t.Fatalf("nested source snapshots = %#v", sources) } if got := sources[0]; got.Destination.String() != "/groups" || got.DestinationUnresolved || got.PlacementMode != configkit.PlacementModeSequenceItem { t.Errorf("outer item snapshot = %#v", got) } if got := sources[1]; got.Destination.String() != "/groups" || !got.DestinationUnresolved || got.PlacementMode != configkit.PlacementModeSequenceItem { t.Errorf("nested item fallback = %#v", got) } if got := sources[2]; got.Destination.String() != "/groups" || !got.DestinationUnresolved || got.PlacementMode != configkit.PlacementModeMapping { t.Errorf("nested helper fallback = %#v", got) } } func TestFacadeSequenceCompositionRegistrationPathIsDetached(t *testing.T) { registrations := []configkit.SequenceComposition{{Path: configkit.Keys("records"), IdentityField: "id"}} definition := configkit.Definition[map[string]any]{ SequenceCompositions: registrations, Version: &configkit.VersionRule{ Path: configkit.Keys("version"), Check: func(configkit.Version, *configkit.Validation) error { registrations[0].Path = configkit.Keys("other") registrations[0].IdentityField = "changed" return nil }, }, } _, err := configkit.Load(configkit.Mapping("registration", map[string]any{ "version": "1", "records": []any{map[string]any{"id": "same"}, map[string]any{"id": "same"}}, }), configkit.Options[map[string]any]{ Definition: definition, SourceVersionMode: configkit.SourceVersionModeIfPresent, }) loadError, ok := err.(*configkit.LoadError) if !ok { t.Fatalf("duplicate registered identity = %v", err) } for _, diagnostic := range loadError.Diagnostics() { if diagnostic.Code == configkit.CodeComposeConflict { return } } t.Fatalf("registration mutation changed the in-flight policy: %#v", loadError.Diagnostics()) } func TestFacadeSourceInfoPlacementCopiesAndZeroValues(t *testing.T) { zero := configkit.SourceInfo{} if zero.PlacementMode != configkit.PlacementModeMapping || zero.DestinationUnresolved { t.Fatalf("zero source info = %#v", zero) } loaded, err := configkit.Load[map[string]any](configkit.Mapping("mapping", map[string]any{"value": true})) if err != nil { t.Fatal(err) } sources := loaded.Sources() if len(sources) != 1 || sources[0].PlacementMode != configkit.PlacementModeMapping || sources[0].DestinationUnresolved { t.Fatalf("mapping source evidence = %#v", sources) } first := sources[0] first.Destination = configkit.Keys("caller") if again := loaded.Sources(); len(again) != 1 || again[0].Destination.String() != "" || again[0].DestinationUnresolved { t.Fatalf("source evidence changed after caller mutation: %#v", again) } } func TestFacadeSequenceReplacementKeepsTypedAndHistoricalEvidenceAligned(t *testing.T) { type record struct { ID string `yaml:"id"` Count int `yaml:"count"` Enabled bool `yaml:"enabled"` Empty string `yaml:"empty"` Nullable *string `yaml:"nullable"` Token string `yaml:"token"` Omitted string `yaml:"omitted"` } type configuration struct { Entries []record `yaml:"entries"` } directory := t.TempDir() mainPath := filepath.Join(directory, "main.yml") underlayPath := filepath.Join(directory, "underlay.yml") if err := os.WriteFile(mainPath, []byte(`entries: - id: current count: 0 enabled: false empty: "" nullable: null token: CURRENT-SECRET-CANARY `), 0o600); err != nil { t.Fatal(err) } if err := os.WriteFile(underlayPath, []byte(`configkit: imports: - glob: records/*.yml destination: [entries] placement: sequence-item `), 0o600); err != nil { t.Fatal(err) } recordsDir := filepath.Join(directory, "records") if err := os.MkdirAll(recordsDir, 0o700); err != nil { t.Fatal(err) } for name, body := range map[string]string{ "a.yml": "id: old-a\ntoken: OLD-SECRET-CANARY-A\n", "b.yml": "id: old-b\ntoken: OLD-SECRET-CANARY-B\n", } { if err := os.WriteFile(filepath.Join(recordsDir, name), []byte(body), 0o600); err != nil { t.Fatal(err) } } var callbackItems []configkit.SourceInfo var callbackContexts []configkit.ResourceContext result, err := configkit.LoadLayered(configkit.Input{Source: configkit.File(mainPath)}, configkit.LayeredOptions[configuration]{ Underlays: []configkit.Underlay{{Inputs: []configkit.Input{{Source: configkit.File(underlayPath), Imports: true}}}}, Definition: configkit.Definition[configuration]{ SequenceCompositions: []configkit.SequenceComposition{{Path: configkit.Keys("entries"), IdentityField: "id"}}, Secret: func(path configkit.Path) bool { return path.String() == "/entries/0/token" || path.String() == "/entries/1/token" }, Resolve: func(value *configuration, resolution *configkit.Resolution) error { for _, field := range []string{"count", "enabled", "empty", "nullable"} { path := configkit.Keys("entries").Index(0).Key(field) if !resolution.IsExplicit(path) { t.Errorf("resolver did not see explicit %s", path.String()) } } if resolution.IsExplicit(configkit.Keys("entries").Index(0).Key("omitted")) { t.Error("resolver treated an omitted field as explicit") } info, found := resolution.InputInfo(configkit.Keys("entries").Index(0).Key("count")) if !found || info.Origin.Layer != configkit.LayerBase { t.Errorf("resolver current-record input info = %#v, %v", info, found) } for _, id := range []string{"source-3", "source-4"} { source, ok := resolution.Source(id) if !ok { t.Errorf("resolver could not query %s", id) continue } context, contextOK := resolution.SourceContext(id) if !contextOK || context.FS == nil || context.BaseDir != "records" { t.Errorf("resolver context for %s = %#v, %v", id, context, contextOK) } callbackItems = append(callbackItems, source) callbackContexts = append(callbackContexts, context) } return nil }, }, }) if err != nil { if loadError, ok := err.(*configkit.LoadError); ok { t.Fatalf("layered item replacement: %#v", loadError.Diagnostics()) } t.Fatalf("layered item replacement: %v", err) } if len(result.Config.Entries) != 1 || result.Config.Entries[0].ID != "current" || result.Config.Entries[0].Count != 0 || result.Config.Entries[0].Enabled || result.Config.Entries[0].Empty != "" || result.Config.Entries[0].Nullable != nil { t.Fatalf("typed replacement result = %#v", result.Config) } if len(callbackItems) != 2 || len(callbackContexts) != 2 { t.Fatalf("callback sources = %#v; contexts = %#v", callbackItems, callbackContexts) } for _, source := range callbackItems { if source.PlacementMode != configkit.PlacementModeSequenceItem || source.Destination.String() != "/entries" || source.DestinationUnresolved { t.Errorf("callback item source = %#v", source) } } metadata := result.Metadata() for _, field := range []string{"count", "enabled", "empty", "nullable"} { path := configkit.Keys("entries").Index(0).Key(field) if info, ok := metadata.Lookup(path); !ok || !info.Explicit || (field == "nullable") != info.Null { t.Errorf("explicit metadata at %s = %#v, %v", path.String(), info, ok) } } if info, ok := metadata.Lookup(configkit.Keys("entries").Index(0).Key("omitted")); ok && info.Explicit { t.Errorf("metadata marked an omitted zero-valued field explicit: %#v", info) } mainID := "" for _, source := range result.Sources() { if source.Path == mainPath { mainID = source.ID } } currentOrigin, ok := metadata.Lookup(configkit.Keys("entries").Index(0).Key("id")) if !ok || len(currentOrigin.Origin.Locations) != 1 || currentOrigin.Origin.Locations[0].SourceID != mainID || mainID == "" { t.Fatalf("replacement origin = %#v, main source %q", currentOrigin, mainID) } oldRecord, ok := result.Explain(configkit.Keys("entries").Index(1).Key("token")) if !ok || oldRecord.Effective.Present { t.Fatalf("removed appended item explanation = %#v, %v", oldRecord, ok) } maskedHistory := false for _, change := range oldRecord.History { maskedHistory = maskedHistory || change.Before.Redacted || change.After.Redacted } if !maskedHistory { t.Fatal("removed appended item lost historical sensitivity") } var effective bytes.Buffer if err := result.WriteEffective(&effective); err != nil { t.Fatal(err) } var explanation bytes.Buffer if err := result.WriteExplanation(&explanation, configkit.Keys("entries").Index(1).Key("token")); err != nil { t.Fatal(err) } for _, output := range []string{effective.String(), explanation.String()} { for _, canary := range []string{"CURRENT-SECRET-CANARY", "OLD-SECRET-CANARY-A", "OLD-SECRET-CANARY-B"} { if strings.Contains(output, canary) { t.Fatalf("sensitive sequence value leaked: %s", output) } } } }