Skip to content

fix(updater): platform-aware install — launch NSIS on Windows, selfupdate on Linux#20

Merged
0xMMA merged 8 commits intomainfrom
fix/updater-platform-aware-install
Apr 5, 2026
Merged

fix(updater): platform-aware install — launch NSIS on Windows, selfupdate on Linux#20
0xMMA merged 8 commits intomainfrom
fix/updater-platform-aware-install

Conversation

@0xMMA
Copy link
Copy Markdown
Owner

@0xMMA 0xMMA commented Apr 5, 2026

Summary

Fixes #18 — App update via "Download & Install" button fails on Windows with "Access is denied."

Root cause (two issues):

  1. The Windows release asset (*-windows-amd64-setup) is an NSIS installer, not a raw binary — piping it through selfupdate.Apply() would corrupt the executable
  2. C:\Program Files\ requires UAC elevation for writes; selfupdate.Apply() writes without elevation

Fix: Split DownloadAndInstall() into platform-specific strategies:

  • Windows: Download NSIS installer to temp → launch via exec.Command (NSIS handles UAC) → app quits so installer can replace locked exe
  • Linux: Download raw binary to temp → selfupdate.Apply() in-place (unchanged behavior, improved error messaging)

Returns InstallResult{restart_required: bool} so the frontend shows the appropriate message:

  • Windows: "Update is installing — the app will close shortly."
  • Linux: "Update installed! Restart the app to use the new version."

Changes

  • internal/features/updater/service.go — Refactored DownloadAndInstall() to download to temp, delegate to applyPlatformUpdate()
  • internal/features/updater/install_windows.go — New: launches NSIS installer, schedules app quit
  • internal/features/updater/install_linux.go — New: selfupdate.Apply() from temp file, preserves file on failure
  • internal/features/updater/model.go — Added InstallResult type
  • internal/features/updater/install_test.go — Regression test + 7 behavior tests (18 total updater tests)
  • main.go — Wires quitFunc callback on updater service
  • Frontend: handles restart_required in settings component

Test plan

  • Regression test proves selfupdate.Apply() fails on read-only dirs (the original bug)
  • 18 Go updater tests pass (download-to-temp, error paths, apply propagation)
  • 131 frontend tests pass (restart-required UI paths)
  • go build compiles cleanly
  • Manual: Windows install to Program Files → trigger update → NSIS wizard launches, app closes

CI (build-linux.yml) will run automatically on this PR.

🤖 Generated with Claude Code

0xMMA and others added 8 commits April 5, 2026 22:05
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ailure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…date on Linux

Fixes #18. The old approach used selfupdate.Apply() which fails on Windows
because (a) the release asset is an NSIS installer, not a raw binary, and
(b) Program Files requires UAC elevation for writes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…propagation test

The defer os.Remove was deleting the temp file before the user could
act on the "install manually" error message. Now only removed on success.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both Linux and Windows builds now run on every PR, with 3-day artifact
retention. Tests run first in a separate job; builds only start after
tests pass. Windows artifacts (binary + NSIS setup) are downloadable
from the Actions tab for local testing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@0xMMA 0xMMA merged commit 62efddf into main Apr 5, 2026
3 checks passed
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.

App update via "Download & Install" Button Fails

1 participant