Repository navigation
Load the elevator in headless mode - #5545
Open
Gabriel Dufresne (GabrielDuf) wants to merge 3 commits into
Open
Gabriel Dufresne (GabrielDuf) wants to merge 3 commits into
Gabriel Dufresne (GabrielDuf) wants to merge 3 commits into
Conversation
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The automatic gsudo fallback can execute an untrusted binary from the current working directory.
1 open issue
What changed in this PR
Fixes headless administrator operations by sharing elevator initialization with the GUI, addressing #5541.
Changes:
- Loads the elevator and migrates update preferences before headless scheduling starts.
- Handles missing bundled elevators and unsupported macOS elevation.
- Adds three bundled-elevator path resolution tests.
| File | Description |
|---|---|
| src/UniGetUI.Tests/ElevatorLoaderTests.cs | Tests local, parent-directory, and missing elevator resolution. |
| src/UniGetUI.Avalonia/Infrastructure/HeadlessDaemonHost.cs | Initializes elevation and migrates preferences before scheduling. |
| src/UniGetUI.Avalonia/Infrastructure/ElevatorLoader.cs | Extracts shared elevator loading and fallback handling. |
| src/UniGetUI.Avalonia/Infrastructure/AvaloniaBootstrapper.cs | Uses the shared loader instead of embedded logic. |
Review effort: Balanced
On Windows, CoreTools.Which searched Environment.CurrentDirectory before any PATH entry, and blank, quoted-empty or relative PATH entries also resolved against the current directory. Starting UniGetUI from a folder holding a planted gsudo.exe, winget.exe, choco.exe or python.exe made that file win over the real one. This was the root of the gsudo concern on the elevator fallback, and it still applied to the ForceUserGSudo opt-in and to every manager executable lookup. The search now covers only fully qualified PATH entries. The Windows elevator decision moves into ResolveWindowsElevatorPathAsync, which takes the executable directory and the two gsudo switches as inputs. The release no-fallback guarantee is no longer hidden behind #if !DEBUG and is now covered by tests. The DEBUG branch also stops logging "Using system GSudo" when gsudo is not installed. The parent-directory lookup in ResolveBundledElevatorPath is kept: #4719 added it for the nested publish layout. Its parent is admin-only on a Program Files install, and on a user-writable install whoever can plant there can already replace UniGetUI.exe. The Linux sudo/pkexec/SSH_ASKPASS resolution is unchanged for the same reason: PATH and environment are the user's own, and a fixed /usr/bin path would break NixOS's /run/wrappers/bin/sudo.
There was a problem hiding this comment.
🤖 Pull request was approved automatically: the AI review is complete and all its review threads are resolved. 🎉
Integration Details
{
"deliveryId": "693943c0-cbd1-11f1-9c09-9b4426c83208",
"headSha": "1c418265ee482715292b41f406cdc9d306bce527",
"reviewer": "copilot-pull-request-reviewer[bot]"
}This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Root cause
HeadlessDaemonHostonly prepared the environment, loaded the loaders and managers, and started the maintenance scheduler. The elevator was loaded only fromAvaloniaBootstrapper's shared-services startup, which headless mode never runs.CoreData.ElevatorPaththerefore stayed empty, and every operation that needed administrator rights stopped inAbstractProcessOperationwith "the elevation tool could not be found" before winget ever started.Fix
AvaloniaBootstrapperinto a newElevatorLoader, so the GUI and headless hosts share one copy.Running the loader on more hosts exposed two gaps in the loader itself:
ElevatorPathto a nonexistentUniGetUI Elevator.exe. That skipped the empty-path guard and failed inprocess.Startwith a rawWin32Exception. macOS now leaves the path empty and logs a warning.ResolveBundledElevatorPathreturned the expected path even when the file wasn't there, with the same effect. It now returnsnull. The loader then falls back to gsudo on PATH, as the TUI loader already does, and logs an error if that isn't found either.Headless also skipped
AutoUpdatesMigration.RunOnce, which the GUI runs after loading managers. A first-ever headless launch could therefore run scheduled updates without the migrated per-package auto-update preferences. It now runs the migration before starting the scheduler.Verification
winget installloggedFileName: ""and the error from the report. After it, the operation launched through gsudo.ElevatorLoaderTestscover the bundled-elevator resolution: next to the executable, in the parent directory, and missing. All 3 pass.dotnet format whitespaceanddotnet format styleboth pass.Not covered
Closes #5541