cat / goq
clone

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

fix/release-build-and-order
goq / docs / public-release-delivery.md
public-release-delivery.md 10.5K rendered
1# Public release delivery23Portal and Sigil have different delivery contracts. Portal is a compiled4desktop download. Sigil is a machine bootstrap for a dedicated Bazzite host.5Neither path may fall back to an unsigned development build.67## Release asset contract89The first public release is a draft or prerelease until capability-ticket10onboarding and the release-candidate hardware pass are complete.1112Sigil publishes exactly these Linux glibc 2.17 x86_64 assets for a tag such as13`v0.3.0-alpha.1`:1415- `sigil-v0.3.0-alpha.1-linux-glibc2.17-x86_64.tar.gz`16- `sigil-v0.3.0-alpha.1-linux-glibc2.17-x86_64.tar.gz.sha256`17- `sigil-v0.3.0-alpha.1-linux-glibc2.17-x86_64.tar.gz.minisig`1819The Sigil asset suffix names the binary target contract, not a support claim.20The public bootstrap and package-owned activation path remain restricted to the21Bazzite appliance until SteamOS or another host environment passes its own22packaging, capability, cold-boot, and hardware acceptance gates. The canonical23suffix is pinned in `release/sigil-target-contract.txt`.2425Portal preserves the package builder's versioned macOS contract:2627- `Portal-0.3.0-alpha.1-arm64.dmg`28- `Portal-0.3.0-alpha.1-arm64.dmg.sha256`29- `Portal-0.3.0-alpha.1-arm64.json`3031Do not advertise x86_64, universal, or Linux Portal downloads until those exact32artifacts pass an equivalent signed packaging gate.3334macOS x86_64, Linux x86_64, and Windows x86_64 are built and attested on every35release as unpublished preview artifacts, retained only as short-lived Actions36artifacts. They are unsigned, are not release assets, and are not a download37channel. The published Portal contract remains exactly the three macOS arm6438files above.3940## Sigil bootstrap trust boundary4142`website/install-sigil` is the public bootstrap source. Before the release43channel opens, replace its `unconfigured` publisher key with the dedicated44Minisign public key and review its fingerprint through a separate trusted45channel. The secret key and its passphrase must never enter the repository or a46general deployment environment.4748The bootstrap:49501. Refuses root, non-Bazzite systems, unsupported architectures, and missing51 bootstrap tools.522. Uses the exact immutable release tag pinned beside the publisher key in the53 reviewed bootstrap source.543. Downloads the versioned archive, checksum, and detached signature from that55 tag. Opening a new channel therefore requires a reviewed website commit.564. Verifies the embedded publisher key before extraction, then verifies the57 exact asset checksum.585. Extracts into a private temporary directory and invokes the package-owned59 atomic stager as the gaming user.606. Does not start or restart Sigil, overwrite identity or host configuration,61 modify `/etc`, or guess ambiguous hardware.6263`scripts/verify-sigil-bootstrap.py` keeps the channel fully closed while the64sentinels are present. Once opened, it requires the bootstrap's embedded key to65exactly match `release/sigil-minisign.pub` and rejects partial configuration or66a malformed immutable release tag before the website can deploy.6768A clean Bazzite image does not need a preinstalled Minisign package. The69bootstrap downloads the exact official Minisign 0.12 Linux archive and checks70its hard-coded SHA-256 before archive inspection, extraction, or execution. It71accepts only the reviewed archive layout (including its inert AppleDouble72metadata members), extracts only the x86_64 verifier into private temporary73state, and invokes that verifier by absolute path rather than trusting `PATH`.74Changing the verifier version, URL, or independently computed content digest75requires a reviewed website commit. The Sigil publisher key and release tag76remain separate pins and keep the release channel closed while either is77`unconfigured`.7879## Sigil candidate and offline signing ceremony8081The repository stores only the reviewed public key in82`release/sigil-minisign.pub`. Its committed `unconfigured` sentinel keeps every83promotion fail-closed until the offline publisher key exists. Never replace the84sentinel with a temporary or CI-generated key.8586For an immutable tag that exactly matches `crates/sigil-host/Cargo.toml`, run87the **Sigil Release** workflow with `build-candidate`. The protected `main`88environment builds clean tagged source, runs the complete repository gate,89creates exactly these unsigned draft assets, and retains the same bytes as a90short-lived Actions artifact:9192- `sigil-$tag-linux-glibc2.17-x86_64.tar.gz`93- `sigil-$tag-linux-glibc2.17-x86_64.tar.gz.sha256`9495Move those bytes to the offline publisher machine. After independently96confirming the tag commit and reviewed public key, sign without exporting the97secret key or its passphrase:9899```bash100scripts/sign-bazzite-release.sh \101 --tag "$tag" \102 --archive "/absolute/offline/path/sigil-$tag-linux-glibc2.17-x86_64.tar.gz" \103 --source-commit "$tag_commit" \104 --minisign-key /absolute/offline/path/sigil-release.key \105 --public-key-file /absolute/offline/path/sigil-minisign.pub106```107108Before promotion, run the **Portal release** workflow for the same tag. It109requires the untouched two-asset Sigil draft, attaches exactly the ad-hoc110signed Portal DMG, checksum, and manifest, verifies the five-asset combined111draft, and leaves it unpublished. Transfer only the resulting Sigil `.minisig`112back to the online release operator and attach it to that draft. Do not use113`--clobber` for any asset.114115Run **Sigil Release** again with `promote-signed-draft`. It requires the exact116six-asset public-alpha set, verifies the detached Sigil signature with the117committed public key, checks the outer digest, inspects the archive without118extraction, binds both products to the same tag and commit, re-verifies the119Portal digest and release manifest, then mounts the downloaded DMG on a native120arm64 macOS runner and repeats the ad-hoc signature, architecture, identifier,121and payload checks, including proof that no notarization ticket is present. Only then does it122replace the incomplete draft notes and publish the prerelease. The workflow has123no input, environment, or secret capable of124receiving the offline secret key.125126`scripts/package-bazzite-release.sh` intentionally cannot sign. Its product127mode requires a clean worktree, an existing tag resolving exactly to `HEAD`, a128tag equal to Sigil's Cargo version, and the stable public asset name. The two129development flags are an inseparable escape hatch and cannot claim a release130tag. `scripts/verify-sigil-release.sh` is the common candidate, offline, and131promotion verifier.132133No public goq release exists under the former distro-named suffix. Unpublished134drafts or locally staged candidates using `bazzite-x86_64` must be discarded135and rebuilt; release verification intentionally provides no compatibility136alias that could make two names identify the same public bytes.137138## Public Bazzite acceptance record139140Repository tests exercise a complete package fixture through fresh install,141same-release rerun, upgrade, rollback, identity/config preservation, hostile142payload rejection, and proof that no `systemctl start`, `restart`, or `enable`143was attempted. That is not a substitute for the public-command gate.144145Closing issue #4 still requires operator evidence from clean Bazzite using two146distinct signed candidates. Record, without node IDs or credentials:1471481. The Bazzite image/version, x86_64 architecture, public bootstrap SHA-256,149 release asset SHA-256, and release tag/commit.1502. A clean `curl -fsSL https://goq.sh/install-sigil | bash` installation with151 service active/enabled state captured before and after.1523. An idempotent rerun with unchanged `current`, `previous`, identity, and host153 configuration.1544. Promotion to the second signed candidate followed by the same public command,155 proving new `current`, old `previous`, and no implicit service interruption.1565. `sigil-spark-host-rollback` without `--restart`, proving the links reverse,157 all release checksums revalidate, and service state remains unchanged.158159## Portal signing boundary160161Portal is **not** signed with an Apple Developer ID and is **not** notarized.162The project has no Apple Developer Program membership, and there is no free163path to notarization. This is a deliberate, recorded decision rather than an164unfinished step.165166The DMG carries only the ad-hoc signature that arm64 macOS requires in order to167execute a binary at all. An ad-hoc signature asserts nothing about origin, so168the packaging gate additionally proves that no certificate authority chain, no169Apple TeamIdentifier, and no notarization ticket crept into a build that claims170to be ad-hoc.171172Trust therefore comes from provenance, not from Apple:173174- a GitHub/Sigstore build-provenance attestation bound to the exact workflow,175 tag ref, and source commit;176- the published SHA-256 beside the DMG;177- the release manifest, which records `signing: "adhoc"` and `notarized: false`178 rather than claiming verification the artifact does not have.179180Promotion requires each of the three Portal assets to verify against the exact181workflow, tag ref, and source commit. Users are expected to check the digest182and, ideally, `gh attestation verify`.183184The consequence for users is real and must never be hidden: macOS blocks the185first launch, and the user has to allow Portal under System Settings, Privacy186and Security. The website says so, and the release notes say so.187188`scripts/package-macos-client.sh --signing developer-id` still implements the189full Developer ID, notarization, stapling, and Gatekeeper gate for the day a190membership exists. It is not exercised by CI and must be re-validated end to191end before it is trusted; enabling it also means restoring the192`release/portal-apple-team-id.txt` pin.193194The first release automation must verify that the git tag, every Cargo package195version, Tauri version, artifact filenames, and manifests agree before it196publishes the GitHub Release. Upload every required asset to a draft release,197verify the complete set, and only then mark it as a prerelease.198199goq.sh reads `website/portal-release.json`, which is deliberately committed as200unavailable until an operator verifies the promoted prerelease and submits a201reviewed manifest change. Invalid, missing, or unavailable manifest data never202falls back to a development build. See the203[Portal release runbook](portal-release.md) for the issue #5 procedure.204205## Tracked gates206207- [Capability tickets and Portal onboarding](https://github.com/FelineStateMachine/goq/issues/3)208- [Signed Sigil package and install command](https://github.com/FelineStateMachine/goq/issues/4)209- [Signed and notarized Portal downloads](https://github.com/FelineStateMachine/goq/issues/5)210- [Public-alpha hardware and network acceptance](https://github.com/FelineStateMachine/goq/issues/6)