239 lines
9.1 KiB
Bash
Executable File
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"
|