7c0836ea69
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 7s
CI / Detect changes (pull_request) Successful in 11s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 14s
E2E API Smoke Test / detect-changes (pull_request) Successful in 11s
E2E Chat / detect-changes (pull_request) Successful in 13s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 10s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 7s
Harness Replays / detect-changes (pull_request) Successful in 5s
publish-runtime-autobump / pr-validate (pull_request) Successful in 30s
publish-runtime-autobump / bump-and-tag (pull_request) Has been skipped
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 10s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 5s
gate-check-v3 / gate-check (pull_request) Successful in 6s
qa-review / approved (pull_request) Failing after 4s
security-review / approved (pull_request) Failing after 4s
sop-checklist / na-declarations (pull_request) N/A: (none)
sop-checklist / all-items-acked (pull_request) Successful in 5s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m12s
sop-tier-check / tier-check (pull_request) Successful in 6s
CI / Canvas (Next.js) (pull_request) Successful in 4m9s
CI / Platform (Go) (pull_request) Successful in 4m22s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Failing after 32s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 4s
Harness Replays / Harness Replays (pull_request) Successful in 3s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Failing after 33s
E2E Chat / E2E Chat (pull_request) Failing after 57s
CI / Python Lint & Test (pull_request) Successful in 7m4s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / all-required (pull_request) Successful in 6m49s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 55s
Wire container-side `git` HTTPS authentication to the persona credentials
that already arrive via workspace_secrets (GITEA_USER / GITEA_TOKEN,
GIT_HTTP_USERNAME / GIT_HTTP_PASSWORD) without mutating ~/.gitconfig or
~/.git-credentials inside the container.
Mechanism:
1. New generic GIT_ASKPASS helper baked into the workspace runtime
image at /usr/local/bin/molecule-askpass. Script body is hostname-
free and vendor-neutral — the deployer decides which remote the
credentials apply to by virtue of populating the env vars.
2. applyAgentGitIdentity (already the per-agent commit-identity
chokepoint at workspace_provision_shared.go:134) now also sets
GIT_ASKPASS=/usr/local/bin/molecule-askpass via the new
applyGitAskpass helper. Idempotent — respects pre-existing
workspace_secret / env-mutator overrides.
When git encounters an HTTPS auth challenge on a host with no configured
credential.helper, it invokes GIT_ASKPASS to read the username + password
from env. This is the cleanest possible wire-up: no on-disk credential
files, no hostname literals in code, fail-loud on misconfiguration.
Tests added: GIT_ASKPASS set on success, operator-override respected,
empty-name no-op symmetry, nil-map safety.
Companion PRs on the 3 open-source workspace templates ship the same
generic askpass script at scripts/git-askpass.sh → identical install
path. Image build + helper script are intentionally split so the
platform PR can ship without breaking external template builds, and vice
versa: applyGitAskpass setting a missing helper is harmless (git would
just emit "exec: not found" and fall through to whatever auth chain
existed before — same baseline as no env-only patch at all).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
105 lines
5.1 KiB
Docker
105 lines
5.1 KiB
Docker
FROM python:3.11-slim@sha256:e78299e55776ca065dcb769f80161f48465ad352014240eb5fe4712e22505e9b
|
|
|
|
WORKDIR /app
|
|
|
|
# Install Node.js, git, gh CLI in a single layer to minimize image size
|
|
RUN apt-get update && \
|
|
apt-get install -y --no-install-recommends curl git ca-certificates && \
|
|
# Node.js 22
|
|
curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
|
|
apt-get install -y --no-install-recommends nodejs && \
|
|
# GitHub CLI
|
|
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
|
|
| dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && \
|
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
|
|
> /etc/apt/sources.list.d/github-cli.list && \
|
|
apt-get update && apt-get install -y --no-install-recommends gh && \
|
|
# Cleanup apt caches and temp files
|
|
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false && \
|
|
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
|
|
|
# Create non-root user (claude --dangerously-skip-permissions refuses root)
|
|
RUN useradd -m -s /bin/bash agent
|
|
|
|
# Install base Python dependencies (A2A SDK + HTTP only)
|
|
COPY requirements.txt .
|
|
RUN pip install --no-cache-dir -r requirements.txt
|
|
|
|
# Copy runtime code (adapters/ has been removed — adapters now live in standalone
|
|
# template repos and install molecule-ai-workspace-runtime from PyPI)
|
|
COPY *.py ./
|
|
COPY entrypoint.sh ./
|
|
COPY skill_loader/ ./skill_loader/
|
|
COPY builtin_tools/ ./builtin_tools/
|
|
COPY plugins_registry/ ./plugins_registry/
|
|
COPY policies/ ./policies/
|
|
|
|
# Create CLI aliases
|
|
RUN ln -s /app/a2a_cli.py /usr/local/bin/a2a && chmod +x /app/a2a_cli.py /app/a2a_mcp_server.py && \
|
|
ln -s /app/molecule_ai_status.py /usr/local/bin/molecule-monorepo-status && chmod +x /app/molecule_ai_status.py
|
|
|
|
# gh wrapper — auto-prefixes PR / issue titles with the agent role + appends
|
|
# a body footer. Every agent in the template shares one GitHub PAT so plain
|
|
# `gh pr list` can't distinguish workspaces; the wrapper reads GIT_AUTHOR_NAME
|
|
# (set by the platform provisioner, "Molecule AI <Role>") and rewrites the
|
|
# title/body accordingly. Fails open when the env is missing. Anything that
|
|
# isn't `gh pr create` or `gh issue create` passes through untouched.
|
|
# /usr/local/bin is earlier in PATH than /usr/bin/gh so this shadows the
|
|
# real binary without renaming it.
|
|
COPY scripts/gh-wrapper.sh /usr/local/bin/gh
|
|
RUN chmod +x /usr/local/bin/gh
|
|
|
|
# Copy the git credential helper so entrypoint.sh can register it at boot.
|
|
# molecule-git-token-helper.sh fetches a fresh GitHub App installation token
|
|
# from the platform on every git push/fetch, preventing stale-token failures
|
|
# after the ~60 min GitHub App token TTL (issue #613 / #547).
|
|
COPY scripts/molecule-git-token-helper.sh ./scripts/
|
|
RUN chmod +x ./scripts/molecule-git-token-helper.sh
|
|
|
|
# Copy the background token refresh daemon. Runs as a background process
|
|
# started by entrypoint.sh — refreshes gh CLI auth and the credential
|
|
# helper cache every 45 min so tokens never expire mid-operation.
|
|
COPY scripts/molecule-gh-token-refresh.sh ./scripts/
|
|
RUN chmod +x ./scripts/molecule-gh-token-refresh.sh
|
|
|
|
# Generic GIT_ASKPASS helper. Reads HTTPS Basic-Auth credentials from env
|
|
# vars (GIT_HTTP_USERNAME / GIT_HTTP_PASSWORD, with GITEA_USER / GITEA_TOKEN
|
|
# as fallback) and emits them on the git credential-prompt protocol so
|
|
# container-side `git` can authenticate to any private HTTPS remote
|
|
# without on-disk .gitconfig / .git-credentials mutation. The platform
|
|
# provisioner sets GIT_ASKPASS=/usr/local/bin/molecule-askpass via
|
|
# applyAgentGitIdentity (workspace-server/internal/handlers/agent_git_identity.go).
|
|
# Filename is the only project-specific marker; the script body contains
|
|
# no vendor literals and is identical to the script shipped in each
|
|
# open-source workspace template (scripts/git-askpass.sh).
|
|
COPY scripts/molecule-askpass /usr/local/bin/molecule-askpass
|
|
RUN chmod +x /usr/local/bin/molecule-askpass
|
|
|
|
# Dirs and permissions
|
|
RUN mkdir -p /workspace /plugins /home/agent/.claude /home/agent/.config /home/agent/.local \
|
|
/home/agent/.molecule-token-cache && \
|
|
chown -R agent:agent /app /home/agent /workspace
|
|
|
|
# Install gosu for clean root → agent user handoff in entrypoint.
|
|
# The entrypoint starts as root to fix volume ownership, then exec's
|
|
# as the agent user so Claude Code's --dangerously-skip-permissions works.
|
|
RUN apt-get update && apt-get install -y --no-install-recommends gosu && \
|
|
rm -rf /var/lib/apt/lists/*
|
|
|
|
VOLUME /configs
|
|
VOLUME /workspace
|
|
|
|
EXPOSE 8000
|
|
|
|
# HEALTHCHECK: probe the A2A agent-card endpoint so orchestrators and
|
|
# container runtimes can detect a live, responsive workspace agent.
|
|
# Uses curl (present in python:3.11-slim base) against the uvicorn server.
|
|
# PORT is injected at runtime via the molecule-runtime entrypoint; the
|
|
# default matches EXPOSE.
|
|
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
|
CMD curl -sf http://localhost:${PORT:-8000}/agent/card >/dev/null || exit 1
|
|
|
|
RUN chmod +x /app/entrypoint.sh
|
|
# Start as root — entrypoint fixes volume permissions then drops to agent
|
|
CMD ["./entrypoint.sh"]
|