update_apply used to flatly refuse to run for the GUI binary and point
the user to a manual download instead. Since both desktop apps already
elevate to root/administrator before showing their window, the
process applying the update already has everything it needs — no
second authentication round is required.
- New guara_core::update::apply_desktop[_with_progress], alongside the
existing CLI-only apply() (left untouched): detects the install kind
at runtime (AppImage via the APPIMAGE env var — current_exe() is
unreliable there, same FUSE-mount issue elevated_exe() already works
around and this reuses; Deb otherwise on Linux; WindowsInstaller on
Windows), matches the right release asset by the GUI bundle naming
(_amd64/_aarch64.AppImage, _amd64/_arm64.deb, _x64-setup.exe — a
different suffix convention than the CLI tarballs), verifies SHA-256
when a sidecar is published, and installs:
- AppImage: downloads to a temp file in the same directory (same
filesystem, atomic rename), renames over the running file, execs
it in place (same PID, same already-root privileges — no elevation
dance needed).
- .deb: runs `dpkg -i` directly (already root), then execs
current_exe() again now that dpkg replaced it on disk.
- Windows: runs the downloaded installer with /S (silent) detached,
then exits immediately to release the file lock on our own .exe.
Does NOT claim to relaunch the app afterwards — there is no
documented NSIS or Tauri flag for that (verified against NSIS's
and Tauri's own docs: Tauri's own updater restarts the app from its
own Rust code after the installer exits, not via a command-line
switch), and blocking here on the installer's exit status risks a
self-deadlock if its script waits for this process to close before
it can overwrite the running .exe. Needs a real Windows machine to
confirm the actual post-install behavior.
- Engine::update_apply_desktop wires it into the Tauri `update_apply`
command, which now also takes AppHandle and emits `update-progress`
events (downloading/verifying/installing/restarting) for the UI.
- Sabiá: the existing #btnUpdate handler changed the button's label to
"update to X" but never actually called apply — wired it for real,
with the same progress feedback.
- Guará: restored the "Update now" action in the update card (removed
during the updater-unification migration), wired to the new command.
- scripts/build-gui.sh: generates a .sha256 next to every file in
dist-gui/, matching the existing convention for CLI release
archives, so apply_desktop can verify downloads the same way CLI
update --apply already does.
- 3 new unit tests per repo: install-kind detection, GUI asset suffix
matching against real release naming, and the existing CLI-refusal
test still passes unchanged.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
Replaces the signed tauri-plugin-updater (latest.json manifest, minisign
key pair) with the same simple mechanism Sabiá already uses: query the
Gitea Releases API directly, download the matching platform archive,
verify its SHA-256 checksum, and swap the binary in place. The CI job
that built the old latest.json manifest is removed in the next commit,
alongside an unrelated runner-routing change to the same workflow file.
- New guara-core::update module (check/apply), ported from
sabia-core::update and adapted to Guará's own release asset naming
(guara-<tag>-<platform>.tar.gz, matching scripts/package-cli.sh).
- New Engine::update_check / Engine::update_apply, wired into the RPC
service for the browser UI.
- New CLI subcommand: "guara update" (check) and "guara update --apply"
(download, verify, replace), mirroring "sabia update".
- GUI: replaced the Tauri plugin-updater flow (download_and_install,
update-progress events, in-app restart) with a call to the new
update_check/update_apply commands. The desktop app can no longer
self-install in one click — it now points the user to the Releases
page, same as Sabiá's desktop app already does.
- Removed tauri-plugin-updater, createUpdaterArtifacts and the
updater.pubkey config, the signing-key loading in build-gui.sh, the
CI step testing the old latest.json generator, and the now-unused
make-latest-json.py/test_make_latest_json.py scripts.
- Documented the break for existing installs in CHANGELOG.md /
CHANGELOG.pt-BR.md: versions up to 1.3.2 won't find this release
automatically and need one manual download.
Trade-off accepted knowingly: SHA-256 verifies integrity against
Gitea's own API but, unlike the retired signed mechanism, does not
protect against a compromised Gitea server independently of it. This
is Lucas's own self-hosted instance, not a third-party mirror.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
On the aarch64 Gitea runner, tauri-bundler's prepare_tools step runs
'dd ... seek=8 conv=notrunc' on the cached linuxdeploy-x86_64 binary to
hide it from AppImage integration tools. That zeroed bytes 8-10 of the
file; our cached binary there was a bash wrapper script, so the dd wrote
into the middle of its shebang/interpreter line, corrupting it, and the
bundler's subsequent spawn failed with ENOENT ('failed to bundle
project: No such file or directory').
Replace the shell wrapper with a small native ELF launcher compiled with
cc: bytes 8-10 of an ELF header are EI_PAD padding, unused by the
loader, so the same dd leaves it executable. The launcher sets the same
environment the old wrapper did and execs the real aarch64 linuxdeploy
binary. Also cache AppRun-x86_64 explicitly so the bundler does not need
to fetch it itself mid-build.
Verified locally: compiled a minimal ELF binary, ran the same dd
command against it, confirmed it still executes (the shebang-script
equivalent does not).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
The updater reads latest.json from Gitea, built by scripts/make-latest-json.py
against the Gitea API (no gh CLI). Release workflow builds the Linux CLI and
the Linux+Windows desktop app, signs the updater artifacts and attaches
everything to the release.
Needs the repo secrets TAURI_SIGNING_PRIVATE_KEY and
TAURI_SIGNING_PRIVATE_KEY_PASSWORD, which I could not set (secret-store writes
are reserved for the user) - set them from ~/.tauri/guara-updater.key and
.pass before pushing a tag.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>