Files
zegit-forgejo-runner/Dockerfile
agent 7052b41f5e build: chromium, font-noto and postgresql-client for the browser gates
zegit's `browser tests` (chromedp + CDP virtual authenticator) and
`lighthouse` jobs were github.com-only, so when `ci` was routed to this
runner on 2026-08-31 they stopped running anywhere. Chromium 149 (Alpine
3.23) with font-noto lets both run here; psql lets the lighthouse job
create and drop its own database on ci-postgres instead of migrating the
shared maintenance database from under the integration suite's template.

Verified locally (docker build, amd64): chromium-browser 149.0.7827.53,
psql 18.6, 45 font files, node 24.18.1, still uid 1000.
2026-09-08 07:51:10 +02:00

98 lines
5.0 KiB
Docker

# Custom toolchain image for the self-hosted Gitea Actions (Forgejo) runner.
#
# The cluster runs act_runner in *host mode* (docker disabled), so workflow steps
# execute INSIDE this image. The stock forgejo/runner image is minimal and lacks
# node (needed by JS actions: actions/checkout, setup-go, ...), git, make, etc.
# The runner pod is non-root with all caps dropped, so it cannot apt/apk-add at
# runtime -- the tools must be baked in here.
#
# PUBLISHING IS AUTOMATED. Run the "build image" workflow on GitHub with a tag
# (e.g. 12.11.1-ci4); it builds both architectures and pushes to
# ghcr.io/zegit-zoo/zegit-forgejo-runner. ./push-image.sh remains for building
# by hand. README.md explains why the registry moved off Gitea (Cloudflare's
# request-body cap returns 413 on a registry layer) and why the build cannot run
# on our own runners (host mode, all capabilities dropped).
#
# Then in flux-config set the image on BOTH deployment-zegit-runner and
# deployment-forgejo-runner, digest-pinned.
#
# The image is NOT public. Pulls need a registry credential in
# forgejo-runner-system -- github-registry-credentials for ghcr.io. An earlier
# version of this comment claimed the package was public and needed no secret;
# that was wrong for the Gitea registry too, which is private.
FROM code.forgejo.org/forgejo/runner:12.11.1
USER root
# nodejs -> JS actions runtime (actions/checkout, actions/setup-go, ...)
# git -> checkout
# git-daemon -> provides git-http-backend, which Alpine splits OUT of the `git`
# package (git alone ships git-remote-http/https but NOT the CGI
# backend). Without it, internal/forgeprobe's smart-HTTP tests died
# with "fork/exec git-http-backend: no such file or directory" and
# reported three FAILURES for a missing tool — which turned Gitea CI
# red on every zegit master commit while GitHub stayed green, for
# hours, unnoticed.
# bash -> `shell: bash` steps and many action entrypoints
# coreutils-> GNU userland (alpine busybox tools trip up some scripts)
# curl,tar -> setup-go / gitleaks download + extract their own arch-specific binaries
# make -> zegit Makefile targets
# ca-certificates -> trusted roots for HTTPS to gitea/github/goproxy
# openssl -> the release tag gate verifies the Control Plane's SIGNED quorum
# verdict (Ed25519 DSSE) with `openssl pkeyutl -verify -rawin`.
# Absent, that command failed "command not found" and the gate's
# `|| { echo ...; exit 1; }` reported it as "Quorum verdict
# signature FAILED verification" -- a TOOLING gap narrated as a
# SECURITY verdict, pointing the investigation at a perfectly
# valid signed approval instead of at this image. It blocked
# v0.0.134 and v0.0.135 on 2026-08-31.
# jq -> the same story one step earlier: the gate parsed that envelope
# with `jq -e`, and a missing jq was reported as "not a signed
# DSSE envelope". jq is the reflex tool for JSON in shell steps,
# so its absence keeps resurfacing as a misleading failure in
# whichever step reaches for it next.
# gcc,musl-dev -> C toolchain for cgo; `go test -race` (the Makefile test
# target) requires cgo, which needs a C compiler + libc headers
# (musl on Alpine)
# python3,py3-yaml -> the repo's own gates are Python: credentials-coverage.sh,
# validate-admission.sh and feature-lint.sh all shell out to
# python3, and credentials-coverage parses manifests with yaml
#
# chromium, font-noto -> the browser gates (2026-09-08): zegit's `browser
# tests` (chromedp + a CDP virtual authenticator over the WebAuthn
# ceremony pages) and `lighthouse` (treosh/lighthouse-ci-action
# via chrome-launcher) were github.com-only jobs, so when `ci`
# was routed to this runner on 2026-08-31 they stopped running
# anywhere. chromedp finds `chromium`/`chromium-browser` on PATH;
# chrome-launcher honours CHROME_PATH. font-noto so text renders
# (an empty font set makes layout/contrast audits meaningless).
# postgresql-client -> `psql`, so the lighthouse job can CREATE/DROP its own
# database on the runner's ci-postgres (ZEGIT_TESTPG_DSN) instead
# of migrating the shared maintenance database from under the
# integration suite's template.
#
# Go is intentionally NOT baked in: actions/setup-go fetches the pinned version
# per-run (node + tar are present), so the image needs no rebuild on Go bumps.
RUN apk add --no-cache \
nodejs \
git \
git-daemon \
bash \
coreutils \
curl \
tar \
make \
ca-certificates \
gcc \
musl-dev \
python3 \
py3-yaml \
openssl \
jq \
chromium \
font-noto \
postgresql-client
# Match the runner pod's runAsUser (1000); keep the image non-root by default.
USER 1000