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 these 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. |
APPLE_CERTIFICATE |
The Developer ID Application certificate and its private key, exported from Keychain as .p12, base64 encoded. |
APPLE_CERTIFICATE_PASSWORD |
The .p12 export password. |
APPLE_SIGNING_IDENTITY |
Developer ID Application: Lenzo International Private Limited (6WUKC69WYX) |
APPLE_TEAM_ID |
6WUKC69WYX |
APPLE_ID |
An Apple ID on that team, for notarization. |
APPLE_PASSWORD |
An app-specific password for that Apple ID (account.apple.com ▸ Sign-In and Security). |
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:
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 .dmg and the app in it are signed and notarized (see Code signing below),
so the cask installs them as they are, with nothing stripped.
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,
after notarize-dmg has stapled it.
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 only lets the updater trust a download. Gatekeeper
needs the app itself signed with a Developer ID and notarized by Apple, which
the macOS build does with the APPLE_* secrets. Local pnpm tauri builds stay
ad-hoc signed ("signingIdentity": "-" in tauri.conf.json); the
APPLE_SIGNING_IDENTITY variable overrides it in CI.
To test the Apple secrets without releasing, run the macOS signing check
workflow (Actions tab, or it runs on PRs that touch the signing setup). It
builds a signed, notarized app and checks it with codesign, spctl and
stapler.
The certificate expires on 26 November 2027. Before then, the Account Holder
creates a new Developer ID Application certificate from a fresh signing request
(Keychain Access ▸ Certificate Assistant ▸ Request a Certificate From a
Certificate Authority), and the new .p12 replaces APPLE_CERTIFICATE and
APPLE_CERTIFICATE_PASSWORD. Apps already shipped keep working after it
expires. On a Mac without Xcode, security find-identity -v -p codesigning
only lists the certificate once Apple's
Developer ID G2 intermediate
is in the keychain.
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.