clone

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

The edge can send the mirror bucket a token

cat committed 3e6ffab
With the Fly secret FORGE_MIRROR_TOKEN set, the edge sends it as X-Forge-Mirror-Token on each request for the offline copy, so a Cloudflare WAF rule in front of the bucket can later refuse requests without it. Without the secret the header is empty. Scenario: the bucket sees the token, and the reply doesn't carry it.
commit
3e6ffab7b6c67950bc8c4dc702a6e0d275ddd489
parent
835172a22647d43ff8752262a9148c26cf5b2e5e
author
cat <admin@dev.site>
ci
✓ passed in 120s, signed by cat
kind
feat risk score 1.0 of 3, Jev's estimate
review
#30 Security: sign-in, invites, owner pages, lake, caps and the edge
ci attestation
forge-attestation 1
type ci
commit 3e6ffab7b6c67950bc8c4dc702a6e0d275ddd489
tree f3797edcbabad265b5cb33bb718374fc7d63c6dc
script .forge/ci 8d2000a416f8160bcf710d98b72af9eb76287f58
result pass
exit 0
started 2026-10-19T08:00:12Z
duration 120s
runner (not shown here; refs/notes/ci has it)
system Darwin 25.5.0 arm64
env host
log sha256:bf5a81f934e4aee612b2a8504022d153b14c9096de9b80a50f6ada0efeab7c80 325 lines
|pushed wip/i18n
|e86ab4e running .forge/ci: greet.sh: say what it is
|  | sh: /bin/sh
|  | ok   greet
|e86ab4e pass in 0s, signed
|pushed main
|remote: review #4: /dami/greet/reviews/4/
|pushed wip/i18n
|78b1eb6 running .forge/ci: wave at the world
|  | sh: /bin/sh
|  | FAIL greet : got 'hello, world o/', want 'hello, world'
|78b1eb6 fail in 0s, signed
|forge: 1 commit(s) did not pass
|remote: review #6: /dami/greet/reviews/6/
|pushed ana/wave
|b2b9445 running .forge/ci: update the test for the wave
|  | sh: /bin/sh
|  | ok   greet
|b2b9445 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 4f60fa6 -> /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
|48aef83 running .forge/ci: web, server and Python versions of greet
|  | sh: /bin/sh
|  | ok   greet
|48aef83 pass in 0s, signed
|pushed main
|ff22780 running .forge/ci: messages: notes for the later regions
|  | sh: /bin/sh
|  | ok   greet
|ff22780 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: mkdir -p guide/fonts && cp site/assets/fonts/*.woff2 guide/fonts/
|site guide: deployed 58aa462 -> /sites/dami/forge/guide/
|(node:54203) 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 -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.GT5BJv/wt/demo/root/.forge/www
|(node:54377) 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 0s -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.GT5BJv/wt/demo/root/.forge/www
|(node:54564) 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 -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.GT5BJv/wt/demo/root/.forge/www
|(node:54744) 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 -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.GT5BJv/wt/demo/root/.forge/www
|(node:55460) 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 -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.GT5BJv/wt/demo/root/.forge/www
|235 of 235 pages render the same without 11ty
|guide: 8 files, links ok
|ok

Signature: good, cat

5 files changed, +45 -1
MREADME.md4+++-
Mdeploy/edge/Caddyfile4++++
Mdeploy/edge/fly.toml3+++
Mdeploy/edge/start.sh2++
Atest/scenarios/edge-mirror-token.sh33++++++++++++++++++++++++++++++
M README.md +3 -1
M deploy/edge/Caddyfile +4 -0
M deploy/edge/fly.toml +3 -0
M deploy/edge/start.sh +2 -0
A test/scenarios/edge-mirror-token.sh +33 -0
@@ -0,0 +1,33 @@
1+# With FORGE_MIRROR_TOKEN set (a Fly secret), the edge sends it to the2+# mirror bucket as X-Forge-Mirror-Token on each request for the offline3+# copy, so a rule in front of the bucket can refuse requests without it.4+. "$(dirname "$0")/../lib.sh"5+command -v caddy >/dev/null 2>&1 || { note "caddy is not installed: skipped running it"; exit 0; }6+# The bucket: answers every request, and writes down the token it came7+# with. It takes a port of its own and says which.8+node -e '9+const fs = require("fs");10+const s = require("http").createServer((req, res) => {11+ fs.appendFileSync(process.argv[1], `${req.url} ${req.headers["x-forge-mirror-token"] ?? "-"}\n`);12+ res.writeHead(200, { "Content-Type": "text/html" }).end("<p>copy</p>");13+}).listen(0, "127.0.0.1", () => fs.writeFileSync(process.argv[2], String(s.address().port)));14+' "$T/seen" "$T/mport" &15+T_PIDS="$T_PIDS $!"16+n=017+until [ -s "$T/mport" ] || [ "$n" -ge 50 ]; do sleep 0.1; n=$((n + 1)); done18+mport=$(cat "$T/mport")19+eport=$(free_port)20+dead=$(free_port)21+# On 127.0.0.1 only, so no other scenario's server can take the port there.22+sed "s/^:8080 {/:$eport {/; s/127\.0\.0\.1:8081/127.0.0.1:$dead/" "$T_HOME/deploy/edge/Caddyfile" |23+ awk '{ print } $0 == "\tadmin off" { print "\tdefault_bind 127.0.0.1" }' >"$T/Caddyfile.edge"24+FORGE_DOMAIN=src.test FORGE_MIRROR_URL=http://127.0.0.1:$mport FORGE_MIRROR_TOKEN=s3cret-token XDG_DATA_HOME=$T/xdg XDG_CONFIG_HOME=$T/xdg \25+ caddy run --config "$T/Caddyfile.edge" --adapter caddyfile >"$T/caddy.edge.log" 2>&1 &26+T_PIDS="$T_PIDS $!"27+wait_http "http://127.0.0.1:$mport/"28+wait_http "http://127.0.0.1:$eport/"29+http -s -i -H 'Host: src.test' "http://127.0.0.1:$eport/dami/greet/" | tr -d '\r' >"$T/res"30+has "$T/res" '^X-Forge-Offline: mirror'31+has "$T/res" '<p>copy</p>'32+has "$T/seen" '^/dami/greet/index\.html s3cret-token$'33+lacks "$T/res" 's3cret-token'