| M | README.md | 5 | +++- |
| M | bin/ | 8 | ++++- |
| A | test/ | 46 | ++++++++++++++++++++++++++++++ |
@@ -211,7 +211,10 @@ any left in the wrong place.
211211 212212 A private repo's pages are built like any repo's, into213213 `.forge/private/www` instead of `www`, with the same layout: pages, search214-index, `code.db`, release downloads, insights exports. They link the same hashed assets, which the build puts in214+index, `code.db`, release downloads, insights exports. The build writes215+them in `.forge/private/build.<pid>` and swaps them in from there, so216+they are never outside `.forge/private`, which only git can read, even217+mid-build. They link the same hashed assets, which the build puts in215218 `www/assets` (they are the forge's scripts and styles, nothing of the216219 repo), and their header marks the repo private. Caddy serves a file of217220 `www` when there is one and hands every other path to@@ -2472,7 +2472,11 @@ build_all() {
24722472 # hashed assets, so the build's assets go into www/assets as any build's24732473 # do; they are templates' CSS and the forge's scripts, nothing of the repo.24742474 # The rest of what the build writes (index and owner pages) is dropped.2475-# Runs in a subshell of cmd_build, for its EXIT trap.2475+# It builds in a scratch directory beside the private root, under the2476+# directory only the forge can read, so the pages and release links are2477+# never outside it, even mid-build, and the swaps stay renames (the assets'2478+# too: www is under .forge as well). Runs in a subshell of cmd_build, for2479+# its EXIT trap.24762480 build_private() {24772481 only=$124782482 lock=$FORGE_STATE/build.lock@@ -2482,7 +2486,7 @@ build_private() {
24822486 [ "$n" -lt 600 ] || die "build lock held: $lock"24832487 sleep 124842488 done2485- out=$FORGE_STATE/build.$$2489+ out=$(dirname "$FORGE_PRIVATE_WWW")/build.$$24862490 trap 'rm -rf "$out"; rmdir "$lock" 2>/dev/null' EXIT24872491 rm -rf "$out"24882492 t0=$(date +%s)@@ -0,0 +1,46 @@
1+# A private repo's build writes its pages, and links its release files, in2+# a scratch directory under .forge/private, which only the forge can read,3+# never in .forge/build.*, so nothing of the repo is outside it even4+# mid-build; the swap into the private root keeps the links hard links.5+# A stand-in node first on PATH (11ty runs through env node) notes where6+# each build writes, and how its parent is kept, while it runs.7+. "$(dirname "$0")/../lib.sh"8+user dami9+repo --private dami/secret10+repo dami/open11+clone dami dami/secret "$T/w/d"12+at "$T/w/d" commit "first"13+at "$T/w/d" git tag v114+ok push_as dami "$T/w/d" origin main15+mkdir "$T/f"16+printf 'secret tool\n' >"$T/f/tool"17+FORGE_USER=dami ok at "$T/w/d" "$FORGE" release publish v1 "$T/f/tool"18+19+mkdir "$T/bin"20+cat >"$T/bin/node" <<EOF21+#!/bin/sh22+case \${1:-} in *eleventy*) printf '%s %s %s\n' "\${FORGE_PRIVATE:-0}" "\$FORGE_WWW" "\$(ls -ld "\$(dirname "\$FORGE_WWW")" | cut -c1-10)" >>"$T/builds" ;; esac23+exec "$(command -v node)" "\$@"24+EOF25+chmod +x "$T/bin/node"26+PATH=$T/bin:$PATH build dami/secret27+PATH=$T/bin:$PATH build dami/open28+29+eq "$(grep -c . "$T/builds")" 230+set -- $(sed -n 1p "$T/builds")31+eq "$1" 132+case $2 in "$FORGE_ROOT/.forge/private/build."[0-9]*) ;; *) fail "the private build wrote in $2" ;; esac33+eq "$3" drwx------34+missing "$2"35+set -- $(sed -n 2p "$T/builds")36+eq "$1" 037+case $2 in "$FORGE_ROOT/.forge/build."[0-9]*) ;; *) fail "the public build wrote in $2" ;; esac38+if find "$FORGE_ROOT/.forge" -maxdepth 2 -name 'build.[0-9]*' | grep -q .; then fail "a build left its scratch directory"; fi39+40+p=$FORGE_ROOT/.forge/private/www/dami/secret41+exists "$p/index.html"42+tree=$(git --git-dir="$FORGE_ROOT/dami/secret.git" rev-parse 'refs/releases/v1^{tree}')43+inode() { ls -i "$1" | awk '{ print $1 }'; }44+eq "$(inode "$p/releases/download/v1/tool")" "$(inode "$FORGE_ROOT/.forge/private/store/$tree/tool")"45+missing "$FORGE_WWW/dami/secret"46+exists "$FORGE_WWW/assets"