cat / goq
clone

turns a linux box into a private steam streaming appliance: plug in, tap your key, play from another computer

fix/drop-hero-notarization-note
goq / scripts / tests / sigil-release-verifier.sh
sigil-release-verifier.sh 7.9K executable
1#!/usr/bin/env bash23set -euo pipefail45script_dir="$(CDPATH='' cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"6repo_dir="$(CDPATH='' cd -- "$script_dir/../.." && pwd -P)"7verifier="$repo_dir/scripts/verify-sigil-release.sh"8temp_parent="${TMPDIR:-/tmp}"9temp_parent="${temp_parent%/}"10temp_root="$(mktemp -d "$temp_parent/sigil-release-verifier.XXXXXX")"11release_tag=v0.1.012source_commit=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1314cleanup() {15 local status=$?16 trap - EXIT INT TERM HUP17 case "$temp_root" in18 "$temp_parent"/sigil-release-verifier.??????) rm -rf -- "$temp_root" ;;19 esac20 exit "$status"21}22trap cleanup EXIT INT TERM HUP2324make_fixture() {25 local output_dir="$1"26 local variant="${2:-valid}"27 install -d -m 0700 "$output_dir"28 python3 - "$output_dir" "$release_tag" "$source_commit" "$variant" <<'PY'29import gzip30import hashlib31import io32import json33import pathlib34import sys35import tarfile3637root = pathlib.Path(sys.argv[1])38tag = sys.argv[2]39commit = sys.argv[3]40variant = sys.argv[4]41asset = f"sigil-{tag}-linux-glibc2.17-x86_64.tar.gz"42archive_path = root / asset4344manifest = {45 "format": 2,46 "product": "sigil-host",47 "primary_executable": "sigil",48 "compatibility_executable": "sigil-host",49 "version": tag[1:],50 "target": "x86_64-unknown-linux-gnu.2.17",51 "profile": "release",52 "features": ["in-process-gstreamer"],53 "demo_auth_bypass": False,54 "demo_direct_node": False,55 "git_commit": commit,56 "git_dirty": False,57 "cargo_lock_sha256": "b" * 64,58 "rust_toolchain_sha256": "c" * 64,59 "cargo_zigbuild": "cargo-zigbuild 0.23.0",60 "binary_provenance": "self-built-clean-head",61 "binary_provenance_verified": True,62 "release_tag": tag,63 "asset_name": asset,64 "release_kind": "product-candidate",65}66if variant == "default-features":67 manifest["features"] = ["default"]68if variant == "demo-auth-bypass":69 manifest["demo_auth_bypass"] = True70binary = b"fixture executable\n"71release = {72 "sigil": binary,73 "sigil-host": binary,74 "sigil-probe": b"fixture probe\n",75 "assets/50-sigil-spark-audio.conf": b"audio\n",76 "assets/70-sigil-remote-input.rules": b"udev\n",77 "assets/72-sigil-uinput.rules": b"early uinput\n",78 "assets/99-sigil-uinput.rules": b"final uinput\n",79 "assets/sigil-host.service": b"[Service]\nExecStart=/fixture\n",80 "docs/sigil-host-activation.md": b"# Activation fixture\n",81 "tools/rollback-bazzite-release.sh": b"#!/usr/bin/env bash\nexit 0\n",82 "LICENSE": b"MIT\n",83 "release-manifest.json": (json.dumps(manifest, sort_keys=True, indent=2) + "\n").encode(),84}8586def sums(files):87 return "".join(f"{hashlib.sha256(data).hexdigest()} {name}\n" for name, data in files.items()).encode()8889release_sums = sums(release)90release_id = hashlib.sha256(release_sums).hexdigest().encode() + b"\n"91payload = {92 "release-id": release_id,93 "install-bazzite-package.sh": b"#!/usr/bin/env bash\nexit 0\n",94 "stage-this-release.sh": b"#!/usr/bin/env bash\nexit 0\n",95 "release/SHA256SUMS": release_sums,96}97package_sums = sums(payload)98files = {"payload/PACKAGE-SHA256SUMS": package_sums}99files.update({f"payload/{name}": data for name, data in payload.items()})100files.update({f"payload/release/{name}": data for name, data in release.items()})101dirs = [102 "payload/release",103 "payload/release/assets",104 "payload/release/docs",105 "payload/release/tools",106]107if variant == "unexpected":108 files["payload/unexpected"] = b"unexpected\n"109110with archive_path.open("wb") as raw:111 with gzip.GzipFile(filename="", mode="wb", fileobj=raw, mtime=0) as compressed:112 with tarfile.open(fileobj=compressed, mode="w", format=tarfile.PAX_FORMAT) as archive:113 for name in dirs:114 info = tarfile.TarInfo(name)115 info.type = tarfile.DIRTYPE116 info.mode = 0o700117 info.uid = info.gid = info.mtime = 0118 archive.addfile(info)119 for name in sorted(files):120 data = files[name]121 info = tarfile.TarInfo(name)122 info.mode = 0o755 if name.endswith((".sh", "/sigil", "/sigil-host", "/sigil-probe")) else 0o644123 info.uid = info.gid = info.mtime = 0124 if variant == "symlink" and name == "payload/release/sigil":125 info.type = tarfile.SYMTYPE126 info.linkname = "sigil-host"127 archive.addfile(info)128 else:129 info.size = len(data)130 archive.addfile(info, io.BytesIO(data))131 if variant == "duplicate" and name == "payload/release/sigil-host":132 archive.addfile(info, io.BytesIO(data))133134digest = hashlib.sha256(archive_path.read_bytes()).hexdigest()135(root / f"{asset}.sha256").write_text(f"{digest} {asset}\n")136PY137}138139assert_rejected() {140 local name="$1"141 local expected="$2"142 shift 2143 local log="$temp_root/$name.log"144 if "$@" >"$log" 2>&1; then145 printf 'FAIL: %s unexpectedly succeeded\n' "$name" >&2146 exit 1147 fi148 grep -Fq "$expected" "$log" || {149 printf 'FAIL: %s did not report %s\n' "$name" "$expected" >&2150 sed -n '1,120p' "$log" >&2151 exit 1152 }153}154155valid_dir="$temp_root/valid"156make_fixture "$valid_dir"157archive="$valid_dir/sigil-$release_tag-linux-glibc2.17-x86_64.tar.gz"158"$verifier" --tag "$release_tag" --archive "$archive" \159 --source-commit "$source_commit" --candidate | grep -Fq 'sigil_release_verification=ok'160161legacy_contract="bazzite""-x86_64"162legacy_archive="$valid_dir/sigil-$release_tag-$legacy_contract.tar.gz"163cp "$archive" "$legacy_archive"164cp "$archive.sha256" "$legacy_archive.sha256"165assert_rejected legacy-distro-name \166 "archive must be named sigil-$release_tag-linux-glibc2.17-x86_64.tar.gz" \167 "$verifier" --tag "$release_tag" --archive "$legacy_archive" --candidate168169printf 'not a signature\n' >"$archive.minisig"170key_file="$temp_root/test.pub"171printf '%s\n%s\n' 'untrusted comment: test key' \172 'RWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' >"$key_file"173fake_bin="$temp_root/bin"174install -d -m 0700 "$fake_bin"175printf '%s\n' '#!/usr/bin/env bash' 'exit 0' >"$fake_bin/minisign"176chmod 0755 "$fake_bin/minisign"177PATH="$fake_bin:$PATH" "$verifier" --tag "$release_tag" --archive "$archive" \178 --source-commit "$source_commit" --public-key-file "$key_file" \179 | grep -Fq 'publisher_verification=published'180181assert_rejected wrong-commit 'commit does not match' \182 env PATH="$fake_bin:$PATH" "$verifier" --tag "$release_tag" --archive "$archive" \183 --source-commit bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb --public-key-file "$key_file"184185bad_checksum_dir="$temp_root/bad-checksum"186make_fixture "$bad_checksum_dir"187bad_archive="$bad_checksum_dir/sigil-$release_tag-linux-glibc2.17-x86_64.tar.gz"188printf '%064d %s\n' 0 "$(basename -- "$bad_archive")" >"$bad_archive.sha256"189assert_rejected bad-checksum 'checksum declaration does not exactly match' \190 "$verifier" --tag "$release_tag" --archive "$bad_archive" --candidate191192for variant in symlink duplicate unexpected default-features demo-auth-bypass; do193 fixture_dir="$temp_root/$variant"194 make_fixture "$fixture_dir" "$variant"195 fixture_archive="$fixture_dir/sigil-$release_tag-linux-glibc2.17-x86_64.tar.gz"196 case "$variant" in197 symlink) expected='unsafe type' ;;198 duplicate) expected='duplicate members' ;;199 unexpected) expected='do not match the package allowlist' ;;200 default-features) expected='field features does not match the product contract' ;;201 demo-auth-bypass) expected='field demo_auth_bypass does not match the product contract' ;;202 esac203 assert_rejected "$variant" "$expected" \204 "$verifier" --tag "$release_tag" --archive "$fixture_archive" --candidate205done206207unconfigured="$temp_root/unconfigured.pub"208printf 'unconfigured\n' >"$unconfigured"209assert_rejected unconfigured-key 'unconfigured or malformed' \210 env PATH="$fake_bin:$PATH" "$verifier" --tag "$release_tag" --archive "$archive" \211 --public-key-file "$unconfigured"212213printf 'sigil_release_verifier_tests=ok\n'