Skip to content

feat: tell the operator when a newer release exists - #174

Open
faithfulojebiyi wants to merge 1 commit into
mainfrom
feat/update-available-notice
Open

feat: tell the operator when a newer release exists#174
faithfulojebiyi wants to merge 1 commit into
mainfrom
feat/update-available-notice

Conversation

@faithfulojebiyi

Copy link
Copy Markdown
Contributor

Option A from the update discussion: a notice, not an updater. It never downloads or installs anything.

Today there is no update mechanism at all, so anyone who installed a broken build is stranded — v0.3.0 shows "damaged", v0.3.1 has a dead microphone, and neither will ever tell its user that v0.3.2 fixed it.

What it does

  • Toast once per launch when a newer release is published, with a Download action. A toast rather than a persistent banner because this app is on screen during live services; an optional download must not compete with the verse being broadcast. Dismissed is dismissed until next launch.
  • Settings → Diagnostics row beside the existing version: "Up to date" / "Rhema 0.3.3 is available" / "Update check unavailable", with Download or "Check again".

Design notes

  • The check runs in Rust, not the webview. The app's CSP is connect-src 'self'; a version string isn't worth widening it for.
  • Failures render nothing. fetchUpdateStatus resolves to null — being offline is ordinary in a church building, not an incident worth a dialog.
  • Unparseable versions never prompt. Prerelease tags, nightly, garbage → "not newer", so a version we can't reason about can't nag anyone. /releases/latest already excludes prereleases and drafts.
  • tauri-plugin-opener was dead weight: the JS package was a dependency but the Rust plugin was never initialised and had no capability entry, so opening a URL would have failed. Now registered, with its permission scoped to https://github.com/openbezal/rhema/* rather than arbitrary URLs.

Verification

Unit tests, then mutation-tested to prove they aren't decorative. I wrote tests and implementation in one pass rather than test-first, so instead of claiming the discipline I checked the guarantee it's meant to provide — three deliberate mutations, each caught:

Mutation Tests failed
is_newer always returns false 4
comparison inverted (l < c) 5
v prefix no longer stripped 1

Green again after restoring. 8 Rust tests cover patch/minor/major, v prefix, ragged component counts, double-digit components (0.10.0 > 0.9.0), unparseable input, and payload parsing with unknown fields. 2 frontend tests cover the silent-failure contract.

End-to-end in a real signed bundle, both paths, read from the log rather than assumed:

[UPDATE] current=0.3.2 latest=0.3.2 newer=false     ← no toast, correct
[UPDATE] current=0.3.0 latest=0.3.2 newer=true      ← toast shown

The second was forced by temporarily lowering the bundle version, and I screenshotted the running app to confirm the toast actually renders: "Rhema 0.3.2 is available / You are running 0.3.0." with a Download button. The temporary version change is reverted; git diff on tauri.conf.json is empty.

Regression checks against the v0.3.2 fixes (since signing/entitlements were the last two regressions):

Check Result
Entitlements still embedded disable-library-validation ✓, device.audio-input
Mic usage string in Info.plist present
Signature before launch valid
Signature after launch valid
NDI dylib loadable under these entitlements LOADED

Suite: 222 frontend tests, 23 Rust tests, cargo clippy clean on the new file, and zero new lint problems (145 with and without the change, via stash -u).

Two process problems this surfaced

  1. bun run typecheck was a no-op. tsc --noEmit against a solution tsconfig.json with "files": [] checks zero project files — --listFiles confirms. It passed while this branch had a real type error, which only bun run build's tsc -b caught. Changed to tsc -b --noEmit and verified by injecting a deliberate error and watching it fail.
  2. My first "no regressions" check was worthless — the build had failed and I inspected the stale bundle. Caught by reading the build log rather than trusting the exit path.

Not included (deliberately)

Auto-install, "skip this version" persistence, update channels. Full auto-update (tauri-plugin-updater) is worth doing once there's an Apple Developer ID — with ad-hoc signing, every auto-update would likely re-prompt for microphone permission, since macOS ties TCC decisions to signing identity.

There is no update mechanism at all today, so anyone who installed a
broken build has no way to learn a fix shipped — v0.3.0 shows "damaged"
and v0.3.1 has a dead microphone, and both are dead ends for whoever
downloaded them.

This is a notice, not an updater: it never downloads or installs
anything. A toast once per launch when a newer release is published, and
a row in Settings > Diagnostics beside the version with Download and
"Check again". A toast rather than a persistent banner because this app
is on screen during live services, and an optional download must not
compete with the verse being broadcast.

The check runs in Rust rather than the webview. The app's CSP is
`connect-src 'self'`, and a version string is not worth widening it for.
Failures resolve to null and render nothing — being offline is ordinary
in a lot of church buildings, not an incident worth a dialog.

Version comparison is numeric per component with zero-padding for ragged
counts, and anything unparseable — prerelease tags, "nightly", garbage —
reports "not newer" so a version we cannot reason about never nags
anyone to install it. /releases/latest already excludes prereleases and
drafts, so only complete public releases are ever reported.

Also registers tauri-plugin-opener on the Rust side. The JS package was
already a dependency but the plugin was never initialised and had no
capability entry, so opening a URL would have failed. Its permission is
scoped to https://github.com/openbezal/rhema/* rather than allowing
arbitrary URLs.

Fixes the typecheck script while here: `tsc --noEmit` against a solution
tsconfig with `files: []` checked zero files and had been silently
passing. Build mode follows the project references, and it immediately
caught a real narrowing error in this change.
@manuelinfosec

Copy link
Copy Markdown
Collaborator

Screenshot?

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.

2 participants