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

239 lines
9.1 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/open-shorebird-release-manifest.XXXXXX")"
trap 'rm -rf "$TMP_DIR"' EXIT
PYTHON_BIN=python3
if ! command -v "$PYTHON_BIN" >/dev/null 2>&1; then
PYTHON_BIN=python
fi
INPUT_DIR="$TMP_DIR/artifacts"
mkdir -p "$INPUT_DIR/cli-linux" "$INPUT_DIR/server-linux" "$INPUT_DIR/mirror-patch/artifacts/mirror"
printf 'cli archive\n' > "$INPUT_DIR/cli-linux/open-shorebird-cli-linux-x64.tar.gz"
printf 'server archive\n' > "$INPUT_DIR/server-linux/shorebird-server-linux-amd64.tar.gz"
printf 'patch archive\n' > "$INPUT_DIR/mirror-patch/artifacts/mirror/patch-linux-x64.zip"
"$ROOT/scripts/write_sha256.sh" "$INPUT_DIR/cli-linux/open-shorebird-cli-linux-x64.tar.gz"
"$ROOT/scripts/write_sha256.sh" "$INPUT_DIR/server-linux/shorebird-server-linux-amd64.tar.gz"
"$ROOT/scripts/write_sha256.sh" "$INPUT_DIR/mirror-patch/artifacts/mirror/patch-linux-x64.zip"
"$PYTHON_BIN" "$ROOT/scripts/write_release_manifest.py" \
"$INPUT_DIR" \
--github-sha test-sha \
--require 'cli-linux/*open-shorebird-cli-linux-x64.tar.gz' \
--require 'server-linux/*shorebird-server-linux-amd64.tar.gz' \
--require 'mirror-patch/*patch-linux-x64.zip' \
--output "$TMP_DIR/release-manifest.json"
"$PYTHON_BIN" "$ROOT/scripts/validate_release_manifest.py" \
--github-sha test-sha \
"$INPUT_DIR" \
"$TMP_DIR/release-manifest.json"
"$PYTHON_BIN" - "$TMP_DIR/release-manifest.json" <<'PY'
import json
import sys
manifest = json.load(open(sys.argv[1], encoding="utf-8"))
assert manifest["format_version"] == 1
assert manifest["github_sha"] == "test-sha"
assert manifest["artifact_count"] == 3
paths = {artifact["path"] for artifact in manifest["artifacts"]}
assert "cli-linux/open-shorebird-cli-linux-x64.tar.gz" in paths
assert "server-linux/shorebird-server-linux-amd64.tar.gz" in paths
assert "mirror-patch/artifacts/mirror/patch-linux-x64.zip" in paths
for artifact in manifest["artifacts"]:
assert artifact["artifact_group"] in {
"cli-linux",
"server-linux",
"mirror-patch",
}
assert artifact["filename"] == artifact["path"].split("/")[-1]
assert len(artifact["sha256"]) == 64
assert artifact["size"] > 0
assert artifact["sidecar"].endswith(".sha256")
PY
TAMPERED_MANIFEST="$TMP_DIR/tampered-release-manifest.json"
"$PYTHON_BIN" - "$TMP_DIR/release-manifest.json" "$TAMPERED_MANIFEST" <<'PY'
import json
import sys
source, output = sys.argv[1:]
manifest = json.load(open(source, encoding="utf-8"))
manifest["artifacts"][0]["sha256"] = "0" * 64
json.dump(manifest, open(output, "w", encoding="utf-8"))
PY
if "$PYTHON_BIN" "$ROOT/scripts/validate_release_manifest.py" \
"$INPUT_DIR" \
"$TAMPERED_MANIFEST" >/dev/null 2>&1; then
echo "validate_release_manifest.py unexpectedly accepted a tampered digest" >&2
exit 70
fi
if "$PYTHON_BIN" "$ROOT/scripts/validate_release_manifest.py" \
--github-sha wrong-sha \
"$INPUT_DIR" \
"$TMP_DIR/release-manifest.json" >"$TMP_DIR/wrong-sha.log" 2>&1; then
echo "validate_release_manifest.py unexpectedly accepted the wrong github_sha" >&2
exit 70
fi
grep -q "github_sha is" "$TMP_DIR/wrong-sha.log"
UNLISTED_ARTIFACTS="$TMP_DIR/unlisted-artifacts"
cp -R "$INPUT_DIR" "$UNLISTED_ARTIFACTS"
printf 'extra artifact\n' > "$UNLISTED_ARTIFACTS/extra.tar.gz"
"$ROOT/scripts/write_sha256.sh" "$UNLISTED_ARTIFACTS/extra.tar.gz"
if "$PYTHON_BIN" "$ROOT/scripts/validate_release_manifest.py" \
"$UNLISTED_ARTIFACTS" \
"$TMP_DIR/release-manifest.json" >/dev/null 2>&1; then
echo "validate_release_manifest.py unexpectedly accepted an unlisted artifact" >&2
exit 70
fi
UNSAFE_MANIFEST="$TMP_DIR/unsafe-release-manifest.json"
"$PYTHON_BIN" - "$TMP_DIR/release-manifest.json" "$UNSAFE_MANIFEST" <<'PY'
import json
import sys
source, output = sys.argv[1:]
manifest = json.load(open(source, encoding="utf-8"))
manifest["artifacts"][0]["path"] = r"cli-linux\open-shorebird-cli-linux-x64.tar.gz"
manifest["artifacts"][0]["sidecar"] = (
r"cli-linux\open-shorebird-cli-linux-x64.tar.gz.sha256"
)
json.dump(manifest, open(output, "w", encoding="utf-8"))
PY
if "$PYTHON_BIN" "$ROOT/scripts/validate_release_manifest.py" \
"$INPUT_DIR" \
"$UNSAFE_MANIFEST" >/dev/null 2>&1; then
echo "validate_release_manifest.py unexpectedly accepted an unsafe artifact path" >&2
exit 70
fi
BAD_PROVENANCE_MANIFEST="$TMP_DIR/bad-provenance-release-manifest.json"
"$PYTHON_BIN" - "$TMP_DIR/release-manifest.json" "$BAD_PROVENANCE_MANIFEST" <<'PY'
import json
import sys
source, output = sys.argv[1:]
manifest = json.load(open(source, encoding="utf-8"))
manifest["artifacts"][0]["artifact_group"] = "wrong-group"
manifest["artifacts"][1]["filename"] = "wrong-name.tar.gz"
json.dump(manifest, open(output, "w", encoding="utf-8"))
PY
if "$PYTHON_BIN" "$ROOT/scripts/validate_release_manifest.py" \
"$INPUT_DIR" \
"$BAD_PROVENANCE_MANIFEST" >/dev/null 2>&1; then
echo "validate_release_manifest.py unexpectedly accepted bad provenance fields" >&2
exit 70
fi
SYMLINK_LISTED_ARTIFACT="$TMP_DIR/symlink-listed-artifact"
cp -R "$INPUT_DIR" "$SYMLINK_LISTED_ARTIFACT"
rm "$SYMLINK_LISTED_ARTIFACT/cli-linux/open-shorebird-cli-linux-x64.tar.gz"
ln -s "$INPUT_DIR/cli-linux/open-shorebird-cli-linux-x64.tar.gz" \
"$SYMLINK_LISTED_ARTIFACT/cli-linux/open-shorebird-cli-linux-x64.tar.gz"
if "$PYTHON_BIN" "$ROOT/scripts/validate_release_manifest.py" \
"$SYMLINK_LISTED_ARTIFACT" \
"$TMP_DIR/release-manifest.json" >/dev/null 2>&1; then
echo "validate_release_manifest.py unexpectedly accepted a symlink artifact" >&2
exit 70
fi
EMPTY_LISTED_ARTIFACT="$TMP_DIR/empty-listed-artifact"
cp -R "$INPUT_DIR" "$EMPTY_LISTED_ARTIFACT"
printf '' > "$EMPTY_LISTED_ARTIFACT/cli-linux/open-shorebird-cli-linux-x64.tar.gz"
"$ROOT/scripts/write_sha256.sh" \
"$EMPTY_LISTED_ARTIFACT/cli-linux/open-shorebird-cli-linux-x64.tar.gz"
EMPTY_LISTED_MANIFEST="$TMP_DIR/empty-listed-release-manifest.json"
"$PYTHON_BIN" - "$TMP_DIR/release-manifest.json" "$EMPTY_LISTED_MANIFEST" <<'PY'
import hashlib
import json
import sys
source, output = sys.argv[1:]
manifest = json.load(open(source, encoding="utf-8"))
empty_digest = hashlib.sha256(b"").hexdigest()
for artifact in manifest["artifacts"]:
if artifact["path"] == "cli-linux/open-shorebird-cli-linux-x64.tar.gz":
artifact["sha256"] = empty_digest
artifact["size"] = 0
json.dump(manifest, open(output, "w", encoding="utf-8"))
PY
if "$PYTHON_BIN" "$ROOT/scripts/validate_release_manifest.py" \
"$EMPTY_LISTED_ARTIFACT" \
"$EMPTY_LISTED_MANIFEST" >"$TMP_DIR/empty-listed.log" 2>&1; then
echo "validate_release_manifest.py unexpectedly accepted an empty artifact" >&2
exit 70
fi
grep -q "empty artifacts are not allowed" "$TMP_DIR/empty-listed.log"
SYMLINK_INPUT="$TMP_DIR/symlink-input"
mkdir -p "$SYMLINK_INPUT"
printf 'symlink target\n' > "$SYMLINK_INPUT/target.tar.gz"
"$ROOT/scripts/write_sha256.sh" "$SYMLINK_INPUT/target.tar.gz"
ln -s target.tar.gz "$SYMLINK_INPUT/link.tar.gz"
if "$PYTHON_BIN" "$ROOT/scripts/write_release_manifest.py" \
"$SYMLINK_INPUT" \
--output "$TMP_DIR/symlink-input.json" >/dev/null 2>&1; then
echo "write_release_manifest.py unexpectedly accepted a symlink artifact" >&2
exit 70
fi
MISSING_SIDECAR="$TMP_DIR/missing-sidecar"
mkdir -p "$MISSING_SIDECAR"
printf 'missing sidecar\n' > "$MISSING_SIDECAR/artifact.tar.gz"
if "$PYTHON_BIN" "$ROOT/scripts/write_release_manifest.py" \
"$MISSING_SIDECAR" \
--output "$TMP_DIR/missing.json" >/dev/null 2>&1; then
echo "write_release_manifest.py unexpectedly accepted a missing sidecar" >&2
exit 70
fi
BAD_SIDECAR="$TMP_DIR/bad-sidecar"
mkdir -p "$BAD_SIDECAR"
printf 'bad sidecar\n' > "$BAD_SIDECAR/artifact.tar.gz"
printf '%064d artifact.tar.gz\n' 0 > "$BAD_SIDECAR/artifact.tar.gz.sha256"
if "$PYTHON_BIN" "$ROOT/scripts/write_release_manifest.py" \
"$BAD_SIDECAR" \
--output "$TMP_DIR/bad.json" >/dev/null 2>&1; then
echo "write_release_manifest.py unexpectedly accepted a bad sidecar" >&2
exit 70
fi
EMPTY_ARTIFACT="$TMP_DIR/empty-artifact"
mkdir -p "$EMPTY_ARTIFACT"
printf '' > "$EMPTY_ARTIFACT/artifact.tar.gz"
"$ROOT/scripts/write_sha256.sh" "$EMPTY_ARTIFACT/artifact.tar.gz"
if "$PYTHON_BIN" "$ROOT/scripts/write_release_manifest.py" \
"$EMPTY_ARTIFACT" \
--output "$TMP_DIR/empty.json" >"$TMP_DIR/empty-artifact.log" 2>&1; then
echo "write_release_manifest.py unexpectedly accepted an empty artifact" >&2
exit 70
fi
grep -q "empty artifacts are not allowed" "$TMP_DIR/empty-artifact.log"
ORPHAN_SIDECAR="$TMP_DIR/orphan-sidecar"
mkdir -p "$ORPHAN_SIDECAR"
printf '%064d missing.tar.gz\n' 0 > "$ORPHAN_SIDECAR/missing.tar.gz.sha256"
if "$PYTHON_BIN" "$ROOT/scripts/write_release_manifest.py" \
"$ORPHAN_SIDECAR" \
--output "$TMP_DIR/orphan.json" >/dev/null 2>&1; then
echo "write_release_manifest.py unexpectedly accepted an orphan sidecar" >&2
exit 70
fi
if "$PYTHON_BIN" "$ROOT/scripts/write_release_manifest.py" \
"$INPUT_DIR" \
--require 'missing-artifact/*.tar.gz' \
--output "$TMP_DIR/missing-required.json" >/dev/null 2>&1; then
echo "write_release_manifest.py unexpectedly accepted a missing required artifact" >&2
exit 70
fi
echo "write_release_manifest.py smoke test passed"