Files
Tomas DvorakandDevin edef002beb feat: Desktop auto-updater + release SBOMs
- tauri-plugin-updater + process: pubkey embedded in tauri.conf.json,
  createUpdaterArtifacts, endpoint = GitHub latest.json manifest.
- Connect screen checks before auto-connect (bounded 5s) — a saved
  URL would otherwise navigate away before the check resolves.
  "Update & restart" downloads, verifies minisign, installs, relaunches.
- Release workflow signs updater artifacts with
  TAURI_SIGNING_PRIVATE_KEY secrets, ships the .sig files, and assembles
  latest.json from them. No key → no manifest → no update, never a
  silent unsigned install.
- anchore/sbom-action emits CycloneDX SBOMs per GHCR image plus the
  source tree, attached to every release.

Note: the signing keypair was generated locally
(~/.tauri/primora-updater.key); the private half must be added to repo
secrets before the next release for updates to activate.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-24 20:41:16 +02:00

2.9 KiB

@primora/desktop

Tauri 2 shell around a self-hosted Primora deployment. On first run it asks for the deployment URL; after that the webview renders the same SolidJS console the server serves. Nothing is embedded — no backend, no database. The self-hosted model is preserved.

Prerequisites

  • Rust (rustup) and Node.js.
  • Linux webview deps: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev

Run

npm run dev --workspace @primora/desktop      # dev window (debug build)
npm run bundle --workspace @primora/desktop   # release bundles → src-tauri/target/release/bundle

Notes

  • Config lives at ~/.config/dev.tdvorak.primora/config.json — one field, server_url.
  • System tray: Show Primora, Change Server… (clears the URL, back to the connect screen), Quit. Closing the window hides to the tray; a second launch focuses the existing window (single-instance).
  • The connect screen only checks that the host answers; if the URL turns out not to be a Primora deployment, use the tray's Change Server.
  • macOS blocks plain-HTTP loads to non-localhost hosts (ATS). Use HTTPS, or http://localhost for a local deployment.

Secrets Vault

The tray menu's Secrets Vault… opens a local window (ui/vault.html) for the CLI's encrypted vault — init, timed unlock/lock, list with copy-to-clipboard, add/delete, .env import. Values are never displayed; copy goes straight to the clipboard.

The desktop app does not reimplement the vault: IPC commands shell out to the primora binary on PATH (PRIMORA_CLI overrides the binary path). One vault file, one crypto implementation — terminal and desktop always agree. Requires npm i -g @primora/cli; without it the window shows install instructions.

Injection and the credential broker stay CLI-only (primora inject, primora agent).

  • Deep links / push notifications: deliberately omitted — nothing needs them yet.

Auto-updates

tauri-plugin-updater checks releases/latest/download/latest.json on the GitHub repo when the connect screen loads; if a newer signed release exists it offers "Update & restart" — download, minisign verification, install, relaunch. No update manifest or signature failure = silent no-op; unsigned artifacts can never install.

Release side (already wired in .github/workflows/release.yml): the desktop job signs updater artifacts with TAURI_SIGNING_PRIVATE_KEY (+ optional TAURI_SIGNING_PRIVATE_KEY_PASSWORD) repo secrets, uploads the .sig files, and the release job assembles latest.json from them. Without the secret the build still succeeds but emits no signatures — and no manifest.

The matching public key is embedded in tauri.conf.json. The private key lives only in repo secrets and on the maintainer's machine — regenerate with npx tauri signer generate and update both if it is ever lost.