Sarala ships an opt-in auto-updater (Help ▸ Check for Updates…). It pulls a JSON manifest from a GitHub Gist, compares the version against the running build, and, if newer, downloads the signed artifact from a GitHub Release, verifies its minisign signature, installs it, and restarts the app.
- Updater config lives in
src-tauri/tauri.conf.jsonunderplugins.updater(pubkey+endpoints). - Update artifacts are produced by
bundle.createUpdaterArtifacts: true. - The frontend flow is
src/updater.ts; relaunch is the Rustrelaunchcommand (app.restart()) insrc-tauri/src/main.rs.
Updater artifacts must be signed; signing cannot be disabled in Tauri v2. This minisign key is separate from Apple/Windows code-signing.
pnpm tauri signer generate -w ~/.tauri/sarala.keyThis prints a public key and writes the password-protected private key to
~/.tauri/sarala.key.
- Paste the public key into
src-tauri/tauri.conf.json→plugins.updater.pubkey(replaceREPLACE_WITH_MINISIGN_PUBLIC_KEY). - Never commit the private key or its password. Keep them in
~/.tauri/and in GitHub Actions secrets.
The updater endpoint in tauri.conf.json points at this gist:
https://gist.githubusercontent.com/solancer/47a3dee0bace9ff5134878f55d887157/raw/latest.json
The /raw/ form without a revision hash always serves the latest revision, so
don't pin a revision in the endpoint, or the app will be stuck on one manifest.
CI rewrites this gist's latest.json on every release (see below).
The release workflow (.github/workflows/release.yml) needs three repo secrets
(Settings ▸ Secrets and variables ▸ Actions):
| Secret | Value |
|---|---|
TAURI_SIGNING_PRIVATE_KEY |
Contents of ~/.tauri/sarala.key (the minisign private key). |
TAURI_SIGNING_PRIVATE_KEY_PASSWORD |
The password you set when generating it. |
GIST_TOKEN |
A GitHub PAT with the gist scope. The default GITHUB_TOKEN is repo-scoped and cannot edit a user-owned gist. |
Building locally instead? Export the two
TAURI_SIGNING_*values in your shell beforepnpm tauri build(see the manual fallback at the bottom).
The snap is not built in GitHub Actions. It's built by the Snap Store
build service, which is connected to this repo and builds snap/snapcraft.yaml
(a core22, strictly-confined build that compiles the app and unpacks Tauri's
.deb into the snap) natively on amd64 and arm64. One-time setup:
-
Register the name once (the snap name must be globally unique):
snapcraft register sarala
-
Connect the repo: at https://snapcraft.io/sarala/builds, link the GitHub repository. From then on every push to
maintriggers a build and uploads the resulting revisions to the edge channel automatically, with no repo secret or workflow required (which is why there's nosnap.yml). -
Promote to stable from the snap's Releases page once a revision looks good (or
snapcraft release sarala <revision> stable). Edge is your testing channel;snap install sarala --edgeto try a build before promoting.
First-revision review: a brand-new snap's first revision goes through a one-time manual review by Canonical, and the store won't process newer uploads until that clears (you'll see "Waiting for previous upload(s) to complete their review process"). Clear or prioritize it from https://dashboard.snapcraft.io/, or ask on https://forum.snapcraft.io/c/store-requests. After it's approved, later revisions publish without manual steps.
Canonical's security bot scans published snaps daily and emails when a staged
.deb has since received a USN, for example "sarala contains outdated Ubuntu
packages" naming gstreamer1.0-plugins-good.
Nothing in this repo is at fault when that arrives. Those packages are not
listed in snapcraft.yaml; they come in transitively via libwebkit2gtk-4.1-0
and are frozen at whatever the Ubuntu archive held on the day the revision was
built. There is no version to bump and no automatic rebuild; the fix is
simply to build again so apt pulls the patched versions:
-
Trigger a build at https://snapcraft.io/sarala/builds (Trigger new build), or push any commit to
main, since the build service watches the repo. -
When the new revisions land in edge, promote them:
snapcraft release sarala <revision> stable
Both architectures need promoting; the email names one revision per arch (e.g. r17 amd64, r18 arm64).
Because the packages are pinned at build time, a snap that goes unreleased for a while will drift again. Rebuilding every month or two, or whenever one of these emails lands, keeps the published revision current without needing an app release.
Auto-updater note: a snap is a read-only image that the Snap Store keeps updated, so Tauri's in-app updater can't (and shouldn't) replace the binary there. The Check for Updates… action will simply fail to install inside the snap, and that's expected;
snap refreshis the update path for this package.
Casks/sarala.rb is a Homebrew cask served straight from this repo, so Mac users
can install without an Apple Developer account or notarization:
brew tap solancer/sarala https://github.com/solancer/sarala
brew trust --cask solancer/sarala/sarala
brew install --cask --yes saralaTwo Homebrew 6 behaviours are baked into that snippet, so keep it in sync with the README's copy:
brew trustis required: Homebrew 6 refuses to load casks from third-party taps until they're trusted, otherwise users hit "Refusing to load cask solancer/sarala/sarala from untrusted tap". (brew trust solancer/saralatrusts the whole tap instead of just this cask.)--yesskips the new confirmation prompt. Ask mode is the default in Homebrew 6, so a barebrew install --cask saralaprintsWould install 1 cask:and waits for input, which reads as a hang when an unrelated tap-trust warning scrolls the prompt off screen.
The universal .dmg is ad-hoc signed by Tauri's build (verified:
codesign reports flags=...(adhoc,linker-signed)), which is enough to run on
Apple Silicon. It is not Apple-notarized, so the cask's postflight strips
com.apple.quarantine after install, and that attribute is what makes Gatekeeper
demand notarization on first launch, so removing it lets the ad-hoc-signed app
open with no extra flags. This is deliberately disallowed by the official
homebrew/cask repo (which mandates notarization), but fine for our self-hosted
tap. Users who'd rather keep quarantine can install with --quarantine.
No setup needed: the update-cask job in release.yml bumps the cask's
version + sha256 to the new .dmg and commits it to main on every release.
If main is ever branch-protected, that push needs a PAT with contents:write
instead of the default GITHUB_TOKEN.
-
Bump + tag with the helper (updates
package.json,src-tauri/tauri.conf.json, andsrc-tauri/Cargo.toml, commits, tags):pnpm release 0.2.0 # then push when ready pnpm release 0.2.0 --push # or bump, tag, and push in one go
-
Pushing the
vX.Y.Ztag triggers.github/workflows/release.yml, which:- builds + signs on macOS (universal), Windows, and Linux;
- creates the GitHub Release
vX.Y.Zwith the installers and updater artifacts (Sarala.app.tar.gz,*-setup.exe,*.AppImage, each +.sig); - generates
latest.jsonand pushes it to the gist, which is the moment existing installs start seeing the update.
-
Watch it at https://github.com/solancer/sarala/actions. That's it, with no manual signature pasting.
The updater compares the manifest version against tauri.conf.json's
version, so step 1 keeping them in lockstep is what makes the update visible.
{
"version": "0.2.0",
"notes": "What's new in this release.",
"pub_date": "2026-06-16T10:00:00Z",
"platforms": {
"darwin-aarch64": {
"signature": "<contents of Sarala.app.tar.gz.sig>",
"url": "https://github.com/solancer/sarala/releases/download/v0.2.0/Sarala.app.tar.gz"
},
"darwin-x86_64": {
"signature": "<contents of Sarala.app.tar.gz.sig>",
"url": "https://github.com/solancer/sarala/releases/download/v0.2.0/Sarala.app.tar.gz"
},
"windows-x86_64": {
"signature": "<contents of the .exe.sig>",
"url": "https://github.com/solancer/sarala/releases/download/v0.2.0/Sarala_0.2.0_x64-setup.exe"
},
"linux-x86_64": {
"signature": "<contents of the .AppImage.sig>",
"url": "https://github.com/solancer/sarala/releases/download/v0.2.0/sarala_0.2.0_amd64.AppImage"
}
}
}Notes:
- A macOS universal build is listed under both
darwin-aarch64anddarwin-x86_64pointing at the same.tar.gz. If you ship per-arch builds instead, point each key at its own artifact. signatureis the contents of the.sigfile (a base64 blob), not a path or URL.
The minisign signature above is not Apple code-signing. On macOS, Gatekeeper blocks an unsigned/un-notarized auto-update the same way it blocks a first install. For a real public release you need both:
- The updater's minisign signature (above), and
- An Apple Developer ID codesigned + notarized
.app.
Until the Apple Developer account is set up, auto-updates will install but Gatekeeper may refuse to launch the replaced app on other machines. Windows has an analogous (softer) SmartScreen story; an Authenticode cert removes the warning.
If you ever need to release without the workflow:
-
Export the signing env vars:
export TAURI_SIGNING_PRIVATE_KEY="$(cat ~/.tauri/sarala.key)" export TAURI_SIGNING_PRIVATE_KEY_PASSWORD="<the password you set>"
-
pnpm tauri buildon each OS (no single host builds all three). Each emits the artifact plus a sibling.sig:- macOS:
Sarala.app.tar.gz+.sig - Windows:
Sarala_<ver>_x64-setup.exe+.sig - Linux:
sarala_<ver>_amd64.AppImage+.sig
- macOS:
-
Create a GitHub Release tagged
v<version>and upload the artifacts. -
Hand-edit the gist's
latest.json(shape above): bumpversion, setpub_date, paste each.sig's contents intosignature, and point eachurlat the Release download link.