Skip to content

Desktop app — release, signing & auto-update

Covers the developer-credential work (TODO §D4). The pipeline is .github/workflows/desktop-release.yml; trigger it by pushing a desktop-v* tag.

終端機視窗
cargo tauri signer generate -w ~/.tauri/duduclaw.key
  • Put the public key in src-tauri/tauri.conf.json > plugins.updater.pubkey.
  • Put the private key + password in repo secrets TAURI_SIGNING_PRIVATE_KEY / TAURI_SIGNING_PRIVATE_KEY_PASSWORD.

The updater endpoint is the GitHub latest.json (already configured). On each release tauri-action emits a signed latest.json; the client verifies the signature before installing, and rejects a mismatch (§D4.4).

Secrets:

Secret What
APPLE_CERTIFICATE base64 of the Developer ID Application .p12
APPLE_CERTIFICATE_PASSWORD its password
APPLE_SIGNING_IDENTITY Developer ID Application: <Name> (<TEAMID>)
APPLE_ID / APPLE_PASSWORD Apple account + app-specific password
APPLE_TEAM_ID 10-char team id

tauri-action signs (hardened runtime, using src-tauri/entitlements.plist) and notarizes when these are present. For a manual artifact use scripts/desktop/sign-notarize-macos.sh.

Acceptance (§D4.1): download the .dmg on a machine that never saw the cert → it opens with no “unidentified developer” Gatekeeper prompt.

Secrets WINDOWS_CERT_PFX_BASE64 / WINDOWS_CERT_PASSWORD. The workflow signs the .msi via scripts/desktop/sign-windows.ps1. Acceptance (§D4.2): SmartScreen does not block (EV = immediate trust).

.AppImage + .deb are built unsigned (WebKitGTK runtime dep declared). Not a release blocker (§D4.3).

The normal path is the core release ritual — scripts/release.sh <bump> bumps src-tauri/tauri.conf.json with every other manifest and tags BOTH v<X.Y.Z> and desktop-v<X.Y.Z> on the bump commit; git push --tags then triggers this pipeline alongside the core one. (Desktop sat frozen at 1.33.0 for 11 releases while these were separate manual steps — don’t go back to hand-tagging.)

For a desktop-only rebuild of an existing version:

終端機視窗
git tag desktop-v1.44.0 <bump-commit>
git push origin desktop-v1.44.0

The workflow builds the 4-target matrix, signs/notarizes, and publishes the release directly (no draft) with installers + latest.json. A final job copies latest.json to the fixed-tag desktop-updater release — that fixed URL is the updater endpoint, because releases/latest/... would point at the much more frequent core releases and 404.

5a. Updates when attached to an external gateway (unreleased)

Section titled “5a. Updates when attached to an external gateway (unreleased)”

The shell still downloads new versions in the background. When it runs its own gateway sidecar it behaves as before: notification, tray「重啟並更新」, install on quit. When it is attached to a gateway it does not own, the app and the gateway are separate installs on separate channels, so the shell does not install on its own: the notification and the tray item point at the dashboard 系統更新 page, and quitting does not install the staged update. That page updates the gateway first and the app only up to the gateway’s version. The page reads the relation through the desktop_update_info command (bundled or external).

  • Never commit certs/keys; only GitHub secrets.
  • Rotate the Apple app-specific password and the updater key on personnel change.
  • Keep tauri.conf.json version == core Cargo.toml workspace version so the updater never ships a shell/core mismatch (§D4.4 / §D4.5).