fetch_ml/scripts/verify_release.sh
Jeremie Fraeys 1dcc1e11d5
chore(build): update build system, scripts, and additional tests
- Update Makefile with native build targets (preparing for C++)
- Add profiler and performance regression detector commands
- Update CI/testing scripts
- Add additional unit tests for API, jupyter, queue, manifest
2026-02-12 12:05:55 -05:00

147 lines
3.6 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage:
scripts/verify_release.sh --dir <release_dir> [--repo <org>/<repo>]
What it does:
- Verifies checksums.txt signature (keyless cosign) if cosign + checksums.txt.sig/.cert are present
- Verifies *.tar.gz files against checksums.txt
Notes:
- --repo enables strict Sigstore identity checking against the release workflow.
- Without cosign, the script still verifies SHA256 hashes.
Examples:
scripts/verify_release.sh --dir ./release --repo jfraeys/fetch_ml
scripts/verify_release.sh --dir .
EOF
}
release_dir=""
repo=""
while [[ $# -gt 0 ]]; do
case "$1" in
--dir)
release_dir="${2:-}"
shift 2
;;
--repo)
repo="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "unknown argument: $1" >&2
usage >&2
exit 2
;;
esac
done
if [[ -z "$release_dir" ]]; then
echo "missing --dir" >&2
usage >&2
exit 2
fi
if [[ ! -d "$release_dir" ]]; then
echo "directory not found: $release_dir" >&2
exit 2
fi
cd "$release_dir"
if [[ ! -f checksums.txt ]]; then
echo "missing checksums.txt in $release_dir" >&2
exit 2
fi
has_cosign=false
if command -v cosign >/dev/null 2>&1; then
has_cosign=true
fi
verify_sigstore() {
if [[ ! -f checksums.txt.sig ]] || [[ ! -f checksums.txt.cert ]]; then
echo "[verify] cosign available, but checksums.txt.sig/.cert not found; skipping signature verification" >&2
return 0
fi
if [[ -z "$repo" ]]; then
echo "[verify] verifying signature (no repo identity pin; pass --repo to pin identity)" >&2
COSIGN_YES=true cosign verify-blob \
--certificate checksums.txt.cert \
--signature checksums.txt.sig \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
checksums.txt >/dev/null
echo "[ok] checksums.txt signature verified (un-pinned identity)"
return 0
fi
local identity
identity="^https://github.com/${repo}/\.forgejo/workflows/release-mirror\.yml@refs/tags/v.*$"
echo "[verify] verifying signature (repo identity pin may not apply for mirrored releases; pass --repo for logging only)" >&2
COSIGN_YES=true cosign verify-blob \
--certificate checksums.txt.cert \
--signature checksums.txt.sig \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
checksums.txt >/dev/null
echo "[ok] checksums.txt signature verified (un-pinned identity; expected identity regexp: ${identity})"
}
verify_hashes() {
local failures=0
local has_sha256sum=false
if command -v sha256sum >/dev/null 2>&1; then
has_sha256sum=true
fi
while IFS= read -r expected file; do
[[ -z "${expected}" ]] && continue
[[ -z "${file}" ]] && continue
if [[ ! -f "$file" ]]; then
continue
fi
local actual
if [[ "$has_sha256sum" == true ]]; then
actual="$(sha256sum "$file" | awk '{print $1}')"
else
actual="$(shasum -a 256 "$file" | awk '{print $1}')"
fi
if [[ "$actual" != "$expected" ]]; then
echo "[fail] $file" >&2
echo " expected: $expected" >&2
echo " actual: $actual" >&2
failures=$((failures+1))
fi
done < <(awk '{print $1, $2}' checksums.txt)
if [[ $failures -gt 0 ]]; then
echo "[fail] checksum verification failed ($failures file(s))" >&2
exit 1
fi
echo "[ok] all available artifacts match checksums.txt"
}
if [[ "$has_cosign" == true ]]; then
verify_sigstore
else
echo "[verify] cosign not installed; skipping signature verification" >&2
fi
verify_hashes
echo "[ok] release verification complete"