fetch_ml/scripts/release/verify-checksums.sh
Jeremie Fraeys 8b75f71a6a
refactor: reorganize scripts into categorized structure
Consolidate 26+ scattered scripts into maintainable hierarchy:

New Structure:
- ci/          CI/CD validation (checks.sh, test.sh, verify-paths.sh)
- dev/         Development workflow (smoke-test.sh, manage-artifacts.sh)
- release/     Release preparation (cleanup.sh, prepare.sh, sanitize.sh, verify.sh, verify-checksums.sh)
- testing/     Test infrastructure (unchanged)
- benchmarks/  Performance tools (track-performance.sh)
- maintenance/ System cleanup (unchanged)
- lib/         Shared functions (unchanged)

Key Changes:
- Unified 6 cleanup-*.sh scripts into release/cleanup.sh with targets
- Merged smoke-test-native.sh into dev/smoke-test.sh --native flag
- Renamed scripts to follow lowercase-hyphen convention
- Moved root-level scripts to appropriate categories
- Updated all Makefile references
- Updated scripts/README.md with new structure

Script count: 26 → 17 (35% reduction)

Breaking Changes:
- Old paths no longer exist, update any direct script calls
- Use make targets (e.g., make ci-checks) for stability
2026-02-18 17:56:59 -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"