diff --git a/scripts/create-release.sh b/scripts/create-release.sh index fedd5c3c..c35ddb11 100755 --- a/scripts/create-release.sh +++ b/scripts/create-release.sh @@ -212,8 +212,10 @@ if [ -n "${RELEASE_MASTER_MNEMONIC:-}" ] || [ -t 0 ]; then "$SIGNER" ceremony verify "$PROJECT_ROOT/releases/manifest.json" else echo "⚠ WARNING: no TTY and RELEASE_MASTER_MNEMONIC unset — manifest left UNSIGNED." - echo " Sign it before publishing: bash scripts/sign-manifest.sh" - echo " (publish-release-assets.sh refuses to ship an unsigned manifest)" + echo " This run will ABORT before committing (step 7 refuses an unsigned" + echo " manifest), because nodes read releases/manifest.json from branch main" + echo " and would refuse to auto-apply it." + echo " Sign it, then re-run: bash scripts/sign-manifest.sh" fi cp "$PROJECT_ROOT/releases/manifest.json" "$PROJECT_ROOT/release-manifest.json" @@ -225,6 +227,36 @@ install -m 0755 "$PROJECT_ROOT/core/target/release/archipelago" "$VERSION_DIR/ar install -m 0644 "$FRONTEND_ARCHIVE" "$VERSION_DIR/archipelago-frontend-${VERSION}.tar.gz" "$SCRIPT_DIR/check-release-manifest.sh" +# §A supply-chain gate, mirroring publish-release-assets.sh — but EARLIER, +# because publishing is not the first way an unsigned manifest reaches the +# fleet. Nodes fetch releases/manifest.json straight from branch `main` +# (see the verification URLs printed below), so the COMMIT is what exposes +# it, not the publish. publish-release-assets.sh refusing to ship is a +# backstop that arrives one step too late: by then the unsigned manifest is +# already on main and the fleet is already refusing to auto-apply. +# +# This is why every cycle needed a manual catch. The signing block above is +# conditional — no TTY and no RELEASE_MASTER_MNEMONIC means it prints a +# warning and falls through — and the commit then happened anyway. A release +# commit carrying a manifest no node will accept has no valid use, so refuse +# to create one rather than leave a tag that has to be re-cut. +EXPECTED_DID="did:key:z6MkkidEnEpo6qHMCNSZoNKWtvQvxq3whnaME9wGgEFhq7ur" +if ! grep -q '"signature":' "$PROJECT_ROOT/releases/manifest.json" \ + || ! grep -q "\"signed_by\": \"$EXPECTED_DID\"" "$PROJECT_ROOT/releases/manifest.json"; then + echo "" >&2 + echo "Error: releases/manifest.json is NOT signed by the release root." >&2 + echo " Refusing to commit — nodes read this file from branch main and will" >&2 + echo " refuse to auto-apply it, so the release would be dead on arrival." >&2 + echo "" >&2 + echo " Sign it, then re-run this script:" >&2 + echo " bash scripts/sign-manifest.sh" >&2 + echo "" >&2 + echo " (Signing needs a TTY for the mnemonic prompt, or RELEASE_MASTER_MNEMONIC set.)" >&2 + exit 1 +fi +"$SIGNER" ceremony verify "$PROJECT_ROOT/releases/manifest.json" \ + || { echo "Error: manifest signature failed cryptographic verification — refusing to commit" >&2; exit 1; } + echo "[7/8] Committing version bump..." git -C "$PROJECT_ROOT" add \ core/archipelago/Cargo.toml \