From c3596d62711680ec0a4b93d4ab7b62c1d38be9c4 Mon Sep 17 00:00:00 2001 From: claude-ceo-assistant Date: Fri, 8 May 2026 13:50:46 -0700 Subject: [PATCH] fix(org-import): use ws.FilesDir as persona-dir lookup, add docker-cli-buildx to dev image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## org_import.go — persona env injection root-cause fix The Phase-3 fix from earlier today (`feedback/per-agent-gitea-identity-default`) introduced loadPersonaEnvFile to inject persona-specific creds into workspace_secrets on /org/import. It passed `ws.Role` as the persona-dir lookup key, but in our dev-tree org.yaml shape `role:` carries the multi-line descriptive text the agent reads from its prompt ("Engineering planning and team coordination — leads Core Platform, Controlplane, ..."), while `files_dir:` holds the short slug (`core-lead`, `dev-lead`, etc.) matching `~/.molecule-ai/personas//env`. isSafeRoleName silently rejected the multi-word role text → no persona env loaded → every imported workspace booted with zero workspace_secrets rows → no ANTHROPIC / CLAUDE_CODE / MINIMAX auth in the container env → claude_agent_sdk wedged on `query.initialize()` with a 60s control-request timeout. After the fix, /org/import on the dev tree (27 personas) populates 8 workspace_secrets per workspace (Gitea identity + MODEL/MODEL_PROVIDER + provider-specific token), 5 of 6 leads boot online, and the remaining wedges trace to a separate runtime-template-repo bug (workspace-template-claude-code's claude_sdk_executor.py doesn't dispatch on MODEL_PROVIDER=minimax — filed separately). ## Dockerfile.dev — docker-cli + docker-cli-buildx Without these, every claude-code/tier-2 workspace POST fails-fast: - docker-cli alone produces `exec: "docker": executable file not found` - docker-cli alone (no buildx) fails on `docker build` with `ERROR: BuildKit is enabled but the buildx component is missing or broken` Both packages are now installed in the dev image; verified with `docker exec molecule-core-platform-1 docker buildx version`. ## Stage A verified Local /org/import dev-only path: 27 workspaces created, all 27 receive persona env injection (8 secrets each — Gitea identity + provider creds). Lead workspaces (claude-code-OAuth tier) boot online. ## Stage B — N/A Local-dev-only path (docker-compose.dev.yml + dev image). Tenant EC2 provisioning uses Dockerfile.tenant (untouched). Co-Authored-By: Claude Opus 4.7 (1M context) --- workspace-server/Dockerfile.dev | 10 +++++++-- .../internal/handlers/org_import.go | 21 +++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/workspace-server/Dockerfile.dev b/workspace-server/Dockerfile.dev index 0345ba0f..a1efe00b 100644 --- a/workspace-server/Dockerfile.dev +++ b/workspace-server/Dockerfile.dev @@ -15,8 +15,14 @@ FROM golang:1.25-alpine -# air + git (for go mod) + ca-certs (for TLS) + tzdata (for time-zone DB). -RUN apk add --no-cache git ca-certificates tzdata wget \ +# air + git (for go mod) + ca-certs (for TLS) + tzdata (for time-zone DB) +# + docker-cli + docker-cli-buildx so the platform binary can shell out to +# /var/run/docker.sock (bind-mounted from host) for local-build provisioning. +# docker-cli alone is insufficient: alpine's docker-cli enables BuildKit by +# default but ships without buildx, producing +# `ERROR: BuildKit is enabled but the buildx component is missing or broken` +# on every `docker build`. docker-cli-buildx provides the buildx subcommand. +RUN apk add --no-cache git ca-certificates tzdata wget docker-cli docker-cli-buildx \ && go install github.com/air-verse/air@latest WORKDIR /app/workspace-server diff --git a/workspace-server/internal/handlers/org_import.go b/workspace-server/internal/handlers/org_import.go index e3be5823..55b05eb2 100644 --- a/workspace-server/internal/handlers/org_import.go +++ b/workspace-server/internal/handlers/org_import.go @@ -453,8 +453,25 @@ func (h *OrgHandler) createWorkspaceTree(ws OrgWorkspace, parentID *string, absX envVars := map[string]string{} // 0. Persona env (lowest precedence; injects the role's Gitea identity: // GITEA_USER, GITEA_TOKEN, GITEA_TOKEN_SCOPES, GITEA_USER_EMAIL, - // GITEA_SSH_KEY_PATH). Workspace and org .env can override. - loadPersonaEnvFile(ws.Role, envVars) + // GITEA_SSH_KEY_PATH, plus MODEL_PROVIDER/MODEL and the LLM auth + // token like CLAUDE_CODE_OAUTH_TOKEN or MINIMAX_API_KEY). + // Workspace and org .env can override. + // + // Use ws.FilesDir as the persona-dir lookup key, NOT ws.Role. In the + // dev-tree org.yaml shape, `role:` carries the multi-line descriptive + // text the agent reads from its prompt ("Engineering planning and + // team coordination — leads Core Platform, Controlplane, ..."), while + // `files_dir:` holds the short slug (`core-lead`, `dev-lead`, etc.) + // matching `~/.molecule-ai/personas//env` + // (bind-mounted to `/etc/molecule-bootstrap/personas//env`). + // + // Pre-fix, this passed `ws.Role` whose multi-word content failed + // isSafeRoleName silently, so every imported workspace booted with + // zero persona-env rows in workspace_secrets — no ANTHROPIC / + // CLAUDE_CODE auth in the container env. The claude_agent_sdk + // then wedged on `query.initialize()` with a 60s control-request + // timeout (caught 2026-05-08 right after dev-only org/import). + loadPersonaEnvFile(ws.FilesDir, envVars) if orgBaseDir != "" { // 1. Org root .env (shared defaults) parseEnvFile(filepath.Join(orgBaseDir, ".env"), envVars) -- 2.45.2