fix(provisioner): Forensic #145 — preserve workspace-authored SCM token, strip only operator/global bleed #2320
Reference in New Issue
Block a user
Delete Branch "fix/forensic145-preserve-workspace-scm-token"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Forensic #145 guard: preserve workspace-authored SCM token, strip only operator/global bleed
Root cause (confirmed by live ground-truth probe)
Codex reviewer agents (and any tenant agent) silently lost their
GITEA_TOKENinside the container:/configs/secrets.d/held only the globalCODEX_AUTH_JSON,$GITEA_TOKENwas absent, and a Giteawhoamireturned 401/404 → reviewers could exec but could not post reviews, stalling the 2nd-approval path.The token exists in the CP as a workspace-scoped secret, and CP-side delivery (cp#444) is correct. But
CPProvisioner.Start()(the Forensic #145 guard,workspace-server/internal/provisioner/cp_provisioner.go) strips every key inscmWriteTokenKeys(GITEA_TOKEN, …) by key-name alone, with no provenance awareness — so it dropped the workspace-authored token before it ever reached the CP delivery layer.The guard's real and still-valid purpose (per its own comment) is to stop operator / persona-merged (global-scoped) SCM-write tokens from bleeding into a tenant container. It was never meant to block a workspace token the org admin deliberately set for that workspace's reviewer.
Fix (provenance-aware, fail-safe — the security intent is preserved, not removed)
loadWorkspaceSecretsalready computed aglobalKeysprovenance set anddeletes a key from it when a workspace secret overrides it. This PR adds the positive mirror: aworkspaceKeysset of keys sourced from theworkspace_secretstable.prepareProvisionContext→WorkspaceConfig.WorkspaceSecretKeys(carried by both Docker- and CP-mode configs).buildCPTenantEnv) now strips an SCM-write token unless it is positively inWorkspaceSecretKeys. Operator/global and persona/mutator-injected tokens are NOT in that set → still stripped. Nil map → strips everything (fail-safe) — a missing provenance map can never leak.Security invariants (each a passing table-test row in
TestBuildCPTenantEnv_ForensicGuardProvenance)global_secrets→ STRIPPEDworkspace_secrets→ PRESERVEDWorkspaceSecretKeys == nil→ all 6 SCM keys STRIPPED (fail-safe)Plus
TestLoadWorkspaceSecrets_WorkspaceKeysProvenance(workspace key lands inworkspaceKeys, removed fromglobalKeys; operator-only key stays global) andTestBuildCPTenantEnv_AdminTokenInjected.Scope
CP/EC2 path only (where the affected codex reviewers run). Docker-mode
buildContainerEnvis unchanged (it stays strictly more-stripping → no security regression); symmetric Docker treatment is a noted follow-up, not needed for this fix.Verification
go build ./...,go vet ./...clean.go test ./internal/provisioner/... ./internal/handlers/...green. Integration-tag failures are pre-existing (no Postgres locally; CI provides one). gofmt clean on edited files.SOP checklist
secrets.dlisting +whoamiHTTP), traced to the exact strip site; not a symptom patch.whoami=200 + a posted review).🤖 Generated with Claude Code