Skip to content

fix(updater): scope the installer for every machine install, not just unelevated ones - #42

Merged
jpicklyk merged 1 commit into
mainfrom
fix/updater-elevated-scope
Sep 22, 2026
Merged

jpicklyk merged 1 commit into
mainfrom
fix/updater-elevated-scope

Conversation

@jpicklyk

Copy link
Copy Markdown
Owner

Summary

Re-review follow-up on #41, caught before 0.13.3 shipped (tag and draft were withdrawn).

/allusers was attached to the elevation gate, so it only reached installers we launched ourselves. A machine install that is already elevated — started "as administrator", or an admin account with UAC consent disabled — fell through to the plugin's own /P /UPDATE /R /ARGS, no scope switch, and MultiUser took the path #41 proved broken: per-user key wins, Program Files skipped.

What the plugin omits is the scope, not the elevation. So:

  • the install path keys on running_machine_install() alone;
  • machine_install_needs_elevation() survives as the predicate behind the Settings hint, which is genuinely about whether a prompt appears;
  • the verb follows the same logic — runas only when something needs raising, open when already elevated (a second hop would be pointless and can re-prompt).

Mechanism correction

The re-review read the real MultiUser.nsh, and my explanation was wrong in a load-bearing way. NSIS reads the default-mode value from HKLM first, HKCU second — not the other way round. The fix works for a better reason than I gave: the value name is CurrentUser and an all-users install writes one named AllUsers, so the HKLM read is always empty for this template. Only the HKCU read can decide, and it can only ever flip the mode to per-user. The command-line check then runs last and unconditionally, so the switch always wins.

The ordering test's comment was wrong the same way: MultiUser would still see a trailing /allusers (it scans the whole command line), but NSIS GetOptions stops at the next unquoted switch, so the switch would truncate the relaunch arguments and lose a file opened from the command line.

Test plan

  • cargo test --lib app_update 13/13, cargo clippy -- -D warnings clean
  • npm test 2100/2100, npm run build clean
  • Not re-run live: the previous e2e covered the unelevated path, which is unchanged. The already-elevated path is now the same code with a different verb.

🤖 Generated with Claude Code

… unelevated ones

The scope switch rode on the elevation gate, so an already-elevated
machine install — launched "as administrator", or an admin account with
UAC consent off — fell through to the plugin's own `/P /UPDATE /R /ARGS`
with no `/allusers` and updated the per-user copy again. What the plugin
omits is the scope, not the elevation, so the install path now keys on
`running_machine_install` alone; `machine_install_needs_elevation` stays
as the Settings hint's predicate. The verb follows suit: `runas` only
when there is something to raise, `open` when already elevated.

Also corrects the mechanism this rests on, from the re-review's reading
of MultiUser.nsh: NSIS reads the default-mode value from HKLM *first*,
not HKCU. It works because the value name is `CurrentUser` and an
all-users install writes `AllUsers`, so the HKLM read is always empty
here and only the HKCU read can decide — a stronger guarantee than the
one the comment claimed. The ordering test's comment was wrong for the
same kind of reason: MultiUser would still see a trailing switch, but
NSIS `GetOptions` would truncate the relaunch arguments at it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jpicklyk
jpicklyk merged commit 9cbf352 into main Sep 22, 2026
@jpicklyk
jpicklyk deleted the fix/updater-elevated-scope branch September 22, 2026 14:52
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