Skip to content

fix(updates): every Linux format and portable copies update themselves - #28

Open
Richards0nd wants to merge 1 commit into
mainfrom
fix/auto-update-every-package
Open

Richards0nd wants to merge 1 commit into
mainfrom
fix/auto-update-every-package

Conversation

@Richards0nd

@Richards0nd Richards0nd commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Problem

The updater only installed updates on the Windows installers, macOS and a writable AppImage. Users who installed the .deb, .rpm, the Arch .pkg.tar.zst (or the AUR's lowquery-bin), or a portable copy only saw a Download link to the release page. latest.json had no entry for those formats, and the release did not sign them.

Change

App (src-tauri/src/updates.rs)

  • The check and the install now run in Rust (check_update, install_update), and the JS @tauri-apps/plugin-updater and updater:default are removed. The policy is detected on first use, off the main thread:

    Channel Detected by Installs with
    installer NSIS/MSI/App bundle type updater plugin (unchanged)
    appimage APPIMAGE updater plugin (unchanged), only if the folder is writable
    deb / rpm bundle type patched by the bundler updater plugin: pkexec dpkg -i / rpm -U
    pacman /usr or /opt path owned per pacman -Qqo pkexec pacman -U --noconfirm, from a 0700 temp folder
    portable anything else (Linux, Windows) replaces its own executable if its folder is writable (Linux: rename over; Windows: running exe → LowQuery.exe.old, removed on next start)
    package /usr//opt not owned by pacman download link (unchanged)
  • Each channel reads its own latest.json key, so no install ever receives another format. Every download is verified against the update key before anything is written.

  • The portable executable is read from the signed .tar.gz/.zip into memory. Nothing is extracted to disk. deny.toml now explains why the existing zip advisories still don't apply.

  • Debug builds never replace themselves.

Release

  • The Linux job signs .deb, .rpm, .pkg.tar.zst and the portable .tar.gz (tauri signer sign --app-version). The Windows job signs the portable .zip.
  • update_manifest.py adds linux-x86_64-{deb,rpm,pacman,portable} and windows-x86_64-portable, all of them required. There is still no generic linux-x86_64 key.

UI: the update dialog says the system will ask for a password on deb/rpm/pacman installs.

Installs from 0.5.3 and earlier still show the download link once. Self-update starts with the release that contains this change.

Verification

End-to-end on real installs. Old build = this branch built as 0.5.2, with a test update key and a local latest.json. New release = the official v0.5.3 assets, re-signed with the test key. A throwaway hook (not in this PR) ran check(true) and install() at startup under Xvfb. In the containers pkexec was a pass-through shim, because they already run as root:

Distro Channel detected Result
Arch (archlinux:base-devel) pacman lowquery-bin 0.5.2-1 → 0.5.3-1; /usr/bin/lowquery = official binary; relaunched
Ubuntu 24.04 deb low-query 0.5.2 → 0.5.3 via dpkg; relaunched
Fedora 42 rpm low-query-0.5.2-1 → 0.5.3-1; relaunched
Host (Arch), portable folder portable executable replaced by the official 0.5.3 binary, mode kept, no leftovers
Portable, wrong signature in latest.json portable "The signature verification failed", binary unchanged

Checks: bun run check, bun test (72 pass), bun run build, cargo fmt --check, cargo clippy --lib --tests -D warnings, cargo test --locked --lib (183 pass, including the new tests for archive reading, executable replacement and the pacman payload guard), python -m unittest discover -s .github/scripts.

Not run: the Windows portable path on real Windows. Its code compiles for x86_64-pc-windows-gnu, but replacing a running .exe there has not been tested. The release workflow itself has not been run, because it needs the signing secrets.

…ub Releases

Only the Windows installers, macOS and a writable AppImage could install
an update. .deb, .rpm, the Arch package (and the AUR's lowquery-bin) and
portable copies only got a link to the release page.

- updates.rs now owns the check and the install. It detects how this
  copy was installed (bundle type, APPIMAGE, pacman -Qqo, portable
  folder) and reads the latest.json entry for that format, so an install
  never receives another format.
- .deb/.rpm install through the updater plugin (pkexec dpkg -i / rpm -U).
  The Arch package goes through pkexec pacman -U, from a private temp
  folder. Portable copies on Linux and Windows replace their own
  executable after the download's signature is checked.
- The release signs the .deb, .rpm, .pkg.tar.zst and the portable .tar.gz
  and .zip, and latest.json lists linux-x86_64-{deb,rpm,pacman,portable}
  and windows-x86_64-portable.
- The interface calls check_update/install_update. The JS updater plugin
  and its capability are removed.
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.

1 participant