From 639b4dbb9f3aa3090a37cb841f2cf49cda7948fe Mon Sep 17 00:00:00 2001 From: rabbitblood Date: Sun, 19 Apr 2026 21:56:21 -0700 Subject: [PATCH] fix: stop hardcoding CLAUDE_CODE_OAUTH_TOKEN in required_env (#1028) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The provisioner was unconditionally writing CLAUDE_CODE_OAUTH_TOKEN into config.yaml's required_env for all claude-code workspaces. When the baked token expired, preflight rejected every workspace — even those with a valid token injected via the secrets API at runtime. Changes: - workspace_provision.go: remove hardcoded required_env for claude-code and codex runtimes; tokens are injected at container start via secrets - workspace_provision_test.go: flip assertion to reject hardcoded token Co-Authored-By: Claude Opus 4.6 (1M context) --- .../internal/handlers/workspace_provision.go | 10 +++++----- .../internal/handlers/workspace_provision_test.go | 9 ++++----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/workspace-server/internal/handlers/workspace_provision.go b/workspace-server/internal/handlers/workspace_provision.go index f023e240..4c954008 100644 --- a/workspace-server/internal/handlers/workspace_provision.go +++ b/workspace-server/internal/handlers/workspace_provision.go @@ -439,12 +439,12 @@ func (h *WorkspaceHandler) ensureDefaultConfig(workspaceID string, payload model // Model always at top level — config.py reads raw["model"] for all runtimes. configYAML += fmt.Sprintf("model: %s\n", quoteModel) - // Add required_env based on runtime — preflight checks these are set via secrets API. + // Add runtime_config. required_env is intentionally omitted — the + // platform injects secrets at container-start time via the secrets API, + // and preflight already validates that the env vars are present before + // the agent loop starts. Hardcoding token names here caused #1028 + // (expired CLAUDE_CODE_OAUTH_TOKEN baked into config.yaml). switch runtime { - case "claude-code": - configYAML += "runtime_config:\n required_env:\n - CLAUDE_CODE_OAUTH_TOKEN\n timeout: 0\n" - case "codex": - configYAML += "runtime_config:\n required_env:\n - OPENAI_API_KEY\n timeout: 0\n" case "langgraph", "deepagents": // These runtimes read API keys from env directly, no runtime_config needed. default: diff --git a/workspace-server/internal/handlers/workspace_provision_test.go b/workspace-server/internal/handlers/workspace_provision_test.go index 3dafa96f..9eda95df 100644 --- a/workspace-server/internal/handlers/workspace_provision_test.go +++ b/workspace-server/internal/handlers/workspace_provision_test.go @@ -247,11 +247,10 @@ func TestEnsureDefaultConfig_ClaudeCode(t *testing.T) { if !contains(content, "runtime_config:") { t.Errorf("config.yaml should have runtime_config section for claude-code, got:\n%s", content) } - if !contains(content, "required_env:") { - t.Errorf("config.yaml should have required_env for claude-code, got:\n%s", content) - } - if !contains(content, "CLAUDE_CODE_OAUTH_TOKEN") { - t.Errorf("config.yaml should require CLAUDE_CODE_OAUTH_TOKEN, got:\n%s", content) + // required_env is no longer hardcoded — tokens are injected at runtime + // via the secrets API (#1028). + if contains(content, "CLAUDE_CODE_OAUTH_TOKEN") { + t.Errorf("config.yaml should NOT hardcode CLAUDE_CODE_OAUTH_TOKEN (fix #1028), got:\n%s", content) } // Should NOT have .auth-token file if _, ok := files[".auth-token"]; ok {