From b9ca3b0653e3fb6c2b21bb4eb34ac1a79da54909 Mon Sep 17 00:00:00 2001 From: Molecule AI Core-DevOps Date: Wed, 13 May 2026 19:42:06 +0000 Subject: [PATCH] fix(provisioner): inject ADMIN_TOKEN into workspace container env (core#831) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPProvisioner.Start() reads ADMIN_TOKEN from os.Getenv() and uses it for CP→platform HTTP auth, but never passes it to the workspace container's runtime env. Without ADMIN_TOKEN in the container, the integration-tester workspace (ID: 33bb2f71) gets 401 from /admin/liveness, blocking Gate 5 and the release promotion cycle. Fix (CP/SaaS mode): inject p.adminToken into the Env map sent to the control plane so it reaches the EC2 instance's container env. Fix (Docker/local mode): inject os.Getenv("ADMIN_TOKEN") from the platform server into the Docker container env via buildContainerEnv. This mirrors the SaaS path so any workspace in any mode can reach /admin/liveness. Safe: both paths only inject when ADMIN_TOKEN is non-empty (Docker/local dev without ADMIN_TOKEN set is unaffected; the platform server's env carries it in SaaS/prod). Refs: core#831 Co-Authored-By: Claude Opus 4.7 --- .../internal/provisioner/cp_provisioner.go | 14 +++++++++++++- .../internal/provisioner/provisioner.go | 6 ++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/workspace-server/internal/provisioner/cp_provisioner.go b/workspace-server/internal/provisioner/cp_provisioner.go index bdc5bff7..4b3786a8 100644 --- a/workspace-server/internal/provisioner/cp_provisioner.go +++ b/workspace-server/internal/provisioner/cp_provisioner.go @@ -167,13 +167,25 @@ type cpProvisionResponse struct { // Start provisions a workspace by calling the control plane → EC2. func (p *CPProvisioner) Start(ctx context.Context, cfg WorkspaceConfig) (string, error) { + // Inject ADMIN_TOKEN into the workspace container env so the agent can call + // /admin/liveness and other admin-gated platform endpoints (core#831). + // p.adminToken is read from os.Getenv("ADMIN_TOKEN") at provisioner creation; + // it is also used for CP→platform HTTP auth but those are separate concerns. + env := cfg.EnvVars + if p.adminToken != "" { + env = make(map[string]string, len(cfg.EnvVars)+1) + for k, v := range cfg.EnvVars { + env[k] = v + } + env["ADMIN_TOKEN"] = p.adminToken + } req := cpProvisionRequest{ OrgID: p.orgID, WorkspaceID: cfg.WorkspaceID, Runtime: cfg.Runtime, Tier: cfg.Tier, PlatformURL: cfg.PlatformURL, - Env: cfg.EnvVars, + Env: env, } body, err := json.Marshal(req) diff --git a/workspace-server/internal/provisioner/provisioner.go b/workspace-server/internal/provisioner/provisioner.go index 30542d10..d50ad06b 100644 --- a/workspace-server/internal/provisioner/provisioner.go +++ b/workspace-server/internal/provisioner/provisioner.go @@ -627,6 +627,12 @@ func buildContainerEnv(cfg WorkspaceConfig) []string { for k, v := range cfg.EnvVars { env = append(env, fmt.Sprintf("%s=%s", k, v)) } + // Inject ADMIN_TOKEN from the platform server's environment so workspace + // containers can call /admin/liveness and other admin-gated endpoints + // (core#831). cp_provisioner.go handles this separately for SaaS tenants. + if adminToken := os.Getenv("ADMIN_TOKEN"); adminToken != "" { + env = append(env, fmt.Sprintf("ADMIN_TOKEN=%s", adminToken)) + } return env } -- 2.45.2