With FORGE_CI_CONTAINER=1, .forge/ci builds the forge's image from the commit under test (forge:test, or FORGE_TEST_IMAGE) and runs test/container.sh after the host's run, so an attestation can say the scenarios pass as root in the container as well. It is off by default: the first build compiles tailcat, rclone and litestream and takes minutes, and it needs Docker. README.md says so beside test/container.sh.
- commit
- 8e63d4d0b4ae096eeb8e55f5e70d6a33a09b2259
- parent
- 0a05b713b00bb453003962e1e2b1bc59206773fb
- author
- cat <admin@dev.site>
- ci
- ✓ passed in 110s, signed by cat
- kind
- build risk score 0.7 of 3, Jev's estimate
- review
- #5 Pass the scenarios in the container, as root
ci attestation
forge-attestation 1 type ci commit 8e63d4d0b4ae096eeb8e55f5e70d6a33a09b2259 tree c4df62053bb7bcdffdfb2ccc4b6436066b4d1787 script .forge/ci 38df37c0d5a6382f60569079a0dd821094e37e4a result pass exit 0 started 2026-10-18T23:08:05Z duration 110s runner (not shown here; refs/notes/ci has it) system Darwin 25.5.0 arm64 env host log sha256:67c62d403ed33fd673bf9701d3af3df341c2c8407431b1f65a95996226b987cc 321 lines |remote: review #4: /dami/greet/reviews/4/ |pushed wip/i18n |29d2485 running .forge/ci: greet.sh: say what it is | | sh: /bin/sh | | ok greet |29d2485 pass in 0s, signed |pushed main |remote: review #4: /dami/greet/reviews/4/ |pushed wip/i18n |660d2e9 running .forge/ci: wave at the world | | sh: /bin/sh | | FAIL greet : got 'hello, world o/', want 'hello, world' |660d2e9 fail in 0s, signed |forge: 1 commit(s) did not pass |remote: review #6: /dami/greet/reviews/6/ |pushed ana/wave |5d0e65a running .forge/ci: update the test for the wave | | sh: /bin/sh | | ok greet |5d0e65a 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 8ed91aa -> /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 |51bdb02 running .forge/ci: web, server and Python versions of greet | | sh: /bin/sh | | ok greet |51bdb02 pass in 0s, signed |pushed main |5d35faf running .forge/ci: messages: notes for the later regions | | sh: /bin/sh | | ok greet |5d35faf 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 18b7cde -> /sites/dami/forge/guide/ |(node:63256) 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 0s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www |(node:63615) 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:63754) 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:63885) 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 1s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www |(node:64551) 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 0s -> /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
| M | .forge/ | 6 | ++++++ |
| M | README.md | 4 | ++++ |
@@ -6,6 +6,12 @@ npm ci --silent --no-audit --no-fund
66 npx tsc -p .77 # Scenarios: one behavior each, in a throwaway forge of its own (test/lib.sh).88 sh test/run.sh9+# And in the forge's container, as root, when FORGE_CI_CONTAINER=1 asks10+# for it (test/container.sh): it builds the image, minutes the first time.11+if [ "${FORGE_CI_CONTAINER:-}" = 1 ]; then12+ docker build -q -t "${FORGE_TEST_IMAGE:-forge:test}" . >/dev/null13+ sh test/container.sh14+fi915 # Strict templates: printing an undefined or null value fails the build.1016 FORGE_STRICT=1 sh demo/make-demo.sh >/dev/null1117 test -f demo/root/.forge/www/dami/greet/reviews/3/index.html@@ -1189,6 +1189,10 @@ docker build -t forge:test . # once, and after Dockerfile or package changes
11891189 sh test/container.sh [word...] # this checkout's code, the image's node_modules11901190 ```11911191 1192+`FORGE_CI_CONTAINER=1 forge attest` has `.forge/ci` build that image and run1193+them there too, after the host's run; it is off by default, since the1194+first build takes minutes.1195+11921196 ## Reading pages11931197 11941198 The index and each owner's page show repos as cards on shelves by category,