123 lines
5.6 KiB
Bash
Executable File
123 lines
5.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
|
mkdir -p -- "$ROOT/dist"
|
|
WORK=$(mktemp -d "$ROOT/dist/.local-release-check.XXXXXXXX")
|
|
trap 'rm -rf -- "$WORK"' EXIT
|
|
PACKAGE_VERSION="local-$(basename -- "$WORK" | tr -cd '[:alnum:]')"
|
|
PACKAGE_RELEASE="$ROOT/dist/release-$PACKAGE_VERSION"
|
|
PACKAGE_STAGE="$ROOT/dist/package-$PACKAGE_VERSION"
|
|
PACKAGE_ARCHIVE="$ROOT/dist/packages/sip-go-agent-$PACKAGE_VERSION-linux-amd64.tar.gz"
|
|
for path in "$PACKAGE_RELEASE" "$PACKAGE_STAGE" "$PACKAGE_ARCHIVE" "$PACKAGE_ARCHIVE.sha256"; do
|
|
if [[ -e "$path" || -L "$path" ]]; then
|
|
echo "local package test path already exists: $path" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
mkdir -- "$PACKAGE_RELEASE"
|
|
trap 'rm -rf -- "$WORK" "$PACKAGE_RELEASE" "$PACKAGE_STAGE"; rm -f -- "$PACKAGE_ARCHIVE" "$PACKAGE_ARCHIVE.sha256"' EXIT
|
|
printf 'keep existing package output\n' > "$PACKAGE_RELEASE/sentinel"
|
|
|
|
protected="$WORK/preexisting"
|
|
mkdir -- "$protected"
|
|
printf 'keep existing release output\n' > "$protected/sentinel"
|
|
if RELEASE_VERSION=local-development "$ROOT/scripts/build-release.sh" "$protected" > "$WORK/rejected.log" 2>&1; then
|
|
echo 'release build accepted a preexisting output directory' >&2
|
|
exit 1
|
|
fi
|
|
if [[ ! -f "$protected/sentinel" ]] || [[ $(<"$protected/sentinel") != 'keep existing release output' ]]; then
|
|
echo 'release build removed or changed a preexisting file' >&2
|
|
exit 1
|
|
fi
|
|
if "$ROOT/deploys/build-package.sh" "$PACKAGE_VERSION" > "$WORK/package-rejected.log" 2>&1; then
|
|
echo 'package build accepted a preexisting release directory' >&2
|
|
exit 1
|
|
fi
|
|
if [[ ! -f "$PACKAGE_RELEASE/sentinel" ]] || [[ $(<"$PACKAGE_RELEASE/sentinel") != 'keep existing package output' ]]; then
|
|
echo 'package build removed or changed a preexisting file' >&2
|
|
exit 1
|
|
fi
|
|
|
|
"$ROOT/scripts/check-proto.sh" > "$WORK/proto.log"
|
|
"$ROOT/scripts/check-contracts.sh" > "$WORK/contracts.log"
|
|
RELEASE_VERSION=local-development "$ROOT/scripts/build-release.sh" "$WORK/release" > "$WORK/build.log" 2>&1 || {
|
|
tail -n 25 "$WORK/build.log" >&2
|
|
exit 1
|
|
}
|
|
(cd -- "$WORK/release" && sha256sum --check SHA256SUMS > /dev/null)
|
|
python3 - "$ROOT" "$WORK/release" <<'PY'
|
|
import hashlib
|
|
import json
|
|
import pathlib
|
|
import sys
|
|
|
|
root, release = map(pathlib.Path, sys.argv[1:])
|
|
manifest = json.loads((release / "manifest.json").read_text())
|
|
assert manifest["manifest_version"] == 1
|
|
assert manifest["scope"] == manifest["version"] == "local-development"
|
|
assert manifest["security"] == {"credentials_embedded": False, "production_approval": False}
|
|
assert manifest["binary"]["sha256"] == hashlib.sha256((release / "sip-go-agent").read_bytes()).hexdigest()
|
|
assert manifest["go_version"].startswith("go version go1.27.1 ")
|
|
|
|
topology = json.loads((root / "contracts/local/mq-topology.json").read_text())
|
|
assert topology["ownership"] == "saas"
|
|
assert topology["dispatcher"]["control"]["queue"].endswith(".v1")
|
|
assert topology["dispatcher"]["task"]["queue"].endswith(".v1")
|
|
assert topology["saas"]["result"]["queue"].endswith(".v1")
|
|
expected_attestation = {
|
|
"local_contract_manifest_sha256": hashlib.sha256((root / "contracts/local/manifest.json").read_bytes()).hexdigest(),
|
|
"local_mq_topology_sha256": hashlib.sha256((root / "contracts/local/mq-topology.json").read_bytes()).hexdigest(),
|
|
"historical_upstream_manifest_sha256": hashlib.sha256((root / "contracts/upstream/manifest.txt").read_bytes()).hexdigest(),
|
|
"proto_manifest_sha256": hashlib.sha256((root / "proto/manifest.json").read_bytes()).hexdigest(),
|
|
}
|
|
assert manifest["contract_attestation"] == expected_attestation
|
|
print("local artifact SHA-256:", manifest["binary"]["sha256"])
|
|
print("current local contract SHA-256:", expected_attestation["local_contract_manifest_sha256"])
|
|
print("source dirty:", manifest["source_dirty"])
|
|
print("production approved:", manifest["security"]["production_approval"])
|
|
PY
|
|
|
|
if "$WORK/release/sip-go-agent" dispatcher --help | grep -Eq -- '--tenant-key|--consume'; then
|
|
echo 'release exposes deprecated Dispatcher queue/tenant switches' >&2
|
|
exit 1
|
|
fi
|
|
for mode in mixed real; do
|
|
blocked_db="$WORK/blocked-$mode.sqlite"
|
|
if DISPATCHER_SQLITE_PATH="$blocked_db" "$WORK/release/sip-go-agent" dispatcher --mode "$mode" > "$WORK/blocked-$mode.log" 2>&1; then
|
|
echo "release accepted unapproved $mode execution" >&2
|
|
exit 1
|
|
fi
|
|
if ! grep -Fq 'Dispatcher accepts only isolated Mock mode' "$WORK/blocked-$mode.log" || test -e "$blocked_db"; then
|
|
echo "release reached resources before rejecting $mode execution" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
rm -- "$PACKAGE_RELEASE/sentinel"
|
|
rmdir -- "$PACKAGE_RELEASE"
|
|
"$ROOT/deploys/build-package.sh" "$PACKAGE_VERSION" > "$WORK/package.log" 2>&1 || {
|
|
tail -n 25 "$WORK/package.log" >&2
|
|
exit 1
|
|
}
|
|
(cd -- "$(dirname -- "$PACKAGE_ARCHIVE")" && sha256sum --check "$(basename -- "$PACKAGE_ARCHIVE").sha256" > /dev/null)
|
|
mkdir -- "$WORK/extracted"
|
|
tar -C "$WORK/extracted" -xzf "$PACKAGE_ARCHIVE"
|
|
(cd -- "$WORK/extracted" && sha256sum --check package.SHA256SUMS > /dev/null)
|
|
python3 - "$WORK/extracted" "$PACKAGE_VERSION" <<'PY'
|
|
import json
|
|
import pathlib
|
|
import sys
|
|
|
|
package, version = pathlib.Path(sys.argv[1]), sys.argv[2]
|
|
manifest = json.loads((package / "manifest.json").read_text())
|
|
assert manifest["version"] == version
|
|
assert manifest["scope"] == "local-development"
|
|
assert manifest["security"]["production_approval"] is False
|
|
assert set(manifest["contract_attestation"]) == {
|
|
"local_contract_manifest_sha256", "local_mq_topology_sha256",
|
|
"historical_upstream_manifest_sha256", "proto_manifest_sha256",
|
|
}
|
|
assert all(len(digest) == 64 for digest in manifest["contract_attestation"].values())
|
|
PY
|
|
echo 'local release/package artifact and current contract/queue gates passed; no deployment or dial attempted'
|