After a GitHub Release is published, .github/workflows/publish.yml fans it
out to the package channels below. Each channel is a thin pointer at the
release's attested artifacts; nothing is rebuilt. Jobs whose secret isn't
configured yet skip with a notice, so channels can be enabled one at a time.
Before anything else: create an environment protection rule —
Settings → Environments → release-publish → add yourself as a required
reviewer. Every fanout job then pauses for one click before any publish
credential is touched.
- First publish is manual, in dependency order (see the runbook in
TODO-hardening.md):cargo login, thencargo publish -p <crate> --lockedtier by tier. - On crates.io, for each crate: Settings → Trusted Publishing → add
GitHub repository
framefilter/keyroost, workflowpublish.yml, environmentrelease-publish. - Done — future releases publish via short-lived OIDC tokens; there is no long-lived secret to steal.
- Create an AUR account; add a dedicated SSH key to it (not your personal key).
- Create the package base once: clone
ssh://aur@aur.archlinux.org/keyroost-bin.git, renderpackaging/aur/{PKGBUILD,.SRCINFO}.templateby hand for the current release (fill@VERSION@,@SHA_LINUX@from SHA256SUMS,@SHA_UDEV@= sha256 ofudev/70-keyroost-fido.rules), commit, push. - Add the SSH private key as repo secret
AUR_SSH_PRIVATE_KEY.
- Create a public repo
framefilter/homebrew-keyroost(empty is fine; the workflow createsFormula/keyroost.rb). - Create a fine-grained PAT with
contents: writeon that repo only; add it as secretTAP_PUSH_TOKEN. - Users:
brew tap framefilter/keyroost && brew install keyroost.
-
First submission is manual (Microsoft reviews new packages): fill the three templates in
packaging/winget/(@VERSION@, and@SHA_WIN@from the signed zip's.sha256sidecar — see the note below) and PR them tomicrosoft/winget-pkgsundermanifests/f/Framefilter/Keyroost/<version>/, or runwingetcreate newinteractively. -
Create a classic PAT with
public_repo; add it as secretWINGET_TOKEN. -
Version bumps are PR'd by the workflow, but not on the release run. Since v0.7.6 the winget job holds for the Token2-signed Windows build (policy, 2026-07-17): on the tag fanout it prints
winget is HOLDING for the Token2-signed buildand exits 0. That skip is the designed outcome, not a failure. The submission happens later:tag → fanout (winget notices + skips) → Token2 signs → maintainer attaches keyroost-vX.Y.Z-windows-x86_64-signed.zip (+ .sha256) as NEW assets (never replacing the CI zips — that invalidates SHA256SUMS/provenance) → gh workflow run publish.yml -f tag=vX.Y.Z → every other job no-ops; winget Authenticode-verifies every PE in the zip, then submits the PRMicrosoft's validation pipeline merges routine bumps within hours to days. A hard failure of this job (rather than a skip) means the
WINGET_TOKENPAT is set but rejected — renew it. Full release-day sequence:RELEASING.mdsteps 4–5.
git tag vX.Y.Z && git push origin vX.Y.Z
→ release.yml: builds Linux/macOS/Windows archives, SHA256SUMS,
provenance attestation, publishes the GitHub Release
→ linux-bundles.yml (same tag, in parallel): AppImage + flatpak bundle,
attached to that same Release
→ publish.yml (after your one-click environment approval):
crates.io — the whole workspace in dependency order (OIDC)
AUR — keyroost-bin PKGBUILD/.SRCINFO push
Homebrew — tap formula push
winget — SKIPS with a notice: holds for the Token2-signed zip,
then submits on a re-dispatch (see above)
→ cargo-binstall needs nothing: it finds the new archives by version