172 lines
9.5 KiB
Docker
172 lines
9.5 KiB
Docker
# Per-repo harbor task Dockerfile for potion-wp-site (potion-polyglot PHP member).
|
|
#
|
|
# HAND-AUTHORED, not generated: PHP is not a runtime kind gen-harbor-dockerfiles.ts knows,
|
|
# and adding one for a single member would be a larger change than it earns. The generator
|
|
# gets a new kind when a second first-party PHP member turns up; the other estates'
|
|
# members are Rust/JVM/.NET/Node. Precedent: strongsuit-client and strongsuit-server are also
|
|
# hand-authored and sit outside MEMBERS.
|
|
#
|
|
# The repo is a full WordPress 5.9.2 checkout, but the first-party code is one directory:
|
|
# wp-content/themes/potion, an Automattic _s derivative with real templates, an SCSS
|
|
# pipeline and JS. WordPress core and the stock plugins around it are vendored.
|
|
#
|
|
# What makes this member gradable without a test suite is that the theme ships genuine
|
|
# deterministic offline checks, and they are the reason to bake the toolchain rather than
|
|
# just the source:
|
|
# composer lint:php -> php-parallel-lint across the theme
|
|
# composer lint:wpcs -> phpcs against the WordPress-theme ruleset the repo commits
|
|
# itself in phpcs.xml.dist
|
|
# npm run lint:js -> wp-scripts lint-js over js/*.js
|
|
# npm run lint:scss -> wp-scripts lint-style over sass/**/*.scss
|
|
#
|
|
# No database. Grading needs none: every check above is static. *Running* the site would
|
|
# need MySQL plus an import of one of the two committed SQL dumps — a documented run-app
|
|
# limitation, the same shape as potion-api needing Mongo, and why this member is
|
|
# runtime:'none' in TOOLKIT_GROUPS rather than bootable in Explore.
|
|
FROM php:8.1-cli-bookworm
|
|
ARG TOOLKIT_BUILD_ID=dev
|
|
|
|
# Node 16 for the theme's node-sass/wp-scripts toolchain. node-sass builds native bindings
|
|
# against a specific ABI and has no prebuilt binary for current Node, so a modern major
|
|
# would fail to install rather than merely warn.
|
|
ENV NODE_VERSION=16.20.2
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
git curl unzip ca-certificates xz-utils libzip-dev \
|
|
&& rm -rf /var/lib/apt/lists/* \
|
|
&& curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-arm64.tar.xz" \
|
|
-o /tmp/node.tar.xz \
|
|
&& tar -xJf /tmp/node.tar.xz -C /usr/local --strip-components=1 \
|
|
&& rm /tmp/node.tar.xz \
|
|
&& node --version && npm --version
|
|
|
|
# Python >=3.10 for the reduced-toolset agent's str_replace_editor (dataclass kw_only).
|
|
# This block used to ASSERT the base already had it, on the claim that php:8.1-bookworm
|
|
# ships python3.11. It does not — the assertion failed with exit 127 (python3: not found),
|
|
# so the image could not build and this member could not be graded. Install a managed
|
|
# interpreter via uv, the same way every generated per-member Dockerfile does.
|
|
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 \
|
|
&& python3 --version
|
|
|
|
# composer, pinned by installer checksum rather than piping the web to php.
|
|
RUN curl -fsSL https://getcomposer.org/installer -o /tmp/composer-setup.php \
|
|
&& php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer \
|
|
&& rm /tmp/composer-setup.php \
|
|
&& composer --version
|
|
|
|
# --- Playwright + Chromium, when the task opts in ----------------------------
|
|
# Installed only when task.toml sets `[metadata] browser = true`. A Dockerfile cannot read
|
|
# task.toml, so build-workspace.sh writes that answer to environment/browser-optin.
|
|
# Self-contained under /opt — the member's own runtime is untouched.
|
|
ENV PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright
|
|
COPY browser-optin /tmp/browser-optin
|
|
RUN set -eu; \
|
|
if [ "$(cat /tmp/browser-optin)" != "1" ]; then echo "browser: task did not opt in; skipping Playwright"; exit 0; fi; \
|
|
set -x; \
|
|
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/*; \
|
|
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; \
|
|
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; \
|
|
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
|
|
|
|
WORKDIR /workspace
|
|
# `COPY workspace/ .`, matching every generated per-member Dockerfile: build-workspace.sh
|
|
# materialises the task tree at environment/workspace/, so a `COPY repo ...` here cannot
|
|
# resolve and the image fails to build with "/repo: not found" — i.e. the member could not
|
|
# be graded at all. Caught by authoring a task against this member rather than only
|
|
# against the default one.
|
|
COPY workspace/ .
|
|
|
|
# Bake the theme's dev dependencies so the checks run offline. Both are best-effort: the
|
|
# source plus a working toolchain is the substrate, and a registry hiccup at build time
|
|
# must not make the whole member ungradable.
|
|
# composer >=2.9 refuses by default to install any package carrying a security advisory,
|
|
# and the theme's own linter (wp-coding-standards/wpcs 2.x, via wptrt/wpthemereview) is
|
|
# flagged — so `composer install` resolved to nothing, vendor/bin stayed empty, and BOTH
|
|
# deterministic checks failed with "Could not open input file" rather than with a verdict.
|
|
# The advisory is on a dev-only linter that runs offline against this repo's own source, so
|
|
# the block is turned off for this vendored toolchain rather than pinning the checks away.
|
|
# Second half of the same story: composer 2 ABORTS a non-interactive install unless the
|
|
# phpcodesniffer-composer-installer plugin is explicitly allowed, which is why the vendor
|
|
# tree came out half-populated (packages downloaded, none installed, no vendor/bin entries).
|
|
# That plugin is also what registers the WordPress standard with phpcs, so lint:wpcs cannot
|
|
# work without it.
|
|
RUN cd /workspace/wp-content/themes/potion \
|
|
&& composer config --no-plugins policy.advisories.block false \
|
|
&& composer config --no-plugins allow-plugins.dealerdirect/phpcodesniffer-composer-installer true \
|
|
&& (composer install --no-interaction --no-progress || \
|
|
echo "warning: composer install incomplete — lint:php / lint:wpcs may be unavailable") \
|
|
&& (npm install --no-audit --no-fund || \
|
|
echo "warning: npm install incomplete — lint:js / lint:scss may be unavailable")
|
|
|
|
ENV TOOLKIT_BUILD_ID=${TOOLKIT_BUILD_ID}
|
|
|
|
# Install the Codex CLI at BUILD time, for the same reason claude is: the agent-setup
|
|
# install needs the network, which the trial DNS jail blocks. Hard-fail rather than let a
|
|
# codex-less image cache and break every trial on that repo at agent-setup.
|
|
RUN for i in 1 2 3; do \
|
|
if curl -fsSL https://chatgpt.com/codex/install.sh -o /tmp/codex-install.sh \
|
|
&& CODEX_INSTALL_DIR=/usr/local/bin CODEX_NON_INTERACTIVE=true sh /tmp/codex-install.sh; then break; fi; \
|
|
echo "WARNING: codex install attempt $i failed; retrying in 5s" >&2; sleep 5; \
|
|
done; \
|
|
rm -f /tmp/codex-install.sh; \
|
|
if ! command -v codex >/dev/null 2>&1 && [ -x "$HOME/.local/bin/codex" ]; then \
|
|
ln -sf "$HOME/.local/bin/codex" /usr/local/bin/codex; \
|
|
fi; \
|
|
if ! command -v codex >/dev/null 2>&1 && command -v npm >/dev/null 2>&1; then \
|
|
npm install -g @openai/codex@latest || true; \
|
|
fi; \
|
|
command -v codex >/dev/null 2>&1 \
|
|
&& echo "codex installed at $(command -v codex)" \
|
|
|| echo "WARNING: codex CLI not installed (see the install output above)" >&2
|
|
|
|
# Resolver for the trial DNS allowlist (scripts/lib/dns-jail.sh); if this
|
|
# does not land, trials just run 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
|
|
# Restrict DNS to the model endpoint when DNSJAIL_ALLOW is set (the agent supplies it).
|
|
# Source: scripts/lib/dns-jail-container.sh, staged here by build-workspace.sh.
|
|
COPY dns-jail/ /opt/raccoon-dns-jail/
|
|
RUN if [ -f /opt/raccoon-dns-jail/dns-jail-container.sh ]; then \
|
|
install -m 0755 /opt/raccoon-dns-jail/dns-jail-container.sh /usr/local/bin/raccoon-dns-jail \
|
|
&& sh -n /usr/local/bin/raccoon-dns-jail; \
|
|
else echo "NOTE: no DNS jail script staged; trials on this image run unjailed" >&2; fi
|
|
|