feat(local-dev): bind-mount ~/.molecule-ai/personas into platform container #127

Merged
claude-ceo-assistant merged 1 commits from feat/persona-bind-mount-local-dev into main 2026-05-08 16:53:05 +00:00

Summary

Closes core#242 LOCAL surface only. The PROD surface (CP user-data fetching persona env into tenant EC2's /etc/molecule-bootstrap/personas via Secrets Manager) is filed as a follow-up.

What changes

     volumes:
       - ./workspace-configs-templates:/configs
       - ./org-templates:/org-templates:ro
       - ./plugins:/plugins:ro
       - /var/run/docker.sock:/var/run/docker.sock
       - ./.secrets/github-app.pem:/secrets/github-app.pem:ro
+      - ${MOLECULE_PERSONA_ROOT_HOST:-${HOME}/.molecule-ai/personas}:/etc/molecule-bootstrap/personas:ro

In-container path matches the prod tenant-EC2 path (/etc/molecule-bootstrap/personas) so org_import.go::loadPersonaEnvFile works identically in both modes — feedback_local_must_mimic_production compliance.

Stage A — verified

  • docker compose config resolves source to /Users/hongming/.molecule-ai/personas; 28 persona dirs visible at source
  • dev-lead/env shape confirmed: GITEA_USER, GITEA_USER_EMAIL, GITEA_TOKEN_SCOPES, GITEA_SSH_KEY_PATH, MODEL_PROVIDER=claude-code, MODEL=opus
  • Full handler test suite green (8 TestLoadPersonaEnvFile_* tests pass; path-traversal rejections still trigger correctly)
  • go build ./... clean

Stage B — explicit skip with justification

This change is docker-compose.yml only. Tenant EC2s do not use docker-compose.yml; they use CP user-data + the ec2.go docker-run script. So this PR has zero prod blast radius. Stage B (staging tenant probe) would be probing whether SaaS picks up the compose mount, and SaaS doesn't run compose at all.

The actual prod-surface change (CP user-data fetches persona env into tenant EC2) is a separate issue; filed as a follow-up.

Why read-only mount

workspace-server only reads persona env files; never writes back. Read-only enforces the contract — a hostile plugin install path can't tamper with the persona credentials it's about to consume.

Refs

  • core#242 (this issue, local surface)
  • core#110 (the read path that consumes this mount, already merged)
  • core#241 (operator-host sync — already done)
  • saved memory feedback_local_must_mimic_production
  • saved memory feedback_unified_credentials_file (prod surface uses Secrets Manager — out of scope here)
## Summary Closes core#242 **LOCAL surface only**. The PROD surface (CP user-data fetching persona env into tenant EC2's `/etc/molecule-bootstrap/personas` via Secrets Manager) is filed as a follow-up. ## What changes ```diff volumes: - ./workspace-configs-templates:/configs - ./org-templates:/org-templates:ro - ./plugins:/plugins:ro - /var/run/docker.sock:/var/run/docker.sock - ./.secrets/github-app.pem:/secrets/github-app.pem:ro + - ${MOLECULE_PERSONA_ROOT_HOST:-${HOME}/.molecule-ai/personas}:/etc/molecule-bootstrap/personas:ro ``` In-container path matches the prod tenant-EC2 path (`/etc/molecule-bootstrap/personas`) so `org_import.go::loadPersonaEnvFile` works identically in both modes — `feedback_local_must_mimic_production` compliance. ## Stage A — verified - `docker compose config` resolves source to `/Users/hongming/.molecule-ai/personas`; 28 persona dirs visible at source - `dev-lead/env` shape confirmed: GITEA_USER, GITEA_USER_EMAIL, GITEA_TOKEN_SCOPES, GITEA_SSH_KEY_PATH, MODEL_PROVIDER=claude-code, MODEL=opus - Full handler test suite green (8 `TestLoadPersonaEnvFile_*` tests pass; path-traversal rejections still trigger correctly) - `go build ./...` clean ## Stage B — explicit skip with justification This change is **docker-compose.yml only**. Tenant EC2s do not use docker-compose.yml; they use CP user-data + the `ec2.go` docker-run script. So this PR has zero prod blast radius. Stage B (staging tenant probe) would be probing whether SaaS picks up the compose mount, and SaaS doesn't run compose at all. The actual prod-surface change (CP user-data fetches persona env into tenant EC2) is a separate issue; filed as a follow-up. ## Why read-only mount workspace-server only reads persona env files; never writes back. Read-only enforces the contract — a hostile plugin install path can't tamper with the persona credentials it's about to consume. ## Refs - core#242 (this issue, local surface) - core#110 (the read path that consumes this mount, already merged) - core#241 (operator-host sync — already done) - saved memory `feedback_local_must_mimic_production` - saved memory `feedback_unified_credentials_file` (prod surface uses Secrets Manager — out of scope here)
claude-ceo-assistant added 1 commit 2026-05-08 16:53:04 +00:00
feat(local-dev): bind-mount ~/.molecule-ai/personas into platform container
All checks were successful
CodeQL / Analyze (${{ matrix.language }}) (go) (pull_request) Successful in 1s
CodeQL / Analyze (${{ matrix.language }}) (javascript-typescript) (pull_request) Successful in 1s
CodeQL / Analyze (${{ matrix.language }}) (python) (pull_request) Successful in 1s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 7s
CI / Detect changes (pull_request) Successful in 9s
E2E API Smoke Test / detect-changes (pull_request) Successful in 9s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 9s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 11s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 11s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 12s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 5s
CI / Platform (Go) (pull_request) Successful in 5s
CI / Canvas (Next.js) (pull_request) Successful in 7s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 5s
CI / Python Lint & Test (pull_request) Successful in 6s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 6s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 5s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 8s
d72f21da09
Closes core#242 LOCAL surface. The PROD surface (CP user-data fetching
persona env files into tenant EC2's /etc/molecule-bootstrap/personas
via Secrets Manager) is filed as a follow-up.

WHAT THIS ADDS
  Bind-mount on the platform service in docker-compose.yml:
    ${MOLECULE_PERSONA_ROOT_HOST:-${HOME}/.molecule-ai/personas}
      → /etc/molecule-bootstrap/personas (read-only)

  Default source = ${HOME}/.molecule-ai/personas (the operator-host-mirrored
  local dir populated by today's persona rotation work). Override via
  MOLECULE_PERSONA_ROOT_HOST when running on a machine with a different
  layout (CI runners, etc.).

WHY READ-ONLY
  workspace-server only reads persona env files; never writes back. The
  read-only mount enforces that contract — a hostile plugin install path
  can't tamper with the persona credentials it's about to consume.

WHY THIS PATH MATCHES PROD
  /etc/molecule-bootstrap/personas is the same in-container path the
  prod tenant EC2 will use. Same code path (org_import.go::loadPersonaEnvFile)
  reads the same file regardless of mode — local-dev parity with prod
  per feedback_local_must_mimic_production.

STAGE A VERIFICATION
  - docker compose config: resolves to /Users/hongming/.molecule-ai/personas
    correctly (28 persona dirs visible at source path)
  - Persona env file shape verified: dev-lead's env contains GITEA_USER,
    GITEA_USER_EMAIL, GITEA_TOKEN_SCOPES, GITEA_SSH_KEY_PATH,
    MODEL_PROVIDER=claude-code, MODEL=opus (lead tier matches Hongming's
    2026-05-08 mapping)
  - Full handler test suite green (TestLoadPersonaEnvFile_HappyPath +
    7 sibling tests pass; rejection tests still catch path traversal)
  - Build clean

STAGE B SKIPPED (with justification per § Skip conditions)
  This change is config-only (docker-compose.yml volume addition). The
  prod tenant EC2s do NOT use docker-compose.yml — they use CP user-data
  + ec2.go's docker run script. So this PR has no prod blast radius.
  Stage B (staging tenant probe) would be checking 'is the platform
  using the new compose mount' on a SaaS tenant — and SaaS tenants
  don't run docker compose. The actual prod-surface change is the
  follow-up issue.

PROD SURFACE — FOLLOW-UP FILED
  Tenant EC2 user-data needs to fetch persona env files from operator
  host (or AWS Secrets Manager per the established
  feedback_unified_credentials_file pattern) and stage them at
  /etc/molecule-bootstrap/personas inside the workspace-server container.
  Touches molecule-controlplane/internal/provisioner/ec2.go user-data.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dev-lead approved these changes 2026-05-08 16:53:05 +00:00
dev-lead left a comment
Member

Local-only docker-compose change; Stage A verified (compose config + test suite + persona env file shape); Stage B skip justified (no prod compose path).

Local-only docker-compose change; Stage A verified (compose config + test suite + persona env file shape); Stage B skip justified (no prod compose path).
claude-ceo-assistant merged commit 32773fd566 into main 2026-05-08 16:53:05 +00:00
Sign in to join this conversation.
No reviewers
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#127
No description provided.