From e65e43b0725022d5644e9f1a5d5fadce03f5e7a4 Mon Sep 17 00:00:00 2001 From: Olia Gavrysh Date: Mon, 25 Nov 2024 14:50:24 -0800 Subject: [PATCH 01/11] Adding a proposal for the new CLI command to fix vulnerabilities --- accepted/2024/package-update-command.md | 333 ++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 accepted/2024/package-update-command.md diff --git a/accepted/2024/package-update-command.md b/accepted/2024/package-update-command.md new file mode 100644 index 000000000..2a9f11d7f --- /dev/null +++ b/accepted/2024/package-update-command.md @@ -0,0 +1,333 @@ +# dotnet package update command + +- [Olia Gavrysh](https://github.com/OliaG/) +- Start Date (2024-11-11) +- [#8087](https://github.com/NuGet/Home/issues/8087) + +## Summary + + +The `dotnet package update` feature is designed to enhance the user experience by enabling .NET developers to address security vulnerabilities, deprecated packages, and outdated versions of their NuGet dependencies with a single command. +This improvement will, in turn, bolster the overall security and reliability of .NET applications. The feature will build upon the existing NuGet Audit functionality. + +## Motivation + + +Even though .NET developers now have the opportunity to learn about vulnerabilities and deprecated dependencies in their NuGet packages, addressing these issues remains a significant challenge. It requires a lot of manual work and knowledge about newer versions, which can be quite daunting. When the solution to these problems takes time, developers are less likely to act on it immediately, leading to these upgrades being postponed or never addressed. Additionally, developers might not always use the most efficient ways of resolving these issues, especially when dealing with multiple nested transitive dependencies. This is why developers will benefit greatly from a single command that attempts to automate all the work and update all the packages, efficiently eliminating vulnerabilities and deprecated versions. + +## User experience + +### Updating all packages to the latest vesioin + +When users want to ensure their NuGet dependencies are up to date, they can run a command in .NET CLI `dotnet package update`. + +```CLI +C:\> dotnet package update + +Fixing outdated packages in ContosoUniversity.sln + Updated UmbracoForms 8.4.1 to 8.7.1 + Updated Newtonsoft.Json 11.0.1 to 13.0.3 + +Updated 2 packages in 36 scanned packages. +``` + +### Fixing vulnerabilities + +When users run `dotnet build` or `dotnet restore` commands in CLI, if they see any warnings related to vulnerabilities in their project’s NuGet dependencies, they can run `dotnet package update --vulnerable` CLI command to fix all the mentioned issues. + +In the future this can be extended to fix deprecated versions. + +## Explanation + +### Functional explanation + + + + +#### dotnet audit + +The `dotnet audit` command will scan your project and solution's dependencies and look for known vulnerabilities, deprecations, and outdated packages. If any vulnerabilities, deprecations, or outdated packages are found, a remediation will be calculated to then `fix` which will be applied to the resulting package graph. + +Example: + +![dotnet audit](/meta/resources/dotnetaudit/dotnetaudit.png) + +``` +$ dotnet audit + +Fetching package metadata from: 'https://api.nuget.org/v3/index.json' +Loaded 23 security advisories from 'https://api.nuget.org/v3/index.json' +Scanning ContosoUniversity.sln (36 NuGet dependencies) + +error: Vulnernable packages found! +[net5.0]: +Top-level Package Requested Resolved Severity Advisory URL +> UmbracoForms 8.4.1 8.4.1 Moderate https://github.com/advisories/GHSA-8m73-w2r2-6xxj + +Transitive Package Resolved Severity Advisory URL +> Microsoft.Data.OData 5.2.0 Moderate https://github.com/advisories/GHSA-mv2r-q4g5-j8q5 + +Found 1 top-level Moderate severity vulnerability & 1 transtive Moderate severity vulnerability package(s) in 36 scanned packages. + +Run 'dotnet audit fix' to fix them. + +warning: Deprecated packages found! +[net5.0]: +Top-level Package Requested Resolved Reason(s) Alternative +> anurse.testing.TestDeprecatedPackage 1.0.0 1.0.0 Legacy Microsoft.AspNetCore.Mvc > 0.0.0 + +Found 1 top-level Legacy deprecated package(s) in 36 scanned packages. + +Run 'dotnet audit fix' to fix them. + +warning: Outdated packages found! +[net5.0]: +Top-level Package Resolved Latest +> anurse.testing.TestDeprecatedPackage 1.0.0 2.0.0 +> UmbracoForms 8.4.1 8.7.1 + +Found 2 top-level outdated package(s) in 36 scanned packages. + +Run 'dotnet audit fix' to fix them. +``` + +##### Endpoints + +NuGet will use existing endpoints to optimize the speed of audit results. + +- [Deprecation](https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#package-deprecation) +- [Vulnerability](https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#vulnerabilities) +- Outdated - No existing endpoint, will need to call a source. + +##### dotnet audit --json + +To get a detailed audit report in a JSON format. + +``` +{ + "audit": { + "vulnerabilities": { + "low": "0", + "moderate": "2", + "high": "0", + "critical": "0", + "dependencies": [ + { + "name": "UmbracoForms", + "requestedVersion": "8.4.1", + "resolvedVersion": "8.4.1", + "vulnerabilitySeverity": "Moderate", + "advisoryUrl": "https://github.com/advisories/GHSA-8m73-w2r2-6xxj", + "transitiveDependencies": [ + { + "name": "Microsoft.Data.OData", + "resolvedVersion": "5.2.0", + "severity": "Moderate", + "advisoryUrl": "https://github.com/advisories/GHSA-mv2r-q4g5-j8q5" + } + ] + } + ] + }, + "deprecations": { + "legacy": "1", + "critical-bugs": "0", + "other": "0", + "dependencies": [ + { + "name": "anurse.testing.TestDeprecatedPackage", + "requestedVersion": "1.0.0", + "resolvedVersion": "1.0.0", + "reason": "Legacy", + "alternativeDependencies": [ + { + "name": "Microsoft.AspNetCore.MVC", + "version": "0.0.0" + } + ] + } + ] + }, + "outdated": { + "packages": "2", + "dependencies": [ + { + "name": "anurse.testing.TestDeprecatedPackage", + "resolvedVersion": "1.0.0", + "latestVersion": "2.0.0" + }, + { + "name": "UmbracoForms", + "resolvedVersion": "8.4.1", + "latestVersion": "8.7.1" + } + ] + }, + "scannedDependencies": "36" + } +} +``` + +##### dotnet audit Exit Codes + +- 0 - The command will exit with a 0 exit code if no vulnerabilities, deprecations, or outdated packages were found. +- 1 - The command will exit with a 1 exit code if a vulnerability, deprecation, or outdated package was found. +- 2 - The command will exit with a 2 exit code if it unexpectedly failed. +- 3 - The command will exit with a 3 exit code if an unsupported project is detected. + +#### dotnet audit fix + +The `dotnet audit fix` command will provide a remediation that is calculated with an implicit `dotnet audit` to then apply directly to a resulting package graph. It can add packages, remove packages, and update packages depending on the problem it's attempting to resolve. It does not take into consideration downgrading to a compatible version if a higher one has already been specified. + +![dotnet audit fix](/meta/resources/dotnetaudit/dotnetauditfix.png) + +``` +$ dotnet audit fix + +Fixing vulnernable packages in ContosoUniversity.sln + Upgrading UmbracoForms 8.4.1 to 8.7.1 + +Fixing deprecated packages in ContosoUniversity.sln + Replacing anurse.testing.TestDeprecatedPackage 1.0.0 with Microsoft.AspNetCore.Mvc 2.2.0 + +Fixing outdated packages in ContosoUniversity.sln + Packages are currently up-to-date. + +Fixed 2 packages in 36 scanned packages. +``` + +##### dotnet audit fix --dry-run + +Does a dry run to give an idea of what `audit fix` will do. Provides output, but does not commit the fix. + +##### dotnet audit fix --json + +```json + "added": [ + { + "name": "Microsoft.AspNetCore.MVC", + "version": "2.2.0" + } + ], + "removed": [ + { + "name": "anurse.testing.TestDeprecatedPackage", + "version": "1.0.0" + } + ], + "updated": [ + { + "name": "UmbracoForms", + "version": "8.7.1", + "previousVersion": "8.4.1" + } + ], + "failures": [], + "warnings": [] +``` + +##### dotnet audit fix Exit Codes + +- 0 - The command will exit with a 0 exit code if no vulnerabilities, deprecations, or outdated packages were found *or* remediation was able to fix all issues. +- 1 - The command will exit with a 1 exit code if a vulnerability, deprecation, or outdated package was found *and* remediation is not able to fix all issues. +- 2 - The command will exit with a 2 exit code if it unexpectedly failed. +- 3 - The command will exit with a 3 exit code if an unsupported project is detected. + +#### Vulnerabilities + +When vulnerable packages are detected, an error is thrown by default. + +#### Deprecation + +When deprecated packages are detected, a warning is thrown by default. + +#### Outdated + +When outdated packages are detected, a warning is thrown by default. + +#### CLI Usage + +``` +dotnet audit --help +dotnet audit [||] [-v|--verbosity ] [--json] +``` + +``` +dotnet audit fix --help +dotnet audit fix [||] [-v|--verbosity ] [--dry-run] [--json] [--interactive] +``` + +### Technical explanation + + + +## Drawbacks + + +There's a number of [dotnet tools](https://github.com/natemcmaster/dotnet-tools) that exist to solve many of these painpoints. Much of the information to put together this experience exists within NuGet.org's Server API & could created as a dotnet tool. + +There are a number of auditing tools in other ecosystems that are third-party / developed by the community. For other ecosystems, these features are built into the first-party CLI experiences. + +## Rationale and alternatives + + + + +There already exists a dotnet CLI commands called `dotnet list package` with options such as `--vulnerable, --deprecated, --outdated` which will list any known vulnerabilities, deprecations, and outdated packages in a project or solution. These options currently cannot be combined. Although this provides valuable information to understand the state of your dependencies, there does not exist a tool that allows you to quickly audit a project/solution & provide a way to act further on. + +When a developer is prompted with information such as a known vulnerability, deprecated package, or outdated version, they should have a clear understanding of how to best proceed with the information provided. In most cases, simply updating the dependency will suffice. + +Additionally, there already exists many third-party solutions that try to solve this problem with varying degrees of success. Some solutions can help alert about known vulnerabilities and some can help alert about outdated packages. No single tool seems to check for a "healthy" dependency list & that's another reason why we're looking to combine these experiences into a single command. + +## Prior Art + + + + + +- [snyk](https://snyk.io/) +- [npm audit](https://docs.npmjs.com/cli/v7/commands/npm-audit) +- [cargo audit](https://github.com/RustSec/cargo-audit) +- [dotnet outdated](https://github.com/dotnet-outdated/dotnet-outdated) +- [dotnet retire](https://github.com/retirenet/dotnet-retire) +- [NuGet Defense](https://github.com/digitalcoyote/NuGetDefense) + +## Unresolved Questions + + + + +- Should the command be named `audit` or `check`? + - `audit` is the more consistent name for package manager tooling with other ecosystems. + - `check` is the more consistent name with dotnet CLI. +- Should this command only audit `vulnerabilities`? Or should it audit & be proactive as to `vulnerabilities`, `deprecations`, and `outdated` packages? +- How much information should be present in the --json output? + +## Future Possibilities + + +- `dotnet audit` can be run on every `restore` which can throw warnings or errors to the user to take action against a vulnerable, deprecated, or outdated software supply chain. +- `dotnet audit` and `dotnet audit fix` output & resolutions can be extended by the .NET ecosystem to build tooling & new experiences around. +- `dotnet audit` and `dotnet audit fix` experiences can be extended into Visual Studio IDEs providing users with more visualizations of potential problems in their dependencies & ways to resolve them with a single click experience. +- `dotnet audit` can be added to CI/CD environments for an extra layer of monitoring such as a GitHub Action template. +- + +## NAMING Option 4 + +Update all packages to the latest: + +``` +dotnet package update +``` + +Update only vuln: + +``` +dotnet package update --vulnerable +``` + +Update a single package with package identifies to a provided version or latesf by default + +Ability to supply multiple pckgs, in that case how do we specify versions for each? Maybe multiple versions disable for now ans listen to the feedback. + +If updates lead to restore doesn't succeeds (warnings or errors), we require --force to make the change. From d33ee5060fa3e3ed4bbcd6dc0cb1e6746c7632a7 Mon Sep 17 00:00:00 2001 From: Olia Gavrysh Date: Mon, 9 Dec 2024 20:03:20 -0800 Subject: [PATCH 02/11] Updated the doc --- accepted/2024/package-update-command.md | 303 +++++++----------------- 1 file changed, 88 insertions(+), 215 deletions(-) diff --git a/accepted/2024/package-update-command.md b/accepted/2024/package-update-command.md index 2a9f11d7f..054fccb6e 100644 --- a/accepted/2024/package-update-command.md +++ b/accepted/2024/package-update-command.md @@ -2,7 +2,8 @@ - [Olia Gavrysh](https://github.com/OliaG/) - Start Date (2024-11-11) -- [#8087](https://github.com/NuGet/Home/issues/8087) +- [#13372](https://github.com/NuGet/Home/issues/13372) +- [#4103](https://github.com/NuGet/Home/issues/4103) ## Summary @@ -13,11 +14,36 @@ This improvement will, in turn, bolster the overall security and reliability of ## Motivation -Even though .NET developers now have the opportunity to learn about vulnerabilities and deprecated dependencies in their NuGet packages, addressing these issues remains a significant challenge. It requires a lot of manual work and knowledge about newer versions, which can be quite daunting. When the solution to these problems takes time, developers are less likely to act on it immediately, leading to these upgrades being postponed or never addressed. Additionally, developers might not always use the most efficient ways of resolving these issues, especially when dealing with multiple nested transitive dependencies. This is why developers will benefit greatly from a single command that attempts to automate all the work and update all the packages, efficiently eliminating vulnerabilities and deprecated versions. +Even though .NET developers now have the opportunity to learn about vulnerabilities and deprecated dependencies in their NuGet packages and addressing those issues, there are gaps in user experience, especially in the CLI workflows. + +### Existing capabilities + +Visual Studio + +- Has a means to show outdated packages +- Has a means to show deprecate/vulnerable packages +- Has a means to update all packages to latest +- Has a means to update a single package to latest (which can be challenging) +- Has a vulnerability filter, which in turn can allow you to update all vulnerable packages to latest +dotnet + +CLI + +- Has a means to show outdated packages +- Has a means to show deprecated/vulnerable packages +- Has a means to update a single package +- Does not have means to update multiple packages at once + +### Gaps in CLI experience + +- No means to update to all latest packages on the CLI +- No means for update heuristics, such as, update my vulnerable packages + +This proposal is focused on bringing the CLI experience up to funcional parity with the experience in Visual Studio and make developers more productive by providing a single command to update all packages to the latest version and a way to update all vulnerable packages. ## User experience -### Updating all packages to the latest vesioin +### Updating all packages to the latest version When users want to ensure their NuGet dependencies are up to date, they can run a command in .NET CLI `dotnet package update`. @@ -33,7 +59,17 @@ Updated 2 packages in 36 scanned packages. ### Fixing vulnerabilities -When users run `dotnet build` or `dotnet restore` commands in CLI, if they see any warnings related to vulnerabilities in their project’s NuGet dependencies, they can run `dotnet package update --vulnerable` CLI command to fix all the mentioned issues. +When users run `dotnet build` or `dotnet restore` commands in CLI, if they see any warnings related to vulnerabilities in their project’s NuGet dependencies, they can run `dotnet package update --vulnerable` CLI command to try to remediate all the vulnerabilities. + +```CLI +C:\> dotnet package update --vulnerable + + +Fixing vulnernable packages in ContosoUniversity.sln + Upgrading UmbracoForms 8.4.1 to 8.7.1 + +Fixed 1 package in 36 scanned packages. +``` In the future this can be extended to fix deprecated versions. @@ -44,16 +80,32 @@ In the future this can be extended to fix deprecated versions. -#### dotnet audit +#### dotnet package update -The `dotnet audit` command will scan your project and solution's dependencies and look for known vulnerabilities, deprecations, and outdated packages. If any vulnerabilities, deprecations, or outdated packages are found, a remediation will be calculated to then `fix` which will be applied to the resulting package graph. +The `dotnet package update` command will update all the NuGet dependencies to the latest versions. -Example: +```CLI +C:\> dotnet package update --help +dotnet package update [|] [--vulnerable] [--mode ] [-v|--verbosity ] [--json] +``` -![dotnet audit](/meta/resources/dotnetaudit/dotnetaudit.png) +#### --vulnerable -``` -$ dotnet audit +This flag will try to update only packages that have direct or transitive vulnerabilities. The remediation is calculated with an implicit dotnet audit to then apply directly to a resulting package graph. It can add packages, remove packages, and update packages depending on the problem it's attempting to resolve. It does not take into consideration downgrading to a compatible version if a higher one has already been specified. +The algorithm of the fixing process will have the following steps: + +1. Identify vulnerabilities in the graph +1. Distinguish which are top level, transitive level, etc., +1. Resolve any compatibility conflicts +1. Apply the patch/update/fix +1. Restore dependencies +1. Verify that issues were resolved . Provide the report to the user. +1. If the issues were not resolved or were partially resolved, we will still commit the fixes and notify users about what was and was not fixed and what are the recommended manual steps with links to documentation. + +Example: + +```CLI +C:\> dotnet package update --vulnerable Fetching package metadata from: 'https://api.nuget.org/v3/index.json' Loaded 23 security advisories from 'https://api.nuget.org/v3/index.json' @@ -69,138 +121,26 @@ Transitive Package Resolved Severity Advisory URL Found 1 top-level Moderate severity vulnerability & 1 transtive Moderate severity vulnerability package(s) in 36 scanned packages. -Run 'dotnet audit fix' to fix them. - -warning: Deprecated packages found! -[net5.0]: -Top-level Package Requested Resolved Reason(s) Alternative -> anurse.testing.TestDeprecatedPackage 1.0.0 1.0.0 Legacy Microsoft.AspNetCore.Mvc > 0.0.0 - -Found 1 top-level Legacy deprecated package(s) in 36 scanned packages. - -Run 'dotnet audit fix' to fix them. - -warning: Outdated packages found! -[net5.0]: -Top-level Package Resolved Latest -> anurse.testing.TestDeprecatedPackage 1.0.0 2.0.0 -> UmbracoForms 8.4.1 8.7.1 - -Found 2 top-level outdated package(s) in 36 scanned packages. - -Run 'dotnet audit fix' to fix them. -``` - -##### Endpoints - -NuGet will use existing endpoints to optimize the speed of audit results. - -- [Deprecation](https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#package-deprecation) -- [Vulnerability](https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#vulnerabilities) -- Outdated - No existing endpoint, will need to call a source. - -##### dotnet audit --json - -To get a detailed audit report in a JSON format. - -``` -{ - "audit": { - "vulnerabilities": { - "low": "0", - "moderate": "2", - "high": "0", - "critical": "0", - "dependencies": [ - { - "name": "UmbracoForms", - "requestedVersion": "8.4.1", - "resolvedVersion": "8.4.1", - "vulnerabilitySeverity": "Moderate", - "advisoryUrl": "https://github.com/advisories/GHSA-8m73-w2r2-6xxj", - "transitiveDependencies": [ - { - "name": "Microsoft.Data.OData", - "resolvedVersion": "5.2.0", - "severity": "Moderate", - "advisoryUrl": "https://github.com/advisories/GHSA-mv2r-q4g5-j8q5" - } - ] - } - ] - }, - "deprecations": { - "legacy": "1", - "critical-bugs": "0", - "other": "0", - "dependencies": [ - { - "name": "anurse.testing.TestDeprecatedPackage", - "requestedVersion": "1.0.0", - "resolvedVersion": "1.0.0", - "reason": "Legacy", - "alternativeDependencies": [ - { - "name": "Microsoft.AspNetCore.MVC", - "version": "0.0.0" - } - ] - } - ] - }, - "outdated": { - "packages": "2", - "dependencies": [ - { - "name": "anurse.testing.TestDeprecatedPackage", - "resolvedVersion": "1.0.0", - "latestVersion": "2.0.0" - }, - { - "name": "UmbracoForms", - "resolvedVersion": "8.4.1", - "latestVersion": "8.7.1" - } - ] - }, - "scannedDependencies": "36" - } -} -``` - -##### dotnet audit Exit Codes - -- 0 - The command will exit with a 0 exit code if no vulnerabilities, deprecations, or outdated packages were found. -- 1 - The command will exit with a 1 exit code if a vulnerability, deprecation, or outdated package was found. -- 2 - The command will exit with a 2 exit code if it unexpectedly failed. -- 3 - The command will exit with a 3 exit code if an unsupported project is detected. - -#### dotnet audit fix - -The `dotnet audit fix` command will provide a remediation that is calculated with an implicit `dotnet audit` to then apply directly to a resulting package graph. It can add packages, remove packages, and update packages depending on the problem it's attempting to resolve. It does not take into consideration downgrading to a compatible version if a higher one has already been specified. - -![dotnet audit fix](/meta/resources/dotnetaudit/dotnetauditfix.png) - -``` -$ dotnet audit fix - Fixing vulnernable packages in ContosoUniversity.sln Upgrading UmbracoForms 8.4.1 to 8.7.1 -Fixing deprecated packages in ContosoUniversity.sln - Replacing anurse.testing.TestDeprecatedPackage 1.0.0 with Microsoft.AspNetCore.Mvc 2.2.0 - -Fixing outdated packages in ContosoUniversity.sln - Packages are currently up-to-date. - Fixed 2 packages in 36 scanned packages. ``` -##### dotnet audit fix --dry-run +#### --mode + +Priority: P1 for `promote`; P2 for `closest` and switching the default to `closest`. + +| Mode | Explanation | +|------|-------------| +| `promote` | the algorithm will always promote transitive packages to top level. This is an easy to implement feature that we will release in MVP. | +| `closest` | the algorithm will try to upgrade the direct package reference, and if that doesn't work, it will walk the graph one dependency level at a time trying to upgrade that, until it gets to the package with the known vulnerability. Once this mode is implemented, it should be set to be the default one. | -Does a dry run to give an idea of what `audit fix` will do. Provides output, but does not commit the fix. +#### --format json -##### dotnet audit fix --json +Priority: P2 + +Provides a detailed report in a JSON format: ```json "added": [ @@ -226,58 +166,23 @@ Does a dry run to give an idea of what `audit fix` will do. Provides output, but "warnings": [] ``` -##### dotnet audit fix Exit Codes - -- 0 - The command will exit with a 0 exit code if no vulnerabilities, deprecations, or outdated packages were found *or* remediation was able to fix all issues. -- 1 - The command will exit with a 1 exit code if a vulnerability, deprecation, or outdated package was found *and* remediation is not able to fix all issues. -- 2 - The command will exit with a 2 exit code if it unexpectedly failed. -- 3 - The command will exit with a 3 exit code if an unsupported project is detected. - -#### Vulnerabilities - -When vulnerable packages are detected, an error is thrown by default. - -#### Deprecation - -When deprecated packages are detected, a warning is thrown by default. - -#### Outdated - -When outdated packages are detected, a warning is thrown by default. - -#### CLI Usage - -``` -dotnet audit --help -dotnet audit [||] [-v|--verbosity ] [--json] -``` - -``` -dotnet audit fix --help -dotnet audit fix [||] [-v|--verbosity ] [--dry-run] [--json] [--interactive] -``` - -### Technical explanation - - +In the "failures" and "warnings" should be the information about what projects were not updated due to failed pipeline or different reassons like no solution was found, the format of the project file is not supported, etc. -## Drawbacks +##### Exit Codes - -There's a number of [dotnet tools](https://github.com/natemcmaster/dotnet-tools) that exist to solve many of these painpoints. Much of the information to put together this experience exists within NuGet.org's Server API & could created as a dotnet tool. +Priority: P1 -There are a number of auditing tools in other ecosystems that are third-party / developed by the community. For other ecosystems, these features are built into the first-party CLI experiences. +- 0 - The command will exit with a 0 exit code if no vulnerabilities or outdated packages were found and no changes were made. +- 1 - The command will exit with a 1 exit code if changes were successfull and the PR is submitted. +- 2 - The command will exit with a 2 exit code if any error has occured, PR will not be submitted. -## Rationale and alternatives - - - - -There already exists a dotnet CLI commands called `dotnet list package` with options such as `--vulnerable, --deprecated, --outdated` which will list any known vulnerabilities, deprecations, and outdated packages in a project or solution. These options currently cannot be combined. Although this provides valuable information to understand the state of your dependencies, there does not exist a tool that allows you to quickly audit a project/solution & provide a way to act further on. +##### Endpoints -When a developer is prompted with information such as a known vulnerability, deprecated package, or outdated version, they should have a clear understanding of how to best proceed with the information provided. In most cases, simply updating the dependency will suffice. +NuGet will use existing endpoints to optimize the speed of audit results. -Additionally, there already exists many third-party solutions that try to solve this problem with varying degrees of success. Some solutions can help alert about known vulnerabilities and some can help alert about outdated packages. No single tool seems to check for a "healthy" dependency list & that's another reason why we're looking to combine these experiences into a single command. +- [Vulnerability](https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#vulnerabilities) +- Outdated - no existing endpoint, will need to call a source. +- [Deprecation](https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#package-deprecation) for future possible improvements. ## Prior Art @@ -292,42 +197,10 @@ Additionally, there already exists many third-party solutions that try to solve - [dotnet retire](https://github.com/retirenet/dotnet-retire) - [NuGet Defense](https://github.com/digitalcoyote/NuGetDefense) -## Unresolved Questions - - - - -- Should the command be named `audit` or `check`? - - `audit` is the more consistent name for package manager tooling with other ecosystems. - - `check` is the more consistent name with dotnet CLI. -- Should this command only audit `vulnerabilities`? Or should it audit & be proactive as to `vulnerabilities`, `deprecations`, and `outdated` packages? -- How much information should be present in the --json output? - ## Future Possibilities -- `dotnet audit` can be run on every `restore` which can throw warnings or errors to the user to take action against a vulnerable, deprecated, or outdated software supply chain. -- `dotnet audit` and `dotnet audit fix` output & resolutions can be extended by the .NET ecosystem to build tooling & new experiences around. -- `dotnet audit` and `dotnet audit fix` experiences can be extended into Visual Studio IDEs providing users with more visualizations of potential problems in their dependencies & ways to resolve them with a single click experience. -- `dotnet audit` can be added to CI/CD environments for an extra layer of monitoring such as a GitHub Action template. -- - -## NAMING Option 4 - -Update all packages to the latest: - -``` -dotnet package update -``` - -Update only vuln: - -``` -dotnet package update --vulnerable -``` - -Update a single package with package identifies to a provided version or latesf by default - -Ability to supply multiple pckgs, in that case how do we specify versions for each? Maybe multiple versions disable for now ans listen to the feedback. -If updates lead to restore doesn't succeeds (warnings or errors), we require --force to make the change. +- In the future the basic algorithm could check for breaking changes in fixed versions. +- This functionality may be reused to implement a one-click fix in the Visual Studio UI experience. +- Enable fixes for deprecations and outdated versions as well together with an option for the users to choose what they want to fix (vulnerabilities, depreciation, outdated versions). From 2aca5367ac27725e0afcb86e301f140d2d946155 Mon Sep 17 00:00:00 2001 From: Olia Gavrysh Date: Mon, 16 Dec 2024 16:17:26 -0800 Subject: [PATCH 03/11] Addressed review comments --- accepted/2024/package-update-command.md | 58 +++++++++++++++++++------ 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/accepted/2024/package-update-command.md b/accepted/2024/package-update-command.md index 054fccb6e..292a8fc85 100644 --- a/accepted/2024/package-update-command.md +++ b/accepted/2024/package-update-command.md @@ -45,30 +45,37 @@ This proposal is focused on bringing the CLI experience up to funcional parity w ### Updating all packages to the latest version -When users want to ensure their NuGet dependencies are up to date, they can run a command in .NET CLI `dotnet package update`. +When users want to ensure their NuGet dependencies are up to date, they can run a command in .NET CLI `dotnet package update` for a project or a solution. ```CLI -C:\> dotnet package update +C:\> dotnet package update [|] Fixing outdated packages in ContosoUniversity.sln - Updated UmbracoForms 8.4.1 to 8.7.1 - Updated Newtonsoft.Json 11.0.1 to 13.0.3 + ContosoLibrary: + Updated UmbracoForms 8.4.1 to 8.7.1 + Updated Newtonsoft.Json 11.0.1 to 13.0.3 + + ContosoApp: + Updated UmbracoForms 8.4.0 to 8.7.1 -Updated 2 packages in 36 scanned packages. +Updated 3 packages in 36 scanned packages. ``` ### Fixing vulnerabilities -When users run `dotnet build` or `dotnet restore` commands in CLI, if they see any warnings related to vulnerabilities in their project’s NuGet dependencies, they can run `dotnet package update --vulnerable` CLI command to try to remediate all the vulnerabilities. +When users run `dotnet build` or `dotnet restore` commands in CLI, if they see any warnings related to vulnerabilities in their project’s NuGet dependencies, they can run `dotnet package update --vulnerable` CLI command to try to remediate all the vulnerabilities. This includes both direct and transitive. ```CLI -C:\> dotnet package update --vulnerable - +C:\ContosoApp\> dotnet package update --vulnerable Fixing vulnernable packages in ContosoUniversity.sln - Upgrading UmbracoForms 8.4.1 to 8.7.1 + ContosoLibrary: + Upgrading UmbracoForms 8.4.1 to 8.7.1 + + ContosoApp: + Updated UmbracoForms 8.4.0 to 8.7.1 -Fixed 1 package in 36 scanned packages. +Fixed 2 packages in 36 scanned packages. ``` In the future this can be extended to fix deprecated versions. @@ -105,7 +112,22 @@ The algorithm of the fixing process will have the following steps: Example: ```CLI -C:\> dotnet package update --vulnerable +C:\ContosoApp\> dotnet package update --vulnerable + +Fixing vulnernable packages in ContosoUniversity.sln + ContosoLibrary: + Upgrading UmbracoForms 8.4.1 to 8.7.1 + + ContosoApp: + Updated UmbracoForms 8.4.0 to 8.7.1 + +Fixed 2 packages in 36 scanned packages. +``` + +Another option for the output with more information (will review with CLI team to decide which one to pick): + +```CLI +C:\> dotnet package update --vulnerable [|] Fetching package metadata from: 'https://api.nuget.org/v3/index.json' Loaded 23 security advisories from 'https://api.nuget.org/v3/index.json' @@ -173,8 +195,8 @@ In the "failures" and "warnings" should be the information about what projects w Priority: P1 - 0 - The command will exit with a 0 exit code if no vulnerabilities or outdated packages were found and no changes were made. -- 1 - The command will exit with a 1 exit code if changes were successfull and the PR is submitted. -- 2 - The command will exit with a 2 exit code if any error has occured, PR will not be submitted. +- 1 - The command will exit with a 1 exit code if changes were successful and the PR is submitted. +- 2 - The command will exit with a 2 exit code if any error has occurred, PR will not be submitted. ##### Endpoints @@ -184,6 +206,16 @@ NuGet will use existing endpoints to optimize the speed of audit results. - Outdated - no existing endpoint, will need to call a source. - [Deprecation](https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#package-deprecation) for future possible improvements. +## Rationale and alternatives + + + + + +### Alternatives considrered + +We could enable the option for the users to pick if they want only direct vulnerabilities to be resolved or direct and transitive. We decided to not do so and implement the resolution of all vulnerabilities as we believe that better corresponds to our goal of increasing security across all .NET applications. + ## Prior Art From 55419dbaef9cf91f347cb708540935d2627f49f8 Mon Sep 17 00:00:00 2001 From: Andy Zivkovic Date: Sat, 4 Jan 2025 21:00:57 +1030 Subject: [PATCH 04/11] Update prior art section --- accepted/2024/package-update-command.md | 42 ++++++++++++++++++++----- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/accepted/2024/package-update-command.md b/accepted/2024/package-update-command.md index 292a8fc85..4d1deccdd 100644 --- a/accepted/2024/package-update-command.md +++ b/accepted/2024/package-update-command.md @@ -212,7 +212,7 @@ NuGet will use existing endpoints to optimize the speed of audit results. -### Alternatives considrered +### Alternatives considered We could enable the option for the users to pick if they want only direct vulnerabilities to be resolved or direct and transitive. We decided to not do so and implement the resolution of all vulnerabilities as we believe that better corresponds to our goal of increasing security across all .NET applications. @@ -222,13 +222,41 @@ We could enable the option for the users to pick if they want only direct vulner -- [snyk](https://snyk.io/) -- [npm audit](https://docs.npmjs.com/cli/v7/commands/npm-audit) -- [cargo audit](https://github.com/RustSec/cargo-audit) + +### [npm audit](https://docs.npmjs.com/cli/v7/commands/npm-audit) + +NPM has audit built in, which runs automatically on `npm install`, and it has an `npm audit fix` command. +The docs say fix will upgrade to a compatible version (it doesn't specify what compatible means, my guess is the matching the version range requested), and `--force` can be used to allow it to pick any version. +NPM Audit sends the list of used packages to the package registry, which responds with which packages are vulnerable (and presumably what versions vulnerabilities are fixed with). + +There is an `npm update` command, to update all packages to the latest version. +However, it appears to be constrained to the version ranges specified by each package in `package.json`, so in effect it just updates the lock file to the highest floating range requested. +The command `npm install` is used to install packages, but the docs don't specify the behavior if a different version of the package is already installed. +Neither command appears to have audit related functionality, or features to upgrade packages with known vulnerabilities, although audit runs by default on any install/update. + +### [cargo audit](https://github.com/RustSec/cargo-audit) + +Rust's cargo does not have audit functionality built in, and a crate must be installed, in addition to being run manually. +The `cargo-audit` crate supports both checking for vulnerabilities, as well as a fix command. +Cargo's audit appears to use a git repository as its data source. + +### [pip audit](https://pypi.org/project/pip-audit/) + +Python's pip does not appear to have an audit function built in, so it needs to be explicitly installed and run by customers who want to use it. +It has a `--fix` command, but the documentation doesn't provide any additional information. +The docs say that it gets advisory information from the PyPI JSON API, which appears to be a per-package details endpoint. + - [dotnet outdated](https://github.com/dotnet-outdated/dotnet-outdated) -- [dotnet retire](https://github.com/retirenet/dotnet-retire) -- [NuGet Defense](https://github.com/digitalcoyote/NuGetDefense) - + +The `dotnet-outdated` tool is a general package update tool for .NET projects on the CLI. +It does not appear to have functionality related to updating only packages with security advisories. + +- [OWASP Dependency-Check (Maven)](https://owasp.org/www-project-dependency-check/) + +Maven is a build tool for Java, including package management. +It supports plugins, and OWASP's Dependency-Check can be used as a plugin to detect packages with known vulnerabilities. +The docs don't mention any tooling to automatically update package versions to without vulnerabilities. + ## Future Possibilities From 0e49998d5c2d378bba5a40ddf36d4e32a6f630dc Mon Sep 17 00:00:00 2001 From: Olia Gavrysh <31997351+OliaG@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:21:09 -0800 Subject: [PATCH 05/11] addressed review comments Co-authored-by: Andy Zivkovic --- accepted/2024/package-update-command.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/accepted/2024/package-update-command.md b/accepted/2024/package-update-command.md index 4d1deccdd..74435bee1 100644 --- a/accepted/2024/package-update-command.md +++ b/accepted/2024/package-update-command.md @@ -9,7 +9,8 @@ The `dotnet package update` feature is designed to enhance the user experience by enabling .NET developers to address security vulnerabilities, deprecated packages, and outdated versions of their NuGet dependencies with a single command. -This improvement will, in turn, bolster the overall security and reliability of .NET applications. The feature will build upon the existing NuGet Audit functionality. +This improvement will, in turn, bolster the overall security and reliability of .NET applications. +The feature will build upon the existing NuGet Audit functionality. ## Motivation From 7a793ae5a738e386ef432c8e2055cdc83b76ca31 Mon Sep 17 00:00:00 2001 From: Olia Gavrysh <31997351+OliaG@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:21:34 -0800 Subject: [PATCH 06/11] Update accepted/2024/package-update-command.md Co-authored-by: Andy Zivkovic --- accepted/2024/package-update-command.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2024/package-update-command.md b/accepted/2024/package-update-command.md index 74435bee1..4464f7259 100644 --- a/accepted/2024/package-update-command.md +++ b/accepted/2024/package-update-command.md @@ -49,7 +49,7 @@ This proposal is focused on bringing the CLI experience up to funcional parity w When users want to ensure their NuGet dependencies are up to date, they can run a command in .NET CLI `dotnet package update` for a project or a solution. ```CLI -C:\> dotnet package update [|] +C:\> dotnet package update [|] Fixing outdated packages in ContosoUniversity.sln ContosoLibrary: From 660e61eb126e4a2183802944f55c432f68394534 Mon Sep 17 00:00:00 2001 From: Olia Gavrysh <31997351+OliaG@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:23:32 -0800 Subject: [PATCH 07/11] Apply suggestions from code review Co-authored-by: Andy Zivkovic --- accepted/2024/package-update-command.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/accepted/2024/package-update-command.md b/accepted/2024/package-update-command.md index 4464f7259..9ea9e81cb 100644 --- a/accepted/2024/package-update-command.md +++ b/accepted/2024/package-update-command.md @@ -26,7 +26,6 @@ Visual Studio - Has a means to update all packages to latest - Has a means to update a single package to latest (which can be challenging) - Has a vulnerability filter, which in turn can allow you to update all vulnerable packages to latest -dotnet CLI @@ -90,7 +89,7 @@ In the future this can be extended to fix deprecated versions. #### dotnet package update -The `dotnet package update` command will update all the NuGet dependencies to the latest versions. +The `dotnet package update` command without any other arguments or options will update all the NuGet dependencies to the latest versions. ```CLI C:\> dotnet package update --help @@ -99,7 +98,10 @@ dotnet package update [|] [--vulnerable] [--mode ] [-v| #### --vulnerable -This flag will try to update only packages that have direct or transitive vulnerabilities. The remediation is calculated with an implicit dotnet audit to then apply directly to a resulting package graph. It can add packages, remove packages, and update packages depending on the problem it's attempting to resolve. It does not take into consideration downgrading to a compatible version if a higher one has already been specified. +This flag will try to update only packages that have direct or transitive vulnerabilities. +The remediation is calculated with an implicit dotnet audit to then apply directly to a resulting package graph. +It can add packages, remove packages, and update packages depending on the problem it's attempting to resolve. +It does not take into consideration downgrading to a compatible version if a higher one has already been specified. The algorithm of the fixing process will have the following steps: 1. Identify vulnerabilities in the graph @@ -196,8 +198,8 @@ In the "failures" and "warnings" should be the information about what projects w Priority: P1 - 0 - The command will exit with a 0 exit code if no vulnerabilities or outdated packages were found and no changes were made. -- 1 - The command will exit with a 1 exit code if changes were successful and the PR is submitted. -- 2 - The command will exit with a 2 exit code if any error has occurred, PR will not be submitted. +- 1 - The command will exit with a 1 exit code if changes were successful. +- 2 - The command will exit with a 2 exit code if any error has occurred. ##### Endpoints @@ -215,7 +217,8 @@ NuGet will use existing endpoints to optimize the speed of audit results. ### Alternatives considered -We could enable the option for the users to pick if they want only direct vulnerabilities to be resolved or direct and transitive. We decided to not do so and implement the resolution of all vulnerabilities as we believe that better corresponds to our goal of increasing security across all .NET applications. +We could enable the option for the users to pick if they want only direct vulnerabilities to be resolved or direct and transitive. +We decided to not do so and implement the resolution of all vulnerabilities as we believe that better corresponds to our goal of increasing security across all .NET applications. ## Prior Art From 92c4a79ed617ad5455ec8260aaeb2532a404cfd4 Mon Sep 17 00:00:00 2001 From: Andy Zivkovic Date: Fri, 13 Jun 2025 11:23:01 +0930 Subject: [PATCH 08/11] Major update --- accepted/2024/package-update-command.md | 236 ++++++++++++------------ 1 file changed, 119 insertions(+), 117 deletions(-) diff --git a/accepted/2024/package-update-command.md b/accepted/2024/package-update-command.md index 9ea9e81cb..2715009be 100644 --- a/accepted/2024/package-update-command.md +++ b/accepted/2024/package-update-command.md @@ -1,9 +1,11 @@ # dotnet package update command - [Olia Gavrysh](https://github.com/OliaG/) +- [Andy Zivkovic](https://github.com/zivkan/) - Start Date (2024-11-11) - [#13372](https://github.com/NuGet/Home/issues/13372) - [#4103](https://github.com/NuGet/Home/issues/4103) +- [#14304](https://github.com/NuGet/Home/issues/14304) ## Summary @@ -39,80 +41,66 @@ CLI - No means to update to all latest packages on the CLI - No means for update heuristics, such as, update my vulnerable packages -This proposal is focused on bringing the CLI experience up to funcional parity with the experience in Visual Studio and make developers more productive by providing a single command to update all packages to the latest version and a way to update all vulnerable packages. +This proposal is focused on bringing the CLI experience up to functional parity with the experience in Visual Studio and make developers more productive by providing a single command to update all packages to the latest version and a way to update all vulnerable packages. -## User experience +## Explanation -### Updating all packages to the latest version +### Functional explanation -When users want to ensure their NuGet dependencies are up to date, they can run a command in .NET CLI `dotnet package update` for a project or a solution. +The `dotnet package update -h` help text might look something like this: -```CLI -C:\> dotnet package update [|] +```text +Description: + Update referenced packages in a project or solution. -Fixing outdated packages in ContosoUniversity.sln - ContosoLibrary: - Updated UmbracoForms 8.4.1 to 8.7.1 - Updated Newtonsoft.Json 11.0.1 to 13.0.3 +Usage: + NuGet.CommandLine.XPlat package update [...] [options] - ContosoApp: - Updated UmbracoForms 8.4.0 to 8.7.1 - -Updated 3 packages in 36 scanned packages. +Arguments: + Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. + +Options: + --format Specifies the output format type. + --mode The implementation will have a description here to explain the differences between direct and promote. + --project Path to a project or solution file, or a directory. + --vulnerable Update packages with a known vulnerability. + -?, -h, --help Show help and usage information ``` -### Fixing vulnerabilities +### Scenarios -When users run `dotnet build` or `dotnet restore` commands in CLI, if they see any warnings related to vulnerabilities in their project’s NuGet dependencies, they can run `dotnet package update --vulnerable` CLI command to try to remediate all the vulnerabilities. This includes both direct and transitive. +#### Works with other features -```CLI -C:\ContosoApp\> dotnet package update --vulnerable +This probably can go without saying, but it's expected that all `dotnet package update` commands work with all other Nuget features. -Fixing vulnernable packages in ContosoUniversity.sln - ContosoLibrary: - Upgrading UmbracoForms 8.4.1 to 8.7.1 - - ContosoApp: - Updated UmbracoForms 8.4.0 to 8.7.1 - -Fixed 2 packages in 36 scanned packages. -``` +For example, projects that use Central Package Management should have versions updated in the Directory.Packages.props file. +Another example is when a nuget.config has enabled Package Source Mapping, the updated packages must take into account the versions available on the enabled sources, so that subsequent restores will be successful. -In the future this can be extended to fix deprecated versions. +Similarly, since `dotnet package update` is part of the .NET SDK, it's only expected to work with projects that work with `dotnet build`. +Therefore, some Visual Studio projects will not work, where they can't be built with the dotnet CLI. -## Explanation +#### Updating all packages to the latest version -### Functional explanation +Running `dotnet package update` without specifying any packages, or options such as `--vulnerable`, will automatically update all packages to the highest version. - - +```text +C:\> dotnet package update -#### dotnet package update +Fixing outdated packages in ContosoUniversity.sln + ContosoLibrary: + Updated UmbracoForms 8.4.1 to 8.7.1 + Updated Newtonsoft.Json 11.0.1 to 13.0.3 -The `dotnet package update` command without any other arguments or options will update all the NuGet dependencies to the latest versions. + ContosoApp: + Updated UmbracoForms 8.4.0 to 8.7.1 -```CLI -C:\> dotnet package update --help -dotnet package update [|] [--vulnerable] [--mode ] [-v|--verbosity ] [--json] +Updated 3 packages in 36 scanned packages. ``` -#### --vulnerable +#### Fixing vulnerabilities -This flag will try to update only packages that have direct or transitive vulnerabilities. -The remediation is calculated with an implicit dotnet audit to then apply directly to a resulting package graph. -It can add packages, remove packages, and update packages depending on the problem it's attempting to resolve. -It does not take into consideration downgrading to a compatible version if a higher one has already been specified. -The algorithm of the fixing process will have the following steps: - -1. Identify vulnerabilities in the graph -1. Distinguish which are top level, transitive level, etc., -1. Resolve any compatibility conflicts -1. Apply the patch/update/fix -1. Restore dependencies -1. Verify that issues were resolved . Provide the report to the user. -1. If the issues were not resolved or were partially resolved, we will still commit the fixes and notify users about what was and was not fixed and what are the recommended manual steps with links to documentation. - -Example: +When users run `dotnet build` or `dotnet restore` commands in CLI, if they see any warnings related to vulnerabilities in their project’s NuGet dependencies, they can run `dotnet package update --vulnerable` CLI command to try to remediate all the vulnerabilities. +This includes both direct and transitive. ```CLI C:\ContosoApp\> dotnet package update --vulnerable @@ -127,87 +115,70 @@ Fixing vulnernable packages in ContosoUniversity.sln Fixed 2 packages in 36 scanned packages. ``` -Another option for the output with more information (will review with CLI team to decide which one to pick): +Using the `--vulnerable` option should update the package to the lowest version that is higher than the currently reference version, which does not have a known vulnerability. +For example, if `Contoso.Security` version 1.0.0 is currently referenced by the project, and the package source has versions 1.0.1 and 2.0.0 available, 1.0.1 should be selected. +This is in contrast to `dotnet package update Contoso.Security` which will update to the highest version of the package. -```CLI -C:\> dotnet package update --vulnerable [|] +If package identifiers are provided in addition to the `--vulnerable` option, only those packages should be updated. +Any package provided that does not have a known vulnerability will be skipped. -Fetching package metadata from: 'https://api.nuget.org/v3/index.json' -Loaded 23 security advisories from 'https://api.nuget.org/v3/index.json' -Scanning ContosoUniversity.sln (36 NuGet dependencies) +The `--mode` option will allow customers to choose what strategy of resolving vulnerabilities will be used. +The `direct` mode would only look for direct package references with known vulnerabilities and upgrade them. +The `promote` mode would also check transitive packages (equivalent to restore's `all`), and add a PackageReference to the package (therefore promoting it to a direct reference). +Later, more advanced modes can be added. -error: Vulnernable packages found! -[net5.0]: -Top-level Package Requested Resolved Severity Advisory URL -> UmbracoForms 8.4.1 8.4.1 Moderate https://github.com/advisories/GHSA-8m73-w2r2-6xxj +In the future a similar option to fix deprecated versions can be added. -Transitive Package Resolved Severity Advisory URL -> Microsoft.Data.OData 5.2.0 Moderate https://github.com/advisories/GHSA-mv2r-q4g5-j8q5 +#### --format json -Found 1 top-level Moderate severity vulnerability & 1 transtive Moderate severity vulnerability package(s) in 36 scanned packages. +Priority: P2 -Fixing vulnernable packages in ContosoUniversity.sln - Upgrading UmbracoForms 8.4.1 to 8.7.1 +A JSON schema will be decided closer to implementation. +A new design document will be created specifically for it, to avoid slowing down the approval of this design document and implementation of other features. -Fixed 2 packages in 36 scanned packages. -``` +There is potential complexity with designing the schema, as the text output can be tailored to the command line arguments provided. +For example, `dotnet package update` to update all packages might update just the packages that were updated. +But `dotnet package update pkg1 pkg2 pkg3` might say pkg1 and pkg2 were updated, but pkg3 was already up to date. +Similarly, using `--vulnerable` could have vulnerability specific output. -#### --mode +Some consideration may be needed to decide how much of the same information should be reported in the json (particularly when packages are not updated), and if the json schema should be the same for all commands, or if `--vulnerable` should have a different output schema than without `--vulnerable`. -Priority: P1 for `promote`; P2 for `closest` and switching the default to `closest`. +Please provide feedback at -| Mode | Explanation | -|------|-------------| -| `promote` | the algorithm will always promote transitive packages to top level. This is an easy to implement feature that we will release in MVP. | -| `closest` | the algorithm will try to upgrade the direct package reference, and if that doesn't work, it will walk the graph one dependency level at a time trying to upgrade that, until it gets to the package with the known vulnerability. Once this mode is implemented, it should be set to be the default one. | +#### Exit Codes -#### --format json +Priority: P1 -Priority: P2 +- 0 - The command will exit with a 0 exit code if at least one package was updated without any error. +- 1 - The command will exit with a 1 exit code if no packages were updated, but otherwise no error occurred. +- 2 - The command will exit with a 2 exit code if any error has occurred. -Provides a detailed report in a JSON format: - -```json - "added": [ - { - "name": "Microsoft.AspNetCore.MVC", - "version": "2.2.0" - } - ], - "removed": [ - { - "name": "anurse.testing.TestDeprecatedPackage", - "version": "1.0.0" - } - ], - "updated": [ - { - "name": "UmbracoForms", - "version": "8.7.1", - "previousVersion": "8.4.1" - } - ], - "failures": [], - "warnings": [] -``` +### Technical explanation -In the "failures" and "warnings" should be the information about what projects were not updated due to failed pipeline or different reassons like no solution was found, the format of the project file is not supported, etc. + -##### Exit Codes +#### dotnet CLI integration -Priority: P1 +The dotnet CLI has many features, and are evolving while we implement this design. +So, there is a lot of additional scope for quality of life improvements. +But we should also adhere to general CLI design principals. -- 0 - The command will exit with a 0 exit code if no vulnerabilities or outdated packages were found and no changes were made. -- 1 - The command will exit with a 1 exit code if changes were successful. -- 2 - The command will exit with a 2 exit code if any error has occurred. +One example is that bad input should be handled in the command line parser. +For example, is a version string is expected, it should be validated in System.CommandLine's argument or option validator, or custom parser. +Don't do validation in the command runner's logic and then provide these input errors in a different user experience than other parser errors. -##### Endpoints +Another example, tab completion. +Not only of the command and its options, but if a package name is partially typed, tab completion could complete the full package name. +In the scope of `dotnet package update`, this likely means packages already installed in projects, whereas `dotnet package add` would check package sources for available packages. +Similarly for package versions. -NuGet will use existing endpoints to optimize the speed of audit results. +In .NET 9, MSBuild enabled the Terminal Logger by default. +It's easiest if you test `dotnet build` and `dotnet build -tl:false` yourself on a solution with at least 10 projects (some of which can be built in parallel) to understand how it changes output. +But my short description is that it no longer treats the console as a forward-only output, but parallel work can be displayed one line per task and lines are updated to show progress. +Similarly, we should consider what output would give customers the best experience, especially when a large solution is being updated, so many projects and packages might be impacted, therefore taking some time before the command is complete. -- [Vulnerability](https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#vulnerabilities) -- Outdated - no existing endpoint, will need to call a source. -- [Deprecation](https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#package-deprecation) for future possible improvements. +Most of these improvements can be considered low priority enhancements after the initial feature set is implemented. +But easy opportunities to make quality-of-life improvements should be taken rather than delaying them as lower priority. ## Rationale and alternatives @@ -217,8 +188,38 @@ NuGet will use existing endpoints to optimize the speed of audit results. ### Alternatives considered -We could enable the option for the users to pick if they want only direct vulnerabilities to be resolved or direct and transitive. -We decided to not do so and implement the resolution of all vulnerabilities as we believe that better corresponds to our goal of increasing security across all .NET applications. +#### Extending dotnet package update + +The existing `dotnet package add` command can already update a PackageReference to a newer version. +However, it would be unintuitive for `dotnet package add` without any arguments updated all packages to the highest version, given the verb is `add`. +Similarly, `dotnet package add --update` feels unusual, and something like `dotnet package add --vulnerable` to update already referenced packages don't feel right. +Therefore, a new `dotnet package update` command is more desirable. + +#### A vulnerability specific command + +Command names similar to `dotnet nuget fix`, `dotnet nuget audit fix`, `dotnet package audit` were considered, but while discussing with some stakeholders, we thought that `dotnet package update --vulnerable` would be the most intuitive, even if it does require more letters to be typed. + +#### Considering `--version` option + +The `dotnet package add` command had a `--version` option since it was first created. +Similarly, other commands such as `dotnet tool install` have `--version` options. +In the 9.0.300 .NET SDK, `dotnet add package` was extended to allow specifying the version in the package id string, using syntax `{package id}@{version}`, for example `NuGet.Protocol@6.10.0`. +Other dotnet CLI have also been updated to allow this `@` syntax. + +Since the `@` syntax is new, it's probably not well known, so some people might expect a `--version` option. +But if the CLI help output explicitly mentions it, like `dotnet package add -h` does, then it should be easily discoverable. + +Another scenario is when a customer wants to update multiple packages to the same version, they might like `dotnet package update pkg1 pkg2 --version 12.34.56`. + +However, allowing this would raise questions like `dotnet package update pkg1@1.2.3 pkg2@2.3.4 pkg3 pkg4 --version 3.4.5`. +In this example, which packages does the version 3.4.5 apply to? +Personally, I find pkg3 and pkg4 the most intuitive. +Put another way, specifying `--version` could mean disabling "update to highest version". + +Alternatively, we could not provide the `--version` option at all for new commands and embrace the `@` syntax. +The biggest downside to this is when multiple packages are updated to the same version, that version string needs to be repeated multiple times. +With the .NET Libraries team updating all of their packages every release, even when there are no code changes in a patch version (possibly only a dependency version update, but sometimes not even that), it will be a common scenario that multiple `System.*` and `Microsoft.*` packages will be updated at the same time to the same version. +But it avoids all ambiguity. ## Prior Art @@ -265,6 +266,7 @@ The docs don't mention any tooling to automatically update package versions to w -- In the future the basic algorithm could check for breaking changes in fixed versions. +- A new mode for `--vulnerable` that would walk the package graph for transitive packages with known vulnerabilities, and update the package closest to the direct reference. +- When transitive packages are promoted to resolve a vulnerability warning, somehow mark the package reference (or package version, in case of CPM), so a later package update can remove the pinning when it's no longer needed. - This functionality may be reused to implement a one-click fix in the Visual Studio UI experience. - Enable fixes for deprecations and outdated versions as well together with an option for the users to choose what they want to fix (vulnerabilities, depreciation, outdated versions). From ce92042d02f306b3d9ea6be5557954c0096e74ee Mon Sep 17 00:00:00 2001 From: Andy Zivkovic Date: Fri, 13 Jun 2025 11:32:53 +0930 Subject: [PATCH 09/11] things I forgot --- accepted/2024/package-update-command.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/accepted/2024/package-update-command.md b/accepted/2024/package-update-command.md index 2715009be..463155272 100644 --- a/accepted/2024/package-update-command.md +++ b/accepted/2024/package-update-command.md @@ -100,7 +100,7 @@ Updated 3 packages in 36 scanned packages. #### Fixing vulnerabilities When users run `dotnet build` or `dotnet restore` commands in CLI, if they see any warnings related to vulnerabilities in their project’s NuGet dependencies, they can run `dotnet package update --vulnerable` CLI command to try to remediate all the vulnerabilities. -This includes both direct and transitive. +The `--mode` option can be used to choose between direct package references only, or to also update transitive packages. ```CLI C:\ContosoApp\> dotnet package update --vulnerable @@ -126,6 +126,7 @@ The `--mode` option will allow customers to choose what strategy of resolving vu The `direct` mode would only look for direct package references with known vulnerabilities and upgrade them. The `promote` mode would also check transitive packages (equivalent to restore's `all`), and add a PackageReference to the package (therefore promoting it to a direct reference). Later, more advanced modes can be added. +When a project is using CPM and transitive pinning is enabled, no PackageReference should be added, just the PackageVersion in the Directory.Packages.props file. In the future a similar option to fix deprecated versions can be added. @@ -262,6 +263,19 @@ Maven is a build tool for Java, including package management. It supports plugins, and OWASP's Dependency-Check can be used as a plugin to detect packages with known vulnerabilities. The docs don't mention any tooling to automatically update package versions to without vulnerabilities. +## Unresolved Questions + + + + + +- CPM integration + +CPM adds more complexity than other NuGet features. +Should `dotnet package update` upgrade `GlobalPackageReference`s? +Should it allow you to modify Directory.Packages.props when only one project is provided, not the whole solution? +When run on a solution, should it check for unused `PackageVersion`s and provide a way to remove them? + ## Future Possibilities From e4695f5dcab7075d2c39909ca825452796f34e1f Mon Sep 17 00:00:00 2001 From: Andy Zivkovic Date: Tue, 17 Jun 2025 10:44:22 +0930 Subject: [PATCH 10/11] feedback --- accepted/2024/package-update-command.md | 58 ++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/accepted/2024/package-update-command.md b/accepted/2024/package-update-command.md index 463155272..280f28912 100644 --- a/accepted/2024/package-update-command.md +++ b/accepted/2024/package-update-command.md @@ -54,12 +54,13 @@ Description: Update referenced packages in a project or solution. Usage: - NuGet.CommandLine.XPlat package update [...] [options] + dotnet package update [...] [options] Arguments: Package reference in the form of a package identifier like 'Newtonsoft.Json' or package identifier and version separated by '@' like 'Newtonsoft.Json@13.0.3'. Options: + --dry-run Output what changes would be made, but don't modify any files. --format Specifies the output format type. --mode The implementation will have a description here to explain the differences between direct and promote. --project Path to a project or solution file, or a directory. @@ -128,7 +129,8 @@ The `promote` mode would also check transitive packages (equivalent to restore's Later, more advanced modes can be added. When a project is using CPM and transitive pinning is enabled, no PackageReference should be added, just the PackageVersion in the Directory.Packages.props file. -In the future a similar option to fix deprecated versions can be added. +If multiple packages have vulnerability warnings, but `dotnet package update --vulnerable` is only able to resolve some, but not all, of the warnings, it should make the changes it can, but return an exit code showing an error. +This only applies when the command is run without specifying any package ids (so update all packages with known vulnerabilities), or if multiple package ids are provided on the command line, and the package vulnerability that cannot be resolved is one of the provided packages. #### --format json @@ -151,8 +153,29 @@ Please provide feedback at Priority: P1 - 0 - The command will exit with a 0 exit code if at least one package was updated without any error. -- 1 - The command will exit with a 1 exit code if no packages were updated, but otherwise no error occurred. -- 2 - The command will exit with a 2 exit code if any error has occurred. +- 1 - The command will exit with a 1 exit code if the CLI options are invalid. +- 2 - The command will exit with a 2 exit code if no packages were updated, but otherwise no error occurred. +- 3 - The command will exit with a 3 exit code if any error has occurred. + +The dotnet CLI uses exit code 1 when the CLI parser detects an error before running the command action, so we can't modify this exit code. + +Exit code 2 is probably the most controversial. +The convention is that success is zero and non-zero is a failure of some kind. +Whether no packages are updated is a success or failure depends on the scenario. +Some customers might want to just make sure that all the packages are already at the highest version, so they consider no updates needed as a success. +However, other customers will only run the command when they know they want a package to be updated, in which case a failure to find a higher version is an error. +Since the name of the command is update, exit code 2 is chosen, and customers will need to handle the non-zero exit code in their shell or CI scripts. + +Examples are: + +* If `dotnet package update Contoso@1..0` is run, the exit code will be 1 because `1..0` is not a valid NuGet version range, causing the CLI parser to fail. +* If `dotnet package update Contoso@3.2.1` is run, but package version 3.2.1 does not exist, exit code 3 will be returned. +* If `dotnet package update Contoso` is run, but the package is already at the highest version available on all package sources, then exit code 2 is returned. +* If `dotnet package update Pkg1 Pkg2` is run and Pkg1 was updated to a newer version bu Pkg2 was already at the highest version, exit code 0 will be used since at least one update was found. +* If `dotnet package update` is run on a project using `TreatWarningsAsErrors`, and the preview restore has a warning (that is elevated to an error), exit code 3 will be used since `dotnet restore` would also have an error if the update was applied. +* If `dotnet package update Contoso.Shared` is run, but no project references that package, exit code 3 will be used. +* In any case where a project or solution file can't be found (or when a directory is provided and multiple are found), then exit code 3 will be used. +* If `dotnet package update --vulnerable` is run, but not all vulnerabilities could be automatically resolved, then exit code 3 will be used, but any packages whose vulnerabilities could be resolved will be applied. ### Technical explanation @@ -189,7 +212,7 @@ But easy opportunities to make quality-of-life improvements should be taken rath ### Alternatives considered -#### Extending dotnet package update +#### Extending dotnet package add The existing `dotnet package add` command can already update a PackageReference to a newer version. However, it would be unintuitive for `dotnet package add` without any arguments updated all packages to the highest version, given the verb is `add`. @@ -222,6 +245,22 @@ The biggest downside to this is when multiple packages are updated to the same v With the .NET Libraries team updating all of their packages every release, even when there are no code changes in a patch version (possibly only a dependency version update, but sometimes not even that), it will be a common scenario that multiple `System.*` and `Microsoft.*` packages will be updated at the same time to the same version. But it avoids all ambiguity. +#### Specifying target frameworks + +The `dotnet package add` command, as well as `dotnet build`, `dotnet test`, `dotnet run` commands, have a `--framework` option to specify which target framework the command should act on. + +I chose not to add it to `dotnet package update` because this command is intended to update packages that are already installed, and the use case for build, test, publish, and run are different to package add or update. +It's a good option for `dotnet package add`. +But for update, the common scenario will be to update the package for all target frameworks that the package is installed in. + +Additionally, if a package reference's condition does not match the command line's `--framework` provided, there is ambiguity if the package reference should have it's condition modified. +Doing so would make the project use different versions of the package for different target frameworks. +Not modifying the condition would change the package version for a target framework that was not specified on the command line. +Neither behavior is obviously preferred, causing the proposed option to have ambiguous results. + +For the early versions of the command, we can say this is an advanced scenario, and as such, advanced scenarios need hand-editing without tooling support. +If we get sufficient customer feedback, we can revisit this. + ## Prior Art @@ -280,7 +319,14 @@ When run on a solution, should it check for unused `PackageVersion`s and provide +- Some kind of `--force` or `--no-restore` or `--do-not-treat-warnings-as-errors`. + All NuGet's existing install/upgrade gestures will do a preview restore and will not modify projects is the preview restore has any error. + But when multiple packages have warnings causing errors, it becomes difficult to resolve the warnings one by one. + There is still value in failing the update if there are "real" errors, so there should be a way to ignore `TreatWarningsAsErrors` for an update command. - A new mode for `--vulnerable` that would walk the package graph for transitive packages with known vulnerabilities, and update the package closest to the direct reference. + [See the NuGet Audit 2.0 blog post](https://devblogs.microsoft.com/dotnet/nugetaudit-2-0-elevating-security-and-trust-in-package-management/#recommended-way-to-resolve-warnings) for more details. - When transitive packages are promoted to resolve a vulnerability warning, somehow mark the package reference (or package version, in case of CPM), so a later package update can remove the pinning when it's no longer needed. - This functionality may be reused to implement a one-click fix in the Visual Studio UI experience. -- Enable fixes for deprecations and outdated versions as well together with an option for the users to choose what they want to fix (vulnerabilities, depreciation, outdated versions). +- Enable fixes for deprecations with an option for the users to choose what they want to fix (vulnerabilities, depreciation, outdated versions). +- Modify the NuGet Audit warnings to specify that `dotnet package update --vulnerable` can be used to resolve the warnings. + At this time it's not possible to modify restore warnings depending if restore is running on the command line or in Visual Studio, and we wouldn't want to tell customers using VS to use the CLI, so that would be a requirement before implementing a warning message update to instruct customers to use a CLI tool. From 13feb26aa0b212c9d3d1f8f6913c15fa7b144cfe Mon Sep 17 00:00:00 2001 From: Andy Zivkovic Date: Tue, 17 Jun 2025 15:55:50 +0930 Subject: [PATCH 11/11] remove unresolved questions --- accepted/2024/package-update-command.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/accepted/2024/package-update-command.md b/accepted/2024/package-update-command.md index 280f28912..6cd51b9b9 100644 --- a/accepted/2024/package-update-command.md +++ b/accepted/2024/package-update-command.md @@ -308,13 +308,6 @@ The docs don't mention any tooling to automatically update package versions to w -- CPM integration - -CPM adds more complexity than other NuGet features. -Should `dotnet package update` upgrade `GlobalPackageReference`s? -Should it allow you to modify Directory.Packages.props when only one project is provided, not the whole solution? -When run on a solution, should it check for unused `PackageVersion`s and provide a way to remove them? - ## Future Possibilities