157 lines
9.0 KiB
Docker
157 lines
9.0 KiB
Docker
# Polyglot Explore container for the potion-polyglot toolkit (Potion).
|
|
#
|
|
# One image hosts every member repo (worker switches with `run-app <repo>`). Runtime union
|
|
# across the estate: Node (dominant — 26 members, spanning the Node 14 lambdas to the Node 20
|
|
# API), Python (17 — ML pipelines, Flask services, data ETL), Terraform (5), PHP (1).
|
|
#
|
|
# This image only decides what run-app can BOOT. What makes a member gradable is its
|
|
# harbor-tasks/raccoon-shared/Dockerfile.<member>, and a member with no inherited test suite is
|
|
# still gradable via the rubric — so a member absent from this image is not "not worth grading".
|
|
# Postgres is baked as cheap insurance (no member's verifier requires it).
|
|
#
|
|
# NOT baked (deliberately):
|
|
# - (nothing yet — see the MongoDB note below)
|
|
#
|
|
# MongoDB IS required, and IS installable here. No member's *verifier* needs it (potion-app is
|
|
# jsdom, potion-api's usable suites are sinon-mocked), but `run-app` on potion-app and potion-api
|
|
# both do, and those are the two apps a worker is most likely to boot. An earlier note in this
|
|
# file claimed MongoDB ships no arm64 debian-bookworm package and skipped it. That is true only of
|
|
# MongoDB's *Debian* repo; the **Ubuntu jammy arm64** packages install cleanly on bookworm —
|
|
# verified 2026-07-31 on this platform: mongodb-org-server 8.0.28 installs, mongod starts, and a
|
|
# write round-trips. Bake it from that repo rather than demoting the estate's flagship app to
|
|
# read-only.
|
|
# - GPU/CUDA — the potion-ai* members load weights from a now-defunct bucket (never in git),
|
|
# so they are read-and-edit here regardless.
|
|
# - PHP/MySQL — potion-wp-site's first-party code (its custom theme) IS graded, through its
|
|
# own hand-authored harbor image with php-cli + composer; it just doesn't boot in Explore.
|
|
#
|
|
# Runtimes:
|
|
# - Node 14 / 16 / 18 / 20 via nvm (run-app's node selector switches per member)
|
|
# - Python 3.10 via uv (agent str_replace_editor needs >=3.10; also the Python members)
|
|
# - PostgreSQL baked in
|
|
FROM debian:bookworm
|
|
|
|
ENV DEBIAN_FRONTEND=noninteractive
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
build-essential git curl ca-certificates gnupg procps sudo xz-utils \
|
|
libssl-dev zlib1g-dev \
|
|
postgresql postgresql-client \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# --- Node via nvm: 14 / 16 / 18 / 20 (prebuilt). Default 20 symlinked to /usr/local/bin so the
|
|
# toolkit's own `node -e` (run-app/welcome read toolkit.json) always works; run-app switches PATH
|
|
# per member. yarn into each version. v20.* glob (Docker RUN uses dash; nvm.sh is bash-only). ---
|
|
ENV NVM_DIR=/usr/local/nvm
|
|
RUN mkdir -p "$NVM_DIR" \
|
|
&& curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash \
|
|
&& bash -c '. "$NVM_DIR/nvm.sh" \
|
|
&& for v in 14 16 18 20; do nvm install "$v" && nvm use "$v" && npm install -g yarn; done \
|
|
&& nvm alias default 20' \
|
|
&& for b in node npm npx yarn; do ln -sf "$NVM_DIR"/versions/node/v20.*/bin/"$b" /usr/local/bin/"$b"; done
|
|
|
|
# --- MongoDB 8.0 (the product DB: potion-app + potion-api both need it to BOOT) ---
|
|
# From MongoDB's **Ubuntu jammy** arm64 repo, not the Debian one. MongoDB publishes no arm64
|
|
# packages for debian/bookworm (verified: no apt candidate), which is why an earlier revision of
|
|
# this image skipped Mongo and left the estate's flagship app unbootable. The jammy arm64 build
|
|
# installs and runs fine here — verified on this platform: mongodb-org-server 8.0.28 installs,
|
|
# mongod starts, a write round-trips. `mongodb-mongosh` ships the shell so a worker can inspect
|
|
# the DB. Data lives in /data/db, created here so mongod can start as root in the sandbox.
|
|
RUN curl -fsSL https://pgp.mongodb.com/server-8.0.asc \
|
|
| gpg --dearmor -o /usr/share/keyrings/mongodb-8.gpg \
|
|
&& echo "deb [ signed-by=/usr/share/keyrings/mongodb-8.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/8.0 multiverse" \
|
|
> /etc/apt/sources.list.d/mongodb-org-8.0.list \
|
|
&& apt-get update \
|
|
&& apt-get install -y --no-install-recommends mongodb-org-server mongodb-mongosh \
|
|
&& rm -rf /var/lib/apt/lists/* \
|
|
&& mkdir -p /data/db \
|
|
&& mongod --version | head -1
|
|
|
|
# --- Python via uv ---
|
|
# 3.10 stays the default `python3`: it is what this estate's Python members run under.
|
|
# 3.11 is installed alongside it because harness setup reads the registry with `tomllib`
|
|
# (3.11+), and post-create runs under `set -e` — an image with only 3.10 fails container
|
|
# creation. setup-harnesses.sh tries python3, then python3.13/3.12/3.11, so exposing the
|
|
# newer one under its versioned name is enough and leaves the members' default untouched.
|
|
RUN curl -fsSL https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/bin sh \
|
|
&& uv python install 3.10 \
|
|
&& ln -sf "$(uv python find 3.10)" /usr/local/bin/python3 \
|
|
&& uv python install 3.11 \
|
|
&& ln -sf "$(uv python find 3.11)" /usr/local/bin/python3.11 \
|
|
&& python3 --version \
|
|
&& python3.11 -c "import tomllib; print('tomllib ok on', __import__('sys').version.split()[0])"
|
|
|
|
# --- PostgreSQL trust auth (OVERWRITE pg_hba; Debian default `local … peer` is first-match) ---
|
|
RUN PG_VERSION=$(ls /etc/postgresql) \
|
|
&& printf 'local all all trust\nhost all all 127.0.0.1/32 trust\nhost all all ::1/128 trust\nhost all all 0.0.0.0/0 trust\n' > "/etc/postgresql/${PG_VERSION}/main/pg_hba.conf" \
|
|
&& echo "listen_addresses='*'" >> "/etc/postgresql/${PG_VERSION}/main/postgresql.conf"
|
|
|
|
# Startup: start postgres AND mongod. printf, NOT a heredoc (colima's legacy builder writes an
|
|
# empty file from a Dockerfile heredoc → ENTRYPOINT "exec format error"). No single quotes in the
|
|
# body. mongod is backgrounded with --fork and waited on the same way pg is, so a member's
|
|
# setupCmd/startCmd never races an unready DB; its log goes to /var/log/mongod.log for triage.
|
|
RUN printf '#!/bin/bash\nset -e\nPG_VERSION=$(ls /etc/postgresql)\nsudo pg_ctlcluster ${PG_VERSION} main start\nuntil pg_isready -h localhost -p 5432 -U postgres >/dev/null 2>&1; do sleep 0.5; done\nmkdir -p /data/db\nmongod --dbpath /data/db --bind_ip 127.0.0.1 --fork --logpath /var/log/mongod.log >/dev/null 2>&1 || echo "warning: mongod failed to start, see /var/log/mongod.log"\nuntil mongosh --quiet --eval "db.runCommand({ping:1})" >/dev/null 2>&1; do sleep 0.5; done\nexec "$@"\n' > /usr/local/bin/start-services.sh \
|
|
&& chmod +x /usr/local/bin/start-services.sh
|
|
|
|
USER root
|
|
|
|
# --- Playwright + Chromium, for driving the app in a real browser -------------
|
|
# Self-contained under /opt — the member's own runtime is untouched.
|
|
ENV PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright
|
|
RUN apt-get update -qq \
|
|
&& apt-get install -y -qq --no-install-recommends \
|
|
xz-utils \
|
|
libxcomposite1 \
|
|
libxdamage1 \
|
|
libxfixes3 \
|
|
libxrandr2 \
|
|
libasound2 \
|
|
libatk1.0-0 \
|
|
libatk-bridge2.0-0 \
|
|
libatspi2.0-0 \
|
|
libcups2 \
|
|
libdbus-1-3 \
|
|
libgbm1 \
|
|
libnspr4 \
|
|
libnss3 \
|
|
libxkbcommon0 \
|
|
libpango-1.0-0 \
|
|
libcairo2 \
|
|
libxshmfence1 \
|
|
libx11-xcb1 \
|
|
libxcb-dri3-0 \
|
|
libdrm2 \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
RUN set -eux; \
|
|
arch="$(dpkg --print-architecture)"; \
|
|
case "$arch" in amd64) nodearch=x64;; arm64) nodearch=arm64;; *) echo "unsupported arch: $arch" >&2; exit 1;; esac; \
|
|
curl -fsSL "https://nodejs.org/dist/v20.19.5/node-v20.19.5-linux-${nodearch}.tar.xz" -o /tmp/pw-node.tar.xz; \
|
|
mkdir -p /opt/pw-node; \
|
|
tar -xJf /tmp/pw-node.tar.xz -C /opt/pw-node --strip-components=1; \
|
|
rm /tmp/pw-node.tar.xz; \
|
|
export npm_config_prefix=/opt/pw-node PATH="/opt/pw-node/bin:$PATH"; \
|
|
/opt/pw-node/bin/npm install -g playwright@1.56.0; \
|
|
test -d /opt/pw-node/lib/node_modules/playwright; \
|
|
/opt/pw-node/bin/node /opt/pw-node/lib/node_modules/playwright/cli.js install chromium
|
|
|
|
# `pw <script.js>` runs Node with `require("playwright")` resolvable (CommonJS).
|
|
RUN printf '#!/bin/sh\nNODE_PATH=/opt/pw-node/lib/node_modules exec /opt/pw-node/bin/node "$@"\n' > /usr/local/bin/pw \
|
|
&& chmod +x /usr/local/bin/pw
|
|
|
|
# Fail the build if Chromium cannot start.
|
|
RUN printf 'const{chromium}=require("playwright");(async()=>{const b=await chromium.launch();const p=await b.newPage();await p.setContent("<h1 id=t>ok</h1>");if(await p.textContent("#t")!=="ok")throw new Error("bad render");await b.close();console.log("chromium OK");})()\n' > /tmp/pw-check.js \
|
|
&& pw /tmp/pw-check.js \
|
|
&& rm -f /tmp/pw-check.js
|
|
ENV IS_SANDBOX=1
|
|
RUN mkdir -p /root/.claude && echo '{"permissions":{"deny":["WebFetch","WebSearch"]}}' > /root/.claude/settings.json
|
|
|
|
WORKDIR /workspace
|
|
# Resolver for the DNS jail (.devcontainer/dns-jail-container.sh, applied by
|
|
# post-start.sh); if this does not land, Explore just runs unjailed.
|
|
RUN (command -v apk >/dev/null 2>&1 && apk add --no-cache dnsmasq bind-tools) \
|
|
|| (apt-get update && apt-get install -y --no-install-recommends dnsmasq-base dnsutils \
|
|
&& rm -rf /var/lib/apt/lists/*) \
|
|
|| true
|
|
|
|
ENTRYPOINT ["/usr/local/bin/start-services.sh"]
|
|
CMD ["sleep", "infinity"]
|