forked from molecule-ai/molecule-core
infra: add rebuild-runtime-images.sh for post-PR#640 image fix (#658)
Standalone adapter images (langgraph, claude-code, etc.) use ENTRYPOINT ["molecule-runtime"] which bypasses entrypoint.sh. PR #640's entrypoint.sh fix therefore never runs in adapter images. The correct fix is to bake git config --system into the image at build time. This script: 1. Rebuilds workspace-template:base from the monorepo Dockerfile (which has the fixed entrypoint.sh and molecule-git-token-helper.sh) 2. For each of the 6 runtime adapters: clones the standalone repo, patches its Dockerfile to COPY the credential helper and run git config --system, then builds the final image tagged as workspace-template:<runtime> Usage (run on the host machine, not inside a workspace container): bash workspace-template/rebuild-runtime-images.sh # all 6 bash workspace-template/rebuild-runtime-images.sh claude-code # one See issue #658 for the architectural explanation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1b9be1e289
commit
b13dbc212b
175
workspace-template/rebuild-runtime-images.sh
Executable file
175
workspace-template/rebuild-runtime-images.sh
Executable file
@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env bash
|
||||
# rebuild-runtime-images.sh — Rebuild all 6 workspace runtime Docker images.
|
||||
#
|
||||
# Run this script from the repo root (or from workspace-template/) after any
|
||||
# change to workspace-template/Dockerfile, entrypoint.sh, or the git credential
|
||||
# helper scripts. Also run after PR #640 merged.
|
||||
#
|
||||
# What this does:
|
||||
# 1. Builds workspace-template:base from the monorepo Dockerfile (includes
|
||||
# the fixed entrypoint.sh + molecule-git-token-helper.sh)
|
||||
# 2. For each runtime adapter, clones its standalone repo to a temp dir,
|
||||
# patches its Dockerfile to:
|
||||
# a. COPY the git credential helper into the image
|
||||
# b. Set git config --system to register the helper globally
|
||||
# Then builds and tags workspace-template:<runtime>.
|
||||
#
|
||||
# Why the patch is needed:
|
||||
# Standalone adapter images (molecule-ai-workspace-template-*) use
|
||||
# ENTRYPOINT ["molecule-runtime"] — they do not run entrypoint.sh, so the
|
||||
# git config registration from entrypoint.sh never fires for them. Baking
|
||||
# it into the image via git config --system at Docker build time is the
|
||||
# correct permanent fix (issue #613 / PR #640).
|
||||
#
|
||||
# Prerequisites: docker, git, gh (authenticated)
|
||||
#
|
||||
# Usage (from repo root):
|
||||
# bash workspace-template/rebuild-runtime-images.sh
|
||||
#
|
||||
# To rebuild a single runtime:
|
||||
# bash workspace-template/rebuild-runtime-images.sh claude-code
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
HELPER_SCRIPT="${SCRIPT_DIR}/scripts/molecule-git-token-helper.sh"
|
||||
RUNTIMES=(langgraph claude-code openclaw crewai autogen deepagents)
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
log() { echo -e "${GREEN}[rebuild]${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}[rebuild]${NC} $1"; }
|
||||
err() { echo -e "${RED}[rebuild]${NC} $1"; }
|
||||
|
||||
# ─────────────────────────────────────────────────────
|
||||
# Argument: optional single runtime to rebuild
|
||||
# ─────────────────────────────────────────────────────
|
||||
if [ "${1:-}" != "" ]; then
|
||||
RUNTIMES=("$1")
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────
|
||||
# Preflight checks
|
||||
# ─────────────────────────────────────────────────────
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
err "docker not found — run this on the host machine, not inside a workspace container"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${HELPER_SCRIPT}" ]; then
|
||||
err "molecule-git-token-helper.sh not found at ${HELPER_SCRIPT}"
|
||||
err "Run: git pull origin main (PR #640 adds this file)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Building workspace-template:base from monorepo Dockerfile..."
|
||||
docker build \
|
||||
--no-cache \
|
||||
-t workspace-template:base \
|
||||
-f "${SCRIPT_DIR}/Dockerfile" \
|
||||
"${SCRIPT_DIR}"
|
||||
log "✓ workspace-template:base built"
|
||||
|
||||
# ─────────────────────────────────────────────────────
|
||||
# Build each runtime adapter image
|
||||
# ─────────────────────────────────────────────────────
|
||||
TMPBASE=$(mktemp -d)
|
||||
trap "rm -rf ${TMPBASE}" EXIT
|
||||
|
||||
SUCCESS=()
|
||||
FAILED=()
|
||||
|
||||
for runtime in "${RUNTIMES[@]}"; do
|
||||
log "──────────────────────────────────────────"
|
||||
log "Building workspace-template:${runtime} ..."
|
||||
|
||||
TMPDIR="${TMPBASE}/${runtime}"
|
||||
mkdir -p "${TMPDIR}"
|
||||
|
||||
# Clone the standalone template repo
|
||||
REPO="Molecule-AI/molecule-ai-workspace-template-${runtime}"
|
||||
log " Cloning ${REPO} ..."
|
||||
if ! git clone --depth 1 "https://github.com/${REPO}.git" "${TMPDIR}" 2>&1; then
|
||||
err " Failed to clone ${REPO} — skipping ${runtime}"
|
||||
FAILED+=("${runtime}")
|
||||
continue
|
||||
fi
|
||||
|
||||
# Verify a Dockerfile exists
|
||||
if [ ! -f "${TMPDIR}/Dockerfile" ]; then
|
||||
err " No Dockerfile in ${REPO} — skipping ${runtime}"
|
||||
FAILED+=("${runtime}")
|
||||
continue
|
||||
fi
|
||||
|
||||
# Copy the credential helper into the build context so the Dockerfile can COPY it.
|
||||
cp "${HELPER_SCRIPT}" "${TMPDIR}/molecule-git-token-helper.sh"
|
||||
|
||||
# Patch the Dockerfile:
|
||||
# 1. COPY the helper script into the image at a predictable path
|
||||
# 2. git config --system registers it globally (applies to all users in the
|
||||
# container, survives the root→agent gosu handoff)
|
||||
# 3. Re-declare ENTRYPOINT last (safe — molecule-runtime entrypoint is
|
||||
# unchanged, just ensuring it's after our additions)
|
||||
#
|
||||
# We do NOT replace the ENTRYPOINT or CMD — molecule-runtime remains the
|
||||
# entry point. The git config --system baked into the image layer means
|
||||
# git will call the helper on every push/fetch without any startup script.
|
||||
cat >> "${TMPDIR}/Dockerfile" << 'PATCH'
|
||||
|
||||
# ─── git credential helper (issue #613 / PR #640) ───────────────────────────
|
||||
# Bake the credential helper into the image so git always has a fresh
|
||||
# GitHub App token. git config --system writes to /etc/gitconfig which is
|
||||
# inherited by all users (root → agent gosu handoff). No startup script change
|
||||
# needed — git invokes this helper automatically on push/fetch.
|
||||
COPY molecule-git-token-helper.sh /usr/local/bin/molecule-git-credential-helper
|
||||
RUN chmod +x /usr/local/bin/molecule-git-credential-helper && \
|
||||
git config --system credential.https://github.com.helper \
|
||||
'!molecule-git-credential-helper' && \
|
||||
echo "git credential helper registered (molecule-git-credential-helper)"
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
PATCH
|
||||
|
||||
# Build and tag
|
||||
log " Running docker build ..."
|
||||
if docker build \
|
||||
--no-cache \
|
||||
-t "workspace-template:${runtime}" \
|
||||
"${TMPDIR}" 2>&1 | grep -E "^(Step|#|---|\[|✓|ERROR|error)" ; then
|
||||
log " ✓ workspace-template:${runtime} built"
|
||||
SUCCESS+=("${runtime}")
|
||||
else
|
||||
err " Build failed for ${runtime}"
|
||||
FAILED+=("${runtime}")
|
||||
fi
|
||||
done
|
||||
|
||||
# ─────────────────────────────────────────────────────
|
||||
# Summary
|
||||
# ─────────────────────────────────────────────────────
|
||||
echo ""
|
||||
log "══════════════════════════════════════════"
|
||||
log "Rebuild complete"
|
||||
log "══════════════════════════════════════════"
|
||||
if [ "${#SUCCESS[@]}" -gt 0 ]; then
|
||||
log "✓ Succeeded: ${SUCCESS[*]}"
|
||||
fi
|
||||
if [ "${#FAILED[@]}" -gt 0 ]; then
|
||||
err "✗ Failed: ${FAILED[*]}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log "Verify images:"
|
||||
docker images | grep "workspace-template" | sort
|
||||
|
||||
echo ""
|
||||
log "To restart all running workspaces and pick up new images:"
|
||||
log " docker ps --filter name=molecule --format '{{.Names}}' | xargs -r docker rm -f"
|
||||
log " # Then restart workspaces via Canvas or API"
|
||||
|
||||
if [ "${#FAILED[@]}" -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
Loading…
Reference in New Issue
Block a user