package configkit import ( "bytes" "encoding/json" "errors" "fmt" "io" "os" "path/filepath" "reflect" "strings" "testing" "gitea.maximumdirect.net/eric/ConfigKit/internal/document" ) type explanationConcurrency struct { Transcription struct { Concurrency int `yaml:"concurrency"` } `yaml:"transcription"` } func TestExplainShowsDefaultBaseAndEffectiveProfileValue(t *testing.T) { directory := t.TempDir() mainPath := writeImportFile(t, directory, "config.yml", "configkit:\n imports: [{path: transcription.yml}]\n") writeImportFile(t, directory, "transcription.yml", "transcription:\n concurrency: 8\n") writeImportFile(t, directory, filepath.Join("profiles", "testing.yml"), "transcription:\n concurrency: 1\n") result, err := Load[explanationConcurrency](File(mainPath), Options[explanationConcurrency]{ Imports: true, Profile: "testing", Definition: Definition[explanationConcurrency]{Defaults: func() explanationConcurrency { value := explanationConcurrency{} value.Transcription.Concurrency = 4 return value }}, }) if err != nil { t.Fatal(err) } explanation, ok := result.Explain(Keys("transcription", "concurrency")) if !ok { t.Fatal("known path was not explained") } if got := explanationValues(explanation); !reflect.DeepEqual(got, []string{"4\n", "8\n", "1\n"}) { t.Fatalf("history values = %#v", got) } if explanation.Effective.YAML != "1\n" || explanation.Origin.Layer != LayerProfile || len(explanation.Origin.Locations) != 1 || explanation.Origin.Locations[0].SourceID != "source-3" || explanation.Origin.Locations[0].Line != 2 { t.Fatalf("effective explanation = %#v", explanation) } } type explanationConfig struct { Concurrency int `yaml:"concurrency"` Equal string `yaml:"equal"` Limit int `yaml:"limit"` Items []string `yaml:"items"` Labels map[string]string `yaml:"labels"` Dynamic any `yaml:"dynamic"` Maybe *string `yaml:"maybe"` Empty []string `yaml:"empty"` Credential Secret `yaml:"credential"` Classified Secret `yaml:"classified"` DerivedA string `yaml:"derived_a"` DerivedB string `yaml:"derived_b"` } func TestExplainReplaysCLIResolutionContainersAndSafeHistoricalValues(t *testing.T) { directory := t.TempDir() mainPath := writeImportFile(t, directory, "config.yml", `concurrency: 8 equal: same limit: wrong-before-profile items: [base, removed] labels: {base: retained} dynamic: {retired: HISTORICAL_EXPLAIN_CANARY, public: visible} credential: APP_SECRET classified: APP_SECRET `) writeImportFile(t, directory, filepath.Join("profiles", "testing.yml"), `concurrency: 1 equal: same limit: 7 items: [profile] labels: {profile: retained} dynamic: selected `) result, err := loadWithSecretLookup(File(mainPath), func(name string) (string, bool) { if name != "APP_SECRET" { t.Fatalf("secret lookup = %q", name) } return "RESOLVED_EXPLAIN_CANARY", true }, Options[explanationConfig]{ Profile: "testing", Overrides: []Override{ {Path: Keys("concurrency"), Value: 2, Flag: "--concurrency"}, {Path: Keys("equal"), Value: "same", Flag: "--equal"}, {Path: Keys("items"), Value: []any{"cli", "restored"}, Flag: "--items"}, {Path: Keys("labels"), Value: map[string]any{"cli": "retained"}, Flag: "--label"}, }, Definition: Definition[explanationConfig]{ Defaults: func() explanationConfig { return explanationConfig{ Concurrency: 4, Equal: "same", Labels: map[string]string{"default": "retained"}, Maybe: nil, Empty: []string{}, Credential: SecretEnv("APP_SECRET"), Classified: SecretEnv("APP_SECRET"), } }, Secret: func(path Path) bool { return path.String() == "/dynamic/retired" || path.String() == "/classified" }, Resolve: func(configuration *explanationConfig, resolution *Resolution) error { Normalize(resolution, Keys("concurrency"), &configuration.Concurrency, 3, "normalized\nconcurrency", Keys("labels")) Normalize(resolution, Keys("equal"), &configuration.Equal, "same", "record equal value") Normalize(resolution, Keys("derived_a"), &configuration.DerivedA, "DERIVED_EXPLAIN_A", "derived cycle a", Keys("derived_b")) Normalize(resolution, Keys("derived_b"), &configuration.DerivedB, "DERIVED_EXPLAIN_B", "derived cycle b", Keys("derived_a"), Keys("dynamic")) return nil }, }, }) if err != nil { t.Fatal(err) } concurrency, ok := result.Explain(Keys("concurrency")) if !ok { t.Fatal("concurrency was not explained") } if got := explanationValues(concurrency); !reflect.DeepEqual(got, []string{"4\n", "8\n", "1\n", "2\n", "3\n"}) { t.Fatalf("concurrency history = %#v", got) } if got := historyValueLayers(concurrency); !reflect.DeepEqual(got, []Layer{LayerDefault, LayerBase, LayerProfile, LayerCLI, LayerResolution}) { t.Fatalf("concurrency layers = %#v", got) } if concurrency.History[4].Before.YAML != "2\n" || concurrency.History[4].Reasons[0] != "normalized\nconcurrency" || concurrency.History[4].Dependencies[0].String() != "/labels" { t.Fatalf("resolution history = %#v", concurrency.History[4]) } equal, _ := result.Explain(Keys("equal")) if len(equal.History) != 5 { t.Fatalf("equal writes were lost: %#v", equal.History) } for _, change := range equal.History[1:] { if change.Before.YAML != "same\n" || change.After.YAML != "same\n" { t.Fatalf("equal replacement = %#v", change) } } limit, _ := result.Explain(Keys("limit")) if got := explanationValues(limit); !reflect.DeepEqual(got, []string{"0\n", "wrong-before-profile\n", "7\n"}) { t.Fatalf("overridden invalid input was not retained: %#v", got) } removed, ok := result.Explain(Keys("dynamic", "retired")) if !ok || removed.Effective.Present || len(removed.History) < 2 { t.Fatalf("removed path = %#v, %v", removed, ok) } for _, change := range removed.History { if strings.Contains(change.Before.YAML+change.After.YAML, "HISTORICAL_EXPLAIN_CANARY") { t.Fatalf("historical secret escaped redaction: %#v", change) } } if !removed.History[0].After.Redacted || removed.History[len(removed.History)-1].After.Present { t.Fatalf("removed secret history = %#v", removed.History) } dynamic, _ := result.Explain(Keys("dynamic")) if len(dynamic.History) < 3 || !dynamic.History[1].After.Redacted || strings.Contains(dynamic.History[1].After.YAML, "HISTORICAL_EXPLAIN_CANARY") { t.Fatalf("container redaction history = %#v", dynamic.History) } items, _ := result.Explain(Keys("items")) if len(items.History) != 4 || !strings.Contains(items.History[1].After.YAML, "removed") || strings.Contains(items.History[2].After.YAML, "removed") || !strings.Contains(items.History[3].After.YAML, "restored") { t.Fatalf("atomic sequence history = %#v", items.History) } removedIndex, ok := result.Explain(Keys("items").Index(1)) if !ok || !removedIndex.History[1].Before.Present || removedIndex.History[1].After.Present || !removedIndex.History[2].After.Present { t.Fatalf("sequence descendant history = %#v", removedIndex.History) } labels, _ := result.Explain(Keys("labels")) if len(labels.History) != 4 || !strings.Contains(labels.Effective.YAML, "default: retained") || !strings.Contains(labels.Effective.YAML, "profile: retained") || !strings.Contains(labels.Effective.YAML, "cli: retained") { t.Fatalf("composite mapping history = %#v", labels) } if labels.Origin.Layer != LayerCLI || len(labels.Origin.Locations) != 3 { t.Fatalf("composite effective origin = %#v", labels.Origin) } maybe, _ := result.Explain(Keys("maybe")) empty, _ := result.Explain(Keys("empty")) if !maybe.Effective.Present || maybe.Effective.YAML != "null\n" || !empty.Effective.Present || empty.Effective.YAML != "[]\n" { t.Fatalf("null/empty snapshots = maybe %#v empty %#v", maybe.Effective, empty.Effective) } credential, _ := result.Explain(Keys("credential")) if credential.SecretReference == nil || credential.SecretReference.Name != "APP_SECRET" || credential.Effective.YAML != "APP_SECRET\n" { t.Fatalf("secret reference = %#v", credential) } classified, _ := result.Explain(Keys("classified")) if classified.SecretReference != nil || !classified.Effective.Redacted || strings.Contains(classified.Effective.YAML, "APP_SECRET") { t.Fatalf("classified secret reference = %#v", classified) } var derivedExplanations []Explanation for _, path := range []Path{Keys("derived_a"), Keys("derived_b")} { derived, _ := result.Explain(path) if !derived.Effective.Redacted || strings.Contains(derived.Effective.YAML, "DERIVED_EXPLAIN") { t.Fatalf("dependency closure at %s = %#v", path.String(), derived) } derivedExplanations = append(derivedExplanations, derived) } formatted := fmt.Sprintf("%v %#v %v", removed, credential, derivedExplanations) encoded, marshalErr := json.Marshal(append([]Explanation{removed, credential, classified}, derivedExplanations...)) if marshalErr != nil || strings.Contains(formatted+string(encoded), "RESOLVED_EXPLAIN_CANARY") || strings.Contains(formatted+string(encoded), "HISTORICAL_EXPLAIN_CANARY") || strings.Contains(formatted+string(encoded), "DERIVED_EXPLAIN") { t.Fatalf("public records disclosed a canary: %s %s", formatted, encoded) } concurrency.Path.segments[0].key = "mutated" concurrency.History[4].Reasons[0] = "mutated" concurrency.History[4].Dependencies[0].segments[0].key = "mutated" result.Config.Concurrency = 99 again, _ := result.Explain(Keys("concurrency")) if again.Path.String() != "/concurrency" || again.Effective.YAML != "3\n" || again.History[4].Reasons[0] != "normalized\nconcurrency" || again.History[4].Dependencies[0].String() != "/labels" { t.Fatalf("returned explanation aliased internal history: %#v", again) } var first, second bytes.Buffer if err := result.WriteExplanation(&first, Keys("concurrency")); err != nil { t.Fatal(err) } if err := result.WriteExplanation(&second, Keys("concurrency")); err != nil || first.String() != second.String() { t.Fatalf("nondeterministic rendering: %v\n%s\n%s", err, first.String(), second.String()) } if strings.Contains(first.String(), "\nconcurrency\"") || !strings.Contains(first.String(), `"normalized\nconcurrency"`) { t.Fatalf("reason controls were not escaped: %q", first.String()) } unknownOutput := bytes.NewBufferString("unchanged") if err := result.WriteExplanation(unknownOutput, Keys("unknown")); !errors.Is(err, errExplanationUnknownPath) || unknownOutput.String() != "unchanged" { t.Fatalf("unknown writer = %q, %v", unknownOutput.String(), err) } if _, ok := result.Explain(Keys("items").Index(-1)); ok { t.Fatal("malformed path was explained") } wantWriteError := errors.New("write failed") if err := result.WriteExplanation(errorWriter{err: wantWriteError}, Keys("concurrency")); !errors.Is(err, wantWriteError) { t.Fatalf("writer error = %v", err) } if err := result.WriteExplanation(shortWriter{}, Keys("concurrency")); !errors.Is(err, io.ErrShortWrite) { t.Fatalf("short writer error = %v", err) } var invalidInput bytes.Buffer if err := result.WriteExplanation(&invalidInput, Keys("limit")); err != nil || !strings.Contains(invalidInput.String(), "policy-validated input") || strings.Contains(invalidInput.String(), "wrong-before-profile\n source: layer=\"base\"\n before (canonical typed)") { t.Fatalf("historical representation rendering = %v\n%s", err, invalidInput.String()) } } func TestSecretsBootstrapLoadAndExplanationRemainSeparateAndSafe(t *testing.T) { const name = "CONFIGKIT_EXPLAIN_BOOTSTRAP_TEST" previous, present := os.LookupEnv(name) if err := os.Unsetenv(name); err != nil { t.Fatal(err) } t.Cleanup(func() { if present { _ = os.Setenv(name, previous) } else { _ = os.Unsetenv(name) } }) directory := t.TempDir() writeSecretTestFile(t, directory, name, "BOOTSTRAP_EXPLAIN_CANARY\n") report, err := LoadSecretsDir(directory) if err != nil || len(report.Entries()) != 1 || report.Entries()[0].Status != SecretFileLoaded { t.Fatalf("bootstrap = %#v, %v", report, err) } type config struct { Credential Secret `yaml:"credential"` } result, err := Load[config](Bytes("config.yml", []byte("credential: "+name+"\n"))) if err != nil { t.Fatal(err) } var output bytes.Buffer if err := result.WriteExplanation(&output, Keys("credential")); err != nil { t.Fatal(err) } if !strings.Contains(output.String(), name) || strings.Contains(output.String(), "BOOTSTRAP_EXPLAIN_CANARY") { t.Fatalf("explanation mixed bootstrap value into reference report: %s", output.String()) } } func TestHistoryNodeBudgetCountsSharedTreesOnce(t *testing.T) { leaf := &document.Node{Kind: document.String, Text: "value"} root := &document.Node{Kind: document.Mapping, Mapping: []document.Entry{{Key: "value", Value: leaf}}} applications := []historyApplication{{layer: LayerBase, value: root}} if !historyNodesWithin(2, root, root, root, applications, nil) { t.Fatal("structurally shared history was counted more than once") } other := document.Clone(root) if historyNodesWithin(3, root, other, root, applications, nil) { t.Fatal("distinct retained nodes did not consume the budget") } } func explanationValues(explanation Explanation) []string { values := make([]string, len(explanation.History)) for index, change := range explanation.History { values[index] = change.After.YAML } return values } func historyValueLayers(explanation Explanation) []Layer { layers := make([]Layer, len(explanation.History)) for index, change := range explanation.History { layers[index] = change.Origin.Layer } return layers } func TestExplanationReconcilesDefaultsAfterInputReplacement(t *testing.T) { type cfg struct { M map[string]int `yaml:"m"` } for _, base := range []string{"null", "replaced-text"} { for _, cli := range []bool{false, true} { t.Run(fmt.Sprintf("%s/cli=%v", base, cli), func(t *testing.T) { root := t.TempDir() main := writeImportFile(t, root, "main.yml", "m: "+base+"\n") opts := Options[cfg]{Definition: Definition[cfg]{Defaults: func() cfg { return cfg{M: map[string]int{"a": 1}} }}} if cli { opts.Overrides = []Override{{Path: Keys("m"), Value: map[string]any{"b": 2}, Flag: "--m"}} } else { writeImportFile(t, root, "profiles/p.yml", "m: {b: 2}\n") opts.Profile = "p" } result, err := Load(File(main), opts) if err != nil { t.Fatal(err) } for _, path := range []Path{Keys("m"), Keys("m", "a")} { explanation, ok := result.Explain(path) if !ok { t.Fatal("missing explanation") } last := explanation.History[len(explanation.History)-1] if last.After != explanation.Effective || last.Origin.Operation != ChangeDecoding { t.Fatalf("history does not reconcile final value: %#v", explanation) } info, _ := result.Metadata().Lookup(path) if last.Origin.Layer != info.Origin.Layer { t.Fatal("decoding lost effective origin") } } }) } } } func TestExplanationReplaysResolutionAdditionsAndOverlappingIntent(t *testing.T) { type cfg struct { M map[string]any `yaml:"m"` } for _, overlap := range []bool{false, true} { t.Run(fmt.Sprint(overlap), func(t *testing.T) { result, err := Load(Bytes("base", []byte("m: {old: 1}\n")), Options[cfg]{Definition: Definition[cfg]{Resolve: func(c *cfg, r *Resolution) error { c.M["new"] = map[string]any{"child": int64(7)} delete(c.M, "old") r.Record(Keys("m", "new"), ChangeDerivedDefault, "add nested", Keys("m", "old")) r.Record(Keys("m", "old"), ChangeNormalization, "remove old") if overlap { r.Record(Keys("m"), ChangeNormalization, "update container") } return nil }}}) if err != nil { t.Fatal(err) } for _, path := range []Path{Keys("m"), Keys("m", "new"), Keys("m", "new", "child"), Keys("m", "old")} { x, ok := result.Explain(path) if !ok { t.Fatal("missing known history") } var count int for _, v := range x.History { if v.Origin.Layer == LayerResolution { count++ if overlap && len(v.Reasons) != 3 { t.Fatal("lost overlapping intent") } } } if overlap && count != 1 { t.Fatalf("overlapping records applied %d times", count) } last := x.History[len(x.History)-1] if last.After != x.Effective { t.Fatalf("incorrect replay for %s: %#v", path, x) } } }) } }