Desktop signing & autoupdate
Status: draftTwo kinds of signing
- Apple code signing + notarization — proves the
.app/.dmgcomes from a known developer so macOS runs it without warnings. Uses a Developer ID Application certificate and Apple notarization. These are account-level, so the same credentials used elsewhere (e.g. an Electron project via electron-builder) work here — only the variable names differ. - Tauri updater signing — a separate keypair Tauri uses to sign update packages so the app trusts them. This is Tauri-specific; there is no equivalent in an Electron setup, so it's a new secret. The public key is committed in
apps/desktop/src-tauri/tauri.conf.json; the private key is a secret.
Variable mapping (electron-builder / Brainstorm → Tauri)
bun run desktop:build (and the release workflow) accept either name; the build maps them:
| Purpose | Brainstorm / electron-builder | Tauri |
|---|---|---|
| Developer ID cert (base64 .p12) | CSC_LINK / MAC_CSC_LINK |
APPLE_CERTIFICATE |
| …its password | CSC_KEY_PASSWORD / MAC_CSC_KEY_PASSWORD |
APPLE_CERTIFICATE_PASSWORD |
| Notarize (Apple ID) | APPLE_ID |
APPLE_ID |
| …app-specific password | APPLE_APP_SPECIFIC_PASSWORD |
APPLE_PASSWORD |
| …team id | APPLE_TEAM_ID |
APPLE_TEAM_ID |
| Notarize (API key) — key id | APPLE_API_KEY_ID |
APPLE_API_KEY |
| …issuer | APPLE_API_ISSUER |
APPLE_API_ISSUER |
| …key file path (.p8) | APPLE_API_KEY |
APPLE_API_KEY_PATH |
| Updater private key (new) | — | TAURI_SIGNING_PRIVATE_KEY (+ _PASSWORD) |
Local signed build
# Apple creds (reuse your existing ones) + the updater key, in your env:
export CSC_LINK=... CSC_KEY_PASSWORD=... APPLE_ID=... APPLE_APP_SPECIFIC_PASSWORD=... APPLE_TEAM_ID=...
export TAURI_SIGNING_PRIVATE_KEY="$(cat /path/to/swarm-updater.key)"
bun run desktop:build # signs + notarizes, and emits updater artifacts + .sig
With none set, desktop:build produces an unsigned dev build.
CI (GitHub Releases)
.github/workflows/release.yml builds on a v* tag. Set these repository secrets (the Apple ones are the same values used for the other project):
CSC_LINK, CSC_KEY_PASSWORD, APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD, APPLE_TEAM_ID, TAURI_SIGNING_PRIVATE_KEY, TAURI_SIGNING_PRIVATE_KEY_PASSWORD (empty if the key has no password).
The workflow uploads the .dmg plus the updater artifacts and latest.json to a draft Release; the app's updater polls releases/latest/download/latest.json.
The updater keypair
Generated once with bunx tauri signer generate. The public key lives in tauri.conf.json. Keep the private key secret (repo secret + a safe backup) — losing it means shipped apps can no longer verify updates.
Source: docs/11-desktop-signing.md · v0.8.0.