Files
ekklesiaandClaude Opus 5.5 a9700536bf fix: the file the gate passed is the file published, and stable takes only the approved one
tools/release-gate.sh is the one gate: a fresh install, and the upgrade
from what canary and stable serve, each on a room of that channel, plus
any older release rooms are still on (RELEASE_GATE_FROM). The releases it
upgrades from are fetched over HTTPS and checked against their manifests,
so it needs no credential and a CI runner can run it.

update_canary.sh VERSION PACKAGE gates and publishes that file without
rebuilding it, since a second build is a second, untested file; the hash
is taken before the gate and checked after it. update_stable.sh VERSION
SHA256 refuses anything but the file that was approved.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-29 18:05:54 -05:00

89 lines
2.7 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$ROOT"
source "$ROOT/tools/release-lib.sh"
# Stable never gets a package of its own. It is pointed at one canary
# already published, so the file every classroom downloads is byte for
# byte the one the canary machine ran.
#
# ./update_stable.sh VERSION SHA256 the release that was approved, by
# the checksum it was approved as
# ./update_stable.sh VERSION the release, whatever file it is
# ./update_stable.sh whatever canary is on
#
# With SHA256, anything but that exact file is refused. The checksum is
# the one written down when the release went to canary and passed its
# physical checks, so the approval and the promotion name the same bytes.
expected_hash="${2:-}"
if [[ -n "$expected_hash" && ! "$expected_hash" =~ ^[0-9a-f]{64}$ ]]; then
echo "Not a SHA-256 checksum: $expected_hash" >&2
exit 1
fi
if [[ $# -ge 1 ]]; then
version="$1"
else
if [[ ! -f "$RELEASE_LOCAL/canary/manifest.json" ]]; then
echo "No local canary manifest exists."
exit 1
fi
version="$(python3 -c \
'import json, sys; print(json.load(open(sys.argv[1]))["version"])' \
"$RELEASE_LOCAL/canary/manifest.json")"
fi
release_require_version "$version"
package_name="$(release_package_name "$version")"
package_path="$RELEASE_LOCAL/packages/$package_name"
if [[ ! -f "$package_path" ]]; then
echo "Package does not exist locally:"
echo "$package_path"
exit 1
fi
if [[ "$(release_package_version "$package_path")" != "$version" ]]; then
echo "$package_name says it is $(release_package_version "$package_path")." >&2
exit 1
fi
# A classroom only ever installs a version newer than its own, so a stable
# manifest that went backwards would reach nobody and would only make the
# channel say something untrue.
current="$(release_channel_version stable || true)"
if [[ -n "$current" ]] && ! release_version_gt "$version" "$current"; then
echo "Stable is on $current; $version is not newer." >&2
exit 1
fi
hash="$(sha256sum "$package_path" | awk '{print $1}')"
if [[ -n "$expected_hash" && "$hash" != "$expected_hash" ]]; then
echo "$package_name is not the file that was approved:" >&2
echo " approved: $expected_hash" >&2
echo " here: $hash" >&2
exit 1
fi
echo "Promoting $version to STABLE (from ${current:-nothing})"
# Refuses unless the server already holds exactly this package.
release_publish_manifest stable "$version" "$hash"
echo "$RELEASE_URL/stable/latest.deb -> $package_name"
echo
release_verify_channel stable "$version"
echo
echo "Ekklesia Classroom $version is now STABLE"
echo "$RELEASE_URL/stable/manifest.json"