cat / goq
clone

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

feat: define public release delivery

Dami committed 8eb370c
Separate signed Portal downloads from the Sigil machine bootstrap, publish a fail-closed signed-package installer contract, promote the four streaming hardening tracks, and verify the resulting static delivery surface.
commit
8eb370c851635cd99a3d4fef4586160c3615572e
parent
2a3329ba3bad2b15ad9abdcfcf49164632052f74
author
Dami <dami.etoile@gmail.com>
6 files changed, +214 -18
MREADME.md18+++++-
Adocs/public-release-delivery.md74++++++++++++++++++++++
Mscripts/verify-website.sh14++++-
Mwebsite/_headers5+
Mwebsite/dither.js19+----
Awebsite/install-sigil102++++++++++++++++++++++++++++++
M README.md +16 -2
@@ -81,8 +81,8 @@ authentication.
8181 the remaining integration gate is forwarding a physical controller attached8282 to the client. Keyboard injection is hardware-proven, and the conventional8383 relative mouse replaces Gamescope-incompatible absolute motion.84-7. **Live-proven:** bounded PipeWire audio capture, Opus delivery, and client85- playback. Add a persistent headless sink and quantify A/V synchronization.84+7. **Live-proven:** bounded PipeWire audio capture, a persistent headless sink,85+ Opus delivery, and client playback. Quantify longer-run A/V synchronization.8686 8. Replace or supplement FIDO pairing with short-lived capability tickets.8787 8888 ## Development
@@ -201,6 +201,20 @@ The static `website/` directory is published through Cloudflare Pages after a
201201 merge to `main`. See the [Cloudflare Pages release setup](docs/cloudflare-pages.md)202202 for the one-time project and GitHub environment configuration.203203 204+Portal is distributed as a compiled, signed desktop application; it is never205+installed through a shell pipe. Sigil uses a separate Bazzite machine bootstrap206+at `https://goq.sh/install-sigil`. That bootstrap intentionally fails closed207+until the Minisign publisher trust root and first signed release exist. The208+[public release delivery contract](docs/public-release-delivery.md) defines the209+remaining signing and asset gates.210+211+The promoted streaming-hardening roadmap is tracked as bounded212+[Iroh/MoQ media objects](https://github.com/FelineStateMachine/goq/issues/7),213+[adaptive bitrate](https://github.com/FelineStateMachine/goq/issues/8),214+[motion-sensitive resolution](https://github.com/FelineStateMachine/goq/issues/9),215+and [Auto Codec](https://github.com/FelineStateMachine/goq/issues/10). H.264 at216+1280×800/60 remains the known-safe first target while that work lands.217+204218 ## License205219 206220 MIT
A docs/public-release-delivery.md +74 -0
@@ -0,0 +1,74 @@
1+# Public release delivery2+3+Portal and Sigil have different delivery contracts. Portal is a compiled4+desktop download. Sigil is a machine bootstrap for a dedicated Bazzite host.5+Neither path may fall back to an unsigned development build.6+7+## Release asset contract8+9+The first public release is a draft or prerelease until capability-ticket10+onboarding and the release-candidate hardware pass are complete.11+12+Sigil publishes exactly these x86_64 Bazzite assets for a tag such as13+`v0.3.0-alpha.1`:14+15+- `sigil-v0.3.0-alpha.1-bazzite-x86_64.tar.gz`16+- `sigil-v0.3.0-alpha.1-bazzite-x86_64.tar.gz.sha256`17+- `sigil-v0.3.0-alpha.1-bazzite-x86_64.tar.gz.minisig`18+19+Portal preserves the package builder's versioned macOS contract:20+21+- `Portal-0.3.0-alpha.1-arm64.dmg`22+- `Portal-0.3.0-alpha.1-arm64.dmg.sha256`23+- `Portal-0.3.0-alpha.1-arm64.json`24+25+Do not advertise x86_64, universal, or Linux Portal downloads until those exact26+artifacts pass an equivalent signed packaging gate.27+28+## Sigil bootstrap trust boundary29+30+`website/install-sigil` is the public bootstrap source. Before the release31+channel opens, replace its `unconfigured` publisher key with the dedicated32+Minisign public key and review its fingerprint through a separate trusted33+channel. The secret key and its passphrase must never enter the repository or a34+general deployment environment.35+36+The bootstrap:37+38+1. Refuses root, non-Bazzite systems, unsupported architectures, and missing39+ verification tools.40+2. Uses the exact immutable release tag pinned beside the publisher key in the41+ reviewed bootstrap source.42+3. Downloads the versioned archive, checksum, and detached signature from that43+ tag. Opening a new channel therefore requires a reviewed website commit.44+4. Verifies the embedded publisher key before extraction, then verifies the45+ exact asset checksum.46+5. Extracts into a private temporary directory and invokes the package-owned47+ atomic stager as the gaming user.48+6. Does not start or restart Sigil, overwrite identity or host configuration,49+ modify `/etc`, or guess ambiguous hardware.50+51+A clean Bazzite image may not include Minisign. The public-alpha gate must52+either provision a pinned verifier with its own hard-coded digest or make the53+verifier prerequisite explicit; it must never silently downgrade to SHA-only54+verification.55+56+## Portal signing boundary57+58+The existing macOS package gate requires a Developer ID Application identity,59+hardened runtime, notarization, stapling, strict Gatekeeper assessment, and a60+release build without `demo-direct-node`. Store the certificate and App Store61+Connect credentials only in a separately protected GitHub `release`62+environment with required reviewers.63+64+The first release automation must verify that the git tag, every Cargo package65+version, Tauri version, artifact filenames, and manifests agree before it66+publishes the GitHub Release. Upload every required asset to a draft release,67+verify the complete set, and only then mark it as a prerelease.68+69+## Tracked gates70+71+- [Capability tickets and Portal onboarding](https://github.com/FelineStateMachine/goq/issues/3)72+- [Signed Sigil package and install command](https://github.com/FelineStateMachine/goq/issues/4)73+- [Signed and notarized Portal downloads](https://github.com/FelineStateMachine/goq/issues/5)74+- [Public-alpha hardware and network acceptance](https://github.com/FelineStateMachine/goq/issues/6)
M scripts/verify-website.sh +12 -2
M website/_headers +5 -0
M website/dither.js +5 -14
A website/install-sigil +102 -0
@@ -0,0 +1,102 @@
1+#!/usr/bin/env bash2+3+set -euo pipefail4+umask 0775+6+readonly repository="FelineStateMachine/goq"7+readonly publisher_key="unconfigured"8+readonly release_tag="unconfigured"9+10+die() {11+ printf 'Sigil setup failed: %s\n' "$*" >&212+ exit 113+}14+15+if [[ "$publisher_key" == unconfigured || "$release_tag" == unconfigured ]]; then16+ die "the signed Sigil release channel is not open yet"17+fi18+19+[[ "$(uname -s)" == Linux ]] || die "Sigil requires Linux"20+[[ "$(uname -m)" == x86_64 ]] || die "Sigil currently requires x86_64"21+[[ "$(id -u)" -ne 0 ]] || die "run this command as the dedicated gaming user, not root"22+grep -Eq '^ID="?bazzite"?$' /etc/os-release || die "Sigil currently supports Bazzite"23+24+for command_name in awk curl find grep install minisign mktemp rm sha256sum tar tr wc; do25+ command -v "$command_name" >/dev/null 2>&1 \26+ || die "$command_name is required"27+done28+29+[[ "$release_tag" =~ ^v[0-9][0-9A-Za-z._-]*$ ]] || die "the release tag is malformed"30+31+asset_name="sigil-$release_tag-bazzite-x86_64.tar.gz"32+asset_base="https://github.com/$repository/releases/download/$release_tag/$asset_name"33+temp_parent="${TMPDIR:-/tmp}"34+temp_parent="${temp_parent%/}"35+[[ "$temp_parent" == /* && -d "$temp_parent" && ! -L "$temp_parent" ]] \36+ || die "the temporary directory is unsafe"37+temp_root="$(mktemp -d "$temp_parent/goq-sigil-install.XXXXXX")"38+archive_path="$temp_root/$asset_name"39+checksum_path="$archive_path.sha256"40+signature_path="$archive_path.minisig"41+unpack_path="$temp_root/unpack"42+43+cleanup() {44+ local status=$?45+ trap - EXIT INT TERM HUP46+ case "$temp_root" in47+ "$temp_parent"/goq-sigil-install.??????) rm -rf -- "$temp_root" ;;48+ esac49+ exit "$status"50+}51+trap cleanup EXIT INT TERM HUP52+53+for suffix in '' .sha256 .minisig; do54+ curl --proto '=https' --tlsv1.2 --fail --silent --show-error --location \55+ --retry 3 --retry-all-errors --output "$archive_path$suffix" "$asset_base$suffix"56+done57+58+minisign -Vm "$archive_path" -x "$signature_path" -P "$publisher_key" \59+ || die "the publisher signature is invalid"60+61+[[ "$(wc -l <"$checksum_path" | tr -d ' ')" == 1 ]] \62+ || die "the release checksum file is malformed"63+expected_hash="$(awk 'NF == 2 { print $1 }' "$checksum_path")"64+expected_name="$(awk 'NF == 2 { print $2 }' "$checksum_path")"65+[[ "$expected_hash" =~ ^[0-9a-f]{64}$ && "$expected_name" == "$asset_name" ]] \66+ || die "the release checksum declaration is malformed"67+actual_hash="$(sha256sum "$archive_path" | awk '{ print $1 }')"68+[[ "$actual_hash" == "$expected_hash" ]] || die "the release checksum does not match"69+70+archive_entries="$(tar --list --gzip --file "$archive_path")" \71+ || die "the signed release archive is unreadable"72+[[ -n "$archive_entries" ]] || die "the signed release archive is empty"73+while IFS= read -r archive_entry; do74+ case "$archive_entry" in75+ payload|payload/|payload/*) ;;76+ *) die "the signed release archive escapes its payload root" ;;77+ esac78+ case "/$archive_entry/" in79+ */../*|*/./*) die "the signed release archive contains an unsafe path" ;;80+ esac81+done <<<"$archive_entries"82+if ! LC_ALL=C tar --list --verbose --gzip --file "$archive_path" \83+ | awk '{ type = substr($1, 1, 1); if (type != "-" && type != "d") exit 1 }'84+then85+ die "the signed release archive contains a special file or link"86+fi87+88+install -d -m 0700 "$unpack_path"89+tar --extract --gzip --file "$archive_path" --directory "$unpack_path" \90+ --no-same-owner --no-same-permissions91+payload_path="$unpack_path/payload"92+[[ -d "$payload_path" && ! -L "$payload_path" ]] || die "the package payload is missing"93+[[ -x "$payload_path/stage-this-release.sh" \94+ && ! -L "$payload_path/stage-this-release.sh" ]] || die "the package installer is missing"95+[[ -z "$(find "$payload_path" -type l -print -quit)" ]] \96+ || die "the package payload contains a symbolic link"97+98+"$payload_path/stage-this-release.sh"99+printf '%s\n' \100+ "Sigil runtime $release_tag is installed." \101+ "Continue with the hardware and identity gates in the fresh Bazzite runbook." \102+ "The installer did not start or restart the active Sigil service."