package config import ( "bytes" "errors" "os" "path/filepath" "reflect" "strings" "testing" ck "gitea.maximumdirect.net/eric/ConfigKit" ) const base = "version: 2\nbackends:\n local:\n endpoint: https://local.invalid/v1\nllm:\n proposal_profile: proposal\n" func loadText(text, overlay string, overrides ...ck.Override) (*ck.Result[Config], error) { return Load(ck.Bytes("config.yml", []byte(text)), overlay, overrides...) } func TestDefaultsAndDomainSettings(t *testing.T) { loaded, err := loadText(base, "") if err != nil { t.Fatal(err) } c := loaded.Config if c.LLM.ValidationProfile != "proposal" || c.Backends["local"].Concurrency != 1 || c.Backends["local"].QueueCapacity != 1024 { t.Fatalf("derived settings: %+v %+v", c.LLM, c.Backends) } if !reflect.DeepEqual(c.Pipeline.Modules, []string{"glossary", "homophones", "glossary", "spoken_word", "grammar"}) { t.Fatalf("module order: %v", c.Pipeline.Modules) } if explanation, ok := loaded.Explain(ck.Keys("llm", "validation_profile")); !ok || len(explanation.History) == 0 { t.Fatal("validation inheritance has no recorded derivation") } if _, err := loadText(base+"pipeline:\n modules: []\n", ""); err != nil { t.Fatalf("empty pipeline: %v", err) } if _, err := loadText(base+"pipeline:\n modules: [grammar, glossary, grammar]\n", ""); err != nil { t.Fatalf("repeated modules: %v", err) } } func TestStrictInputAndConstraints(t *testing.T) { for _, tc := range []struct{ name, text string }{ {"old version", strings.Replace(base, "version: 2", "version: 1", 1)}, {"missing version", strings.Replace(base, "version: 2\n", "", 1)}, {"null version", strings.Replace(base, "version: 2", "version: null", 1)}, {"quoted version", strings.Replace(base, "version: 2", "version: '2'", 1)}, {"unknown field", base + "mystery: true\n"}, {"empty validation profile", base + " validation_profile: ''\n"}, {"null validation profile", base + " validation_profile: null\n"}, {"null proposal profile", strings.Replace(base, "proposal_profile: proposal", "proposal_profile: null", 1)}, {"zero backend concurrency", base + " concurrency: 0\n"}, {"invalid target", base + "chunking:\n target_sections: 0\n"}, {"invalid section relation", base + "chunking:\n min_section_tokens: 10000\n"}, {"string normalization", base + "normalization:\n max_segment_gap: 4s\n"}, {"invalid threshold", base + "thresholds:\n glossary: 1.1\n"}, {"removed retention", base + "diagnostics:\n retention: always\n"}, } { t.Run(tc.name, func(t *testing.T) { if _, err := loadText(tc.text, ""); err == nil { t.Fatal("invalid config accepted") } }) } _, err := loadText(strings.Replace(base, "version: 2", "version: 1", 1), "") var loadErr *ck.LoadError if !errors.As(err, &loadErr) || len(loadErr.Diagnostics()) == 0 || !strings.Contains(loadErr.Diagnostics()[0].Message, "docs/migrations/v2.md") { t.Fatalf("migration guidance: %v", err) } for _, tc := range []struct{ name, text string }{ {"optional target null", base + "chunking:\n target_sections: null\n"}, {"zero queue", strings.Replace(base, "llm:\n", " queue_capacity: 0\nllm:\n", 1)}, {"zero retries", base + " transient_retries: 0\n repair_attempts: 0\n"}, {"zero threshold", base + "thresholds:\n grammar: 0\n"}, } { t.Run(tc.name, func(t *testing.T) { if _, err := loadText(tc.text, ""); err != nil { t.Fatal(err) } }) } } func TestOverlayOverrideAndInheritance(t *testing.T) { dir := t.TempDir() if err := os.Mkdir(filepath.Join(dir, "overlays"), 0700); err != nil { t.Fatal(err) } main := filepath.Join(dir, "config.yml") if err := os.WriteFile(main, []byte(base), 0600); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(dir, "overlays", "testing.yml"), []byte("llm:\n proposal_profile: testing\nchunking:\n max_section_tokens: 1000\n"), 0600); err != nil { t.Fatal(err) } loaded, err := Load(ck.File(main), "testing", ck.Override{Path: ck.Keys("llm", "proposal_profile"), Value: "explicit", Flag: "--proposal-profile"}, ck.Override{Path: ck.Keys("chunking", "min_section_tokens"), Value: 500, Flag: "--min-section-tokens"}) if err != nil { t.Fatal(err) } if loaded.Config.LLM.ProposalProfile != "explicit" || loaded.Config.LLM.ValidationProfile != "explicit" || loaded.Config.Chunking.MaxSectionTokens != 1000 || loaded.Config.Chunking.MinSectionTokens != 500 { t.Fatalf("resolved: %+v", loaded.Config) } if got, _ := loaded.Metadata().Lookup(ck.Keys("llm", "proposal_profile")); got.Origin.Layer != ck.LayerCLI { t.Fatalf("override origin: %+v", got) } if got, _ := loaded.Metadata().Lookup(ck.Keys("chunking", "max_section_tokens")); got.Origin.Layer != ck.LayerOverlay { t.Fatalf("overlay origin: %+v", got) } } func TestSurvivingCredentials(t *testing.T) { t.Setenv("BASE_SECRET", "") t.Setenv("NEW_SECRET", "synthetic-secret") withSecret := strings.Replace(base, "llm:\n", " other:\n endpoint: https://other.invalid/v1\n credential: BASE_SECRET\nllm:\n", 1) if _, err := loadText(withSecret, ""); err == nil { t.Fatal("missing unselected backend secret accepted") } replacement := ck.Override{Path: ck.Keys("backends", "other", "credential"), Value: "NEW_SECRET", Flag: "--credential"} loaded, err := loadText(withSecret, "", replacement) if err != nil { t.Fatal(err) } if got := loaded.Config.Backends["other"].Credential.Value(); got != "synthetic-secret" { t.Fatalf("resolved secret: %q", got) } var effective bytes.Buffer if err := loaded.WriteEffective(&effective); err != nil { t.Fatal(err) } if strings.Contains(effective.String(), "synthetic-secret") { t.Fatal("effective output leaked a secret") } null := ck.Override{Path: ck.Keys("backends", "other", "credential"), Value: nil, Flag: "--credential"} loaded, err = loadText(withSecret, "", null) if err != nil || loaded.Config.Backends["other"].Credential != nil { t.Fatalf("null credential: %+v %v", loaded, err) } inherited := `version: 2 backends: parent: endpoint: https://parent.invalid/v1 credential: BASE_SECRET local: extends: parent credential: null llm: proposal_profile: proposal ` if _, err := loadText(inherited, ""); err == nil { t.Fatal("null child credential removed the unselected parent's surviving reference") } t.Setenv("BASE_SECRET", "synthetic-parent-secret") loaded, err = loadText(strings.Replace(inherited, " credential: null\n", "", 1), "") if err != nil { t.Fatal(err) } if got := loaded.Config.Backends["local"].Credential.Value(); got != "synthetic-parent-secret" { t.Fatalf("inherited secret: %q", got) } if got := loaded.Metadata().IsExplicit(ck.Keys("backends", "local", "credential")); !got { t.Fatal("inherited credential is not explicit") } var inheritedEffective bytes.Buffer if err := loaded.WriteEffective(&inheritedEffective); err != nil { t.Fatal(err) } if strings.Contains(inheritedEffective.String(), "synthetic-parent-secret") { t.Fatal("effective output leaked an inherited secret") } loaded, err = loadText(inherited, "") if err != nil || loaded.Config.Backends["local"].Credential != nil { t.Fatalf("child null credential: %+v %v", loaded, err) } if got := loaded.Config.Backends["parent"].Credential.Value(); got != "synthetic-parent-secret" { t.Fatalf("parent credential after child null: %q", got) } t.Setenv("AUDITA_MODEL", "legacy-model") loaded, err = loadText(base, "") if err != nil || loaded.Config.LLM.ProposalProfile != "proposal" { t.Fatalf("legacy environment affected loading: %+v %v", loaded, err) } } func TestSiblingInheritancePreservesBackendSettings(t *testing.T) { text := `version: 2 backends: base: endpoint: https://base.invalid/v1 concurrency: 3 queue_capacity: 0 local: extends: base llm: proposal_profile: proposal ` loaded, err := loadText(text, "") if err != nil { t.Fatal(err) } backend := loaded.Config.Backends["local"] if backend.Endpoint != "https://base.invalid/v1" || backend.Concurrency != 3 || backend.QueueCapacity != 0 { t.Fatalf("inherited backend settings: %+v", backend) } for _, path := range []ck.Path{ ck.Keys("backends", "local", "endpoint"), ck.Keys("backends", "local", "concurrency"), ck.Keys("backends", "local", "queue_capacity"), } { if !loaded.Metadata().IsExplicit(path) { t.Errorf("inherited field %s is not explicit", path.String()) } } overridden, err := loadText(strings.Replace(text, " extends: base\n", " extends: base\n concurrency: 2\n", 1), "") if err != nil { t.Fatal(err) } if got := overridden.Config.Backends["local"].Concurrency; got != 2 { t.Fatalf("child concurrency override: %d", got) } if got := overridden.Config.Backends["local"].QueueCapacity; got != 0 { t.Fatalf("inherited zero queue capacity: %d", got) } } func TestSiblingInheritanceUsesSelectedOverlay(t *testing.T) { dir := t.TempDir() if err := os.Mkdir(filepath.Join(dir, "overlays"), 0700); err != nil { t.Fatal(err) } main := filepath.Join(dir, "config.yml") text := `version: 2 backends: base: endpoint: https://base.invalid/v1 concurrency: 3 queue_capacity: 0 local: extends: base concurrency: 2 llm: proposal_profile: proposal ` if err := os.WriteFile(main, []byte(text), 0600); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(dir, "overlays", "testing.yml"), []byte("backends:\n base:\n endpoint: https://overlay.invalid/v1\n concurrency: 4\n"), 0600); err != nil { t.Fatal(err) } loaded, err := Load(ck.File(main), "testing") if err != nil { t.Fatal(err) } child := loaded.Config.Backends["local"] if child.Endpoint != "https://overlay.invalid/v1" || child.Concurrency != 2 || child.QueueCapacity != 0 { t.Fatalf("overlay inheritance and child override: %+v", child) } } func TestSiblingInheritanceDoesNotBypassBackendValidation(t *testing.T) { for _, tc := range []struct { name string text string }{ { name: "invalid inherited parent setting", text: `version: 2 backends: base: endpoint: https://base.invalid/v1 concurrency: 0 local: extends: base llm: proposal_profile: proposal `, }, { name: "invalid child override", text: `version: 2 backends: base: endpoint: https://base.invalid/v1 concurrency: 3 local: extends: base concurrency: 0 llm: proposal_profile: proposal `, }, } { t.Run(tc.name, func(t *testing.T) { if _, err := loadText(tc.text, ""); err == nil { t.Fatal("invalid backend concurrency accepted") } }) } }