publish-manifest.sh: --product app|wallet (the wallet's own manifest, igneum-wallet-latest.json, the same shape and key; the arm the 0.1.5 release plan named and no script carried; --public then publishes the wallet alone, the live verify reads the wallet's file). Used for Igneum Wallet 0.1.6 on 8 October 2026.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
2de98ee98b
commit
bb98bf3f7f
1 changed files with 24 additions and 16 deletions
|
|
@ -14,6 +14,10 @@
|
|||
# [--public] also publish into dl/public/ (no token: the site's download
|
||||
# links, packaging/ota/publish-public.sh --app, plus --wallet
|
||||
# when the wallet manifest is in the folder); the same deploy
|
||||
# [--product app|wallet] which manifest: igneum-app-latest.json (default) or
|
||||
# igneum-wallet-latest.json (the Igneum Wallet, 0.1.6: the same
|
||||
# shape, its own file, signed with the same key; --public then
|
||||
# publishes the wallet alone, --deploy verifies the wallet's file)
|
||||
# [--tuning tuning.json | --no-tuning] the fleet's per-card kernel tuning (tools/tuning.mjs writes it;
|
||||
# docs/design/miner-tuning.md); carried over from the current
|
||||
# manifest when not given, as is consensus.override
|
||||
|
|
@ -37,6 +41,7 @@ KEY="$HOME/.config/igneum/ota-signing-key"
|
|||
PUB="$HOME/.config/igneum/ota-signing-key.pub"
|
||||
TOKEN_FILE="$HOME/.config/igneum/dl-token"
|
||||
SIGNER="$ROOT/app/igneum-app/target/release/igneum-ota-sign"
|
||||
PRODUCT="app"
|
||||
|
||||
VERSION="" MAC="" WIN="" NOTES="" ACTIVATION="" DEADLINE="" MIN_SUPPORTED="" CHANNEL="devnet" BASE="" DEST="" DEPLOY=0 VERIFY_ONLY=0 TRIES=12
|
||||
OVERRIDE="" TUNING_FILE="" NO_TUNING=0 PUBLIC=0
|
||||
|
|
@ -51,6 +56,7 @@ while [ $# -gt 0 ]; do
|
|||
--override) OVERRIDE="$2"; shift 2 ;; # consensus.override: the exact JSON object every app writes to its override.json (all height switches, not just the new one)
|
||||
--min-supported) MIN_SUPPORTED="$2"; shift 2 ;;
|
||||
--channel) CHANNEL="$2"; shift 2 ;;
|
||||
--product) PRODUCT="$2"; shift 2 ;;
|
||||
--tuning) TUNING_FILE="$2"; shift 2 ;;
|
||||
--no-tuning) NO_TUNING=1; shift ;;
|
||||
--base-url) BASE="$2"; shift 2 ;;
|
||||
|
|
@ -63,6 +69,8 @@ while [ $# -gt 0 ]; do
|
|||
*) echo "unknown argument: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
case "$PRODUCT" in app|wallet) ;; *) echo "--product must be app or wallet" >&2; exit 2 ;; esac
|
||||
MF="igneum-$PRODUCT-latest.json"
|
||||
[ -n "$VERSION" ] || [ "$VERIFY_ONLY" = 1 ] || { echo "--version is required" >&2; exit 2; }
|
||||
[ -n "$VERSION" ] || VERSION="(the folder's)"
|
||||
[ "$VERIFY_ONLY" = 1 ] || case "$VERSION" in [0-9]*.[0-9]*.[0-9]*) ;; *) echo "--version must be major.minor.patch" >&2; exit 2 ;; esac
|
||||
|
|
@ -124,9 +132,9 @@ verify_live_manifest() {
|
|||
tmp="$(mktemp -d)"
|
||||
while [ "$t" -lt "$TRIES" ]; do
|
||||
t=$((t + 1)); verdict=""
|
||||
if ! curl -fsSL -H 'Cache-Control: no-cache' -o "$tmp/m.json" "$BASE/igneum-app-latest.json"; then verdict="is not reachable"
|
||||
elif ! curl -fsSL -H 'Cache-Control: no-cache' -o "$tmp/m.sig" "$BASE/igneum-app-latest.json.sig"; then verdict="has no reachable signature"
|
||||
elif ! cmp -s "$tmp/m.json" "$DEST/igneum-app-latest.json"; then verdict="differs from the local one (live says $(python3 -c 'import json,sys; m=json.load(open(sys.argv[1])); print(m.get("version","?"), m.get("published_at","?"))' "$tmp/m.json" 2>/dev/null || echo unreadable), local $VERSION)"
|
||||
if ! curl -fsSL -H 'Cache-Control: no-cache' -o "$tmp/m.json" "$BASE/$MF"; then verdict="is not reachable"
|
||||
elif ! curl -fsSL -H 'Cache-Control: no-cache' -o "$tmp/m.sig" "$BASE/$MF.sig"; then verdict="has no reachable signature"
|
||||
elif ! cmp -s "$tmp/m.json" "$DEST/$MF"; then verdict="differs from the local one (live says $(python3 -c 'import json,sys; m=json.load(open(sys.argv[1])); print(m.get("version","?"), m.get("published_at","?"))' "$tmp/m.json" 2>/dev/null || echo unreadable), local $VERSION)"
|
||||
elif ! "$SIGNER" verify "$PUB" "$tmp/m.json" "$tmp/m.sig" >/dev/null 2>&1; then verdict="does not verify against $PUB"
|
||||
fi
|
||||
[ -z "$verdict" ] && break
|
||||
|
|
@ -134,15 +142,15 @@ verify_live_manifest() {
|
|||
done
|
||||
rm -rf "$tmp"
|
||||
if [ -n "$verdict" ]; then echo "the live manifest $verdict after $t tr$([ "$t" = 1 ] && echo y || echo ies) ($(( (t - 1) * 5 )) s); check the deploy output, then: $0 --verify-only" >&2; return 1; fi
|
||||
echo "live manifest verified at ${BASE//$TOKEN/<token>}/igneum-app-latest.json (try $t of $TRIES): version $VERSION, byte-identical, signature OK"
|
||||
echo "live manifest verified at ${BASE//$TOKEN/<token>}/$MF (try $t of $TRIES): version $VERSION, byte-identical, signature OK"
|
||||
}
|
||||
|
||||
if [ "$VERIFY_ONLY" = 1 ]; then
|
||||
[ -f "$DEST/igneum-app-latest.json" ] || { echo "no manifest in $DEST" >&2; exit 1; }
|
||||
[ "$VERSION" != "(the folder's)" ] || VERSION="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("version","?"))' "$DEST/igneum-app-latest.json")"
|
||||
[ -f "$DEST/$MF" ] || { echo "no manifest in $DEST" >&2; exit 1; }
|
||||
[ "$VERSION" != "(the folder's)" ] || VERSION="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("version","?"))' "$DEST/$MF")"
|
||||
verify_live_manifest; exit $?
|
||||
fi
|
||||
OLD="$DEST/igneum-app-latest.json"
|
||||
OLD="$DEST/$MF"
|
||||
if [ -f "$OLD" ]; then
|
||||
OLD_VERSION="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("version",""))' "$OLD" 2>/dev/null || true)"
|
||||
if [ "$OLD_VERSION" = "$VERSION" ]; then
|
||||
|
|
@ -172,7 +180,7 @@ elif [ "$NO_TUNING" = 0 ] && [ -f "$OLD" ]; then
|
|||
fi
|
||||
|
||||
# canonical JSON: sorted keys, no whitespace; the signature is over these exact bytes
|
||||
NEW="$DEST/igneum-app-latest.json.new"
|
||||
NEW="$DEST/$MF.new"
|
||||
python3 - "$NEW" "$VERSION" "$CHANNEL" "$NOTES" "$MIN_SUPPORTED" "$ACTIVATION" "$DEADLINE" "$MAC_ENTRY" "$WIN_ENTRY" "${OVERRIDE:-}" "${TUNING:-}" <<'PY'
|
||||
import json, sys, datetime
|
||||
out, version, channel, notes, min_supported, activation, deadline, mac, win, override, tuning = sys.argv[1:12]
|
||||
|
|
@ -197,17 +205,17 @@ open(out, "w").write(json.dumps(m, sort_keys=True, separators=(",", ":"), ensure
|
|||
PY
|
||||
"$SIGNER" sign "$KEY" "$NEW" > "$NEW.sig"
|
||||
"$SIGNER" verify "$PUB" "$NEW" "$NEW.sig"
|
||||
mv "$NEW" "$DEST/igneum-app-latest.json"
|
||||
mv "$NEW.sig" "$DEST/igneum-app-latest.json.sig"
|
||||
echo "manifest: $DEST/igneum-app-latest.json"
|
||||
cat "$DEST/igneum-app-latest.json"; echo
|
||||
echo "signature: $(cat "$DEST/igneum-app-latest.json.sig")"
|
||||
mv "$NEW" "$DEST/$MF"
|
||||
mv "$NEW.sig" "$DEST/$MF.sig"
|
||||
echo "manifest: $DEST/$MF"
|
||||
cat "$DEST/$MF"; echo
|
||||
echo "signature: $(cat "$DEST/$MF.sig")"
|
||||
echo "key fingerprint: $("$SIGNER" fingerprint "$PUB" | tail -1)"
|
||||
|
||||
# --public: the same version into dl/public/ with public URLs (its own signed manifest), the aliases rewritten
|
||||
if [ "$PUBLIC" = 1 ]; then
|
||||
[ -n "$DLSITE" ] || { echo "--public needs the real downloads folder (no --dest)" >&2; exit 1; }
|
||||
pub_args=(--app); [ -f "$DEST/igneum-wallet-latest.json" ] && pub_args+=(--wallet)
|
||||
if [ "$PRODUCT" = wallet ]; then pub_args=(--wallet); else pub_args=(--app); [ -f "$DEST/igneum-wallet-latest.json" ] && pub_args+=(--wallet); fi
|
||||
"$HERE/publish-public.sh" "${pub_args[@]}" || { echo "publish-public.sh failed; dl/public/ not updated" >&2; exit 1; }
|
||||
fi
|
||||
|
||||
|
|
@ -219,12 +227,12 @@ if [ "$DEPLOY" = 1 ]; then
|
|||
verify_live_manifest || exit 1
|
||||
if [ "$PUBLIC" = 1 ]; then "$HERE/publish-public.sh" --verify --no-prune || exit 1; fi
|
||||
# the console's Builds tab (relay/): one build event and a fresh downloads listing; never fatal
|
||||
node "$ROOT/tools/console.mjs" post --kind build --title "OTA manifest $VERSION ($CHANNEL) live" --body "$NOTES" >/dev/null 2>&1 || true
|
||||
node "$ROOT/tools/console.mjs" post --kind build --title "OTA manifest $PRODUCT $VERSION ($CHANNEL) live" --body "$NOTES" >/dev/null 2>&1 || true
|
||||
node "$ROOT/tools/console.mjs" sync-dl >/dev/null 2>&1 || true
|
||||
else
|
||||
if [ -n "$DLSITE" ]; then
|
||||
echo "not deployed: cd $DLSITE && npx --yes vercel@latest --global-config ~/.config/igneum/vercel deploy --prod --yes"
|
||||
echo "then the apps see it at $BASE/igneum-app-latest.json (checked hourly, and from Settings > Check now)"
|
||||
echo "then the apps see it at $BASE/$MF (checked hourly, and from Settings > Check now)"
|
||||
else
|
||||
echo "written to $DEST for $BASE (test manifest; not the downloads folder)"
|
||||
fi
|
||||
|
|
|
|||
Loading…
Reference in a new issue