Skip to content

Add desktop auto-update (Tauri v2 updater)#317

Merged
ericflo merged 1 commit intomainfrom
desktop-auto-update
Apr 16, 2026
Merged

Add desktop auto-update (Tauri v2 updater)#317
ericflo merged 1 commit intomainfrom
desktop-auto-update

Conversation

@ericflo
Copy link
Copy Markdown
Owner

@ericflo ericflo commented Apr 16, 2026

Why

You wrote: "I am worried that if I install it I'll have to keep installing it. please work out an auto-update mechanism and make sure it works on all platforms."

This PR wires up Tauri v2's updater plugin end-to-end so users never have to manually reinstall. The app silently checks on launch, offers to install when a new `desktop-v*` release is published, verifies a minisign signature against the baked-in pubkey, and installs in place.

How it works

ModelRelay.app ──GET──▶ modelrelay.io/updater/desktop/{target}/{arch}/{current_version}
                                        │
                                        └──▶ GitHub Releases API (5-min cache)
                                             └──▶ find *.app.tar.gz / *.AppImage / *-setup.exe + .sig
                                                  └──▶ return JSON { version, url, signature, notes }
                                                       or 204 No Content if current >= latest
  • Check on launch — 5s after startup, silent; dialog only if an update is available.
  • Check from tray / Settings — explicit user action, shows success/no-update state.
  • Cross-platform — Linux .AppImage, macOS .app.tar.gz (aarch64 + x64), Windows -setup.exe (NSIS).
  • Signed — every bundle is verified against the minisign pubkey in `tauri.conf.json` before install. A forged binary can't be installed even if GitHub or the CDN were compromised.

Changes

  • `crates/modelrelay-desktop`:
    • New `updater.rs` module (launch check, manual check, download-progress events).
    • Register `tauri-plugin-updater`, `tauri-plugin-dialog`, `tauri-plugin-process`.
    • Tauri v2 capability file granting updater/dialog/process permissions.
    • Tray menu: Check for Updates… + Settings card with version, progress bar, install button.
    • `tauri.conf.json`: `createUpdaterArtifacts: true`, custom endpoint, pubkey baked in.
  • `crates/modelrelay-cloud`:
    • New `/updater/desktop/{target}/{arch}/{current_version}` route. Returns Tauri's dynamic-server JSON on match, 204 otherwise. Caches the latest release lookup for 5 min and signature file contents for process lifetime.
    • 6 new unit tests covering semver compare, target/arch → filename-suffix mapping, and bundle/sig pairing. All 44 tests pass.
  • `.github/workflows/desktop-release.yml`: pass `TAURI_SIGNING_PRIVATE_KEY` + `_PASSWORD` env vars so `tauri-action` signs the updater bundles.
  • `docs/auto-updates.md`: full explainer — architecture, release flow, key rotation, troubleshooting. README now links to it.

Action required before merge

Add two GitHub Actions secrets to `ericflo/modelrelay`:

Secret Value
`TAURI_SIGNING_PRIVATE_KEY` Full contents of the private key file (the text, not a path).
`TAURI_SIGNING_PRIVATE_KEY_PASSWORD` Empty string (the keypair I generated has no password).

I generated a keypair locally. The public key is already committed to `tauri.conf.json`. You'll receive the private key out-of-band (not in this PR body) to add as the secret above — or you can regenerate your own with `cargo tauri signer generate` and update both the secret and the `pubkey` field.

Without those secrets set, the release workflow still builds installers but won't upload `.sig` files, and the cloud updater endpoint will return 204 (refuses to serve unsigned bundles). Safe fallback, but no auto-update until keys are configured.

Rollout

  1. Merge this PR.
  2. Set the two GitHub secrets.
  3. Tag a release: `git tag desktop-v0.1.2 && git push origin desktop-v0.1.2`.
  4. Users on 0.1.1 will pick up 0.1.2 on their next launch (~5 min cache). First-time users still download from GitHub manually; every release after that is in-place auto-update.

Test plan

  • `cargo fmt --check -p modelrelay-cloud -p modelrelay-desktop` — clean
  • `cargo clippy -p modelrelay-cloud --lib --tests -- -D warnings` — clean
  • `cargo nextest run -p modelrelay-cloud` — 44/44 pass (6 new)
  • Desktop crate `cargo check` — needs GTK system libs (will run on CI Linux/mac/Windows runners)
  • After merge + secrets: tag `desktop-v0.1.2`, confirm `.sig` files appear on the release, install 0.1.1, hit Check for Updates…, verify it downloads and installs 0.1.2.

🤖 Generated with Claude Code

Users no longer need to manually reinstall the desktop app to get new
versions. The app checks for updates on launch and from the tray menu,
verifies minisign-signed bundles against a baked-in pubkey, and installs
them in place.

Changes:
- `modelrelay-desktop`: add tauri-plugin-updater/dialog/process, a
  capability file for v2's explicit-permissions model, a new updater
  module with launch-check + manual-check flows, tray menu entry, and a
  Settings card showing version + progress.
- `modelrelay-cloud`: new `/updater/desktop/{target}/{arch}/{current_version}`
  route that returns Tauri's dynamic updater JSON by looking up the
  latest `desktop-v*` GitHub release (5-minute cache) and reading the
  matching `.sig` file contents. 204 No Content when the client is at or
  ahead of latest, or when no signed artifact exists for that target.
- `.github/workflows/desktop-release.yml`: pass TAURI_SIGNING_PRIVATE_KEY
  / _PASSWORD env vars so tauri-action signs the updater bundles.
- `docs/auto-updates.md`: end-to-end explanation, release workflow,
  signing-key rotation, troubleshooting.

All existing modelrelay-cloud tests still pass; six new tests cover
semver comparison, platform→suffix mapping, and bundle/sig pairing.
@ericflo ericflo merged commit 3fe7a93 into main Apr 16, 2026
6 of 12 checks passed
@ericflo ericflo deleted the desktop-auto-update branch April 16, 2026 22:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant