package codexcfg import ( "os" "path/filepath" "strings" "testing" ) // richConfig mimics a real Codex config.toml: a custom provider, MCP // servers and project trust entries that must survive untouched. const richConfig = `# Codex settings model_provider = "custom" model_reasoning_effort = "high" [model_providers.custom] name = "custom" wire_api = "responses" base_url = "https://cpa.rutua.cn/v1" [mcp_servers.docker] command = "docker.exe" args = ["mcp", "gateway", "run"] [projects.'C:\Users\me\proj'] trust_level = "trusted" ` func newMgr(t *testing.T) (*Manager, string) { t.Helper() dir := t.TempDir() path := filepath.Join(dir, "config.toml") return New(path, filepath.Join(dir, "backups")), path } func writeConfig(t *testing.T, path, content string) { t.Helper() if err := os.WriteFile(path, []byte(content), 0o600); err != nil { t.Fatalf("write config: %v", err) } } func readConfig(t *testing.T, path string) string { t.Helper() data, err := os.ReadFile(path) if err != nil { t.Fatalf("read config: %v", err) } return string(data) } func TestApplyCreatesFileWhenMissing(t *testing.T) { mgr, path := newMgr(t) injection, err := mgr.Apply(ApplyOptions{BaseURL: "http://127.0.0.1:9000", Token: "crl_x"}) if err != nil { t.Fatalf("Apply: %v", err) } if injection.ModelProvider != ProviderID { t.Errorf("model_provider = %q", injection.ModelProvider) } if injection.PriorProvider != "" { t.Errorf("prior provider = %q, want empty", injection.PriorProvider) } got := readConfig(t, path) for _, want := range []string{ `model_provider = "crossrelay"`, "[model_providers.crossrelay]", `name = "crossrelay"`, `wire_api = "responses"`, `base_url = "http://127.0.0.1:9000"`, `experimental_bearer_token = "crl_x"`, "requires_openai_auth = false", } { if !strings.Contains(got, want) { t.Errorf("created config missing %q:\n%s", want, got) } } } func TestApplyPreservesEverythingElse(t *testing.T) { mgr, path := newMgr(t) writeConfig(t, path, richConfig) injection, err := mgr.Apply(ApplyOptions{BaseURL: "http://127.0.0.1:9000", Token: "crl_x"}) if err != nil { t.Fatalf("Apply: %v", err) } if injection.PriorProvider != "custom" { t.Errorf("prior provider = %q, want custom", injection.PriorProvider) } got := readConfig(t, path) for _, want := range []string{ "# Codex settings", `model_reasoning_effort = "high"`, "[model_providers.custom]", `base_url = "https://cpa.rutua.cn/v1"`, "[mcp_servers.docker]", `command = "docker.exe"`, `args = ["mcp", "gateway", "run"]`, `[projects.'C:\Users\me\proj']`, `trust_level = "trusted"`, } { if !strings.Contains(got, want) { t.Errorf("config lost %q after apply:\n%s", want, got) } } if strings.Count(got, "model_reasoning_effort") != 1 { t.Errorf("unrelated key duplicated:\n%s", got) } if strings.Count(got, "[model_providers.") != 2 { t.Errorf("provider tables = %d, want 2:\n%s", strings.Count(got, "[model_providers."), got) } } func TestApplyIsIdempotent(t *testing.T) { mgr, path := newMgr(t) writeConfig(t, path, richConfig) opts := ApplyOptions{BaseURL: "http://127.0.0.1:9000", Token: "crl_x"} if _, err := mgr.Apply(opts); err != nil { t.Fatalf("first Apply: %v", err) } first := readConfig(t, path) if _, err := mgr.Apply(opts); err != nil { t.Fatalf("second Apply: %v", err) } if second := readConfig(t, path); second != first { t.Errorf("second apply changed the file:\nfirst:\n%s\nsecond:\n%s", first, second) } backups, err := mgr.Backups() if err != nil { t.Fatalf("Backups: %v", err) } if len(backups) != 1 { t.Errorf("backups = %d, want 1 (only the changing apply backs up)", len(backups)) } } func TestRemoveManagedRestoresPriorProvider(t *testing.T) { mgr, path := newMgr(t) writeConfig(t, path, richConfig) if _, err := mgr.Apply(ApplyOptions{BaseURL: "http://127.0.0.1:9000", Token: "crl_x"}); err != nil { t.Fatalf("Apply: %v", err) } if err := mgr.RemoveManaged("custom"); err != nil { t.Fatalf("RemoveManaged: %v", err) } got := readConfig(t, path) if !strings.Contains(got, `model_provider = "custom"`) { t.Errorf("prior provider not restored:\n%s", got) } if strings.Contains(got, "crossrelay") { t.Errorf("managed keys survived removal:\n%s", got) } for _, want := range []string{ `model_reasoning_effort = "high"`, "[mcp_servers.docker]", `trust_level = "trusted"`, } { if !strings.Contains(got, want) { t.Errorf("config lost %q after removal:\n%s", want, got) } } } func TestRemoveManagedWithoutPriorDropsKey(t *testing.T) { mgr, path := newMgr(t) writeConfig(t, path, "model_provider = \"crossrelay\"\n\n[model_providers.crossrelay]\nname = \"crossrelay\"\n\n[other]\nx = 1\n") if err := mgr.RemoveManaged(""); err != nil { t.Fatalf("RemoveManaged: %v", err) } got := readConfig(t, path) if strings.Contains(got, "model_provider") { t.Errorf("managed key survived:\n%s", got) } if !strings.Contains(got, "[other]") || !strings.Contains(got, "x = 1") { t.Errorf("unrelated table damaged:\n%s", got) } } func TestRemoveManagedKeepsUserChangedProvider(t *testing.T) { mgr, path := newMgr(t) writeConfig(t, path, richConfig) if _, err := mgr.Apply(ApplyOptions{BaseURL: "http://127.0.0.1:9000", Token: "crl_x"}); err != nil { t.Fatalf("Apply: %v", err) } // The user switches provider by hand after the apply. writeConfig(t, path, strings.Replace(readConfig(t, path), `model_provider = "crossrelay"`, `model_provider = "custom"`, 1)) if err := mgr.RemoveManaged(""); err != nil { t.Fatalf("RemoveManaged: %v", err) } got := readConfig(t, path) if !strings.Contains(got, `model_provider = "custom"`) { t.Errorf("user's provider choice was deleted:\n%s", got) } if strings.Contains(got, "model_providers.crossrelay") { t.Errorf("managed table survived:\n%s", got) } } func TestBackupAndRestoreBackup(t *testing.T) { mgr, path := newMgr(t) writeConfig(t, path, richConfig) if _, err := mgr.Apply(ApplyOptions{BaseURL: "http://127.0.0.1:9000", Token: "crl_x"}); err != nil { t.Fatalf("Apply: %v", err) } backups, err := mgr.Backups() if err != nil { t.Fatalf("Backups: %v", err) } if len(backups) != 1 { t.Fatalf("backups = %d, want 1", len(backups)) } name, err := mgr.RestoreBackup(backups[0].Name) if err != nil { t.Fatalf("RestoreBackup: %v", err) } if name != backups[0].Name { t.Errorf("restored name = %q", name) } if got := readConfig(t, path); got != richConfig { t.Errorf("rollback content mismatch:\n%s", got) } } func TestRestoreBackupRejectsForeignNames(t *testing.T) { mgr, _ := newMgr(t) if _, err := mgr.RestoreBackup("settings-20260101-000000.json"); err == nil { t.Error("RestoreBackup accepted a non-config backup name") } if _, err := mgr.RestoreBackup("../config.toml"); err == nil { t.Error("RestoreBackup accepted a path traversal name") } } func TestCRLFPreserved(t *testing.T) { mgr, path := newMgr(t) crlf := strings.ReplaceAll(richConfig, "\n", "\r\n") writeConfig(t, path, crlf) if _, err := mgr.Apply(ApplyOptions{BaseURL: "http://127.0.0.1:9000", Token: "crl_x"}); err != nil { t.Fatalf("Apply: %v", err) } got := readConfig(t, path) for _, line := range []string{`command = "docker.exe"`, `trust_level = "trusted"`, `model_reasoning_effort = "high"`} { if !strings.Contains(got, line+"\r\n") { t.Errorf("line %q lost its CRLF ending:\n%q", line, got) } } } func TestDefaultPathHonoursCodexHome(t *testing.T) { t.Setenv("CODEX_HOME", `C:\codex-home`) path, err := DefaultPath() if err != nil { t.Fatalf("DefaultPath: %v", err) } if path != filepath.Join(`C:\codex-home`, "config.toml") { t.Errorf("path = %q", path) } }