1# forge release publish: a tag's files, SHA256SUMS and its signature land on2# refs/releases/<tag> in one push with the tag, and are served from3# /<owner>/<repo>/releases/download/<tag>/ byte for byte, as hard links to4# the store; latest/ is the newest tag's. Publishing again replaces them.5. "$(dirname "$0")/../lib.sh"6user dami7repo dami/greet8clone dami dami/greet "$T/w/d"9at "$T/w/d" commit "first"10ok push_as dami "$T/w/d" origin main11at "$T/w/d" git tag v112mkdir "$T/f"13printf 'greet\000\001\002 a binary\n' >"$T/f/greet-linux-amd64"14chmod +x "$T/f/greet-linux-amd64"15printf 'source\n' >"$T/f/greet-1.tar.gz"16export FORGE_USER=dami17ok at "$T/w/d" "$FORGE" release publish v1 "$T/f/greet-linux-amd64" "$T/f/greet-1.tar.gz"18has "$T_LOG" 'remote: release v1: /dami/greet/releases/download/v1/'19has "$T_LOG" 'release v1: published [0-9a-f]+, 2 file.*signed with'20g=$FORGE_ROOT/dami/greet.git21eq "$(git --git-dir="$g" rev-parse v1)" "$(git -C "$T/w/d" rev-parse v1)"22dl=$FORGE_WWW/dami/greet/releases/download23ok cmp "$T/f/greet-linux-amd64" "$dl/v1/greet-linux-amd64"24ok cmp "$T/f/greet-1.tar.gz" "$dl/v1/greet-1.tar.gz"25[ -x "$dl/v1/greet-linux-amd64" ] || fail "the binary lost its mode"26eq "$(cat "$dl/v1/SHA256SUMS")" "$(t_sha256 "$T/f/greet-1.tar.gz") greet-1.tar.gz27$(t_sha256 "$T/f/greet-linux-amd64") greet-linux-amd64"28# The signature is of SHA256SUMS behind a header naming the release.29{ printf 'forge-release 1\nrepo dami/greet\ntag v1\n'; cat "$dl/v1/SHA256SUMS"; } >"$T/message"30ok ssh-keygen -Y verify -f "$FORGE_ROOT/.forge/allowed_signers" -I dami -n forge-release -s "$dl/v1/SHA256SUMS.sig" <"$T/message"31fails ssh-keygen -Y verify -f "$FORGE_ROOT/.forge/allowed_signers" -I dami -n forge-release -s "$dl/v1/SHA256SUMS.sig" <"$dl/v1/SHA256SUMS"32eq "$(ls "$dl/v1" | tr '\n' ' ')" "SHA256SUMS SHA256SUMS.sig greet-1.tar.gz greet-linux-amd64 "33# The commit says what it is, and was signed like a site deploy.34eq "$(git --git-dir="$g" log -1 --format='%(trailers:key=Source-Commit,valueonly)' refs/releases/v1 | sed '/^$/d')" "$(git -C "$T/w/d" rev-parse v1)"35eq "$(git --git-dir="$g" cat-file -p refs/releases/v1 | grep -c '^gpgsig ')" 13637# Hard links into the store, and latest/ links the same files.38store=$FORGE_ROOT/.forge/store/$(git --git-dir="$g" rev-parse 'refs/releases/v1^{tree}')39inode() { ls -i "$1" | awk '{ print $1 }'; }40eq "$(inode "$dl/v1/greet-linux-amd64")" "$(inode "$store/greet-linux-amd64")"41eq "$(inode "$dl/latest/greet-linux-amd64")" "$(inode "$store/greet-linux-amd64")"4243# v2 is newer, so latest/ moves to it; publishing v1 again replaces v1's44# files with no history kept, and latest/ stays on v2.45tick 360046at "$T/w/d" commit "second"47ok push_as dami "$T/w/d" origin main48at "$T/w/d" git tag v249printf 'greet v2\n' >"$T/f/greet-linux-amd64"50ok at "$T/w/d" "$FORGE" release publish v2 "$T/f/greet-linux-amd64"51ok cmp "$T/f/greet-linux-amd64" "$dl/latest/greet-linux-amd64"52missing "$dl/latest/greet-1.tar.gz"53printf 'source, fixed\n' >"$T/f/greet-1.tar.gz"54ok at "$T/w/d" "$FORGE" release publish v1 "$T/f/greet-1.tar.gz"55ok cmp "$T/f/greet-1.tar.gz" "$dl/v1/greet-1.tar.gz"56missing "$dl/v1/greet-linux-amd64"57eq "$(git --git-dir="$g" rev-list --count refs/releases/v1)" 158has "$dl/latest/greet-linux-amd64" 'greet v2'59eq "$(ls "$dl" | tr '\n' ' ')" "latest v1 v2 "6061# The page build swaps the repo's pages in with the downloads still there.62build dami/greet63ok cmp "$T/f/greet-1.tar.gz" "$dl/v1/greet-1.tar.gz"64has "$dl/latest/greet-linux-amd64" 'greet v2'65exists "$FORGE_WWW/dami/greet/releases/index.html"6667# Bad names never leave the machine.68for n in SHA256SUMS .hidden 'a b'; do69 cp "$T/f/greet-1.tar.gz" "$T/f/$n"70 fails_with "file names use" at "$T/w/d" "$FORGE" release publish v2 "$T/f/$n"71done72fails_with "no tag v9" at "$T/w/d" "$FORGE" release publish v9 "$T/f/greet-1.tar.gz"