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]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
6c04f743ed
commit
a9700536bf
@@ -244,20 +244,48 @@ check("container service startup is suppressed", "/usr/sbin/policy-rc.d" in vali
|
|||||||
|
|
||||||
print()
|
print()
|
||||||
print("6. canary release gate")
|
print("6. canary release gate")
|
||||||
validation = canary.index('"$ROOT/tools/validate-trixie-release.sh"')
|
validation = canary.index('"$ROOT/tools/release-gate.sh"')
|
||||||
package_copy = canary.index('cp -n "$package_path"')
|
package_copy = canary.index('cp -n "$package_path"')
|
||||||
first_upload = canary.index("release_upload_package")
|
first_upload = canary.index("release_upload_package")
|
||||||
check("Trixie validation runs before the repository copy", validation < package_copy)
|
check("the release gate runs before the repository copy", validation < package_copy)
|
||||||
check("Trixie validation runs before any upload", validation < first_upload)
|
check("the release gate runs before any upload", validation < first_upload)
|
||||||
# A version is checked before anything is built for it, and again after
|
# A version is checked before anything is built for it, and again after
|
||||||
# the long gate, immediately before the first upload.
|
# the long gate, immediately before the first upload.
|
||||||
check("a spent version is refused before the build",
|
check("a spent version is refused before the build",
|
||||||
canary.index("release_check_new_version") < canary.index("build-release.sh"))
|
canary.index("release_check_new_version") < canary.index("build-release.sh"))
|
||||||
check("and again after the gate",
|
check("and again after the gate",
|
||||||
validation < canary.rindex("release_check_new_version") < first_upload)
|
validation < canary.rindex("release_check_new_version") < first_upload)
|
||||||
check("the stable rooms' upgrade is rehearsed on the same file before publishing",
|
# A package handed in is the one published: a second build is a second,
|
||||||
"VALIDATION_CHANNEL=stable" in canary
|
# untested file.
|
||||||
and canary.index("VALIDATION_CHANNEL=stable") < first_upload)
|
build_at = canary.index('"$ROOT/tools/build-release.sh"')
|
||||||
|
check("a package handed in is not rebuilt",
|
||||||
|
canary.rindex('if [[ -n "$prebuilt" ]]', 0, build_at) < build_at
|
||||||
|
and "else" in canary[canary.rindex('if [[ -n "$prebuilt" ]]', 0, build_at):build_at])
|
||||||
|
check("and must say it is the version being published",
|
||||||
|
'release_package_version "$package_path")" != "$version"' in canary)
|
||||||
|
check("the file is hashed before the gate and checked after it",
|
||||||
|
canary.index('hash="$(sha256sum "$package_path"') < validation
|
||||||
|
< canary.index("changed while it was being gated") < first_upload)
|
||||||
|
check("the repository copy is proven to be the gated file",
|
||||||
|
package_copy < canary.index("is not the file that passed the gate") < first_upload)
|
||||||
|
|
||||||
|
gate = (root / "tools/release-gate.sh").read_text()
|
||||||
|
gate_code = "\n".join(line for line in gate.splitlines()
|
||||||
|
if not line.lstrip().startswith("#"))
|
||||||
|
check("the gate runs a fresh install",
|
||||||
|
'"$ROOT/tools/validate-trixie-release.sh" "$candidate"\n' in gate_code)
|
||||||
|
check("and the upgrade from what canary and stable serve, as rooms of each",
|
||||||
|
"for channel in canary stable" in gate_code
|
||||||
|
and 'VALIDATION_CHANNEL="$channel"' in gate_code)
|
||||||
|
check("the stable rooms' older releases can be rehearsed too",
|
||||||
|
"VALIDATION_CHANNEL=stable" in gate_code and "RELEASE_GATE_FROM" in canary)
|
||||||
|
check("what it upgrades from is checked against its manifest's checksum",
|
||||||
|
'if [[ "$got" != "$from_hash" ]]' in gate_code)
|
||||||
|
check("the gate needs no credential and writes nothing to the server",
|
||||||
|
"release_remote" not in gate_code and "ssh" not in gate_code
|
||||||
|
and "rsync" not in gate_code)
|
||||||
|
check("the gate stops at the first failure",
|
||||||
|
"set -euo pipefail" in gate and "inherit_errexit" in gate)
|
||||||
check("the published channel is read back afterwards",
|
check("the published channel is read back afterwards",
|
||||||
canary.index("release_verify_channel canary") > canary.index("release_publish_manifest canary"))
|
canary.index("release_verify_channel canary") > canary.index("release_publish_manifest canary"))
|
||||||
# The gate checks convergence, not just that the package installs: an
|
# The gate checks convergence, not just that the package installs: an
|
||||||
|
|||||||
@@ -274,8 +274,21 @@ fake_deb 0.2.9 "$LOCAL/packages/ekklesia-classroom_0.2.9_amd64.deb"
|
|||||||
check "refuses a package that was built but never uploaded" \
|
check "refuses a package that was built but never uploaded" \
|
||||||
refuses "$ROOT/update_stable.sh" 0.2.9
|
refuses "$ROOT/update_stable.sh" 0.2.9
|
||||||
rm "$LOCAL/packages/ekklesia-classroom_0.2.9_amd64.deb"
|
rm "$LOCAL/packages/ekklesia-classroom_0.2.9_amd64.deb"
|
||||||
|
check "refuses a checksum that is not one" \
|
||||||
|
refuses "$ROOT/update_stable.sh" 0.2.6.1 not-a-checksum
|
||||||
|
check "refuses a file that is not the one approved" \
|
||||||
|
refuses "$ROOT/update_stable.sh" 0.2.6.1 "$(printf '0%.0s' {1..64})"
|
||||||
check "stable is still 0.2.2 after all of that" \
|
check "stable is still 0.2.2 after all of that" \
|
||||||
test "$(cat "$SERVER/stable/manifest.json")" = "$stable_before"
|
test "$(cat "$SERVER/stable/manifest.json")" = "$stable_before"
|
||||||
|
approved="$(sha256sum "$LOCAL/packages/ekklesia-classroom_0.2.6.1_amd64.deb" | awk '{print $1}')"
|
||||||
|
check "promotes the approved file, named by its checksum" \
|
||||||
|
"$ROOT/update_stable.sh" 0.2.6.1 "$approved"
|
||||||
|
check "and stable now serves exactly that file" \
|
||||||
|
bash -c "grep -q '\"sha256\": \"$approved\"' '$SERVER/stable/manifest.json' \
|
||||||
|
&& cmp -s '$SERVER/stable/latest.deb' '$LOCAL/packages/ekklesia-classroom_0.2.6.1_amd64.deb'"
|
||||||
|
# Back to 0.2.2 for the updater's cases below.
|
||||||
|
printf '%s\n' "$stable_before" > "$SERVER/stable/manifest.json"
|
||||||
|
ln -sfn ../packages/ekklesia-classroom_0.2.2_amd64.deb "$SERVER/stable/latest.deb"
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "7. update_canary.sh"
|
echo "7. update_canary.sh"
|
||||||
@@ -286,6 +299,17 @@ check "without a version it builds nothing and names both choices" \
|
|||||||
check "a published version is refused before anything is built" \
|
check "a published version is refused before anything is built" \
|
||||||
bash -c "! '$ROOT/update_canary.sh' 0.2.6 2>&1 | grep -q 'Validating sources'"
|
bash -c "! '$ROOT/update_canary.sh' 0.2.6 2>&1 | grep -q 'Validating sources'"
|
||||||
check "a malformed version is refused" refuses "$ROOT/update_canary.sh" 0.2.6.1.1
|
check "a malformed version is refused" refuses "$ROOT/update_canary.sh" 0.2.6.1.1
|
||||||
|
# A package handed in is gated and published as it is, so it has to be
|
||||||
|
# the release named, before anything is gated at all.
|
||||||
|
fake_deb 0.2.6.3 "$WORK/ekklesia-classroom_0.2.6.2_amd64.deb"
|
||||||
|
check "a package handed in that says it is another version is refused" \
|
||||||
|
bash -c "out=\$('$ROOT/update_canary.sh' 0.2.6.2 '$WORK/ekklesia-classroom_0.2.6.2_amd64.deb' 2>&1); \
|
||||||
|
[[ \$? -ne 0 ]] && grep -q 'says it is 0.2.6.3' <<< \"\$out\" && ! grep -q 'release gate' <<< \"\$out\""
|
||||||
|
fake_deb 0.2.6.2 "$WORK/renamed.deb"
|
||||||
|
check "and so is one that is not named as the release" \
|
||||||
|
bash -c "out=\$('$ROOT/update_canary.sh' 0.2.6.2 '$WORK/renamed.deb' 2>&1); \
|
||||||
|
[[ \$? -ne 0 ]] && grep -q 'is not named' <<< \"\$out\" && ! grep -q 'release gate' <<< \"\$out\""
|
||||||
|
rm -f "$WORK/ekklesia-classroom_0.2.6.2_amd64.deb" "$WORK/renamed.deb"
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
echo
|
echo
|
||||||
|
|||||||
Executable
+146
@@ -0,0 +1,146 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# THE RELEASE GATE: may this exact file go to a classroom?
|
||||||
|
#
|
||||||
|
# tools/release-gate.sh PACKAGE.deb [FROM_VERSION...]
|
||||||
|
#
|
||||||
|
# Runs tools/validate-trixie-release.sh against PACKAGE as
|
||||||
|
#
|
||||||
|
# * a fresh install;
|
||||||
|
# * an upgrade from what canary serves today, on a canary room;
|
||||||
|
# * an upgrade from what stable serves today, on a stable room;
|
||||||
|
# * an upgrade from each FROM_VERSION, on a stable room — the release a
|
||||||
|
# room is really still on, which can be several behind stable.
|
||||||
|
#
|
||||||
|
# The releases it upgrades from are downloaded over HTTPS the way a
|
||||||
|
# classroom downloads them, and each is checked against the SHA-256 its
|
||||||
|
# manifest publishes, or, for a FROM_VERSION, against the version dpkg
|
||||||
|
# reads out of it. Nothing here needs a credential or writes to the
|
||||||
|
# update server, so a CI runner can run it on code nobody has reviewed.
|
||||||
|
#
|
||||||
|
# Every run is one line in RELEASE_GATE_REPORT (default: printed only),
|
||||||
|
# so the result can be attached to the release it describes.
|
||||||
|
#
|
||||||
|
# It stops at the first failure: a gate that carries on reports a pass
|
||||||
|
# for a machine it never finished building.
|
||||||
|
set -euo pipefail
|
||||||
|
# The fetches below run in $(...), which otherwise ignores set -e: a
|
||||||
|
# manifest that failed to download would go on to compare an empty hash
|
||||||
|
# with an empty hash, and match.
|
||||||
|
shopt -s inherit_errexit
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
source "$ROOT/tools/release-lib.sh"
|
||||||
|
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
echo "Usage: $0 PACKAGE.deb [FROM_VERSION...]" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
candidate="$(realpath "$1")"
|
||||||
|
shift
|
||||||
|
extra_from=("$@")
|
||||||
|
|
||||||
|
[[ -f "$candidate" ]] || { echo "Package not found: $candidate" >&2; exit 1; }
|
||||||
|
|
||||||
|
version="$(release_package_version "$candidate")"
|
||||||
|
release_require_version "$version"
|
||||||
|
|
||||||
|
# The name a release is published under is the version dpkg reads out of
|
||||||
|
# it. A file called 0.2.6.6 that says it is 0.2.6.5 is the wrong file.
|
||||||
|
if [[ "$(basename "$candidate")" != "$(release_package_name "$version")" ]]; then
|
||||||
|
echo "$(basename "$candidate") says it is $version." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
hash="$(sha256sum "$candidate" | awk '{print $1}')"
|
||||||
|
report="${RELEASE_GATE_REPORT:-}"
|
||||||
|
work="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$work"' EXIT
|
||||||
|
|
||||||
|
record() {
|
||||||
|
printf '%s\n' "$1"
|
||||||
|
[[ -z "$report" ]] || printf '%s\n' "$1" >> "$report"
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -z "$report" ]] || : > "$report"
|
||||||
|
record "release gate for $(basename "$candidate")"
|
||||||
|
record "sha256 $hash"
|
||||||
|
record "started $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
|
||||||
|
# A channel's current package, fetched as a classroom fetches it and
|
||||||
|
# proven to be what the manifest promises.
|
||||||
|
fetch_channel() {
|
||||||
|
local channel="$1" manifest from from_hash name got
|
||||||
|
|
||||||
|
manifest="$(curl -fsS -H 'Cache-Control: no-cache' "$RELEASE_URL/$channel/manifest.json")"
|
||||||
|
read -r from from_hash < <(python3 -c 'import json, sys
|
||||||
|
m = json.loads(sys.argv[1])
|
||||||
|
print(m["version"], m["sha256"])' "$manifest")
|
||||||
|
|
||||||
|
release_require_version "$from"
|
||||||
|
[[ "$from_hash" =~ ^[0-9a-f]{64}$ ]]
|
||||||
|
name="$(release_package_name "$from")"
|
||||||
|
curl -fsS -o "$work/$name" "$RELEASE_URL/packages/$name"
|
||||||
|
got="$(sha256sum "$work/$name" | awk '{print $1}')"
|
||||||
|
|
||||||
|
if [[ "$got" != "$from_hash" ]]; then
|
||||||
|
echo "$channel serves $name with sha256 $got; its manifest says $from_hash" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\n' "$work/$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# A published release by version, for the rooms still on an older one.
|
||||||
|
fetch_version() {
|
||||||
|
local from="$1" name
|
||||||
|
|
||||||
|
release_require_version "$from"
|
||||||
|
name="$(release_package_name "$from")"
|
||||||
|
curl -fsS -o "$work/$name" "$RELEASE_URL/packages/$name"
|
||||||
|
|
||||||
|
if [[ "$(release_package_version "$work/$name")" != "$from" ]]; then
|
||||||
|
echo "$name does not say it is $from" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\n' "$work/$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
run() {
|
||||||
|
local label="$1" started
|
||||||
|
shift
|
||||||
|
started=$SECONDS
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== $label"
|
||||||
|
"$@"
|
||||||
|
record "PASS $label ($(( (SECONDS - started) / 60 )) min)"
|
||||||
|
}
|
||||||
|
|
||||||
|
run "fresh install of $version" \
|
||||||
|
"$ROOT/tools/validate-trixie-release.sh" "$candidate"
|
||||||
|
|
||||||
|
for channel in canary stable; do
|
||||||
|
previous="$(fetch_channel "$channel")"
|
||||||
|
from="$(release_package_version "$previous")"
|
||||||
|
|
||||||
|
if ! release_version_gt "$version" "$from"; then
|
||||||
|
echo "$channel is on $from; $version is not newer, so no room could take it." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
run "upgrade $from -> $version on a $channel room ($channel serves $from)" \
|
||||||
|
env VALIDATION_CHANNEL="$channel" \
|
||||||
|
"$ROOT/tools/validate-trixie-release.sh" "$candidate" "$previous"
|
||||||
|
done
|
||||||
|
|
||||||
|
for from in "${extra_from[@]}"; do
|
||||||
|
previous="$(fetch_version "$from")"
|
||||||
|
|
||||||
|
run "upgrade $from -> $version on a stable room" \
|
||||||
|
env VALIDATION_CHANNEL=stable \
|
||||||
|
"$ROOT/tools/validate-trixie-release.sh" "$candidate" "$previous"
|
||||||
|
done
|
||||||
|
|
||||||
|
record "finished $(date -u +%Y-%m-%dT%H:%M:%SZ): $(basename "$candidate") passed the release gate"
|
||||||
+46
-36
@@ -12,9 +12,12 @@ source "$ROOT/tools/release-lib.sh"
|
|||||||
# there are two — 0.2.6 is followed by 0.2.6.1 if it is a fix and by
|
# there are two — 0.2.6 is followed by 0.2.6.1 if it is a fix and by
|
||||||
# 0.2.7 if it is not — and which one a release is, is a decision about
|
# 0.2.7 if it is not — and which one a release is, is a decision about
|
||||||
# what is in it, not arithmetic.
|
# what is in it, not arithmetic.
|
||||||
if [[ $# -ne 1 ]]; then
|
if [[ $# -lt 1 || $# -gt 2 ]]; then
|
||||||
current="$(release_channel_version canary || true)"
|
current="$(release_channel_version canary || true)"
|
||||||
echo "Usage: $0 VERSION" >&2
|
echo "Usage: $0 VERSION [PACKAGE.deb]" >&2
|
||||||
|
echo >&2
|
||||||
|
echo "With PACKAGE.deb, that file is gated and published and nothing is" >&2
|
||||||
|
echo "built, so the file that was tested is the file that is published." >&2
|
||||||
echo >&2
|
echo >&2
|
||||||
echo "Canary is on ${current:-an unknown version}. Name the release, for example:" >&2
|
echo "Canary is on ${current:-an unknown version}. Name the release, for example:" >&2
|
||||||
if [[ -n "$current" ]] && release_version_valid "$current"; then
|
if [[ -n "$current" ]] && release_version_valid "$current"; then
|
||||||
@@ -28,62 +31,69 @@ fi
|
|||||||
version="$1"
|
version="$1"
|
||||||
package_name="$(release_package_name "$version")"
|
package_name="$(release_package_name "$version")"
|
||||||
package_path="$ROOT/dist/$package_name"
|
package_path="$ROOT/dist/$package_name"
|
||||||
|
prebuilt="${2:-}"
|
||||||
|
|
||||||
echo "Current canary: $(release_channel_version canary || echo unknown)"
|
echo "Current canary: $(release_channel_version canary || echo unknown)"
|
||||||
echo "New canary: $version"
|
echo "New canary: $version"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
# RELEASE_GATE_FROM="0.2.2" adds the upgrade from an older release that
|
||||||
|
# rooms are still on to the gate, beside canary's and stable's own.
|
||||||
|
#
|
||||||
# Before anything is built: a version that has been published, or that
|
# Before anything is built: a version that has been published, or that
|
||||||
# would not be newer than everything that has been, stops here.
|
# would not be newer than everything that has been, stops here.
|
||||||
release_check_new_version "$version"
|
release_check_new_version "$version"
|
||||||
|
|
||||||
"$ROOT/tools/build-release.sh" "$version"
|
# ONE FILE, FROM THE GATE TO THE ROOM.
|
||||||
|
#
|
||||||
|
# Given a package, that package is what is gated and published, and
|
||||||
|
# nothing is rebuilt: a build is not byte-for-byte repeatable, so a second
|
||||||
|
# build is a second, untested file. Without one, it is built here.
|
||||||
|
if [[ -n "$prebuilt" ]]; then
|
||||||
|
package_path="$(realpath "$prebuilt")"
|
||||||
|
|
||||||
# Validate the exact artifact that will be published. If a previous canary is
|
if [[ "$(basename "$package_path")" != "$package_name" ]]; then
|
||||||
# available locally, exercise the real upgrade path as well as a fresh install.
|
echo "$prebuilt is not named $package_name." >&2
|
||||||
validation_args=("$package_path")
|
exit 1
|
||||||
|
|
||||||
if [[ -f "$RELEASE_LOCAL/canary/manifest.json" ]]; then
|
|
||||||
previous_package_name="$(python3 -c \
|
|
||||||
'import json, sys; print(json.load(open(sys.argv[1]))["package"].rsplit("/", 1)[-1])' \
|
|
||||||
"$RELEASE_LOCAL/canary/manifest.json")"
|
|
||||||
previous_package="$RELEASE_LOCAL/packages/$previous_package_name"
|
|
||||||
|
|
||||||
if [[ -f "$previous_package" && "$previous_package" != "$package_path" ]]; then
|
|
||||||
validation_args+=("$previous_package")
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "$(release_package_version "$package_path")" != "$version" ]]; then
|
||||||
|
echo "$prebuilt says it is $(release_package_version "$package_path"), not $version." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Publishing the package already built: $package_path"
|
||||||
|
else
|
||||||
|
"$ROOT/tools/build-release.sh" "$version"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
"$ROOT/tools/validate-trixie-release.sh" "${validation_args[@]}"
|
# A fresh install, and the upgrade from whatever canary and stable serve
|
||||||
|
# today, each on a room of that channel. Every canary is a stable release
|
||||||
|
# in waiting, and the desktops are not on the previous canary: they are on
|
||||||
|
# whatever stable names, which can be several releases back (0.2.2 under
|
||||||
|
# 0.2.6.1). A package that upgrades the laptop and breaks the desktops has
|
||||||
|
# to fail here, not on a Sunday. See tools/release-gate.sh.
|
||||||
|
hash="$(sha256sum "$package_path" | awk '{print $1}')"
|
||||||
|
|
||||||
# And the stable rooms' own path, on the same file. Every canary is a
|
"$ROOT/tools/release-gate.sh" "$package_path" ${RELEASE_GATE_FROM:-}
|
||||||
# stable release in waiting, and the desktops are not on the previous
|
|
||||||
# canary: they are on whatever stable names, which can be several
|
|
||||||
# releases back (0.2.2 under 0.2.6.1). A package that upgrades the
|
|
||||||
# laptop and breaks the desktops has to fail here, not on a Sunday.
|
|
||||||
if [[ -f "$RELEASE_LOCAL/stable/manifest.json" ]]; then
|
|
||||||
stable_package_name="$(python3 -c \
|
|
||||||
'import json, sys; print(json.load(open(sys.argv[1]))["package"].rsplit("/", 1)[-1])' \
|
|
||||||
"$RELEASE_LOCAL/stable/manifest.json")"
|
|
||||||
stable_package="$RELEASE_LOCAL/packages/$stable_package_name"
|
|
||||||
|
|
||||||
if [[ -f "$stable_package" && "$stable_package" != "${validation_args[1]:-}" ]]; then
|
|
||||||
echo
|
|
||||||
echo "Rehearsing the stable rooms' upgrade from $stable_package_name"
|
|
||||||
VALIDATION_CHANNEL=stable \
|
|
||||||
"$ROOT/tools/validate-trixie-release.sh" "$package_path" "$stable_package"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Checked again after the gate, which takes long enough for somebody else
|
# Checked again after the gate, which takes long enough for somebody else
|
||||||
# to have published in the meantime.
|
# to have published in the meantime — or for the file to have changed.
|
||||||
release_check_new_version "$version"
|
release_check_new_version "$version"
|
||||||
|
|
||||||
hash="$(sha256sum "$package_path" | awk '{print $1}')"
|
if [[ "$(sha256sum "$package_path" | awk '{print $1}')" != "$hash" ]]; then
|
||||||
|
echo "$package_path changed while it was being gated. Nothing was published." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
mkdir -p "$RELEASE_LOCAL/packages"
|
mkdir -p "$RELEASE_LOCAL/packages"
|
||||||
cp -n "$package_path" "$RELEASE_LOCAL/packages/$package_name"
|
cp -n "$package_path" "$RELEASE_LOCAL/packages/$package_name"
|
||||||
|
|
||||||
|
if [[ "$(sha256sum "$RELEASE_LOCAL/packages/$package_name" | awk '{print $1}')" != "$hash" ]]; then
|
||||||
|
echo "$RELEASE_LOCAL/packages/$package_name is not the file that passed the gate." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Publishing package..."
|
echo "Publishing package..."
|
||||||
release_upload_package "$RELEASE_LOCAL/packages/$package_name"
|
release_upload_package "$RELEASE_LOCAL/packages/$package_name"
|
||||||
|
|||||||
+24
-1
@@ -9,7 +9,23 @@ source "$ROOT/tools/release-lib.sh"
|
|||||||
# Stable never gets a package of its own. It is pointed at one canary
|
# 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
|
# already published, so the file every classroom downloads is byte for
|
||||||
# byte the one the canary machine ran.
|
# byte the one the canary machine ran.
|
||||||
if [[ $# -eq 1 ]]; then
|
#
|
||||||
|
# ./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"
|
version="$1"
|
||||||
else
|
else
|
||||||
if [[ ! -f "$RELEASE_LOCAL/canary/manifest.json" ]]; then
|
if [[ ! -f "$RELEASE_LOCAL/canary/manifest.json" ]]; then
|
||||||
@@ -50,6 +66,13 @@ fi
|
|||||||
|
|
||||||
hash="$(sha256sum "$package_path" | awk '{print $1}')"
|
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})"
|
echo "Promoting $version to STABLE (from ${current:-nothing})"
|
||||||
|
|
||||||
# Refuses unless the server already holds exactly this package.
|
# Refuses unless the server already holds exactly this package.
|
||||||
|
|||||||
Reference in New Issue
Block a user