Files
shorebird-workspace/scripts/verify_downloaded_release_artifacts.sh
2026-06-25 20:08:23 +08:00

170 lines
4.5 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
usage() {
cat >&2 <<'EOF'
usage: verify_downloaded_release_artifacts.sh [--github-sha sha] downloaded-artifacts
Verifies a downloaded full SDK build artifact set. The release manifest and
artifact mirror archive must have valid checksum sidecars, the manifest must
cover every downloaded artifact, and the mirror archive must safely extract to a
valid open Shorebird artifact mirror.
EOF
}
DOWNLOAD_DIR=""
EXPECTED_GITHUB_SHA=""
while [[ "$#" -gt 0 ]]; do
case "$1" in
--github-sha)
if [[ "$#" -lt 2 || -z "${2:-}" ]]; then
echo "--github-sha value is required" >&2
usage
exit 64
fi
EXPECTED_GITHUB_SHA="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
;;
-*)
echo "unknown argument: $1" >&2
usage
exit 64
;;
*)
if [[ -n "$DOWNLOAD_DIR" ]]; then
echo "unexpected extra argument: $1" >&2
usage
exit 64
fi
DOWNLOAD_DIR="$1"
shift
;;
esac
done
if [[ -z "$DOWNLOAD_DIR" ]]; then
usage
exit 64
fi
TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/open-shorebird-downloaded-release.XXXXXX")"
trap 'rm -rf "$TMP_DIR"' EXIT
PYTHON_BIN=python3
if ! command -v "$PYTHON_BIN" >/dev/null 2>&1; then
PYTHON_BIN=python
fi
fail() {
echo "error: $*" >&2
exit 70
}
verify_sha256_sidecar() {
local artifact_path="$1"
local sidecar_path="$2"
[[ -f "$sidecar_path" ]] || fail "missing checksum sidecar: $sidecar_path"
"$PYTHON_BIN" - "$artifact_path" "$sidecar_path" <<'PY'
import hashlib
from pathlib import Path
import sys
artifact_path = Path(sys.argv[1])
sidecar_path = Path(sys.argv[2])
try:
text = sidecar_path.read_text(encoding="utf-8").strip()
except UnicodeDecodeError as error:
print(f"error: {sidecar_path}: invalid UTF-8: {error}", file=sys.stderr)
sys.exit(70)
parts = text.split()
if len(parts) != 2:
print(
f"error: {sidecar_path}: expected '<sha256> <filename>', got {text!r}",
file=sys.stderr,
)
sys.exit(70)
expected_digest, expected_filename = parts
if len(expected_digest) != 64 or any(
char not in "0123456789abcdef" for char in expected_digest
):
print(f"error: {sidecar_path}: invalid sha256 digest {expected_digest!r}", file=sys.stderr)
sys.exit(70)
if expected_filename != artifact_path.name:
print(
f"error: {sidecar_path}: filename mismatch "
f"{expected_filename!r} != {artifact_path.name!r}",
file=sys.stderr,
)
sys.exit(70)
digest = hashlib.sha256()
with artifact_path.open("rb") as artifact:
for chunk in iter(lambda: artifact.read(1024 * 1024), b""):
digest.update(chunk)
actual_digest = digest.hexdigest()
if expected_digest != actual_digest:
print(
f"error: {sidecar_path}: digest mismatch "
f"{expected_digest} != {actual_digest}",
file=sys.stderr,
)
sys.exit(70)
PY
}
[[ -d "$DOWNLOAD_DIR" ]] || fail "missing downloaded artifacts directory: $DOWNLOAD_DIR"
manifest_paths=()
while IFS= read -r path; do
manifest_paths+=("$path")
done < <(find "$DOWNLOAD_DIR" -type f -name open-shorebird-release-manifest.json | sort)
if [[ "${#manifest_paths[@]}" -ne 1 ]]; then
fail "expected exactly one open-shorebird-release-manifest.json, found ${#manifest_paths[@]}"
fi
manifest_path="${manifest_paths[0]}"
manifest_sidecar="$manifest_path.sha256"
verify_sha256_sidecar "$manifest_path" "$manifest_sidecar"
validate_manifest_args=()
if [[ -n "$EXPECTED_GITHUB_SHA" ]]; then
validate_manifest_args+=(--github-sha "$EXPECTED_GITHUB_SHA")
fi
"$PYTHON_BIN" "$ROOT/scripts/validate_release_manifest.py" \
"${validate_manifest_args[@]}" \
"$DOWNLOAD_DIR" \
"$manifest_path"
mirror_archives=()
while IFS= read -r path; do
mirror_archives+=("$path")
done < <(find "$DOWNLOAD_DIR" -type f -name open-shorebird-artifact-mirror.tar.gz | sort)
if [[ "${#mirror_archives[@]}" -ne 1 ]]; then
fail "expected exactly one open-shorebird-artifact-mirror.tar.gz, found ${#mirror_archives[@]}"
fi
mirror_archive="${mirror_archives[0]}"
mirror_sidecar="$mirror_archive.sha256"
verify_sha256_sidecar "$mirror_archive" "$mirror_sidecar"
"$PYTHON_BIN" "$ROOT/scripts/safe_extract_tar.py" "$mirror_archive" "$TMP_DIR"
mirror_root="$TMP_DIR/open-shorebird-artifact-mirror"
[[ -d "$mirror_root" ]] || fail "mirror archive did not contain open-shorebird-artifact-mirror/"
"$PYTHON_BIN" "$ROOT/scripts/validate_artifact_mirror.py" "$mirror_root"
echo "downloaded release artifacts verified: $DOWNLOAD_DIR"