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.3334## Sigil bootstrap trust boundary3536`website/install-sigil` is the public bootstrap source. Before the release37channel opens, replace its `unconfigured` publisher key with the dedicated38Minisign public key and review its fingerprint through a separate trusted39channel. The secret key and its passphrase must never enter the repository or a40general deployment environment.4142The bootstrap:43441. Refuses root, non-Bazzite systems, unsupported architectures, and missing45 bootstrap tools.462. Uses the exact immutable release tag pinned beside the publisher key in the47 reviewed bootstrap source.483. Downloads the versioned archive, checksum, and detached signature from that49 tag. Opening a new channel therefore requires a reviewed website commit.504. Verifies the embedded publisher key before extraction, then verifies the51 exact asset checksum.525. Extracts into a private temporary directory and invokes the package-owned53 atomic stager as the gaming user.546. Does not start or restart Sigil, overwrite identity or host configuration,55 modify `/etc`, or guess ambiguous hardware.5657`scripts/verify-sigil-bootstrap.py` keeps the channel fully closed while the58sentinels are present. Once opened, it requires the bootstrap's embedded key to59exactly match `release/sigil-minisign.pub` and rejects partial configuration or60a malformed immutable release tag before the website can deploy.6162A clean Bazzite image does not need a preinstalled Minisign package. The63bootstrap downloads the exact official Minisign 0.12 Linux archive and checks64its hard-coded SHA-256 before archive inspection, extraction, or execution. It65accepts only the reviewed archive layout (including its inert AppleDouble66metadata members), extracts only the x86_64 verifier into private temporary67state, and invokes that verifier by absolute path rather than trusting `PATH`.68Changing the verifier version, URL, or independently computed content digest69requires a reviewed website commit. The Sigil publisher key and release tag70remain separate pins and keep the release channel closed while either is71`unconfigured`.7273## Sigil candidate and offline signing ceremony7475The repository stores only the reviewed public key in76`release/sigil-minisign.pub`. Its committed `unconfigured` sentinel keeps every77promotion fail-closed until the offline publisher key exists. Never replace the78sentinel with a temporary or CI-generated key.7980For an immutable tag that exactly matches `crates/sigil-host/Cargo.toml`, run81the **Sigil Release** workflow with `build-candidate`. The protected `main`82environment builds clean tagged source, runs the complete repository gate,83creates exactly these unsigned draft assets, and retains the same bytes as a84short-lived Actions artifact:8586- `sigil-$tag-linux-glibc2.17-x86_64.tar.gz`87- `sigil-$tag-linux-glibc2.17-x86_64.tar.gz.sha256`8889Move those bytes to the offline publisher machine. After independently90confirming the tag commit and reviewed public key, sign without exporting the91secret key or its passphrase:9293```bash94scripts/sign-bazzite-release.sh \95 --tag "$tag" \96 --archive "/absolute/offline/path/sigil-$tag-linux-glibc2.17-x86_64.tar.gz" \97 --source-commit "$tag_commit" \98 --minisign-key /absolute/offline/path/sigil-release.key \99 --public-key-file /absolute/offline/path/sigil-minisign.pub100```101102Before promotion, run the **Portal release** workflow for the same tag. It103requires the untouched two-asset Sigil draft, attaches exactly the signed and104notarized Portal DMG, checksum, and manifest, verifies the five-asset combined105draft, and leaves it unpublished. Transfer only the resulting Sigil `.minisig`106back to the online release operator and attach it to that draft. Do not use107`--clobber` for any asset.108109Run **Sigil Release** again with `promote-signed-draft`. It requires the exact110six-asset public-alpha set, verifies the detached Sigil signature with the111committed public key, checks the outer digest, inspects the archive without112extraction, binds both products to the same tag and commit, re-verifies the113Portal digest and release manifest, then mounts the downloaded DMG on a native114arm64 macOS runner and repeats Developer ID, hardened-runtime, Gatekeeper,115stapling, architecture, identifier, and payload checks. Only then does it116replace the incomplete draft notes and publish the prerelease. The workflow has117no input, environment, or secret capable of118receiving the offline secret key.119120`scripts/package-bazzite-release.sh` intentionally cannot sign. Its product121mode requires a clean worktree, an existing tag resolving exactly to `HEAD`, a122tag equal to Sigil's Cargo version, and the stable public asset name. The two123development flags are an inseparable escape hatch and cannot claim a release124tag. `scripts/verify-sigil-release.sh` is the common candidate, offline, and125promotion verifier.126127No public goq release exists under the former distro-named suffix. Unpublished128drafts or locally staged candidates using `bazzite-x86_64` must be discarded129and rebuilt; release verification intentionally provides no compatibility130alias that could make two names identify the same public bytes.131132## Public Bazzite acceptance record133134Repository tests exercise a complete package fixture through fresh install,135same-release rerun, upgrade, rollback, identity/config preservation, hostile136payload rejection, and proof that no `systemctl start`, `restart`, or `enable`137was attempted. That is not a substitute for the public-command gate.138139Closing issue #4 still requires operator evidence from clean Bazzite using two140distinct signed candidates. Record, without node IDs or credentials:1411421. The Bazzite image/version, x86_64 architecture, public bootstrap SHA-256,143 release asset SHA-256, and release tag/commit.1442. A clean `curl -fsSL https://goq.sh/install-sigil | bash` installation with145 service active/enabled state captured before and after.1463. An idempotent rerun with unchanged `current`, `previous`, identity, and host147 configuration.1484. Promotion to the second signed candidate followed by the same public command,149 proving new `current`, old `previous`, and no implicit service interruption.1505. `sigil-spark-host-rollback` without `--restart`, proving the links reverse,151 all release checksums revalidate, and service state remains unchanged.152153## Portal signing boundary154155The existing macOS package gate requires a Developer ID Application identity,156hardened runtime, notarization, stapling, strict Gatekeeper assessment, and a157release build without `demo-direct-node`. Store the certificate and158notarization credentials only in the protected GitHub `main` environment with159required reviewers. The release workflow uses those secrets only in its macOS160arm64 publication job.161162Pin the public Apple TeamIdentifier in `release/portal-apple-team-id.txt` before163the first tag. The protected secret, produced app signature, promotion verifier,164and UAT verifier must all equal that committed value. The Portal tag-ref build165also emits GitHub artifact attestations; promotion requires each of the three166Portal assets to verify against the exact workflow, tag ref, and source commit.167168The first release automation must verify that the git tag, every Cargo package169version, Tauri version, artifact filenames, and manifests agree before it170publishes the GitHub Release. Upload every required asset to a draft release,171verify the complete set, and only then mark it as a prerelease.172173goq.sh reads `website/portal-release.json`, which is deliberately committed as174unavailable until an operator verifies the promoted prerelease and submits a175reviewed manifest change. Invalid, missing, or unavailable manifest data never176falls back to a development build. See the177[Portal release runbook](portal-release.md) for the issue #5 procedure.178179## Tracked gates180181- [Capability tickets and Portal onboarding](https://github.com/FelineStateMachine/goq/issues/3)182- [Signed Sigil package and install command](https://github.com/FelineStateMachine/goq/issues/4)183- [Signed and notarized Portal downloads](https://github.com/FelineStateMachine/goq/issues/5)184- [Public-alpha hardware and network acceptance](https://github.com/FelineStateMachine/goq/issues/6)