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]>
89 lines
2.7 KiB
Bash
Executable File
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"
|