winget-cli icon indicating copy to clipboard operation
winget-cli copied to clipboard

Handle scope better

Open denelon opened this issue 2 years ago • 16 comments

Description of the new feature / enhancement

Several packages have been reported to not properly handle "--scope".

The most likely reasons are due to the installer determining scope based on whether the process is elevated, or the user is a member of the local Administrators group.

One example is Git.Git reported at twitter by @woodyinwoodley

The 2.40.1 manifest is specifying an "inno" installer, but it doesn't appear to support the /CURRENTUSER or /ALLUSERS switch.

The manifest does have entries for both "user" and "machine", but those keys don't actually drive the intended behavior.

The default behavior in the installer checks to see if the user is a member of the local Administrators group to determine if the installer will be installed machine wide or per user.

; Note that we write the Registry values below either to HKLM or to HKCU depending on whether the user running the installer
; is a member of the local Administrators group or not (see the "Check" argument).
; Install under HKEY_LOCAL_MACHINE if an administrator is installing.

https://github.com/git-for-windows/build-extra/blob/6fe3f63731fb39e20f7a668fd54566514ecc83af/installer/install.iss#L214

; Install under HKEY_CURRENT_USER if a non-administrator is installing

https://github.com/git-for-windows/build-extra/blob/6fe3f63731fb39e20f7a668fd54566514ecc83af/installer/install.iss#L221

Proposed technical implementation details

We could add another YAML key to indicate that the scope arguments either aren't properly supported, or we could attempt to provide some kind of error messaging to help users understand why their request can't be honored by WinGet.

We could potentially also check to see if the user is in the local Administrator group to determine what output to display.

denelon avatar May 10 '23 23:05 denelon

We could add another YAML key to indicate that the scope arguments either aren't properly supported

This probably wouldn't even need a new key. It would just need Scope and the associated implementation to be added to the enum for UnsupportedArguments

https://github.com/microsoft/winget-cli/blob/005f765919431d470363d860660228794ad7585e/schemas/JSON/manifests/v1.4.0/manifest.installer.1.4.0.json#L456-L468

or we could attempt to provide some kind of error messaging to help users understand why their request can't be honored by WinGet.

This is also already kind of in place, although it could likely be improved. https://github.com/microsoft/winget-cli/blob/005f765919431d470363d860660228794ad7585e/src/AppInstallerCLICore/Workflows/InstallFlow.cpp#L317 https://github.com/microsoft/winget-cli/blob/005f765919431d470363d860660228794ad7585e/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw#L1446-L1448

Trenly avatar May 11 '23 02:05 Trenly

I think for cases where it depends on whether it runs as admin or not, we could set elevationRequirement=elevationProhibited for user scope and elevationRequirement=requiresElevation for machine scope; then enlighten winget to launch the installers with the right access. We could spin off a separate process with the right permissions and use it only to run the installers from the right context. That could probably also help us get a single UAC from winget during upgrade --all / import, instead of multiple ones from each installer.

florelis avatar May 11 '23 19:05 florelis

I think for cases where it depends on whether it runs as admin or not, we could set elevationRequirement=elevationProhibited for user scope and elevationRequirement=requiresElevation for machine scope;

I think for this particular installer, fixing from manifest is ideal. And works in downlevel.

yao-msft avatar May 11 '23 22:05 yao-msft

I think for cases where it depends on whether it runs as admin or not, we could set elevationRequirement=elevationProhibited for user scope and elevationRequirement=requiresElevation for machine scope;

I think for this particular installer, fixing from manifest is ideal. And works in downlevel.

I dont think that works in this case. Git.git doesn’t depend on elevation status. If an administrator is running the installer - even in a non-elevated context - it will install with machine scope; If a non-admin is running - even in an elevated context - I believe it installs as user scope (depends on how IsAdminLoggedOn is handled for inno)

Trenly avatar May 11 '23 22:05 Trenly

I dont think that works in this case. Git.git doesn’t depend on elevation status. If an administrator is running the installer - even in a non-elevated context - it will install with machine scope; If a non-admin is running - even in an elevated context - I believe it installs as user scope (depends on how IsAdminLoggedOn is handled for inno)

Ah, thanks for the clarification. I must have mis-read something. I feel to truly support this case, there may be changes required to the installer itself.

yao-msft avatar May 12 '23 00:05 yao-msft

I dont think that works in this case. Git.git doesn’t depend on elevation status. If an administrator is running the installer - even in a non-elevated context - it will install with machine scope; If a non-admin is running - even in an elevated context - I believe it installs as user scope (depends on how IsAdminLoggedOn is handled for inno)

Ah, thanks for the clarification. I must have mis-read something. I feel to truly support this case, there may be changes required to the installer itself.

I agree that changing the installer would probably be the best here, but its likely a breaking change for git for windows, which leads me to believe it won’t happen anytime soon. Of course anything is possible, but there are likely other installers out there which don’t respect intended scope, so in my opinion it would be good to have at least some method of declaring this in the manifest

Trenly avatar May 12 '23 01:05 Trenly

I agree that changing the installer would probably be the best here, but its likely a breaking change for git for windows, which leads me to believe it won’t happen anytime soon. Of course anything is possible, but there are likely other installers out there which don’t respect intended scope, so in my opinion it would be good to have at least some method of declaring this in the manifest

Yes, it's certainly doable but unfortunately it does not solve the actual issue. Declaring Log | InstallLocation as unsupported means the installer does not support custom log writing | installing to custom location. While in this case, declaring scope as unsupported is sort of hiding the issue. The installer does support "scope", but in a custom way. Making it unsupported seems not helping user with their goal, but failing gracefully. winget install git.git --scope machine will just fail gracefully with "scope is not supported by this package"

yao-msft avatar May 12 '23 02:05 yao-msft

While in this case, declaring scope as unsupported is sort of hiding the issue.

I hadn't considered it that way. That's a good way of looking at it. There certainly is a tradeoff between accuracy and ease of use

Trenly avatar May 12 '23 03:05 Trenly

Yeah, that's been my concern as well. I think we might need to fail if we can't honor "--scope" as passed in, and provide the appropriate error with what we can determine. That's why I was thinking we might also need to have something that means: *

  • "scope for this installer is determined by running the command as user vs administrator" and
  • "scope for this installer is determined by user being a member of administrators group"

At least that way we don't do something against the wishes of the user arguments, and they can be informed.

denelon avatar May 12 '23 16:05 denelon

As an enterprise user with limited privileges I am allowed to install software which meets the following requirements:

  1. Is available only for my user (Scope: User)
  2. Does not require elevated privileges to be installed/executed

Some software support the above requirement using a very clear approach (e.g. VSCode, User Installer vs System Installer), others do not support it at all (e.g standard Python installer) others require a very custom set of installer parameters (eg. Miniforge3).

While I understand now (from Issue #3286) that "Scope" and "ElevationRequirement" might be divergent, it is my understanding that the expectation from most users is that Scope: User also implies "No elevation required".

I see two potential options:

a) Determine that packages with "Scope: User" MUST 1. install to a user scoped location AND 2. not require Elevation b) Provide clear documentation and different properties to separate the distinction between "Scope" and ""ElevationRequirement"

I would strongly prefer option a) because in my experience it is clear to understand matching the most commonly found use case.

If there are exceptional cases where an applications need to be installed with elevated privileges but the user would like to have it installed to the a user scoped location I believe it should be handled with some CLI override options.

joaompinto avatar May 31 '23 04:05 joaompinto

@Joaompinto thanks for the great write up!

Yes, there is clearly a matrix of desired behavior, and unfortunately a set of installers that don't honor what a user would want.

The original intent behind elevation requirement was to inform WinGet about how the installer behaves generally so the user could be informed (or WinGet could simply do the right thing). The intent behind "scope" was to give the user the ability to specify install scope.

We found several exceptions like the installer for Git looks to see if the current user is a member of local administrators and make its own determination about which scope to install. Another scenario I've run into as an example is when a package installs a service (requires admin) even though the package the user interacts with is installed in user scope (HKCU vs. HKLM).

In general, we try to break everything down into "classes" of problems or behaviors so we can reason about them collectively rather than trying to maintain a list of how each package behaves and implement package specific logic. In terms of "arguments" we can specify in the CLI, we also want to have "preferences" or "requirements" in settings to enable the desired behaviors.

There is a bit of balance between a very complex manifest and fine-grained control in the CLI. I believe we're approaching the point where we have enough installers with various behaviors to define them in terms of classes so we can start to implement the appropriate behaviors in WinGet for them.

I've been thinking in terms of a manifest informing WinGet whether the package "honors" the desired behavior through appropriate switches or arguments, those that simply don't, and those that have other common behaviors we can at least reason about or test. If this metadata is required and not optional, it becomes a breaking change, and we don't take those lightly.

There are also a couple of different "modes" of operation I've been thinking about for WinGet. One is all about an interactive session with a user issuing commands and how we can give them options they can respond to. The other is all about automated tooling that will not respond or make these decisions, and WinGet should simply fail with the appropriate error message. These modes are where I begin to lean into a 2.0 release:

  • #2128

denelon avatar May 31 '23 16:05 denelon

@denelon

I just started experimenting with winget this week, I liked it, from a pure interactive end user experience I need to say that the non determinist and undiscoverable (you need to run to find out) behavior depending on the package name that I chose to install was the less attractive aspect of it.

I am not sure I would consider those cases that are failing as exceptions. In the opensource ecosystem, in my experience there are no clear rules, unless there is explicit documentation or an explicit installer name scheme that identifies that "user level" installation is supported I assume that the installation requires admin privileges.

The documentation at https://learn.microsoft.com/en-us/windows/package-manager/winget/ does not provide any specific statement about the support for "User" vs "System" managed software , so in my exploratory perception the "Scope: User" is a "preview" feature which does not provide a reliable behavior (across different packages). Eventually it makes sense to document it as such for the time being ?

I think the "modes" idea for 2.0 makes all sense. In my selfish interest I hope the user / system related manifest properties is sorted out to be aligned with the more typical install user expected behavior (user/system). While trying to categorize and identify the multiple technical bits that can change across a wide diversity of installers I am afraid yet more exceptions will be discovered. I understand winget aims to support a very wide spectrum of software, but for an early version I would prefer to get better support for software which is already distributed following software packaging best practices.

There is also the other technical challenge, WinGet follows an approach of consuming "upstream installers" without further re-building/repackaging/modification, while this might succeed in the long term, it is quite a challenge on the short term.

I have tried winget for the firs time because RedHat explicitly recommended it as the method to install Podman Desktop, Probably with more engagement of other vendors/upstreams, with a scoring system or similar, we can actually get upstream improve their installers so that we can reduce the need to add metadata to workaround undesired behaviors :)

Thanks for the detailed feedback.

joaompinto avatar May 31 '23 20:05 joaompinto

@Joaompinto I've been working on some documentation around various installer behaviors so we can try to provide guidance on installers for ISVs so they know what WinGet is doing and can make the desired improvements. We've also been adding more logic in the validation infrastructure to look at behaviors associated with install scope.

I agree with you on the suggestions for adding "known issues" to the documentation. I'll start an e-mail thread with our partners at Microsoft Learn to see if we've got a best practice pattern to follow and provide some additional guidance on scope challenges.

denelon avatar Jun 01 '23 15:06 denelon

https://github.com/git-for-windows/git/issues/4758

soredake avatar Jan 06 '24 17:01 soredake

Python >=3.12 no longer requires admin rights by default

https://github.com/python/cpython/issues/113794#issuecomment-1880893458

soredake avatar Jan 08 '24 12:01 soredake

Getting scope right is certainly not easy and should have some requirements attached to it. Its even more compliacted taking into account the dependencies a package might have. We're currently facing a situation where users install Cisco Webex Meetings when given a meeting invite. The provided installer that is installed by clicking on the meeting invite will install in user context. Winget now comes and picks that software up (Cisco.CiscoWebexMeetings) and if you try to update it, will try and use a machine installer because thats the only thing it can find in the repo manifest. This will lead to the user being stuck in a UAC loop if he has no local admin capabilities.

IMO it would therefore be useful to have some relation between the context winget detects the software in and scopes that a update in its manifest provides. Getting that consistent accross dependencies is a whole nother topic though.

MarcoBuess avatar Aug 21 '24 11:08 MarcoBuess