Desktop — release checklist
Walk this checklist before pushing a desktop-v* (or v* if CLI + desktop release together) tag. It's the gate between "code is QA-clean on every platform" (covered by desktop-qa-checklist.md) and "the release is published, signed, and announced".
A box left unticked is a release that ships broken. Resist the urge to bypass.
1. Code freeze
- [ ] All changes intended for the release are merged to
main. - [ ] CI is green on the head commit (lint, unit tests, e2e tests, Trivy).
- [ ] docs/desktop-qa-checklist.md — assignment grid filled, every cell signed off.
- [ ] No P0 or P1 bugs labelled
desktop-qaopen against the release branch.
2. Versioning
- [ ]
package.jsonversion bumped (orrelease-itran successfully and bumped it). - [ ]
charts/iterion/Chart.yamlappVersionmatchespackage.json(CI guard would block otherwise; verify locally withtask chart:sync-version). - [ ]
CHANGELOG.mdupdated (release-it generates from conventional commits; spot-check for missing entries).
3. Signing prerequisites
These are hard prerequisites held outside the repo. Confirm each is current and accessible by the release operator before pushing the tag.
- [ ] Ed25519 updater key: GitHub secret
UPDATER_ED25519_PRIVATEis set, in PEM form, matches the public key embedded incmd/iterion-desktop/updater.go(updaterPublicKeyHexconstant). If the constant has changed since the last release, see "Key rotation" below. - [ ] macOS Apple Developer ID:
APPLE_DEVELOPER_ID_CERT(.p12) andAPPLE_DEVELOPER_ID_CERT_PASSWORDGitHub secrets present;APPLE_NOTARIZE_API_KEY(.p8) +APPLE_NOTARIZE_KEY_ID+APPLE_NOTARIZE_ISSUER_IDpresent. Cert validity > release date + 30 days. - [ ] Microsoft Authenticode:
WINDOWS_SIGNING_CERT(.pfx) andWINDOWS_SIGNING_CERT_PASSWORD(or SignPath / Azure Trusted Signing config) present. Cert validity > release date + 30 days. - [ ] GPG signing key for Linux:
GPG_PRIVATE_KEYandGPG_PASSPHRASEGitHub secrets present (for signing.deb+.AppImage). Public key published to the org's key server /KEYSfile in the release.
If any of these is missing or expired:
- For Ed25519: see "Key rotation".
- For Apple / Microsoft / GPG: pause the release until the operator with cert custody has refreshed the secret. Skipping signing on a public release is grounds to not ship.
4. Release-pipeline dry run (optional but recommended)
- [ ] On a feature branch, run
gh workflow run desktop-release.yml -f dry_run=true(if the workflow supports it) or use adesktop-vX.Y.Z-rc1pre-release tag. - [ ] Verify all 6 platform jobs succeed (macOS universal, windows/amd64, windows/arm64, linux/amd64, linux/arm64).
- [ ] Verify
generate-manifest.shproduced valid JSON (jq -e .against the artefact). - [ ] Verify the generated
.sigfiles are valid Ed25519 signatures of their corresponding artefacts (sample: download one binary + its.sig, runopenssl pkeyutl -verify -pubin -inkey updater_ed25519.pub -rawin -in <artefact> -sigfile <artefact>.sig).
5. Trigger the release
- [ ] Tag and push:
git tag v<X.Y.Z> && git push origin v<X.Y.Z>(or use therelease-itflow). - [ ] Watch
desktop-release.ymlsucceed end-to-end. - [ ] Watch
release.yml(CLI) succeed end-to-end (parallel job on the same tag). - [ ] Watch
brew-update.yml(workflow_runon the above) succeed and patch the brew tap's cask SHA.
6. Post-publish verification
- [ ]
gh release view v<X.Y.Z>shows all expected artefacts (6 binaries × {bundle, .sig} + manifest + manifest.sig + checksum + GPG sigs for Linux). - [ ] Download and run a binary on each platform that wasn't covered by CI:
- Open the .zip on a real Apple Silicon Mac →
/Applications/Iterion.appopens cleanly via Gatekeeper. - Run the .exe-installer on a Windows host → SmartScreen accepts (post Authenticode warmup).
chmod +xand run the AppImage on Ubuntu → opens.
- Open the .zip on a real Apple Silicon Mac →
- [ ] Auto-update test: install vN-1 on a real machine, run
Help → Check for updates, watch the upgrade complete. - [ ] Brew tap:
brew update && brew install iterion-desktop(orbrew upgrade iterion-desktop) → installs vN.
7. Announcement (optional but expected for v1.0)
- [ ] Release notes drafted from
CHANGELOG.mdand the manifesto's "what's new" framing. - [ ] GitHub Release body populated with the announcement.
- [ ] Blog post / changelog entry / tweet drafted.
- [ ] Update README.md "latest release" badges (if any).
- [ ] Update why-iterion.md "How to start" if the install URL or scaffolding differs.
8. Rollback contingency
If a release artefact ships a critical bug after publication:
- [ ] Yank the manifest: edit the GitHub Release to remove or replace
iterion-desktop-manifest.jsonso existing users don't auto-update to the broken version. New users land on a stale version, which is preferred. - [ ] Re-tag a
vX.Y.Z+1patch release with the fix and publish; auto-update will lift users off the broken version. - [ ] Revert the brew cask to the previous good version manually (the cask edits live in the iterion-brew tap repo).
- [ ] Communicate: pin a notice on the GitHub Release describing the issue, recommended action, and patch ETA.
- [ ] Post-mortem: track the regression that escaped CI/QA; add a scenario to desktop-qa-checklist.md so it can't recur.
Key rotation (Ed25519 updater key)
The Ed25519 keypair signing the manifest + artefacts is the trust root for auto-update. Rotate it when:
- The private key is exposed (anywhere outside the GitHub secret store).
- The release operator with custody changes (transfer is itself an exposure window).
- It's been > 2 years since last rotation (defence-in-depth; algorithm is fine, custody isn't).
Rotation procedure:
- Generate a new keypair:
./scripts/desktop/ed25519-keygen.sh ./new-keys. - Update
cmd/iterion-desktop/updater.goupdaterPublicKeyHexto the new public key (hex-encoded). - Cut a release with both the old and new public keys recognised — temporarily widen
verifyManifestto accept either signature, ship that release, wait until > 95% of installs have updated. - Cut a follow-up release that drops the old public key.
- Update the GitHub secret
UPDATER_ED25519_PRIVATEto the new key. - Securely destroy the old private key.
Without the dual-key bridge, users on the old version can't update past the rotation point because their embedded public key won't verify the new manifest.
What's not here
- CLI-only release process — covered by
release.ymland the conventional-commits / release-it flow. The desktop release rides the same tag. - Detailed cert provisioning (how to request an Apple Developer ID, etc.) — out of scope; once you have the cert, this checklist tells you how to use it.
- Marketing / press kit — that's a product call, not a release-engineering call.
