package runtimecodex import ( "context" "encoding/json" "os" "path/filepath" "strings" "testing" "inbox/internal/app/runtimeconfig" "inbox/internal/domain/role" "inbox/internal/domain/skill" ) type fakeRoleCatalog struct { roles []role.Definition } func (f fakeRoleCatalog) ListRoles(_ context.Context) ([]role.Definition, error) { return append([]role.Definition(nil), f.roles...), nil } type fakeRoleResolver struct { resolved map[string]runtimeconfig.ResolvedRole } func (f fakeRoleResolver) ResolveRole(_ context.Context, _ string, roleName string) (runtimeconfig.ResolvedRole, error) { return f.resolved[roleName], nil } func TestMaterializerSyncWritesRoleConfigs(t *testing.T) { ctx := context.Background() root := t.TempDir() materializer := NewMaterializer( fakeRoleCatalog{ roles: []role.Definition{ {Name: "worker", Title: "Worker", IsEnabled: true}, {Name: "disabled_role", Title: "Disabled", IsEnabled: false}, }, }, fakeRoleResolver{ resolved: map[string]runtimeconfig.ResolvedRole{ "worker": { Role: role.Definition{Name: "worker", Title: "Worker", IsEnabled: true}, Config: role.Config{ RoleName: "worker", ConfigTOML: strings.Join([]string{ `model = "gpt-5.2"`, `model_provider = "custom"`, ``, `[shell_environment_policy]`, `inherit = "core"`, `exclude = [ ]`, `include_only = [ ]`, `experimental_use_profile = false`, ``, `[shell_environment_policy.set]`, `XDG_CACHE_HOME = "/tmp/codex-xdg-cache"`, ``, `[model_providers.custom]`, `base_url = "http://example.test/v1"`, `wire_api = "responses"`, ``, `[mcp_servers.playwright]`, `enabled = false`, `command = "npx"`, `args = [ "-y", "@playwright/mcp@latest" ]`, `startup_timeout_sec = 90`, ``, `[projects."/workspace"]`, `trust_level = "trusted"`, }, "\n"), AuthJSON: `{"OPENAI_API_KEY":"token-1"}`, }, Skills: []runtimeconfig.ResolvedSkill{ { Skill: skill.Definition{ ID: "builtin-skill-inbox", SkillKey: "inbox", ContentMarkdown: "# Inbox\n\nUse inbox.", }, }, }, }, }, }, ) if err := materializer.Sync(ctx, "ws_1", root); err != nil { t.Fatalf("Sync() error = %v", err) } configPath := filepath.Join(root, filepath.FromSlash(WorkspaceDir), "worker", ".codex", configFilename) authPath := filepath.Join(root, filepath.FromSlash(WorkspaceDir), "worker", ".codex", authFilename) configBody, err := os.ReadFile(configPath) if err != nil { t.Fatalf("ReadFile(config) error = %v", err) } authBody, err := os.ReadFile(authPath) if err != nil { t.Fatalf("ReadFile(auth) error = %v", err) } if _, err := os.Stat(filepath.Join(root, filepath.FromSlash(WorkspaceDir), "disabled_role")); !os.IsNotExist(err) { t.Fatalf("disabled role should not have runtime codex home") } configText := string(configBody) for _, needle := range []string{ `model = "gpt-5.2"`, `model_provider = "custom"`, `[model_providers.custom]`, `base_url = "http://example.test/v1"`, `[mcp_servers.playwright]`, `[shell_environment_policy.set]`, `[projects."/workspace"]`, } { if !strings.Contains(configText, needle) { t.Fatalf("expected config to contain %q, got:\n%s", needle, configText) } } var auth map[string]string if err := json.Unmarshal(authBody, &auth); err != nil { t.Fatalf("json.Unmarshal(auth) error = %v", err) } if auth["OPENAI_API_KEY"] != "token-1" { t.Fatalf("expected auth OPENAI_API_KEY to be written, got %#v", auth) } skillBody, err := os.ReadFile(filepath.Join(root, filepath.FromSlash(WorkspaceDir), "worker", ".codex", "skills", "inbox", "SKILL.md")) if err != nil { t.Fatalf("ReadFile(skill) error = %v", err) } if string(skillBody) != "# Inbox\n\nUse inbox." { t.Fatalf("unexpected skill body %q", string(skillBody)) } } func TestWriteResolvedRoleHomeWritesOnlyResolvedConfig(t *testing.T) { root := t.TempDir() roleHome, err := WriteResolvedRoleHome(root, runtimeconfig.ResolvedRole{ WorkspaceID: "ws_1", Role: role.Definition{Name: "leader", Title: "Leader", IsEnabled: true}, Config: role.Config{ RoleName: "leader", ConfigTOML: "model = \"gpt-5.4\"", AuthJSON: `{"OPENAI_API_KEY":"token-2"}`, }, }) if err != nil { t.Fatalf("WriteResolvedRoleHome() error = %v", err) } authBody, err := os.ReadFile(filepath.Join(roleHome, ".codex", authFilename)) if err != nil { t.Fatalf("ReadFile(auth) error = %v", err) } var auth map[string]string if err := json.Unmarshal(authBody, &auth); err != nil { t.Fatalf("json.Unmarshal(auth) error = %v", err) } if auth["OPENAI_API_KEY"] != "token-2" { t.Fatalf("expected auth OPENAI_API_KEY to be written, got %#v", auth) } }