#!/usr/bin/env bash # One-step OTA-manifest signer (counterpart to sign-catalog.sh). # # Run: bash scripts/sign-manifest.sh [path/to/manifest.json] # Then: paste your 24-word release master mnemonic, press Enter, then Ctrl-D. # # Signs an explicitly selected pending manifest and cryptographically verifies the # result against the pinned release-root anchor. The mnemonic is read from the # terminal only (never stored, never in shell history, never passed to Claude). # # create-release.sh stages unsigned artifacts; signing is a separate operator # step after the exact pending byte domain has been reviewed. # # The release root was rotated 2026-08-05. From v1.7.123 this signs with the # NEW mnemonic and the signer's own anchor already pins that key, so no # ARCHY_RELEASE_ROOT_PUBKEY override is needed (it was, for .122 only). set -euo pipefail REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" MANIFEST="${1:?explicit pending manifest path required}" [[ "$MANIFEST" = /* ]] || MANIFEST="$REPO/$MANIFEST" [ -f "$MANIFEST" ] || { echo "Manifest not found: $MANIFEST" >&2; exit 1; } case "$(realpath "$MANIFEST")" in "$REPO/releases/pending/"*/manifest.json) ;; *) echo 'Only pending manifests may be signed' >&2; exit 1 ;; esac bash "$REPO/scripts/check-release-manifest.sh" "$MANIFEST" # Use ONLY a prebuilt signer — never compile here (compiling caused hangs in # the earlier catalog ceremony). Prefer the repo's release build. BIN="" VERSION=$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["version"])' "$MANIFEST") SOURCE_COMMIT=$(python3 "$REPO/scripts/release_payload.py" source --version "$VERSION") test "$SOURCE_COMMIT" = "$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["source_commit"])' "$MANIFEST")" for candidate in "$REPO/releases/v$VERSION/archipelago"; do if [[ -x "$candidate" ]]; then BIN="$candidate"; break; fi done if [[ -z "$BIN" ]]; then echo "⏳ No prebuilt signer found. Build one first:" echo " (cd core && cargo build --release -p archipelago)" echo " Nothing was changed." exit 1 fi echo "════════════════════════════════════════════════════════════════" echo " Paste your 24-word release master mnemonic below, press Enter," echo " then press Ctrl-D on a new line." echo "════════════════════════════════════════════════════════════════" "$BIN" ceremony sign "$MANIFEST" echo if "$BIN" ceremony verify "$MANIFEST"; then echo "✅ SUCCESS — manifest signed by the pinned release root: $MANIFEST" if [ "$MANIFEST" = "$REPO/releases/manifest.json" ]; then cp "$MANIFEST" "$REPO/release-manifest.json" fi else echo "❌ Signature did NOT verify against the pinned release-root anchor." echo " Do NOT commit. Check the mnemonic and re-run." exit 1 fi