clone

a personal forge on plain git: static pages, stacked-diff reviews, signed local ci, repo sites and releases

Run the scenarios in the forge's container, as root

cat committed e28b6f3
test/container.sh runs test/run.sh in an image built from the Dockerfile
(forge:test unless FORGE_TEST_IMAGE says otherwise), as root, the way the
forge runs there: Debian's dash, its git, Caddy 2.6 and litestream, a git
user that restores are handed to, and no curl. It mounts this checkout
read-only and runs a copy of it with the image's node_modules and DuckDB
extensions, so only a change to the Dockerfile or the packages needs a
new image. README.md says how, next to how to run the scenarios at all.
commit
e28b6f339e2cff74247745d2732ece5a0239c196
parent
2f1c626cfc0f9c6aa1ed656bc7680eda3e850af0
author
cat <admin@dev.site>
ci
✓ passed in 115s, signed by cat
kind
build risk score 0.5 of 3, Jev's estimate
review
#5 Pass the scenarios in the container, as root
ci attestation
forge-attestation 1
type ci
commit e28b6f339e2cff74247745d2732ece5a0239c196
tree ead68c784ee10768202ccb44868399539dd2d81b
script .forge/ci e6f038ae810b87f90a4be115a762a9c91dd76a01
result pass
exit 0
started 2026-10-18T23:04:54Z
duration 115s
runner (not shown here; refs/notes/ci has it)
system Darwin 25.5.0 arm64
env host
log sha256:af35a83b25e2d9532f88e3432af06b4480e6f189eaa19b891394079ddfb6c934 240 lines
|remote: review #4: /dami/greet/reviews/4/
|pushed wip/i18n
|eab0e48 running .forge/ci: greet.sh: say what it is
|  | sh: /bin/sh
|  | ok   greet
|eab0e48 pass in 0s, signed
|pushed main
|remote: review #4: /dami/greet/reviews/4/
|pushed wip/i18n
|23bd74c running .forge/ci: wave at the world
|  | sh: /bin/sh
|  | FAIL greet : got 'hello, world o/', want 'hello, world'
|23bd74c fail in 0s, signed
|forge: 1 commit(s) did not pass
|remote: review #6: /dami/greet/reviews/6/
|pushed ana/wave
|30535b5 running .forge/ci: update the test for the wave
|  | sh: /bin/sh
|  | ok   greet
|30535b5 pass in 0s, signed
|remote: review #6: /dami/greet/reviews/6/
|pushed ana/wave
|warning: You appear to have cloned an empty repository.
|site home: deployed ceda2a0 -> /sites/ana/dotfiles/home/
|created ana/notes
|remote: review #1: /ana/notes/reviews/1/
|pushed ana/todo
|landing #1 A todo list: ana/todo -> main
|ce247d7 running .forge/ci: web, server and Python versions of greet
|  | sh: /bin/sh
|  | ok   greet
|ce247d7 pass in 0s, signed
|pushed main
|2effb80 running .forge/ci: messages: notes for the later regions
|  | sh: /bin/sh
|  | ok   greet
|2effb80 pass in 0s, signed
|remote: review #7: /dami/greet/reviews/7/
|pushed dami/regions
|created dami/forge
|warning: You appear to have cloned an empty repository.
|site guide: deployed cca2d68 -> /sites/dami/forge/guide/
|(node:22900) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time
|(Use `node --trace-warnings ...` to show where the warning was created)
|built ana/dotfiles in 1s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www
|(node:23042) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time
|(Use `node --trace-warnings ...` to show where the warning was created)
|built ana/notes in 1s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www
|(node:23191) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time
|(Use `node --trace-warnings ...` to show where the warning was created)
|built dami/forge in 1s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www
|(node:23340) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time
|(Use `node --trace-warnings ...` to show where the warning was created)
|built dami/greet in 4s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www
|(node:24058) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time
|(Use `node --trace-warnings ...` to show where the warning was created)
|built - in 1s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www
|226 of 226 pages render the same without 11ty
|guide: 4 files, links ok
|ok

Signature: good, cat

2 files changed, +41 -0
MREADME.md12++++++++++++
Atest/container.sh29+++++++++++++++++++++++++++++
M README.md +12 -0
A test/container.sh +29 -0
@@ -0,0 +1,29 @@
1+#!/bin/sh2+# Run the scenarios in the forge's container, as root, the way the forge3+# runs there: Debian's sh (dash), its git, Caddy, restic and litestream, a4+# git user to hand restores to, and no curl. This checkout's code runs with5+# the image's node_modules and DuckDB extensions, so only a change to the6+# Dockerfile or the packages needs a new image.7+#8+# docker build -t forge:test . the image, once9+# sh test/container.sh every scenario10+# sh test/container.sh private release the ones whose names contain a word11+# FORGE_TEST_IMAGE=forge:local sh test/container.sh another image12+# FORGE_TEST_JOBS=1 sh test/container.sh one at a time13+set -eu14+if [ "${1:-}" = --inside ]; then15+ shift16+ # A copy of the checkout without its own node_modules (built for the17+ # host, maybe not Linux) or anything the forge writes into it.18+ w=$(mktemp -d /tmp/forge-src.XXXXXX)19+ tar -C /opt/forge-src --exclude=./.git --exclude=./node_modules --exclude=./.duckdb --exclude=./.cache \20+ --exclude=./_site --exclude=./demo/root --exclude=./demo/work -cf - . | tar -C "$w" -xf -21+ ln -s /opt/forge/node_modules "$w/node_modules"22+ ln -s /opt/forge/.duckdb "$w/.duckdb"23+ exec sh "$w/test/run.sh" "$@"24+fi25+src=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)26+image=${FORGE_TEST_IMAGE:-forge:test}27+docker image inspect "$image" >/dev/null 2>&1 || { echo "no image $image: docker build -t $image $src" >&2; exit 1; }28+exec docker run --rm ${FORGE_TEST_JOBS:+-e FORGE_TEST_JOBS} -v "$src:/opt/forge-src:ro" "$image" \29+ sh /opt/forge-src/test/container.sh --inside "$@"