fix(release): sign v1.7.122 with the OLD root — the rotation moved the checks a release early
Demo images / Build & push demo images (push) Successful in 4m12s

The rotation commit pointed create-release.sh and publish-release-assets.sh
at the NEW root in the same commit that pins it in the binary. But the
release CARRYING the rotation must be signed with the OLD root: every node
is still running the previous binary, which pins the old key. So the
tooling would have rejected the only signature the fleet can accept, and
the signature it demanded would have ended OTA fleet-wide.

Both checks now expect the old DID for this cycle, with the flip to the new
one called out for v1.7.123+. sign-manifest.sh documents the
ARCHY_RELEASE_ROOT_PUBKEY override needed because the signer built from
this tree already pins the new anchor and would fail to verify its own
correct output.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-05 07:48:51 -04:00
co-authored by Claude Fable 5
parent c35e33d0a7
commit b92e16abc0
3 changed files with 31 additions and 2 deletions
+13 -1
View File
@@ -240,7 +240,19 @@ install -m 0644 "$FRONTEND_ARCHIVE" "$VERSION_DIR/archipelago-frontend-${VERSION
# 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:z6Mkfu5LT8d4DjETtrkATvHh9Dvcbnr7zBCUwfau8Sw7DLWT"
# ⚠ ROTATION IN FLIGHT (v1.7.122-alpha) — this is the OLD root, deliberately.
#
# The trust anchor in the binary already pins the NEW root
# (z6Mkfu5LT…DLWT), because this release is what installs that pin. But the
# manifest THIS release ships must be signed with the OLD root
# (z6Mkkid…q7ur): every node is still running the previous binary, which
# pins the old key and would reject anything else. Signing this one with the
# new key ends OTA fleet-wide and needs hands-on recovery per node.
#
# ➜ NEXT RELEASE (v1.7.123+): change this to the new DID, and the same line
# in publish-release-assets.sh. By then every node runs a binary pinning
# the new root, and an old-key signature is the one that gets rejected.
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
+5 -1
View File
@@ -29,7 +29,11 @@ fail() { echo "Error: $*" >&2; exit 1; }
# with the pinned release-root anchor refuse to auto-apply unsigned manifests,
# and enforcement will tighten to hard-reject — an unsigned publish would
# strand them. Grep proves presence; ceremony verify proves the crypto.
EXPECTED_DID="did:key:z6Mkfu5LT8d4DjETtrkATvHh9Dvcbnr7zBCUwfau8Sw7DLWT"
# ⚠ ROTATION IN FLIGHT (v1.7.122-alpha) — OLD root on purpose; see the same
# block in create-release.sh. Nodes still run the previous binary and pin the
# old key, so the manifest this release publishes must carry an old-key
# signature. Flip both to z6Mkfu5LT…DLWT for v1.7.123+.
EXPECTED_DID="did:key:z6MkkidEnEpo6qHMCNSZoNKWtvQvxq3whnaME9wGgEFhq7ur"
grep -q '"signature":' "$PROJECT_ROOT/releases/manifest.json" \
&& grep -q "\"signed_by\": \"$EXPECTED_DID\"" "$PROJECT_ROOT/releases/manifest.json" \
|| fail "releases/manifest.json is not signed by the release root — run: bash scripts/sign-manifest.sh"
+13
View File
@@ -11,6 +11,19 @@
# Normally create-release.sh signs the manifest inline; this script exists for
# re-signing (e.g. a manifest edited after creation) or signing on a box where
# the release run was non-interactive.
#
# ⚠ ROTATION IN FLIGHT (v1.7.122-alpha). This release must be signed with the
# OLD release root, because every node still runs a binary pinning it — but
# the signer built from THIS tree already pins the NEW root, so its own
# verification would reject a correct old-key signature. Pin the old anchor
# for the duration of the ceremony so signing and verification agree:
#
# ARCHY_RELEASE_ROOT_PUBKEY=5d15cbee8a108f7dd288c02d29a1d9d71f198acc99186aad8008b4f28d469951 \
# bash scripts/sign-manifest.sh
#
# That hex is the OLD root's PUBLIC key (verified to derive to
# did:key:z6Mkkid…q7ur); it is not secret and pins verification only.
# From v1.7.123 the override is unnecessary — drop it and this block.
set -euo pipefail
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"