From b18b5cc1507df04ea9785f8ba613b1ceb2ad93ea Mon Sep 17 00:00:00 2001 From: Donnie Goodson <49205731+donnie-msft@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:57:43 -0800 Subject: [PATCH 1/2] Update Readme verbiage --- meta/README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/meta/README.md b/meta/README.md index 6a78151c6..9ee895423 100644 --- a/meta/README.md +++ b/meta/README.md @@ -3,7 +3,7 @@ ## How do I create a proposal? - Fork or clone https://github.com/NuGet/Home -- Copy `meta/template.md` into `proposed//your-proposal-name.md` +- Copy `meta/template.md` into `accepted//your-proposal-name.md` - Fill in the template with your proposal. - Submit a PR to the `NuGet/Home` repo - (Optional) Create a new discussion to talk about it https://github.com/NuGet/Home/discussions/new @@ -16,19 +16,18 @@ All discussions surrounding a proposal are covered by the [.NET Foundation code ## What happens to a proposal? -When there is consensus among the NuGet contributors and .NET community of the direction of the proposal, and at least one NuGet contributor has signed off on the proposal, it will be merged into the `Proposed` folder. +When there is consensus among the NuGet contributors and .NET community of the direction of the proposal, and at least one NuGet contributor has signed off on the proposal, it will be merged into the `Accepted` folder (eg, `accepted//your-proposal-name.md`). Otherwise, the proposal will be withdrawn by closing the PR with the reasoning mentioned in the PR. ## What happens when a proposal is accepted? -A PR will be opened to move the proposal from `Proposed` to `Accepted` (eg, `accepted//your-proposal-name.md`). The PR can contain any edits to the original proposal can be made based on the acceptance criteria. Once accepted, it will be scheduled by the NuGet contributors to be implemented or put up for grabs for anyone to implement by making a PR in the appropriate repository. ## What happens when a proposal is implemented? -When the changes described in the accepted proposal have been implemented and merged into the relevant repository and due for release the corresponding proposal will remain in the `accepted` folder. The linked GitHub issue will be closed upon merging to the relevant branch. +When the changes described in the accepted proposal have been implemented and merged into the relevant repository and due for release the corresponding proposal will be moved to the `implemented` folder. The linked GitHub issue will be closed upon merging to the relevant branch. -If you'd like to implement an `accepted` proposal, please make a PR in the appropriate repository and mention the proposal in the PR and Issue. +If you'd like to implement an `accepted` proposal, please make a PR in the appropriate repository and mention the proposal in the PR and Issue. ## What happens when a proposal is withdrawn? From 385ed6ed0ff13ec6fe7465a1abae922e774e3fe5 Mon Sep 17 00:00:00 2001 From: Donnie Goodson <49205731+donnie-msft@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:58:04 -0800 Subject: [PATCH 2/2] Move existing Proposals to Accepted folder --- ...llyManagingNuGetPackageVersions-Restore.md | 0 .../CentrallyManagingNuGetPackageVersions.md | 0 .../MachineReadableOutputDotNetListPackage.md | 0 .../DotnetListPackageVulnerable.md | 0 .../FlagVulnerablePackages.md | 0 .../NuGet.orgVulnerabilitiesPhase1.md | 0 .../PackageVulnerability/PMUIVulnerability.md | 0 .../2020/SupportPackageRenames.md | 0 .../2020/Transitive-Dependencies.md | 0 .../CentralPackageManagementTransitive.md | 0 .../2021/NuGetConsumePDBInPackageReference.md | 0 .../2021/NuGetOrgTFMDropdownBadges.md | 0 .../2021/ProjectUpdateEventsInVisualStudio.md | 0 .../2021/TransitiveDependenciesInPMUI.md | 0 ...etTargetFallback-DependenciesResolution.md | 814 ++++++++-------- ...netListPackageMachineReadableJsonOutput.md | 0 .../NuGetExeWarnWhenSDKProjectsGetPacked.md | 198 ++-- .../2022/WarningsNotAsErrors.md | 170 ++-- .../cpm-dotnet-cli-add-package-support.md | 0 .../2022/dotnet-nuget-config-spec.md | 0 .../2022/dotnet-nuget-why-proposal.md | 0 .../duplicate-nuget-item-error-handling.md | 0 .../2022/globalpackagereference.md | 0 .../2022/version-overrides.md | 0 .../2022/vulnerabilities-in-restore.md | 886 +++++++++--------- .../2023/Add-NoHttpCacheOption.md | 0 .../2023/Add-dotnet-search.md | 0 ...ConnectionsDisableCertificateValidation.md | 0 .../2023/PMUI-Readme-rendering.md | 0 .../2023/readme-markdown-install-PMUI.md | 0 ...move-projects-from-list-package-command.md | 0 .../archive/AdvancedSearchOnNuGet.md | 0 .../archive/Deterministic-Pack.md | 0 .../archive/DotNetSignCommands.md | 0 .../archive/DotNetSources/Commands.xml | 0 .../DotNetSources/DotNet-Sources-Support.md | 0 .../archive/Download-Only-Packages.md | 0 .../archive/EmbeddedReadmesTechSpec.md | 0 .../archive/FloatingStableAndPrerelease.md | 0 .../archive/FloatingVersions-In-PMUI.md | 0 .../archive/NuGet-ClientCertificates.md | 0 ...NuGet-FrameworkReference-TransitiveFlow.md | 0 .../archive/NuGet-FrameworkReference.md | 0 .../INuGetProjectServices.md | 0 .../NuGetExtensibilityServices.md | 0 .../archive/NuGetOrgReplicationAPI.md | 0 .../archive/PMUITabSwitchRefactoring.md | 0 .../archive/Package-List-Verbosity.md | 0 ...ageApplicabilityInNuGetPackageManagerUI.md | 0 ...kageIconLicenseDocumentationWithinNupkg.md | 0 ...ackageReference-AllStable-Normalization.md | 0 .../archive/PackageReference-Extern-Alias.md | 0 .../BuildPropsConventionIsUpheld.md | 0 .../DependenciesInNuspecMatchLibRefFolder.md | 0 .../FileNameCaseSensitivity.md | 0 .../RefAssembliesInNuspecMatchRefFolder.md | 0 .../archive/Prerelease-Option.md | 0 .../archive/RefreshMetrics.md | 0 .../archive/RuntimeJsonFromProject.md | 0 .../archive/SearchCommandSpec.md | 0 ...utionLoad-CsprojPackageReferenceRestore.md | 0 ...guration-AdditionalExtensibilityFolders.md | 0 ...VisualStudio-PartialRestoreOptimization.md | 0 proposed/README.md | 11 - 64 files changed, 1034 insertions(+), 1045 deletions(-) rename {proposed => accepted}/2020/CentralNuGetManagement/CentrallyManagingNuGetPackageVersions-Restore.md (100%) rename {proposed => accepted}/2020/CentralNuGetManagement/CentrallyManagingNuGetPackageVersions.md (100%) rename {proposed => accepted}/2020/MachineReadableOutputDotNetListPackage.md (100%) rename {proposed => accepted}/2020/PackageVulnerability/DotnetListPackageVulnerable.md (100%) rename {proposed => accepted}/2020/PackageVulnerability/FlagVulnerablePackages.md (100%) rename {proposed => accepted}/2020/PackageVulnerability/NuGet.orgVulnerabilitiesPhase1.md (100%) rename {proposed => accepted}/2020/PackageVulnerability/PMUIVulnerability.md (100%) rename {proposed => accepted}/2020/SupportPackageRenames.md (100%) rename {proposed => accepted}/2020/Transitive-Dependencies.md (100%) rename {proposed => accepted}/2021/CentralPackageManagementTransitive.md (100%) rename {proposed => accepted}/2021/NuGetConsumePDBInPackageReference.md (100%) rename {proposed => accepted}/2021/NuGetOrgTFMDropdownBadges.md (100%) rename {proposed => accepted}/2021/ProjectUpdateEventsInVisualStudio.md (100%) rename {proposed => accepted}/2021/TransitiveDependenciesInPMUI.md (100%) rename {proposed => accepted}/2022/AssetTargetFallback-DependenciesResolution.md (98%) rename {proposed => accepted}/2022/DotnetListPackageMachineReadableJsonOutput.md (100%) rename {proposed => accepted}/2022/NuGetExeWarnWhenSDKProjectsGetPacked.md (98%) rename {proposed => accepted}/2022/WarningsNotAsErrors.md (98%) rename {proposed => accepted}/2022/cpm-dotnet-cli-add-package-support.md (100%) rename {proposed => accepted}/2022/dotnet-nuget-config-spec.md (100%) rename {proposed => accepted}/2022/dotnet-nuget-why-proposal.md (100%) rename {proposed => accepted}/2022/duplicate-nuget-item-error-handling.md (100%) rename {proposed => accepted}/2022/globalpackagereference.md (100%) rename {proposed => accepted}/2022/version-overrides.md (100%) rename {proposed => accepted}/2022/vulnerabilities-in-restore.md (98%) rename {proposed => accepted}/2023/Add-NoHttpCacheOption.md (100%) rename {proposed => accepted}/2023/Add-dotnet-search.md (100%) rename {proposed => accepted}/2023/InsecureConnectionsDisableCertificateValidation.md (100%) rename {proposed => accepted}/2023/PMUI-Readme-rendering.md (100%) rename {proposed => accepted}/2023/readme-markdown-install-PMUI.md (100%) rename {proposed => accepted}/2023/remove-projects-from-list-package-command.md (100%) rename {proposed => accepted}/archive/AdvancedSearchOnNuGet.md (100%) rename {proposed => accepted}/archive/Deterministic-Pack.md (100%) rename {proposed => accepted}/archive/DotNetSignCommands.md (100%) rename {proposed => accepted}/archive/DotNetSources/Commands.xml (100%) rename {proposed => accepted}/archive/DotNetSources/DotNet-Sources-Support.md (100%) rename {proposed => accepted}/archive/Download-Only-Packages.md (100%) rename {proposed => accepted}/archive/EmbeddedReadmesTechSpec.md (100%) rename {proposed => accepted}/archive/FloatingStableAndPrerelease.md (100%) rename {proposed => accepted}/archive/FloatingVersions-In-PMUI.md (100%) rename {proposed => accepted}/archive/NuGet-ClientCertificates.md (100%) rename {proposed => accepted}/archive/NuGet-FrameworkReference-TransitiveFlow.md (100%) rename {proposed => accepted}/archive/NuGet-FrameworkReference.md (100%) rename {proposed => accepted}/archive/NuGetExtensibility/INuGetProjectServices.md (100%) rename {proposed => accepted}/archive/NuGetExtensibility/NuGetExtensibilityServices.md (100%) rename {proposed => accepted}/archive/NuGetOrgReplicationAPI.md (100%) rename {proposed => accepted}/archive/PMUITabSwitchRefactoring.md (100%) rename {proposed => accepted}/archive/Package-List-Verbosity.md (100%) rename {proposed => accepted}/archive/PackageApplicabilityInNuGetPackageManagerUI.md (100%) rename {proposed => accepted}/archive/PackageIconLicenseDocumentationWithinNupkg.md (100%) rename {proposed => accepted}/archive/PackageReference-AllStable-Normalization.md (100%) rename {proposed => accepted}/archive/PackageReference-Extern-Alias.md (100%) rename {proposed => accepted}/archive/PackageValidation/BuildPropsConventionIsUpheld.md (100%) rename {proposed => accepted}/archive/PackageValidation/DependenciesInNuspecMatchLibRefFolder.md (100%) rename {proposed => accepted}/archive/PackageValidation/FileNameCaseSensitivity.md (100%) rename {proposed => accepted}/archive/PackageValidation/RefAssembliesInNuspecMatchRefFolder.md (100%) rename {proposed => accepted}/archive/Prerelease-Option.md (100%) rename {proposed => accepted}/archive/RefreshMetrics.md (100%) rename {proposed => accepted}/archive/RuntimeJsonFromProject.md (100%) rename {proposed => accepted}/archive/SearchCommandSpec.md (100%) rename {proposed => accepted}/archive/SolutionLoad-CsprojPackageReferenceRestore.md (100%) rename {proposed => accepted}/archive/UserWideConfiguration-AdditionalExtensibilityFolders.md (100%) rename {proposed => accepted}/archive/VisualStudio-PartialRestoreOptimization.md (100%) delete mode 100644 proposed/README.md diff --git a/proposed/2020/CentralNuGetManagement/CentrallyManagingNuGetPackageVersions-Restore.md b/accepted/2020/CentralNuGetManagement/CentrallyManagingNuGetPackageVersions-Restore.md similarity index 100% rename from proposed/2020/CentralNuGetManagement/CentrallyManagingNuGetPackageVersions-Restore.md rename to accepted/2020/CentralNuGetManagement/CentrallyManagingNuGetPackageVersions-Restore.md diff --git a/proposed/2020/CentralNuGetManagement/CentrallyManagingNuGetPackageVersions.md b/accepted/2020/CentralNuGetManagement/CentrallyManagingNuGetPackageVersions.md similarity index 100% rename from proposed/2020/CentralNuGetManagement/CentrallyManagingNuGetPackageVersions.md rename to accepted/2020/CentralNuGetManagement/CentrallyManagingNuGetPackageVersions.md diff --git a/proposed/2020/MachineReadableOutputDotNetListPackage.md b/accepted/2020/MachineReadableOutputDotNetListPackage.md similarity index 100% rename from proposed/2020/MachineReadableOutputDotNetListPackage.md rename to accepted/2020/MachineReadableOutputDotNetListPackage.md diff --git a/proposed/2020/PackageVulnerability/DotnetListPackageVulnerable.md b/accepted/2020/PackageVulnerability/DotnetListPackageVulnerable.md similarity index 100% rename from proposed/2020/PackageVulnerability/DotnetListPackageVulnerable.md rename to accepted/2020/PackageVulnerability/DotnetListPackageVulnerable.md diff --git a/proposed/2020/PackageVulnerability/FlagVulnerablePackages.md b/accepted/2020/PackageVulnerability/FlagVulnerablePackages.md similarity index 100% rename from proposed/2020/PackageVulnerability/FlagVulnerablePackages.md rename to accepted/2020/PackageVulnerability/FlagVulnerablePackages.md diff --git a/proposed/2020/PackageVulnerability/NuGet.orgVulnerabilitiesPhase1.md b/accepted/2020/PackageVulnerability/NuGet.orgVulnerabilitiesPhase1.md similarity index 100% rename from proposed/2020/PackageVulnerability/NuGet.orgVulnerabilitiesPhase1.md rename to accepted/2020/PackageVulnerability/NuGet.orgVulnerabilitiesPhase1.md diff --git a/proposed/2020/PackageVulnerability/PMUIVulnerability.md b/accepted/2020/PackageVulnerability/PMUIVulnerability.md similarity index 100% rename from proposed/2020/PackageVulnerability/PMUIVulnerability.md rename to accepted/2020/PackageVulnerability/PMUIVulnerability.md diff --git a/proposed/2020/SupportPackageRenames.md b/accepted/2020/SupportPackageRenames.md similarity index 100% rename from proposed/2020/SupportPackageRenames.md rename to accepted/2020/SupportPackageRenames.md diff --git a/proposed/2020/Transitive-Dependencies.md b/accepted/2020/Transitive-Dependencies.md similarity index 100% rename from proposed/2020/Transitive-Dependencies.md rename to accepted/2020/Transitive-Dependencies.md diff --git a/proposed/2021/CentralPackageManagementTransitive.md b/accepted/2021/CentralPackageManagementTransitive.md similarity index 100% rename from proposed/2021/CentralPackageManagementTransitive.md rename to accepted/2021/CentralPackageManagementTransitive.md diff --git a/proposed/2021/NuGetConsumePDBInPackageReference.md b/accepted/2021/NuGetConsumePDBInPackageReference.md similarity index 100% rename from proposed/2021/NuGetConsumePDBInPackageReference.md rename to accepted/2021/NuGetConsumePDBInPackageReference.md diff --git a/proposed/2021/NuGetOrgTFMDropdownBadges.md b/accepted/2021/NuGetOrgTFMDropdownBadges.md similarity index 100% rename from proposed/2021/NuGetOrgTFMDropdownBadges.md rename to accepted/2021/NuGetOrgTFMDropdownBadges.md diff --git a/proposed/2021/ProjectUpdateEventsInVisualStudio.md b/accepted/2021/ProjectUpdateEventsInVisualStudio.md similarity index 100% rename from proposed/2021/ProjectUpdateEventsInVisualStudio.md rename to accepted/2021/ProjectUpdateEventsInVisualStudio.md diff --git a/proposed/2021/TransitiveDependenciesInPMUI.md b/accepted/2021/TransitiveDependenciesInPMUI.md similarity index 100% rename from proposed/2021/TransitiveDependenciesInPMUI.md rename to accepted/2021/TransitiveDependenciesInPMUI.md diff --git a/proposed/2022/AssetTargetFallback-DependenciesResolution.md b/accepted/2022/AssetTargetFallback-DependenciesResolution.md similarity index 98% rename from proposed/2022/AssetTargetFallback-DependenciesResolution.md rename to accepted/2022/AssetTargetFallback-DependenciesResolution.md index 313622aa2..32b939abe 100644 --- a/proposed/2022/AssetTargetFallback-DependenciesResolution.md +++ b/accepted/2022/AssetTargetFallback-DependenciesResolution.md @@ -1,407 +1,407 @@ -# Dependencies resolution for packages selected with AssetTargetFallback - -- Author Name [Nikolche Kolev](https://github.com/nkolev92) -- GitHub Issue [5957](https://github.com/NuGet/Home/issues/5957) - Project A referencing package B via AssetTargetFallback, doesn't use that same AssetTargetFallback to pull B's dependency package C -- GitHub PR [4372](https://github.com/NuGet/NuGet.Client/pull/4372) - -## Summary - -This is a write-up for the fix of the long standing bug where packages resolved with AssetTargetFallback do not get their dependencies. - -## Motivation - -While .NET (Core) & .NET Framework are not fully compatible, often times packages written for .NET Framework only can be safely used on .NET (Core) as well. -AssetTargetFallback is the mechanism by which .NET (Core) projects can reference .NET Framework packages and projects. -Unfortunately due to a bug in the implementation, the transitive dependencies of packages and projects were not included. This could easily lead to runtime failures. - -## Explanation - -### Functional explanation - -There is no change that package authors or consumers need to make. -This should be a change that enables more of their scenarios and removes the need to use workarounds for this problem. - -### Technical explanation - -To best understand the motivation behind the proposal here, one needs to understand the history of fallback frameworks in NuGet and how they work. - -#### NuGet fallback frameworks, evolution to AssetTargetFallback - -For the most complete background on AssetTargetFallback, refer to the original [design](#https://github.com/NuGet/Home/wiki/Enable-.NET-Core-2.0-projects-to-work-with-.NET-Framework-4.6.1-compatible-packages). The relevant information on AssetTargetFallback was duplicated from that spec. -The basic idea is that when a package is completely incompatible with the given project framework, we will attempt to select the best matching assets with a fallback framework. - -AssetTargetFallback evaluates all assets groups for the project target framework before moving onto the fallback. -If it does not find compatible assets, it only then moves to the fallback frameworks. In that case, **only** the fallback frameworks will be used. - -#### How does AssetTargetFallback work - -Terms: - -- `default-tfm-match`: Mechanism to find the best match based on the target framework of the project. -- `AssetTargetFallback`: Mechanism to find matching assets based on the targets specified using `AssetTargetFallback`. -- `No-ref-and-lib-rule`: If a package does not have a ref and lib asset groups (folders), then the package is deemed compatible even when there is no assets pulled in to the project by NuGet. This is to support meta-packages that have only dependencies and no assets. - -![Asset Target Fallback selection](../../meta/resources/AssetTargetFallback/ATF-Selection-flow.svg) - -**How does it behave for different package structures?** - -For a .NET Standard 2.0 project, following is a table that explains which assets are pulled in, based on different approaches i.e. `default-tfm-match only` without PTF/ATF, with `AssetTargetFallback` ( for net461). - -_Note: **NE** implies the corresponding mechanism was **Not Evaluated** and hence the assets pulled in by NuGet is due to default-tfm-match !_ - -| Package structure | `default-tfm-match only` (netstandard2.0) | `AssetTargetFallback`(net461) | -|---|---|---| -| `build\foo.targets` | `build\foo.targets` | **NE** `build\foo.targets` | -| `build\netstandard1.0\foo.targets` | `build\netstandard1.0\foo.targets` | **NE** `build\netstandard1.0\foo.targets` | -| `build\net461\foo.targets` | The package gets installed because of `No-ref-and-lib-rule` but no assets gets pulled in | `build\net461\foo.targets` | -| `build\netstandard2.0\foo.targets` `build\net461\bar.targets` `lib\netstandard2.0\libfoo.dll` `ref\net461\libbar.dll` | `build\netstandard2.0\foo.targets` `lib\netstandard2.0\libfoo.dll` | -| `build\net461\bar.targets` `ref\net461\libbar.dll` | No matching asset; Package fails to install | `build\net461\bar.targets` `ref\net461\libbar.dll` | `build\net461\bar.targets` `ref\net461\libbar.dll` | -| `build\bar.targets` `ref\net461\libbar.dll` | `build\bar.targets` | **NE** `build\bar.targets` | - -The caveat in the `AssetTargetFallback` implementation is that it is not considered when resolving the dependencies. -`PackageTargetFallback` did support this, but it also did not make the promise of global resolution that `AssetTargetFallback` does. - -#### NuGet restore behavior - -When restoring a project with PackageReference, NuGet firstly constructs the full dependency graph for the project and then only later do the asset selection & build the assets file. -The dependency resolution is target framework aware because it needs to discover the dependencies for the packages it restores. -Specifically say we have the following project: - -```xml - ... - - A - net472;netstandard2.0 - ... - - - ... -``` - -NuGet will try to resolve the best matching version of `X` from the sources, which in this case it's `1.0.0`. -NuGet then reads this package's nuspec and looks at the dependencies element. - -```xml - - - - - - - - -``` - -For each framework it tries to resolve the best matching dependencies group. For example for `net472` that is `net461`. NuGet then gets package `Y` and does the same exercise. -Along the way NuGet will detect and resolve conflicts for package `Y`, before settling on an exact version. -The `netstandard2.0` gets the same exercise, in this case package `Z` is one that is used. -When NuGet completes the dependency resolution, it has a list of packages that it needs to install in the global packages folder. For example: - -```text -net472: - X 1.0.0 - Y 2.0.0 - W 3.0.0 - -netstandard2.0: - X 1.0.0 - Z 3.0.1 - W 2.1.0 -``` - -Lastly NuGet goes through each package for each framework does the asset selection and if needed applies `PackageTargetFallback` or `AssetTargetFallback`. - -### The root cause of the problem - NuGet AssetTargetFallback and dependencies - -The problem illustrated in the above issue happens due to the fact that NuGet does not consider `AssetTargetFallback` when selecting the dependencies group. - -Here's a simple example using one of NuGet's libraries. - -```xml - ... - - netcoreapp3.0 - net461;net48 - ... - - - ... -``` - -NuGet.PackageManagement is a package that contains only `net472` assets. - -The directory structure of this package is: - -```text -NuGet.PackageManagement.nuspec -lib - net472 - NuGet.PackageManagement.dll -``` - -The dependencies section looks like below: - -```xml - - - - - - - -``` - -At restore time, NuGet constructs the dependency graph. It looks for a matching dependencies group for `netcoreapp3.0` and finds nothing. This means that the graph for this is like below with 3.0.100 P5: - -```json - "targets": { - ".NETCoreApp,Version=v3.0": { - "Microsoft.NETCore.Platforms/3.0.0-preview5.19224.8": { - "type": "package", - "compile": { - "lib/netstandard1.0/_._": {} - }, - "runtime": { - "lib/netstandard1.0/_._": {} - } - }, - "NuGet.PackageManagement/5.1.0": { - "type": "package", - "compile": { - "lib/net472/NuGet.PackageManagement.dll": {} - }, - "runtime": { - "lib/net472/NuGet.PackageManagement.dll": {} - } - } - } - }, -``` - -Restore does not fail, but there will be runtime failure whenever the NuGet.PackageManagement.dll calls into either of its dependencies. - -#### Options - -There are 3 approaches NuGet can take: - -- Synchronized - Dependencies - Dependencies are the source of truth. If the dependencies are selected with AssetTargetFallback, so will the package assets. - -- Synchronized - Package assets - Package assets are the source of truth. If the package assets are selected with AssetTargetFallback, so will the dependencies. - -- Independent - Both package assets and dependencies are going to be selected independently. - -#### Behavior matrix - -Installing the below package to a netcoreapp3.0 project: - -Package A: - -```text -lib/net472/a.dll -lib/netstandard2.0/a.dll -``` - -```xml - - - - - -``` - -Package B: - -```text -lib/net472/b.dll -``` - -```xml - - - - - - - - -``` - -| | No Change | Synchronized - Dependencies | Synchronized - Assets | Not synchronized | -|-|-|-|-|-| -| A | No dependencies & lib/netstandard2.0 | X & lib/net472 | No dependencies & lib/netstandard2.0 (or fail?) | X & lib/netstandard2.0 | -| B | Z & lib/net472 | fails installing | Y & lib/net472 | Z & lib/net472 | - -### Proposed solution - Independent selection of dependencies and package assets with AssetTargetFallback - -When walking the dependencies, NuGet will consider AssetTargetFallback if no dependencies can be found, similarly to what's being done for package assets today, or what was supposed to be done for PackageTargetFallback. - -When selecting package assets and dependencies indepently, we can choose what information we feel relevant to communicate to customers. - -Here's the matrix of scenarios we need to consider. -| Scenario | Warnings | -|-|-| -| No ATF for package assets, no ATF for dependencies | None | -| ATF for package assets, no ATF for dependencies | The current ATF warning raised | -| ATF for package assets, ATF for dependencies | The current ATF warning raised. | -| No ATF for package assets, ATF for dependencies | No warning | - -NuGet will not warn when AssetTargetFallback is used for dependencies. In this special case, effectively what would happen is that we would download more assemblies. The potential runtime errors are not made better or worse by this selection. - -To better understand the reason behind the proposal, let's look at the packages on nuget.org in 2019. - -### Data analysis - Are packages authored consistently? - -This is an analysis of the packages on nuget.org in 2019, while not current, this data is still relevant. -This analysis was done on the latest versions of packages. - -| | Total Count | Total percentage | -|-|-|-| -| (1) Total Packages | 2186044 | 100% | -| (2) Suspected Library Packages | 1869432 | 85.5% | -| (3) .NET Framework packages that do not have cross platform support | 1271227 | 58.2% | -| (4) Packages with cross platform support | 417079 | 19.1% | -| (5) Packages with target framework inconsistencies in compile/dependency groups | 68723 | 3.1% | -| (6) Packages with target framework inconsistencies in compile/dependency groups, but any dependency group | 32022 | 1.46% | -| (7) Packages with target framework inconsistencies in compile/dependency groups, no any dependency group | 36701 | 1.67% | -| (8) Packages with target framework inconsistencies but might work due to compatibility between the missing frameworks (compile -> dependency groups) | 21954 | 1.00% | -| (9) Packages with target framework inconsistencies but might work due to compatibility between the missing frameworks (dependency groups -> compile) | 16133 | 0.74% | -| (10) Packages with target framework inconsistencies that will never match consistently for compile & dependency groups | 14748 | 0.67% | -| (11) Unique package Ids | 202942 | 100% | -| (12) Unique package ids with target framework inconsistencies in compile/dependency groups without any dependency group | 4102 | 2.02% | -| (13) Unique package ids with target framework inconsistencies that will never match consistently for compile & dependency groups (compile -> dependency groups) | 2205 | 1.08% | -| (14) Packages with target framework inconsistencies that will never match consistently for compile & dependency groups where the bad match is .NET Framework (compile -> dependency groups) | 6241 | 0.29% | -| (15) Unique package ids with target framework inconsistencies that will never match consistently for compile & dependency groups (dependency groups -> compile) | 1141| 0.57% | -| (16) Packages with target framework inconsistencies that will never match consistently for compile & dependency groups where the bad match is .NET Framework (dependency groups -> compile) | 11176 | 0.51% | - -- 58.2% (3) of the total packages are .NET Framework but not cross platform. This is the set of packages that require AssetTargetFallback to enable them to be used easily on .NET Core. - -- 3.1% (5) of all (really only 85% can call into this) the packages have inconsistencies in the target frameworks defined in the compile and dependency groups. -These packages can be considered not well authored and are specifically affected by the direction we choose. -Pack warning NU5128 informs package authors that their package has this inconsistency, and the percentage of packages with this inconsistency should decrease as authors adopt the warning's suggestions. - -- Interpolating the numbers from (2), (4) and (5) we can predict that about 2% of packages have potential mismatch in the package assets supported & dependency group target frameworks. -This effectively means that about 64% of packages that could be used with AssetTargetFallback will work with any approach. - -- Interpolating (6) with (2), and (4) we can assume that further 1% of packages are likely to work as long with the package assets are selected first, either independently of dependencies or using them as the source of truth. - -- Finally that also suggests that 1% of the packages have definitive inconsistencies that are going to work with independent asset selection only. - -- Combining all of these numbers we can come to the following: - -- 56.7% of all packages (58% ATF impacted) will install with if we use the dependency group as the source of truth. While does feel correct, is a breaking change for about 1% of all total packages. -- 57% of all packages (58% ATF impacted) will install as long with the package assets are selected first, either independently of dependencies or using them as the source of truth. -- 58% of all packages (all 58% ATF impacted) are more likely if the dependencies and package assets are selected independently. - -- Looking at the download numbers for the packages with incompatibilities with no any dependency group (7), 700 have have more than 1M package downloads, about 3000 have more than 10k downloads. Of the ones that have more than 1M downloads, almost all of those are `System.*` or `Microsoft.*`. - -## Drawbacks - -AssetTargetFallback aside, in NuGet, currently the selection of dependencies and package assets is done independently. -Normally, the dependency groups would perfectly match what the rest of the package supports. However, this assumes that packages are authored consistently. - -Take the below package for example in a net472 project. - -```text -lib/net472/b.dll -lib/net462/b.dll -``` - -```xml - - - - - -``` - -We would select the `net472` asset and package `X`. - -There a number of issues where this behavior has been observed. - -- -- -- -- -- - -The possibility for inconsistency is multiplied with AssetTargetFallback continuing the independent selection. -However, in practice, the packages that would lead to this type of inconsistency are misauthored. - -## Rationale and alternatives - -### Do Nothing - -The fallback target frameworks are a best effort compatibility mode. There is no guarantee that the assets selected with the fallback. It is reasonable that the consumers need to go the extra mile to enable this scenario. -The road to success here is evolving the package authoring ecosystem to add support for cross platform scenarios in their packages where appropriate. -There have been important but not a significant number of issues reported related to this. - -**Risks** - -- Evolving the package eco system will be a slow transition. Many authors might not be willing to add support for cross platform scenarios. -Often times these packages might not be maintained. Other times, the consumers take dependencies on such packages for niche scenarios, where the package is guaranteed to work correctly. -- While not the most pressing issue right now, with more scenarios enabled on .NET Core 3.0, the number of customers hitting this is expected to increase. -- The workaround can be laborious if the package graph is large and all of the packages there are .NET Framework based. - -### Synchronize the selection - Dependencies are the source of truth - -The idea here is we extend the promise of selecting assets globally to the dependencies group as well. -In the well authored package scenario, where each framework supported by the assets has it's own dedicated dependencies group, the source of truth is irrelevant. -For example the NuGet.PackageManagement scenario will easily work. -The challenge is when the answers to these questions is different. - -**Risks** - -We would not consider these packages well authored today, but that has not always been our guidance. Furthermore many packages are authored with a nuspec, where not obvious issues like these can easily happen. - -Say we have `netcoreapp3.0` project and a package like below: - -```text -lib/net472/a.dll -lib/netstandard2.0/a.dll -``` - -```xml - - - - - -``` - -The package author here might have wanted to suggest that their package has no dependencies for `netstandard2.0`, but NuGet does not interpret it such. -Today if you pack a project that multi targets, NuGet will put an empty dependency group for the target frameworks that do not have any package references. - -So with dependencies as the source of truth, this would lead to NuGet selecting: -> lib/net472/a.dll -even though the `netstandard2.0` is clearly the more compatible assembly. - -This potential fix, would also be a breaking change for some customers. - -### Synchronize the selection - package assets are the source of truth - -Similar to the earlier fix, the only difference here is that any conflicts are to be resolved by the package assets selection result. -If we look at the above example with this solution in mind, it preserves backwards compatibility with the current approach. - -The `netstandard2.0` assembly will be selected and no dependencies will be downloaded. - -**Risks** - -- The biggest risk here is the implementation complexity. The dependency resolution decisions are made prior to the package installation. At dependency resolution time only the nuspec and the dependency information is used. This approach would require us to download the package, and run the full assets selection before making decisions about the dependencies. -While still possible, this approach would be a significant undertaking. - -- It is notable that not every package node NuGet processes gets selected. Meaning if there are multiple `Newtonsoft.Json` references, we currently read the dependencies for all of them and select assets for one. With this change we would do the assets selection for all of them in addition to reading the dependencies. - -#### AssetTargetFallback and warnings - -At this point, we're not going to raise any warnings if AssetTargetFallback was used to select a package dependency. - -- We can raise the same warning as the usual ATF case. Similar logic applies as to the no warning scenario. In this case we'd be louder about a potential error. -- Raise a different warning specifically targeting this scenario. Specifically address this particular scenario. Similarly to earlier, the runtime experience will not have been affected by this selection. - -## Prior Art - -## Unresolved Questions - -## Future Possibilities - -This is expected to be the last time we make changes to the AssetTargetFallback feature. +# Dependencies resolution for packages selected with AssetTargetFallback + +- Author Name [Nikolche Kolev](https://github.com/nkolev92) +- GitHub Issue [5957](https://github.com/NuGet/Home/issues/5957) - Project A referencing package B via AssetTargetFallback, doesn't use that same AssetTargetFallback to pull B's dependency package C +- GitHub PR [4372](https://github.com/NuGet/NuGet.Client/pull/4372) + +## Summary + +This is a write-up for the fix of the long standing bug where packages resolved with AssetTargetFallback do not get their dependencies. + +## Motivation + +While .NET (Core) & .NET Framework are not fully compatible, often times packages written for .NET Framework only can be safely used on .NET (Core) as well. +AssetTargetFallback is the mechanism by which .NET (Core) projects can reference .NET Framework packages and projects. +Unfortunately due to a bug in the implementation, the transitive dependencies of packages and projects were not included. This could easily lead to runtime failures. + +## Explanation + +### Functional explanation + +There is no change that package authors or consumers need to make. +This should be a change that enables more of their scenarios and removes the need to use workarounds for this problem. + +### Technical explanation + +To best understand the motivation behind the proposal here, one needs to understand the history of fallback frameworks in NuGet and how they work. + +#### NuGet fallback frameworks, evolution to AssetTargetFallback + +For the most complete background on AssetTargetFallback, refer to the original [design](#https://github.com/NuGet/Home/wiki/Enable-.NET-Core-2.0-projects-to-work-with-.NET-Framework-4.6.1-compatible-packages). The relevant information on AssetTargetFallback was duplicated from that spec. +The basic idea is that when a package is completely incompatible with the given project framework, we will attempt to select the best matching assets with a fallback framework. + +AssetTargetFallback evaluates all assets groups for the project target framework before moving onto the fallback. +If it does not find compatible assets, it only then moves to the fallback frameworks. In that case, **only** the fallback frameworks will be used. + +#### How does AssetTargetFallback work + +Terms: + +- `default-tfm-match`: Mechanism to find the best match based on the target framework of the project. +- `AssetTargetFallback`: Mechanism to find matching assets based on the targets specified using `AssetTargetFallback`. +- `No-ref-and-lib-rule`: If a package does not have a ref and lib asset groups (folders), then the package is deemed compatible even when there is no assets pulled in to the project by NuGet. This is to support meta-packages that have only dependencies and no assets. + +![Asset Target Fallback selection](../../meta/resources/AssetTargetFallback/ATF-Selection-flow.svg) + +**How does it behave for different package structures?** + +For a .NET Standard 2.0 project, following is a table that explains which assets are pulled in, based on different approaches i.e. `default-tfm-match only` without PTF/ATF, with `AssetTargetFallback` ( for net461). + +_Note: **NE** implies the corresponding mechanism was **Not Evaluated** and hence the assets pulled in by NuGet is due to default-tfm-match !_ + +| Package structure | `default-tfm-match only` (netstandard2.0) | `AssetTargetFallback`(net461) | +|---|---|---| +| `build\foo.targets` | `build\foo.targets` | **NE** `build\foo.targets` | +| `build\netstandard1.0\foo.targets` | `build\netstandard1.0\foo.targets` | **NE** `build\netstandard1.0\foo.targets` | +| `build\net461\foo.targets` | The package gets installed because of `No-ref-and-lib-rule` but no assets gets pulled in | `build\net461\foo.targets` | +| `build\netstandard2.0\foo.targets` `build\net461\bar.targets` `lib\netstandard2.0\libfoo.dll` `ref\net461\libbar.dll` | `build\netstandard2.0\foo.targets` `lib\netstandard2.0\libfoo.dll` | +| `build\net461\bar.targets` `ref\net461\libbar.dll` | No matching asset; Package fails to install | `build\net461\bar.targets` `ref\net461\libbar.dll` | `build\net461\bar.targets` `ref\net461\libbar.dll` | +| `build\bar.targets` `ref\net461\libbar.dll` | `build\bar.targets` | **NE** `build\bar.targets` | + +The caveat in the `AssetTargetFallback` implementation is that it is not considered when resolving the dependencies. +`PackageTargetFallback` did support this, but it also did not make the promise of global resolution that `AssetTargetFallback` does. + +#### NuGet restore behavior + +When restoring a project with PackageReference, NuGet firstly constructs the full dependency graph for the project and then only later do the asset selection & build the assets file. +The dependency resolution is target framework aware because it needs to discover the dependencies for the packages it restores. +Specifically say we have the following project: + +```xml + ... + + A + net472;netstandard2.0 + ... + + + ... +``` + +NuGet will try to resolve the best matching version of `X` from the sources, which in this case it's `1.0.0`. +NuGet then reads this package's nuspec and looks at the dependencies element. + +```xml + + + + + + + + +``` + +For each framework it tries to resolve the best matching dependencies group. For example for `net472` that is `net461`. NuGet then gets package `Y` and does the same exercise. +Along the way NuGet will detect and resolve conflicts for package `Y`, before settling on an exact version. +The `netstandard2.0` gets the same exercise, in this case package `Z` is one that is used. +When NuGet completes the dependency resolution, it has a list of packages that it needs to install in the global packages folder. For example: + +```text +net472: + X 1.0.0 + Y 2.0.0 + W 3.0.0 + +netstandard2.0: + X 1.0.0 + Z 3.0.1 + W 2.1.0 +``` + +Lastly NuGet goes through each package for each framework does the asset selection and if needed applies `PackageTargetFallback` or `AssetTargetFallback`. + +### The root cause of the problem - NuGet AssetTargetFallback and dependencies + +The problem illustrated in the above issue happens due to the fact that NuGet does not consider `AssetTargetFallback` when selecting the dependencies group. + +Here's a simple example using one of NuGet's libraries. + +```xml + ... + + netcoreapp3.0 + net461;net48 + ... + + + ... +``` + +NuGet.PackageManagement is a package that contains only `net472` assets. + +The directory structure of this package is: + +```text +NuGet.PackageManagement.nuspec +lib + net472 + NuGet.PackageManagement.dll +``` + +The dependencies section looks like below: + +```xml + + + + + + + +``` + +At restore time, NuGet constructs the dependency graph. It looks for a matching dependencies group for `netcoreapp3.0` and finds nothing. This means that the graph for this is like below with 3.0.100 P5: + +```json + "targets": { + ".NETCoreApp,Version=v3.0": { + "Microsoft.NETCore.Platforms/3.0.0-preview5.19224.8": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "NuGet.PackageManagement/5.1.0": { + "type": "package", + "compile": { + "lib/net472/NuGet.PackageManagement.dll": {} + }, + "runtime": { + "lib/net472/NuGet.PackageManagement.dll": {} + } + } + } + }, +``` + +Restore does not fail, but there will be runtime failure whenever the NuGet.PackageManagement.dll calls into either of its dependencies. + +#### Options + +There are 3 approaches NuGet can take: + +- Synchronized - Dependencies - Dependencies are the source of truth. If the dependencies are selected with AssetTargetFallback, so will the package assets. + +- Synchronized - Package assets - Package assets are the source of truth. If the package assets are selected with AssetTargetFallback, so will the dependencies. + +- Independent - Both package assets and dependencies are going to be selected independently. + +#### Behavior matrix + +Installing the below package to a netcoreapp3.0 project: + +Package A: + +```text +lib/net472/a.dll +lib/netstandard2.0/a.dll +``` + +```xml + + + + + +``` + +Package B: + +```text +lib/net472/b.dll +``` + +```xml + + + + + + + + +``` + +| | No Change | Synchronized - Dependencies | Synchronized - Assets | Not synchronized | +|-|-|-|-|-| +| A | No dependencies & lib/netstandard2.0 | X & lib/net472 | No dependencies & lib/netstandard2.0 (or fail?) | X & lib/netstandard2.0 | +| B | Z & lib/net472 | fails installing | Y & lib/net472 | Z & lib/net472 | + +### Proposed solution - Independent selection of dependencies and package assets with AssetTargetFallback + +When walking the dependencies, NuGet will consider AssetTargetFallback if no dependencies can be found, similarly to what's being done for package assets today, or what was supposed to be done for PackageTargetFallback. + +When selecting package assets and dependencies indepently, we can choose what information we feel relevant to communicate to customers. + +Here's the matrix of scenarios we need to consider. +| Scenario | Warnings | +|-|-| +| No ATF for package assets, no ATF for dependencies | None | +| ATF for package assets, no ATF for dependencies | The current ATF warning raised | +| ATF for package assets, ATF for dependencies | The current ATF warning raised. | +| No ATF for package assets, ATF for dependencies | No warning | + +NuGet will not warn when AssetTargetFallback is used for dependencies. In this special case, effectively what would happen is that we would download more assemblies. The potential runtime errors are not made better or worse by this selection. + +To better understand the reason behind the proposal, let's look at the packages on nuget.org in 2019. + +### Data analysis - Are packages authored consistently? + +This is an analysis of the packages on nuget.org in 2019, while not current, this data is still relevant. +This analysis was done on the latest versions of packages. + +| | Total Count | Total percentage | +|-|-|-| +| (1) Total Packages | 2186044 | 100% | +| (2) Suspected Library Packages | 1869432 | 85.5% | +| (3) .NET Framework packages that do not have cross platform support | 1271227 | 58.2% | +| (4) Packages with cross platform support | 417079 | 19.1% | +| (5) Packages with target framework inconsistencies in compile/dependency groups | 68723 | 3.1% | +| (6) Packages with target framework inconsistencies in compile/dependency groups, but any dependency group | 32022 | 1.46% | +| (7) Packages with target framework inconsistencies in compile/dependency groups, no any dependency group | 36701 | 1.67% | +| (8) Packages with target framework inconsistencies but might work due to compatibility between the missing frameworks (compile -> dependency groups) | 21954 | 1.00% | +| (9) Packages with target framework inconsistencies but might work due to compatibility between the missing frameworks (dependency groups -> compile) | 16133 | 0.74% | +| (10) Packages with target framework inconsistencies that will never match consistently for compile & dependency groups | 14748 | 0.67% | +| (11) Unique package Ids | 202942 | 100% | +| (12) Unique package ids with target framework inconsistencies in compile/dependency groups without any dependency group | 4102 | 2.02% | +| (13) Unique package ids with target framework inconsistencies that will never match consistently for compile & dependency groups (compile -> dependency groups) | 2205 | 1.08% | +| (14) Packages with target framework inconsistencies that will never match consistently for compile & dependency groups where the bad match is .NET Framework (compile -> dependency groups) | 6241 | 0.29% | +| (15) Unique package ids with target framework inconsistencies that will never match consistently for compile & dependency groups (dependency groups -> compile) | 1141| 0.57% | +| (16) Packages with target framework inconsistencies that will never match consistently for compile & dependency groups where the bad match is .NET Framework (dependency groups -> compile) | 11176 | 0.51% | + +- 58.2% (3) of the total packages are .NET Framework but not cross platform. This is the set of packages that require AssetTargetFallback to enable them to be used easily on .NET Core. + +- 3.1% (5) of all (really only 85% can call into this) the packages have inconsistencies in the target frameworks defined in the compile and dependency groups. +These packages can be considered not well authored and are specifically affected by the direction we choose. +Pack warning NU5128 informs package authors that their package has this inconsistency, and the percentage of packages with this inconsistency should decrease as authors adopt the warning's suggestions. + +- Interpolating the numbers from (2), (4) and (5) we can predict that about 2% of packages have potential mismatch in the package assets supported & dependency group target frameworks. +This effectively means that about 64% of packages that could be used with AssetTargetFallback will work with any approach. + +- Interpolating (6) with (2), and (4) we can assume that further 1% of packages are likely to work as long with the package assets are selected first, either independently of dependencies or using them as the source of truth. + +- Finally that also suggests that 1% of the packages have definitive inconsistencies that are going to work with independent asset selection only. + +- Combining all of these numbers we can come to the following: + +- 56.7% of all packages (58% ATF impacted) will install with if we use the dependency group as the source of truth. While does feel correct, is a breaking change for about 1% of all total packages. +- 57% of all packages (58% ATF impacted) will install as long with the package assets are selected first, either independently of dependencies or using them as the source of truth. +- 58% of all packages (all 58% ATF impacted) are more likely if the dependencies and package assets are selected independently. + +- Looking at the download numbers for the packages with incompatibilities with no any dependency group (7), 700 have have more than 1M package downloads, about 3000 have more than 10k downloads. Of the ones that have more than 1M downloads, almost all of those are `System.*` or `Microsoft.*`. + +## Drawbacks + +AssetTargetFallback aside, in NuGet, currently the selection of dependencies and package assets is done independently. +Normally, the dependency groups would perfectly match what the rest of the package supports. However, this assumes that packages are authored consistently. + +Take the below package for example in a net472 project. + +```text +lib/net472/b.dll +lib/net462/b.dll +``` + +```xml + + + + + +``` + +We would select the `net472` asset and package `X`. + +There a number of issues where this behavior has been observed. + +- +- +- +- +- + +The possibility for inconsistency is multiplied with AssetTargetFallback continuing the independent selection. +However, in practice, the packages that would lead to this type of inconsistency are misauthored. + +## Rationale and alternatives + +### Do Nothing + +The fallback target frameworks are a best effort compatibility mode. There is no guarantee that the assets selected with the fallback. It is reasonable that the consumers need to go the extra mile to enable this scenario. +The road to success here is evolving the package authoring ecosystem to add support for cross platform scenarios in their packages where appropriate. +There have been important but not a significant number of issues reported related to this. + +**Risks** + +- Evolving the package eco system will be a slow transition. Many authors might not be willing to add support for cross platform scenarios. +Often times these packages might not be maintained. Other times, the consumers take dependencies on such packages for niche scenarios, where the package is guaranteed to work correctly. +- While not the most pressing issue right now, with more scenarios enabled on .NET Core 3.0, the number of customers hitting this is expected to increase. +- The workaround can be laborious if the package graph is large and all of the packages there are .NET Framework based. + +### Synchronize the selection - Dependencies are the source of truth + +The idea here is we extend the promise of selecting assets globally to the dependencies group as well. +In the well authored package scenario, where each framework supported by the assets has it's own dedicated dependencies group, the source of truth is irrelevant. +For example the NuGet.PackageManagement scenario will easily work. +The challenge is when the answers to these questions is different. + +**Risks** + +We would not consider these packages well authored today, but that has not always been our guidance. Furthermore many packages are authored with a nuspec, where not obvious issues like these can easily happen. + +Say we have `netcoreapp3.0` project and a package like below: + +```text +lib/net472/a.dll +lib/netstandard2.0/a.dll +``` + +```xml + + + + + +``` + +The package author here might have wanted to suggest that their package has no dependencies for `netstandard2.0`, but NuGet does not interpret it such. +Today if you pack a project that multi targets, NuGet will put an empty dependency group for the target frameworks that do not have any package references. + +So with dependencies as the source of truth, this would lead to NuGet selecting: +> lib/net472/a.dll +even though the `netstandard2.0` is clearly the more compatible assembly. + +This potential fix, would also be a breaking change for some customers. + +### Synchronize the selection - package assets are the source of truth + +Similar to the earlier fix, the only difference here is that any conflicts are to be resolved by the package assets selection result. +If we look at the above example with this solution in mind, it preserves backwards compatibility with the current approach. + +The `netstandard2.0` assembly will be selected and no dependencies will be downloaded. + +**Risks** + +- The biggest risk here is the implementation complexity. The dependency resolution decisions are made prior to the package installation. At dependency resolution time only the nuspec and the dependency information is used. This approach would require us to download the package, and run the full assets selection before making decisions about the dependencies. +While still possible, this approach would be a significant undertaking. + +- It is notable that not every package node NuGet processes gets selected. Meaning if there are multiple `Newtonsoft.Json` references, we currently read the dependencies for all of them and select assets for one. With this change we would do the assets selection for all of them in addition to reading the dependencies. + +#### AssetTargetFallback and warnings + +At this point, we're not going to raise any warnings if AssetTargetFallback was used to select a package dependency. + +- We can raise the same warning as the usual ATF case. Similar logic applies as to the no warning scenario. In this case we'd be louder about a potential error. +- Raise a different warning specifically targeting this scenario. Specifically address this particular scenario. Similarly to earlier, the runtime experience will not have been affected by this selection. + +## Prior Art + +## Unresolved Questions + +## Future Possibilities + +This is expected to be the last time we make changes to the AssetTargetFallback feature. diff --git a/proposed/2022/DotnetListPackageMachineReadableJsonOutput.md b/accepted/2022/DotnetListPackageMachineReadableJsonOutput.md similarity index 100% rename from proposed/2022/DotnetListPackageMachineReadableJsonOutput.md rename to accepted/2022/DotnetListPackageMachineReadableJsonOutput.md diff --git a/proposed/2022/NuGetExeWarnWhenSDKProjectsGetPacked.md b/accepted/2022/NuGetExeWarnWhenSDKProjectsGetPacked.md similarity index 98% rename from proposed/2022/NuGetExeWarnWhenSDKProjectsGetPacked.md rename to accepted/2022/NuGetExeWarnWhenSDKProjectsGetPacked.md index 0e070d4cb..95a0a737a 100644 --- a/proposed/2022/NuGetExeWarnWhenSDKProjectsGetPacked.md +++ b/accepted/2022/NuGetExeWarnWhenSDKProjectsGetPacked.md @@ -1,99 +1,99 @@ -# Show error when using NuGet.exe to pack an SDK csproj - -- [Nikolche Kolev](https://github.com/nkolev92) -- GitHub Issue - -## Summary - -NuGet.exe does not support packing SDK-based, or PackageReference projects in general. -If you run NuGet.exe pack on an SDK-based csproj, it might pack, but it will do it incorrectly. -The proposal is to `error` whenever a SDK-based csproj pack is attempted, instructing the user to use `msbuild /t:pack` or `dotnet.exe pack` instead. - -## Motivation - -NuGet.exe does not support packing SDK-based, or PackageReference projects in general. -If you run NuGet.exe pack on an SDK-based csproj, it might pack, but it will do it incorrectly. -The pack SDK experience for PackageReference projects knows how to automatically manage the dependencies and makes multitargeted projects extremely easy to pack. -It is recommended that SDK projects are managed by using `dotnet.exe` instead. - -## Explanation - -### Functional explanation - -#### How packing and SDK-based project with NuGet.exe behaves today - -Scenario 1: Single target framework SDK based projects, with .NET SDK installed on the machine. - -```console -Attempting to build package from 'SDK.csproj'. -MSBuild auto-detection: using msbuild version '17.4.0.37601' from 'C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Current\Bin\amd64'. -Packing files from 'C:\Code\Temp\SDK\bin\Debug\net6.0'. -WARNING: NU5115: Description was not specified. Using 'Description'. -WARNING: NU5115: Author was not specified. Using 'Roki2'. -WARNING: NU5128: Some target frameworks declared in the dependencies group of the nuspec and the lib/ref folder do not have exact matches in the other location. Consult the list of actions below: -- Add a dependency group for net6.0 to the nuspec -Successfully created package 'C:\Code\Temp\SDK\SDK.1.0.0.nupkg'. -``` - -The command packages the single assembly, but does not generate the correct dependencies or any other metadata in the same way that the pack SDK would. - -Scenario 2: Multiple target framework SDK based projects, with .NET SDK installed on the machine. - -```console -Attempting to build package from 'SDK.csproj'. -MSBuild auto-detection: using msbuild version '17.4.0.37601' from 'C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Current\Bin\amd64'. -Error NU5012: Unable to find 'bin\Debug\SDK\bin\Debug\'. Make sure the project has been built. -``` - -NuGet.exe does not understand the concept of multitargetting and just merges the output paths. - -Scenario 3: SDK-based project, without the .NET SDK installed - -```console -The SDK 'Microsoft.NET.Sdk' specified could not be found. C:\Code\Temp\SDK\SDK.csproj -``` - -The parsing fails early. - -### Proposal - -When someone attempts to run pack on an SDK-based project, NuGet will fail with the following error: - -```console -Error NU5049: The `pack` command for SDK-style projects is not supported, use `dotnet pack` to pack this project instead. You may set the ENABLE_LEGACY_NUGETEXE_CSPROJ_PACK environment variable to revert to the previous packing behavior. -``` - -This *breaking change* will be announced via blog well before the NuGet.exe carrying the change ships. - -### Technical explanation - -As described above, whenever there's no SDK installed, there's simply no accurate way for NuGet to detect that a project is SDK-based. -We can do some XML parsing, but it is likely to be error prone. `NuGet.exe pack` is not the only command that will fail, so the customer will likely figure out that they need to install the .NET SDK. After that the same scenarios with the installed .NET SDK will follow. - -To determine whether a project is `.NET SDK` based, we will evaluate the project (part of the normal pack operation), and check for the `UsingMicrosoftNETSDK` property being set. If the property is set, then the project is presumed to be .NET SDK based and will be blocked from packing. - -## Drawbacks - -- The proposal here would be `breaking` for customers, but it's more than likely that the scenario for which they used nuget.exe pack on an SDK based project never worked correctly. - -## Rationale and alternatives - -- Do nothing. This would mean just acknowledging that SDK-based projects support in NuGet.exe would not be added and not do anything to help migrate users to `dotnet.exe pack` and `msbuild /t:pack`. -- Add full pack SDK support into NuGet.exe. While not impossible, this creates maintainability considerations. dotnet.exe has a more involved support for the SDK-based PackageReference projects, and as such is considered to be the `right tool for the job`. -- Call `msbuild /t:pack` from NuGet.exe. This has the same considerations as the previos approach that `dotnet.exe` should be recommended as the right tool for the job. -This is also likely to quietly change the behavior for certain users and change the type of package they're generating. -A change like this likely has a lot more merit in 2018, than 2022 given how long dotnet.exe has been the recommended tool for SDK based projects.. -- Add a warning and proceed packing. - - A behavior change to an error in a minor version can be considered disruptive. This is one of those special cases where the disruption might be warranted. - Instead of an error, we could add a warning instead. Given that NuGet.exe pack by default will usually raise a bunch of warnings, it is likely that if warnings were good enough, the customers would have reviewed said warnings and figured out that all those warnings cannot be addressed correctly. -- Add an information message and proceed warning. Given that the information this tool is not the right one for the job is critical, this is not likely to move the needle enough. - -## Prior Art - -N/A - -## Unresolved Questions - -## Future Possibilities - -- We can consider *warning* or *erroring* when `NuGet.exe pack` is being used on csproj PackageReference projects. Given that you need to undergo a manual migration to PackageReference, this isn't likely to be a priority scenario. +# Show error when using NuGet.exe to pack an SDK csproj + +- [Nikolche Kolev](https://github.com/nkolev92) +- GitHub Issue + +## Summary + +NuGet.exe does not support packing SDK-based, or PackageReference projects in general. +If you run NuGet.exe pack on an SDK-based csproj, it might pack, but it will do it incorrectly. +The proposal is to `error` whenever a SDK-based csproj pack is attempted, instructing the user to use `msbuild /t:pack` or `dotnet.exe pack` instead. + +## Motivation + +NuGet.exe does not support packing SDK-based, or PackageReference projects in general. +If you run NuGet.exe pack on an SDK-based csproj, it might pack, but it will do it incorrectly. +The pack SDK experience for PackageReference projects knows how to automatically manage the dependencies and makes multitargeted projects extremely easy to pack. +It is recommended that SDK projects are managed by using `dotnet.exe` instead. + +## Explanation + +### Functional explanation + +#### How packing and SDK-based project with NuGet.exe behaves today + +Scenario 1: Single target framework SDK based projects, with .NET SDK installed on the machine. + +```console +Attempting to build package from 'SDK.csproj'. +MSBuild auto-detection: using msbuild version '17.4.0.37601' from 'C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Current\Bin\amd64'. +Packing files from 'C:\Code\Temp\SDK\bin\Debug\net6.0'. +WARNING: NU5115: Description was not specified. Using 'Description'. +WARNING: NU5115: Author was not specified. Using 'Roki2'. +WARNING: NU5128: Some target frameworks declared in the dependencies group of the nuspec and the lib/ref folder do not have exact matches in the other location. Consult the list of actions below: +- Add a dependency group for net6.0 to the nuspec +Successfully created package 'C:\Code\Temp\SDK\SDK.1.0.0.nupkg'. +``` + +The command packages the single assembly, but does not generate the correct dependencies or any other metadata in the same way that the pack SDK would. + +Scenario 2: Multiple target framework SDK based projects, with .NET SDK installed on the machine. + +```console +Attempting to build package from 'SDK.csproj'. +MSBuild auto-detection: using msbuild version '17.4.0.37601' from 'C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Current\Bin\amd64'. +Error NU5012: Unable to find 'bin\Debug\SDK\bin\Debug\'. Make sure the project has been built. +``` + +NuGet.exe does not understand the concept of multitargetting and just merges the output paths. + +Scenario 3: SDK-based project, without the .NET SDK installed + +```console +The SDK 'Microsoft.NET.Sdk' specified could not be found. C:\Code\Temp\SDK\SDK.csproj +``` + +The parsing fails early. + +### Proposal + +When someone attempts to run pack on an SDK-based project, NuGet will fail with the following error: + +```console +Error NU5049: The `pack` command for SDK-style projects is not supported, use `dotnet pack` to pack this project instead. You may set the ENABLE_LEGACY_NUGETEXE_CSPROJ_PACK environment variable to revert to the previous packing behavior. +``` + +This *breaking change* will be announced via blog well before the NuGet.exe carrying the change ships. + +### Technical explanation + +As described above, whenever there's no SDK installed, there's simply no accurate way for NuGet to detect that a project is SDK-based. +We can do some XML parsing, but it is likely to be error prone. `NuGet.exe pack` is not the only command that will fail, so the customer will likely figure out that they need to install the .NET SDK. After that the same scenarios with the installed .NET SDK will follow. + +To determine whether a project is `.NET SDK` based, we will evaluate the project (part of the normal pack operation), and check for the `UsingMicrosoftNETSDK` property being set. If the property is set, then the project is presumed to be .NET SDK based and will be blocked from packing. + +## Drawbacks + +- The proposal here would be `breaking` for customers, but it's more than likely that the scenario for which they used nuget.exe pack on an SDK based project never worked correctly. + +## Rationale and alternatives + +- Do nothing. This would mean just acknowledging that SDK-based projects support in NuGet.exe would not be added and not do anything to help migrate users to `dotnet.exe pack` and `msbuild /t:pack`. +- Add full pack SDK support into NuGet.exe. While not impossible, this creates maintainability considerations. dotnet.exe has a more involved support for the SDK-based PackageReference projects, and as such is considered to be the `right tool for the job`. +- Call `msbuild /t:pack` from NuGet.exe. This has the same considerations as the previos approach that `dotnet.exe` should be recommended as the right tool for the job. +This is also likely to quietly change the behavior for certain users and change the type of package they're generating. +A change like this likely has a lot more merit in 2018, than 2022 given how long dotnet.exe has been the recommended tool for SDK based projects.. +- Add a warning and proceed packing. + - A behavior change to an error in a minor version can be considered disruptive. This is one of those special cases where the disruption might be warranted. + Instead of an error, we could add a warning instead. Given that NuGet.exe pack by default will usually raise a bunch of warnings, it is likely that if warnings were good enough, the customers would have reviewed said warnings and figured out that all those warnings cannot be addressed correctly. +- Add an information message and proceed warning. Given that the information this tool is not the right one for the job is critical, this is not likely to move the needle enough. + +## Prior Art + +N/A + +## Unresolved Questions + +## Future Possibilities + +- We can consider *warning* or *erroring* when `NuGet.exe pack` is being used on csproj PackageReference projects. Given that you need to undergo a manual migration to PackageReference, this isn't likely to be a priority scenario. diff --git a/proposed/2022/WarningsNotAsErrors.md b/accepted/2022/WarningsNotAsErrors.md similarity index 98% rename from proposed/2022/WarningsNotAsErrors.md rename to accepted/2022/WarningsNotAsErrors.md index 7f127526d..bdbc0f32e 100644 --- a/proposed/2022/WarningsNotAsErrors.md +++ b/accepted/2022/WarningsNotAsErrors.md @@ -1,85 +1,85 @@ -# Honor WarningsNotAsErrors - -- Author Name -- Start Date 2022-10-01 -- GitHub Issue -- GitHub PR - -## Summary - - -`WarningsNotAsErrors` is an existing [compiler option](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/errors-warnings) that allows users with treat warnings as errors, to not get errors for every warning raised by their build. -NuGet supports `TreatWarningsAsErrors`, `WarningsAsErrors` and `NoWarn`. In this proposal we want to add support for `WarningsNotAsErrors`. - -## Motivation - - - -`TreatWarningsAsErrors` is very commonly used feature in the .NET world. NoWarn allows you to suppress certain warning, but that is often too strong. `WarningsNotAsErrors` provides a middle ground, where the users are aware of the warning, but it doesn't fail their build. -This feature is supported by the compiler, and we want to provide parity for both pack and restore. - -## Explanation - -### Functional explanation - - - -The proposed behavior here matches the compiler behavior. All the scenarios are best represented in a table. - -The precedence order for the 3 properties by NuGet can summarized as: -`NoWarn > WarningsAsErrors > WarningsNotAsErrors`. - -For the following table assume `NU1603` is being raised during restore. - -| TreatWarningsAsErrors | NoWarn | WarningsAsErrors | WarningsNotAsErrors | Behavior | Explanation | -|-----------------------|--------|------------------|---------------------|----------|-------------| -| true | | | | All warnings are treated as errors | | -| true | NU1603 | | | Succeeds with no warning. | NoWarn prevents NU1603 from being raised. | -| false | | NU1603 | | NU1603 is upgraded to an error. | Only a certain list of warnings are being treated as errors | -| true | | | NU1603 | Succeeds with a warning. | Only NU1603 is a warning. If any other warning is raised, it'll be upgraded to an error | -| true | NU1603 | | NU1603 | Succeeds. No warning. | NoWarn takes precedence over both WarningAsErrors and WarningNotAsErrors. | -| false | NU1603 | NU1603 | | Succeeds. No warning. | NoWarn takes precedence over both WarningAsErrors and WarningNotAsErrors. | -| false | | NU1603 | NU1603 | NU1603 is upgraded to an error | WarningsAsErrors takes precedence over WarningsNotAsErrors. This is likely not an intentional user scenario. | -| true | | NU1603 | NU1603 | NU1603 is upgraded to an error | WarningsNotAsErrors takes precedence over TreatWarningsAsErrors, but WarningsAsErrors takes precedence over WarningsNotAsErrors | - -### Technical explanation - -We already have a concept for [holding warning properties](https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.ProjectModel/WarningProperties.cs), and [logic](https://github.com/NuGet/NuGet.Client/blob/f4e0ae1ca207f9f4a388b73c2f7edf18b2078f2a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/WarningPropertiesCollection.cs#L75) that handles the no warn and upgrade warnings. -We will just extend that. - -## Drawbacks - - -- N/A - -## Rationale and alternatives - - - - -- N/A - -## Prior Art - - - - - - -- The compiler has already implemented the feature. - -## Unresolved Questions - - - - - -- Should this feature be enabled in 6.5, 7.0.200 of the .NET SDK. - - This is a behavior change where if someone was using `WarningsNotAsErrors` for NuGet, updating their tooling with change behavior. - - However, given that it currently doesn't work, it is not very likely that users would have that in their project. - - WarningsNotAsErrors is the lowest precedence setting supported by NuGet. - - Any behavior change can be consider a breaking change by people, but given the low likelihood this has as a new feature, I think it should be safe to merge in 6.5. - -## Future Possibilities - - +# Honor WarningsNotAsErrors + +- Author Name +- Start Date 2022-10-01 +- GitHub Issue +- GitHub PR + +## Summary + + +`WarningsNotAsErrors` is an existing [compiler option](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/errors-warnings) that allows users with treat warnings as errors, to not get errors for every warning raised by their build. +NuGet supports `TreatWarningsAsErrors`, `WarningsAsErrors` and `NoWarn`. In this proposal we want to add support for `WarningsNotAsErrors`. + +## Motivation + + + +`TreatWarningsAsErrors` is very commonly used feature in the .NET world. NoWarn allows you to suppress certain warning, but that is often too strong. `WarningsNotAsErrors` provides a middle ground, where the users are aware of the warning, but it doesn't fail their build. +This feature is supported by the compiler, and we want to provide parity for both pack and restore. + +## Explanation + +### Functional explanation + + + +The proposed behavior here matches the compiler behavior. All the scenarios are best represented in a table. + +The precedence order for the 3 properties by NuGet can summarized as: +`NoWarn > WarningsAsErrors > WarningsNotAsErrors`. + +For the following table assume `NU1603` is being raised during restore. + +| TreatWarningsAsErrors | NoWarn | WarningsAsErrors | WarningsNotAsErrors | Behavior | Explanation | +|-----------------------|--------|------------------|---------------------|----------|-------------| +| true | | | | All warnings are treated as errors | | +| true | NU1603 | | | Succeeds with no warning. | NoWarn prevents NU1603 from being raised. | +| false | | NU1603 | | NU1603 is upgraded to an error. | Only a certain list of warnings are being treated as errors | +| true | | | NU1603 | Succeeds with a warning. | Only NU1603 is a warning. If any other warning is raised, it'll be upgraded to an error | +| true | NU1603 | | NU1603 | Succeeds. No warning. | NoWarn takes precedence over both WarningAsErrors and WarningNotAsErrors. | +| false | NU1603 | NU1603 | | Succeeds. No warning. | NoWarn takes precedence over both WarningAsErrors and WarningNotAsErrors. | +| false | | NU1603 | NU1603 | NU1603 is upgraded to an error | WarningsAsErrors takes precedence over WarningsNotAsErrors. This is likely not an intentional user scenario. | +| true | | NU1603 | NU1603 | NU1603 is upgraded to an error | WarningsNotAsErrors takes precedence over TreatWarningsAsErrors, but WarningsAsErrors takes precedence over WarningsNotAsErrors | + +### Technical explanation + +We already have a concept for [holding warning properties](https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.ProjectModel/WarningProperties.cs), and [logic](https://github.com/NuGet/NuGet.Client/blob/f4e0ae1ca207f9f4a388b73c2f7edf18b2078f2a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/WarningPropertiesCollection.cs#L75) that handles the no warn and upgrade warnings. +We will just extend that. + +## Drawbacks + + +- N/A + +## Rationale and alternatives + + + + +- N/A + +## Prior Art + + + + + + +- The compiler has already implemented the feature. + +## Unresolved Questions + + + + + +- Should this feature be enabled in 6.5, 7.0.200 of the .NET SDK. + - This is a behavior change where if someone was using `WarningsNotAsErrors` for NuGet, updating their tooling with change behavior. + - However, given that it currently doesn't work, it is not very likely that users would have that in their project. + - WarningsNotAsErrors is the lowest precedence setting supported by NuGet. + - Any behavior change can be consider a breaking change by people, but given the low likelihood this has as a new feature, I think it should be safe to merge in 6.5. + +## Future Possibilities + + diff --git a/proposed/2022/cpm-dotnet-cli-add-package-support.md b/accepted/2022/cpm-dotnet-cli-add-package-support.md similarity index 100% rename from proposed/2022/cpm-dotnet-cli-add-package-support.md rename to accepted/2022/cpm-dotnet-cli-add-package-support.md diff --git a/proposed/2022/dotnet-nuget-config-spec.md b/accepted/2022/dotnet-nuget-config-spec.md similarity index 100% rename from proposed/2022/dotnet-nuget-config-spec.md rename to accepted/2022/dotnet-nuget-config-spec.md diff --git a/proposed/2022/dotnet-nuget-why-proposal.md b/accepted/2022/dotnet-nuget-why-proposal.md similarity index 100% rename from proposed/2022/dotnet-nuget-why-proposal.md rename to accepted/2022/dotnet-nuget-why-proposal.md diff --git a/proposed/2022/duplicate-nuget-item-error-handling.md b/accepted/2022/duplicate-nuget-item-error-handling.md similarity index 100% rename from proposed/2022/duplicate-nuget-item-error-handling.md rename to accepted/2022/duplicate-nuget-item-error-handling.md diff --git a/proposed/2022/globalpackagereference.md b/accepted/2022/globalpackagereference.md similarity index 100% rename from proposed/2022/globalpackagereference.md rename to accepted/2022/globalpackagereference.md diff --git a/proposed/2022/version-overrides.md b/accepted/2022/version-overrides.md similarity index 100% rename from proposed/2022/version-overrides.md rename to accepted/2022/version-overrides.md diff --git a/proposed/2022/vulnerabilities-in-restore.md b/accepted/2022/vulnerabilities-in-restore.md similarity index 98% rename from proposed/2022/vulnerabilities-in-restore.md rename to accepted/2022/vulnerabilities-in-restore.md index c4e5a0fc6..f19738eb9 100644 --- a/proposed/2022/vulnerabilities-in-restore.md +++ b/accepted/2022/vulnerabilities-in-restore.md @@ -1,443 +1,443 @@ -# Auditing projects for package vulnerabilities during restore - -- [Jon Douglas](https://github.com/JonDouglas/), [Nikolche Kolev](https://github.com/nkolev92), [Peter Yu](https://github.com/ryuyu) -- Issue: [#8087](https://github.com/NuGet/Home/issues/8087) -- Related: [#11549](https://github.com/NuGet/Home/pull/11549) - -## Summary - -Audit your dependencies when restoring your NuGet packages with known security vulnerabilities. - -## Motivation - -Since [launching vulnerability scanning last year](https://devblogs.microsoft.com/nuget/how-to-scan-nuget-packages-for-security-vulnerabilities/), we have seen the world shift towards a zero-trust model with new executive orders, exponentially increasing security advisories and supply chain attacks, and a general sentiment towards securing build environments at all costs. - -While we support basic affordances when browsing for NuGet packages in NuGet.org, dotnet CLI, and Visual Studio, we have learned that our developers use these features, but they want better visibility. - -We ran a survey in 2022 regarding how developers currently feel about known security advisories and here is what we've learned: - -74% of developers would like to be notified of packages at restore/build time. 65% would like to see icons in the solution explorer for problematic packages. 42% of developers would like a security notification in Visual Studio's notification window. 39% of developers would use a dotnet audit command. - -![Notified](./../../meta/resources/VulnerabilitiesInRestore/Notified.png) - -Next, we asked developers how they learned about security vulnerabilities in their software. Majority learned from public reports, 3rd-party vulnerability scanners, and code reviews/accidental discovery. - -![Learned](./../../meta/resources/VulnerabilitiesInRestore/Learned.png) - -The most challenging aspects for ensuring the software they write is secure is three major things: - -1. Evaluating third-party libraries are secure and free of vulnerabilities. -2. Verifying the software they write is free of vulnerabilities. -3. Applying best practices to writing code. - -![Challenging](./../../meta/resources/VulnerabilitiesInRestore/Challenging.png) - -When asked how they understood and resolved the vulnerability, the majority of developers resolved them by updating the dependency or app. - -![Resolved](./../../meta/resources/VulnerabilitiesInRestore/Resolved.png) - -When doing so, the most challenging aspect for them is not breaking something else when doing this and better understanding the vulnerability's information to assess the impact and root cause to see if they are actually affected. - -![ResolveChallenge](./../../meta/resources/VulnerabilitiesInRestore/ResolveChallenge.png) - -## Explanation - -### Functional explanation - -When a restore happens whether implicitly, or explicitly, the packages will be audited for vulnerabilities *if* any of the sources declared provide vulnerability information. -If any vulnerabilities are found, the impact, appropriate remediation, and other advisory metadata will be reported to the developer to take action on. - -For example, a developer might run `dotnet restore` explicitly or `dotnet add package` which runs restore implicitly. If a package being restored contains a known security advisory, they would see output at the bottom of the restore output that indicates how many vulnerabilities, a break-down of their severities, and the appropriate remediation action to take given the context of their environment. Below are a handful of concepts ranging from a low to high verbosity of information - -#### Warning codes - -| Warning Code | Severity | -|--------------|----------| -| NU1901 | low | -| NU1902 | moderate | -| NU1903 | high | -| NU1904 | critical | - -When there are packages used by the project with vulnerabilities, they will be output like like any other warning or error: - -```text -/path/to/project.csproj: warning NU1904: Package 'Contoso.Service.APIs' 1.0.3 has a known critical severity vulnerability, https://github.com/advisories/GHSA-1234-5678-9012. -/path/to/project.csproj: warning NU1902: Package 'Contoso.Forms' 8.4.1 has a known moderate severity vulnerability, https://github.com/advisories/GHSA-1234-5678-9012. -``` - -If a package has more than 1 vulnerability, each vulnerability will have its own warning. These security issues are often likely independent and may be fixed in different versions. - -```bash -/path/to/project.csproj: warning NU1904: Package 'Contoso.Service.APIs' 1.0.3 has a known critical severity vulnerability, https://github.com/advisories/GHSA-1234-5678-9012 -/path/to/project.csproj: warning NU1904: Package 'Contoso.Service.APIs' 1.0.3 has a known moderate severity vulnerability, https://github.com/advisories/GHSA-1234-5678-90XY -``` - -Similarly, if a vulnerable package is either referenced directly by multiple projects, or a project reference causes a package to become a transitive package, it will be listed by each project affected. - -#### Enabling Vulnerability Auditing - -This feature will be opt-in to start and gather feedback from developers. - -To enable the feature, a developer can add `enable` to their project file as a MSBuild property. To disable the feature, a developer can add `disable` or remove the property from the project file. - -#### Setting Vulnerability Auditing Modes - -There will be different modes to audit vulnerabilities based on the developer's or developer's team preference. To do this, a developer will opt-in to a feature called `` which will have different modes such as `direct`, and `all`. - -These modes should be pretty straight-forward. `direct` will scan for any top-level vulnerabilities, and `all` will scan for both top-level and transitive-level vulnerabilities. The default will be `direct` until the experience is ready to be `all` given that transitive vulnerabilities are the majority of vulnerability notices (90%+). - -When a known vulnerability is found that is of the transitive level, it will include the path to the project containing the top-level package and including the name and version of the package the vulnerable transitive dependency is coming from. Transitive level known vulnerabilities should not be a warning, but rather a message/informational MSBuild severity as they should not break builds but still be brought up in the Error List as informational. - -#### Setting an Audit Level - -In cases where a developer only cares about a certain threshold of advisory severity, they can set a MSBuild property to set a level such as `moderate` in which auditing will fail. Possible values match the OSV format of `low`, `moderate`, `high`, and `critical`. - -#### Excluding Advisories - -There is no support for excluding individual advisories at this time. -Developers will be able to `` the four `NU1901` -> `NU1904` warnings or set the `` to suppress certain severities. -See the section [suppress advisories](#suppress-advisories), under the [future possibilities](#future-possibilities) section, for some early thoughts. - -#### Vulnerability warnings in the solution explorer - -Given that restore would be raising a warning, the vulnerability information will automatically appear in the Solution Explorer. -This is the primary motivation for having 1 message per package. - -### Source of known vulnerabilities - -The proposal is that each NuGet feed will be responsible for providing the NuGet client with a list of known vulnerabilities. - -nuget.org currently gets its data from the GitHub Advisories Database. -Therefore, upon initial release, anyone with `https://api.nuget.org/v3/index.json` as a package source and opts into the feature will have GitHub's advisories scanning their packages. -The protocol format is designed to make it easy for other package sources to mirror nuget.org's known vulnerabilities, or [explicitly instruct the NuGet client to use nuget.org's vulnerability data](#allow-sources-to-upstream-vulnerability-information). -Servers can also source their vulnerability data from other sources, as long as they transform the data into [the schema expected by the client](#dedicated-vulnerability-information-resource). - -Servers that use nuget.org as an upstream source for their packages have multiple options in providing nuget.org's vulnerability information. -See the [section on allowing source to upstream vulnerability information](#allow-sources-to-upstream-vulnerability-information). - -### Technical explanation - -During every real restore, i.e. one that regenerates the assets file, NuGet will check all sources that provide vulnerability information and raise warnings for the packages that do. - -*Which sources can provide vulnerability information?* -Only V3 http sources can provide vulnerability information. No additional means of providing vulnerability information are proposed here. - -#### Technical background - -To best understand the technical proposal, it's important to understand the [NuGet package installation process](https://docs.microsoft.com/en-us/nuget/concepts/package-installation-process). - -When a package is seen, the client talks to sources and downloads whichever versions are needed. When talking to V3 sources, the client use the `package content` [resource](https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource), which is a static resource that only has information about the available package versions. Only what is contained *within* the package itself affect restore. Nothing else. This allows an equivalence between `http` and `local` sources. - -#### Dedicated vulnerability information resource - -Checking vulnerability will always take a performance hit, but we want to minimize that. We can: - -- Make fewer http calls. -- Minimize the amount of data we are handling. - -Both of these can be achieved by adding a means to understand whether a source supports vulnerability. We'd add a resource such as the following: - -```json - { - "@id": "https://nikolchevulntest.blob.core.windows.net/newcontainer/vulnerabilityindex.json", - "@type": "VulnerabilityInfo/6.7.0", - "comment": "The endpoint for discovering information about vulnerabilities of packages in this package source." - }, -``` - -When NuGet restores, we check whether a source supports vulnerabilities and if so it can go through a protocol of getting this information. - -The client needs all the data to make decisions about vulnerabilities. -In order to reduce customer bandwidth in frequently re-downloading the vulnerability data, it is recommended for servers to partition the data into multiple files. -Our recommendation is to have one file which new vulnerabilities are added into, and one or more files which contain historic vulnerabilities that is updated infrequently, allowing the client to re-use cached versions of the file(s). -Periodically, the small file's data can be merged into the large file(s), and the small file cleared. - -- The vulnerability resource **must** be an array of objects. -- Each object **must** contain: - - `@name`, a short name for the page, used for caching, and has a few restrictions: - - **must** be unique. - - **must** be between 1 and 32 characters long. - - **must** only contain characters `A` to `Z`, `a` to `z`, `0` to `9`, or be `-` or `_`. - - `@id`, the url that contains the data. - - `@updated`, a UTC timestamp when the content at `@id` was updated last. - - `comment`, a user friendly description. -- The vulnerability resource **must** at minimum contain 1 page. -- The pages within the vulnerability resource **must** be exclusive. - -One idea for data partitioning is: - -- The vulnerability resource contains 2 pages. - - One page, `base`, represents the data up to a certain point in time. - - The second page, `update`, represents the data from the last update of `base`, to present. - - Periodically, for example once a month, the data from `update` **should** be migrated to `base`. - - If an entry needs to be removed from `base`, `base` should be updated. -- Other partitioning strategies are workable as well. It is up to the server implementation to be considerate to customers with low bandwidth or metered download allowances. - -This would allow for the client to do the following: - -1. Fetch the main vulnerability resource if available. -1. Compare its version of the base resource to the remote one, based on the updated property. Re-download if different. -1. Compare its version of the update resource to the remote, based on the updated property. Re-download if different. - -This should allow for incremental downloads over a short period of time, without an unnecessarily complex update protocol. Given that we're downloading a gziped version, it is unlikely that the payload size becomes a problem anytime soon. - -```json -[ - { - "@name": "base", - "@id": "https://api.nuget.org/v3/vulnerability-base.index.json", - "@updated": "2022-11-15T15:30:00.0000000Z", - "comment": "The base data for vulnerability update periodically" - }, - { - "@name": "update", - "@id": "https://api.nuget.org/v3/vulnerability-update.index.json", - "@updated": "2022-11-30T15:30:00.0000000Z", - "comment": "The patch data for the vulnerability. Contains all the vulnerabilities since base was last updated." - } -] -``` - -- The page within the vulnerability resource **must** have the `packageid` as a primary key. -- The value of that **must** be an array of objects. -- The objects within the array of objects **must** contain: - - Severity, an `int`, where `0` means `low`, `1` means `medium`, `2` means `high`, `3` means `critical` - - Advisory url, a url. - - Versions, a version range in [NuGet range syntax](https://learn.microsoft.com/nuget/concepts/package-versioning#version-ranges) of affected package versions. This can contain prerelease versions as appropriate. -- The package id **should** be lower case, but it **must** be a case insensitive string, expected to be a valid package id as prescribed by NuGet. -- The version range **must** be case insensitive and normalized (does not include the metadata information). Server implementations written in .NET can use the `NuGet.Versioning` package's `VersionRange.ToNormalizedString()` method to get a compliant output. - -```json -{ - "adplug": [ - { - "severity": 3, - "url": "https://github.com/advisories/GHSA-874w-m2v2-mj64", - "versions": "(, 2.3.1)" - } - ], - "bond.core.csharp": [ - { - "severity": 2, - "url": "https://github.com/advisories/GHSA-rqrc-8q8f-cp9c", - "versions": "[3.0.0, 9.0.1]" - } - ] -} -``` - -Having a dedicated vulnerability information resource will allow upstreams to easily use the NuGet.org data within their source. - -## Drawbacks - -- Vulnerability checking will have a performance hit. - -## Rationale and alternatives - -Most of the alternatives/ideas covered below are not exclusive. - -### Vulnerability dedicated resources updating alternatives - -There are many ways to solve the updating problem. - -Instead of using the `custom` @updated property, we could instead use HTTP constructs. - -- Use ETag instead of an intermediate resource. This would technically have 1 fewer call than the current proposal. -- Use If-Modified-Since and simply always request both the base and update resources. -- Version the vulnerabilities by the year information was known to source. - - Implement something similar to what the [catalog resource](https://learn.microsoft.com/en-us/nuget/api/catalog-resource) is. - - This would allow certain vulnerabilities to never be re-downloaded, but it will continuously increased, even if it is unlikely to ever become unreasonable. - -- Multiple resource files organized in buckets such as the first character of the package id or some other [arbitrary bucketing method](https://en.wikipedia.org/wiki/Consistent_hashing). - - This will not improve the overall performance, but theoretically would limit the frequency of the data being refreshed. - -- Multiple resource files organized by severity. This could reduce the traffic and make restore faster, but only if customers only care about certain severities. - -### Vulnerability reporting not tied to sources - -All of NuGet's HTTP traffic is through sources. -The vulnerability information does not have to be tied to sources. -It could be something that's configured independently. - -This information could be something that's provided by nuget.org, similarly to licenses.nuget.org. -This would be a url that the user would provide in their configuration. The advantage is that the user does not need their source to provide any vulnerability information. - -- Pros: - - Vulnerabilities are not inherently tied to sources. This is explicit effort undertaken by nuget as shepherds of the eco-system to provide vulnerability information. - - This can be additive. We can ship vulnerabilities tied to sources first and then update later. - -- Cons: - - The client has an established protocol and a means to configure a source. - - Experimentation is arguably easier as we're not introducing new syntax, at least not immediately. - - The challenge is that we'd need to establish a protocol, and something that could be slower on the uptake. - -### Optimizing vulnerability check cadence - -Most restores are no-op and only checking vulnerabilities when restore actually happen is a straightforward optimization. -Sometimes restore use the local data from the global packages folder to complete a restore. -An additional optimization would be to only check the vulnerabilities when we've already made any http call. - -A project that rarely changes package versions, and rarely installs or removes packages, will very infrequently fail NuGet's no-op check on a developer's machine. -Therefore, developers working on such repositories will not provider NuGet many opportunities to check for vulnerabilities as part of a restore. -However, it is expected that such projects will have a CI build which will perform a full restore, so this is not a scenario that we believe needs a design to mitigate at this time. - -## Prior Art - -- NPM automatically audits dependencies when packages are installed. - - NPM achieves this by checking the vulnerabilities for the full graph, by submitting the graph to a compute resource that provides a list of the vulnerabilities. - - The biggest difference is that NuGet restore is run significantly more frequently than npm install is. As such npm's vulnerability checking performance is not as critical as NuGet's. -- [pip-audit](https://github.com/pypa/pip-audit) scans for packages with known vulnerabilities using the Python Packaging Advisory Database. -- [cargo-audit](https://docs.rs/cargo-audit/latest/cargo_audit/) audits cargo.lock files for creates containing security vulnerabilities. -- [snyk](https://snyk.io/product/open-source-security-management/) provides security tools for open source vulnerability scanning and CLI experiences. -- [DependencyCheck](https://github.com/jeremylong/DependencyCheck) scans software for known vulnerabilities. - -## Unresolved Questions - - - - -- Should the opt in property be named `NuGetVulnerabilityAudit`? - - The motivation is that we might want to include deprecation in auditing at some point. Should customers that opted into vulnerability audit get that experience automatically even if they didn't intend to? Customers might only be interested in vulnerability auditing, but not deprecation auditing. -- How does this feature support CPM? Do packages that are not restored but may have a vulnerable version get reported? - -## Future Possibilities - -- Vulnerability scanning can be extended to SBOMs. -- Support can be added to automatically fix vulnerable dependencies (i.e. a fix experience in CLI / Tooling) -- Consideration of SDK/Framework scanning for implicit PackageReference that may be vulnernable. -- Readiness to enable `` to `all` for .NET/VS vNext: - - Customer feedback from .NET 8. - - Satisfaction of direct dependency scanning. - - Noise ratio of transitive dependency scanning (i.e. new warnings) - - Performance/scalability impact of transitive dependency scanning. - - Version resolution to ensure proper vulnerability reporting. - - UI/UX considerations for distinguishing direct/transitive vulnerability warnings. - - Incremental scanning/caching to avoid redundant scans. - - Documentation and education resources for the functionality. - - Prioritization and suppression of severity / advisories. - -Additionally, most of the [`Rationale and alternatives`](#rationale-and-alternatives) are really future possibilities on their own as they are not always exclusive to the current approach. Here's some further possibilities: - -### Suppress advisories - -We can add a way to suppress advisories, either through the NuGet.config, project file or any other configuration file that allows a developer to exclude advisories for various parameters such as a package ID, GHSA ID, or CVE ID. - -An example of how the nuget.config could look like: - -```xml - - - - -``` - -An idea how the project side could look like: -Today, you can suppress warnings by using their warning codes at both the project and the package level. - -Example: - -```xml - - $(NoWarn);NU1901 - - - - - -``` - -We can extend a similar functionality to the advisory urls via their own dedicated property. - -```xml -https://github.com/advisories/GHSA-g3q9-xf95-8hp5 - - - $(NoWarn);https://github.com/advisories/GHSA-g3q9-xf95-8hp5 - - - - - -``` - -The project level and package level metadata are not necessarily a package deal, we can choose to only add one. - -### Allow sources to upstream vulnerability information - -While the NuGet tooling supports multiple sources, not all configurations are going to contain nuget.org, and thus won't easily get the data curated from the [GitHub Advisory Database](https://devblogs.microsoft.com/nuget/how-to-scan-nuget-packages-for-security-vulnerabilities/). - -The [V3 protocol](https://learn.microsoft.com/en-us/nuget/api/overview) and the resource architecture would allow a source to link to a resource that may not be hosted by them. -Not every source would want to setup a pipeline for processing vulnerability information. They can instead just "point" to the nuget.org information. - -For example, an Azure Artifacts source could have this in their index.json: - -```json -{ - "resources" [ - - { - "@id": "https://api.nuget.org/v3/vulnerability.json", - "@type": "VulnerabilityInfo/6.7.0", - "comment": "The base data for vulnerability update periodically" - } - ] -} -``` - -While the nuget.org data only contains vulnerability information about packages on nuget.org, often times an `upstream` source is setup by customers, and while they reference their own private feed, they can still download packages from nuget.org. The vulnerability information is valuable in these scenarios. - -If this upstream approach is taken, it is very likely that the vulnerability checking has a lot of misses, but this is an understood trade-off. - -It is **very important* that if the upstream sources link to the nuget.org vulnerability, the actual nuget.org urls are used wherever possible, as this would allow the client to easily deduplicate the vulnerability information. - -### Command Line Restore output - -Restore output could be modified to provide a vulnerability summary. - -```bash -Found 2 vulnerabilities (0 low, 1 moderate, 0 high, 1 critical) in 2 package(s) - -warning NU1904: Package 'Contoso.Service.APIs' 1.0.3 has a known critical severity vulnerability, https://github.com/advisories/GHSA-1234-5678-9012. -warning NU1902: Package 'Contoso.Forms' 8.4.1 has a known moderate severity vulnerability, https://github.com/advisories/GHSA-1234-5678-9012. -``` - -In cases where no known vulnerabilities are found, restore can provide a normal verbosity message for every project: - -```bash -No known vulnerabilities found for . - -``` - -In addition at normal verbosity, we could log a report for each project whose vulnerabilities were audited. - -```bash -Found 2 vulnerabilities (0 low, 2 moderate, 0 high, 0 critical) in 2 package(s) - -Top-level Package Requested Resolved Severity Advisory URL -> Contoso.Forms 8.4.1 8.4.1 Moderate https://github.com/advisories/GHSA-1234-5678-9012 - -Transitive Package Resolved Severity Advisory URL -> Microsoft.Data.OData 5.2.0 Moderate https://github.com/advisories/GHSA-1234-5678-90XY -``` - -### Providing vulnerability information through a json, remotely or locally - -Other components may want to provide vulnerability information that's not tied to a source. -Whatever approach we take there will be a way to represent the vulnerability information through a json file. - -### Surfacing deprecation information - -Vulnerabilities and deprecation share some similarities. -From a customer point of view, they often also wish to be aware when a package is deprecated. - -However, nuget.org's implementation is that package deprecation information is stored per-version, rather than as ranges, as GitHub's package vulnerability information is. -NuGet.org also has a lot more deprecated package information than vulnerability information. -Therefore, it would be a more significant performance hit. - -At the time of writing, a file containing deprecation information is 140x the size of the vulnerability information. - -### Vulnerabilities in dependencies - -Due to transitive packages, thinking about a package having vulnerabilities is best thought of in the context of a project. -Having vulnerability data at restore time, would allow to potentially gather information about packages that themselves are not vulnerable, but bring in vulnerable packages within their graph. -This information could be a helpful signal for package authors to update their dependency graph. +# Auditing projects for package vulnerabilities during restore + +- [Jon Douglas](https://github.com/JonDouglas/), [Nikolche Kolev](https://github.com/nkolev92), [Peter Yu](https://github.com/ryuyu) +- Issue: [#8087](https://github.com/NuGet/Home/issues/8087) +- Related: [#11549](https://github.com/NuGet/Home/pull/11549) + +## Summary + +Audit your dependencies when restoring your NuGet packages with known security vulnerabilities. + +## Motivation + +Since [launching vulnerability scanning last year](https://devblogs.microsoft.com/nuget/how-to-scan-nuget-packages-for-security-vulnerabilities/), we have seen the world shift towards a zero-trust model with new executive orders, exponentially increasing security advisories and supply chain attacks, and a general sentiment towards securing build environments at all costs. + +While we support basic affordances when browsing for NuGet packages in NuGet.org, dotnet CLI, and Visual Studio, we have learned that our developers use these features, but they want better visibility. + +We ran a survey in 2022 regarding how developers currently feel about known security advisories and here is what we've learned: + +74% of developers would like to be notified of packages at restore/build time. 65% would like to see icons in the solution explorer for problematic packages. 42% of developers would like a security notification in Visual Studio's notification window. 39% of developers would use a dotnet audit command. + +![Notified](./../../meta/resources/VulnerabilitiesInRestore/Notified.png) + +Next, we asked developers how they learned about security vulnerabilities in their software. Majority learned from public reports, 3rd-party vulnerability scanners, and code reviews/accidental discovery. + +![Learned](./../../meta/resources/VulnerabilitiesInRestore/Learned.png) + +The most challenging aspects for ensuring the software they write is secure is three major things: + +1. Evaluating third-party libraries are secure and free of vulnerabilities. +2. Verifying the software they write is free of vulnerabilities. +3. Applying best practices to writing code. + +![Challenging](./../../meta/resources/VulnerabilitiesInRestore/Challenging.png) + +When asked how they understood and resolved the vulnerability, the majority of developers resolved them by updating the dependency or app. + +![Resolved](./../../meta/resources/VulnerabilitiesInRestore/Resolved.png) + +When doing so, the most challenging aspect for them is not breaking something else when doing this and better understanding the vulnerability's information to assess the impact and root cause to see if they are actually affected. + +![ResolveChallenge](./../../meta/resources/VulnerabilitiesInRestore/ResolveChallenge.png) + +## Explanation + +### Functional explanation + +When a restore happens whether implicitly, or explicitly, the packages will be audited for vulnerabilities *if* any of the sources declared provide vulnerability information. +If any vulnerabilities are found, the impact, appropriate remediation, and other advisory metadata will be reported to the developer to take action on. + +For example, a developer might run `dotnet restore` explicitly or `dotnet add package` which runs restore implicitly. If a package being restored contains a known security advisory, they would see output at the bottom of the restore output that indicates how many vulnerabilities, a break-down of their severities, and the appropriate remediation action to take given the context of their environment. Below are a handful of concepts ranging from a low to high verbosity of information + +#### Warning codes + +| Warning Code | Severity | +|--------------|----------| +| NU1901 | low | +| NU1902 | moderate | +| NU1903 | high | +| NU1904 | critical | + +When there are packages used by the project with vulnerabilities, they will be output like like any other warning or error: + +```text +/path/to/project.csproj: warning NU1904: Package 'Contoso.Service.APIs' 1.0.3 has a known critical severity vulnerability, https://github.com/advisories/GHSA-1234-5678-9012. +/path/to/project.csproj: warning NU1902: Package 'Contoso.Forms' 8.4.1 has a known moderate severity vulnerability, https://github.com/advisories/GHSA-1234-5678-9012. +``` + +If a package has more than 1 vulnerability, each vulnerability will have its own warning. These security issues are often likely independent and may be fixed in different versions. + +```bash +/path/to/project.csproj: warning NU1904: Package 'Contoso.Service.APIs' 1.0.3 has a known critical severity vulnerability, https://github.com/advisories/GHSA-1234-5678-9012 +/path/to/project.csproj: warning NU1904: Package 'Contoso.Service.APIs' 1.0.3 has a known moderate severity vulnerability, https://github.com/advisories/GHSA-1234-5678-90XY +``` + +Similarly, if a vulnerable package is either referenced directly by multiple projects, or a project reference causes a package to become a transitive package, it will be listed by each project affected. + +#### Enabling Vulnerability Auditing + +This feature will be opt-in to start and gather feedback from developers. + +To enable the feature, a developer can add `enable` to their project file as a MSBuild property. To disable the feature, a developer can add `disable` or remove the property from the project file. + +#### Setting Vulnerability Auditing Modes + +There will be different modes to audit vulnerabilities based on the developer's or developer's team preference. To do this, a developer will opt-in to a feature called `` which will have different modes such as `direct`, and `all`. + +These modes should be pretty straight-forward. `direct` will scan for any top-level vulnerabilities, and `all` will scan for both top-level and transitive-level vulnerabilities. The default will be `direct` until the experience is ready to be `all` given that transitive vulnerabilities are the majority of vulnerability notices (90%+). + +When a known vulnerability is found that is of the transitive level, it will include the path to the project containing the top-level package and including the name and version of the package the vulnerable transitive dependency is coming from. Transitive level known vulnerabilities should not be a warning, but rather a message/informational MSBuild severity as they should not break builds but still be brought up in the Error List as informational. + +#### Setting an Audit Level + +In cases where a developer only cares about a certain threshold of advisory severity, they can set a MSBuild property to set a level such as `moderate` in which auditing will fail. Possible values match the OSV format of `low`, `moderate`, `high`, and `critical`. + +#### Excluding Advisories + +There is no support for excluding individual advisories at this time. +Developers will be able to `` the four `NU1901` -> `NU1904` warnings or set the `` to suppress certain severities. +See the section [suppress advisories](#suppress-advisories), under the [future possibilities](#future-possibilities) section, for some early thoughts. + +#### Vulnerability warnings in the solution explorer + +Given that restore would be raising a warning, the vulnerability information will automatically appear in the Solution Explorer. +This is the primary motivation for having 1 message per package. + +### Source of known vulnerabilities + +The proposal is that each NuGet feed will be responsible for providing the NuGet client with a list of known vulnerabilities. + +nuget.org currently gets its data from the GitHub Advisories Database. +Therefore, upon initial release, anyone with `https://api.nuget.org/v3/index.json` as a package source and opts into the feature will have GitHub's advisories scanning their packages. +The protocol format is designed to make it easy for other package sources to mirror nuget.org's known vulnerabilities, or [explicitly instruct the NuGet client to use nuget.org's vulnerability data](#allow-sources-to-upstream-vulnerability-information). +Servers can also source their vulnerability data from other sources, as long as they transform the data into [the schema expected by the client](#dedicated-vulnerability-information-resource). + +Servers that use nuget.org as an upstream source for their packages have multiple options in providing nuget.org's vulnerability information. +See the [section on allowing source to upstream vulnerability information](#allow-sources-to-upstream-vulnerability-information). + +### Technical explanation + +During every real restore, i.e. one that regenerates the assets file, NuGet will check all sources that provide vulnerability information and raise warnings for the packages that do. + +*Which sources can provide vulnerability information?* +Only V3 http sources can provide vulnerability information. No additional means of providing vulnerability information are proposed here. + +#### Technical background + +To best understand the technical proposal, it's important to understand the [NuGet package installation process](https://docs.microsoft.com/en-us/nuget/concepts/package-installation-process). + +When a package is seen, the client talks to sources and downloads whichever versions are needed. When talking to V3 sources, the client use the `package content` [resource](https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource), which is a static resource that only has information about the available package versions. Only what is contained *within* the package itself affect restore. Nothing else. This allows an equivalence between `http` and `local` sources. + +#### Dedicated vulnerability information resource + +Checking vulnerability will always take a performance hit, but we want to minimize that. We can: + +- Make fewer http calls. +- Minimize the amount of data we are handling. + +Both of these can be achieved by adding a means to understand whether a source supports vulnerability. We'd add a resource such as the following: + +```json + { + "@id": "https://nikolchevulntest.blob.core.windows.net/newcontainer/vulnerabilityindex.json", + "@type": "VulnerabilityInfo/6.7.0", + "comment": "The endpoint for discovering information about vulnerabilities of packages in this package source." + }, +``` + +When NuGet restores, we check whether a source supports vulnerabilities and if so it can go through a protocol of getting this information. + +The client needs all the data to make decisions about vulnerabilities. +In order to reduce customer bandwidth in frequently re-downloading the vulnerability data, it is recommended for servers to partition the data into multiple files. +Our recommendation is to have one file which new vulnerabilities are added into, and one or more files which contain historic vulnerabilities that is updated infrequently, allowing the client to re-use cached versions of the file(s). +Periodically, the small file's data can be merged into the large file(s), and the small file cleared. + +- The vulnerability resource **must** be an array of objects. +- Each object **must** contain: + - `@name`, a short name for the page, used for caching, and has a few restrictions: + - **must** be unique. + - **must** be between 1 and 32 characters long. + - **must** only contain characters `A` to `Z`, `a` to `z`, `0` to `9`, or be `-` or `_`. + - `@id`, the url that contains the data. + - `@updated`, a UTC timestamp when the content at `@id` was updated last. + - `comment`, a user friendly description. +- The vulnerability resource **must** at minimum contain 1 page. +- The pages within the vulnerability resource **must** be exclusive. + +One idea for data partitioning is: + +- The vulnerability resource contains 2 pages. + - One page, `base`, represents the data up to a certain point in time. + - The second page, `update`, represents the data from the last update of `base`, to present. + - Periodically, for example once a month, the data from `update` **should** be migrated to `base`. + - If an entry needs to be removed from `base`, `base` should be updated. +- Other partitioning strategies are workable as well. It is up to the server implementation to be considerate to customers with low bandwidth or metered download allowances. + +This would allow for the client to do the following: + +1. Fetch the main vulnerability resource if available. +1. Compare its version of the base resource to the remote one, based on the updated property. Re-download if different. +1. Compare its version of the update resource to the remote, based on the updated property. Re-download if different. + +This should allow for incremental downloads over a short period of time, without an unnecessarily complex update protocol. Given that we're downloading a gziped version, it is unlikely that the payload size becomes a problem anytime soon. + +```json +[ + { + "@name": "base", + "@id": "https://api.nuget.org/v3/vulnerability-base.index.json", + "@updated": "2022-11-15T15:30:00.0000000Z", + "comment": "The base data for vulnerability update periodically" + }, + { + "@name": "update", + "@id": "https://api.nuget.org/v3/vulnerability-update.index.json", + "@updated": "2022-11-30T15:30:00.0000000Z", + "comment": "The patch data for the vulnerability. Contains all the vulnerabilities since base was last updated." + } +] +``` + +- The page within the vulnerability resource **must** have the `packageid` as a primary key. +- The value of that **must** be an array of objects. +- The objects within the array of objects **must** contain: + - Severity, an `int`, where `0` means `low`, `1` means `medium`, `2` means `high`, `3` means `critical` + - Advisory url, a url. + - Versions, a version range in [NuGet range syntax](https://learn.microsoft.com/nuget/concepts/package-versioning#version-ranges) of affected package versions. This can contain prerelease versions as appropriate. +- The package id **should** be lower case, but it **must** be a case insensitive string, expected to be a valid package id as prescribed by NuGet. +- The version range **must** be case insensitive and normalized (does not include the metadata information). Server implementations written in .NET can use the `NuGet.Versioning` package's `VersionRange.ToNormalizedString()` method to get a compliant output. + +```json +{ + "adplug": [ + { + "severity": 3, + "url": "https://github.com/advisories/GHSA-874w-m2v2-mj64", + "versions": "(, 2.3.1)" + } + ], + "bond.core.csharp": [ + { + "severity": 2, + "url": "https://github.com/advisories/GHSA-rqrc-8q8f-cp9c", + "versions": "[3.0.0, 9.0.1]" + } + ] +} +``` + +Having a dedicated vulnerability information resource will allow upstreams to easily use the NuGet.org data within their source. + +## Drawbacks + +- Vulnerability checking will have a performance hit. + +## Rationale and alternatives + +Most of the alternatives/ideas covered below are not exclusive. + +### Vulnerability dedicated resources updating alternatives + +There are many ways to solve the updating problem. + +Instead of using the `custom` @updated property, we could instead use HTTP constructs. + +- Use ETag instead of an intermediate resource. This would technically have 1 fewer call than the current proposal. +- Use If-Modified-Since and simply always request both the base and update resources. +- Version the vulnerabilities by the year information was known to source. + - Implement something similar to what the [catalog resource](https://learn.microsoft.com/en-us/nuget/api/catalog-resource) is. + - This would allow certain vulnerabilities to never be re-downloaded, but it will continuously increased, even if it is unlikely to ever become unreasonable. + +- Multiple resource files organized in buckets such as the first character of the package id or some other [arbitrary bucketing method](https://en.wikipedia.org/wiki/Consistent_hashing). + - This will not improve the overall performance, but theoretically would limit the frequency of the data being refreshed. + +- Multiple resource files organized by severity. This could reduce the traffic and make restore faster, but only if customers only care about certain severities. + +### Vulnerability reporting not tied to sources + +All of NuGet's HTTP traffic is through sources. +The vulnerability information does not have to be tied to sources. +It could be something that's configured independently. + +This information could be something that's provided by nuget.org, similarly to licenses.nuget.org. +This would be a url that the user would provide in their configuration. The advantage is that the user does not need their source to provide any vulnerability information. + +- Pros: + - Vulnerabilities are not inherently tied to sources. This is explicit effort undertaken by nuget as shepherds of the eco-system to provide vulnerability information. + - This can be additive. We can ship vulnerabilities tied to sources first and then update later. + +- Cons: + - The client has an established protocol and a means to configure a source. + - Experimentation is arguably easier as we're not introducing new syntax, at least not immediately. + - The challenge is that we'd need to establish a protocol, and something that could be slower on the uptake. + +### Optimizing vulnerability check cadence + +Most restores are no-op and only checking vulnerabilities when restore actually happen is a straightforward optimization. +Sometimes restore use the local data from the global packages folder to complete a restore. +An additional optimization would be to only check the vulnerabilities when we've already made any http call. + +A project that rarely changes package versions, and rarely installs or removes packages, will very infrequently fail NuGet's no-op check on a developer's machine. +Therefore, developers working on such repositories will not provider NuGet many opportunities to check for vulnerabilities as part of a restore. +However, it is expected that such projects will have a CI build which will perform a full restore, so this is not a scenario that we believe needs a design to mitigate at this time. + +## Prior Art + +- NPM automatically audits dependencies when packages are installed. + - NPM achieves this by checking the vulnerabilities for the full graph, by submitting the graph to a compute resource that provides a list of the vulnerabilities. + - The biggest difference is that NuGet restore is run significantly more frequently than npm install is. As such npm's vulnerability checking performance is not as critical as NuGet's. +- [pip-audit](https://github.com/pypa/pip-audit) scans for packages with known vulnerabilities using the Python Packaging Advisory Database. +- [cargo-audit](https://docs.rs/cargo-audit/latest/cargo_audit/) audits cargo.lock files for creates containing security vulnerabilities. +- [snyk](https://snyk.io/product/open-source-security-management/) provides security tools for open source vulnerability scanning and CLI experiences. +- [DependencyCheck](https://github.com/jeremylong/DependencyCheck) scans software for known vulnerabilities. + +## Unresolved Questions + + + + +- Should the opt in property be named `NuGetVulnerabilityAudit`? + - The motivation is that we might want to include deprecation in auditing at some point. Should customers that opted into vulnerability audit get that experience automatically even if they didn't intend to? Customers might only be interested in vulnerability auditing, but not deprecation auditing. +- How does this feature support CPM? Do packages that are not restored but may have a vulnerable version get reported? + +## Future Possibilities + +- Vulnerability scanning can be extended to SBOMs. +- Support can be added to automatically fix vulnerable dependencies (i.e. a fix experience in CLI / Tooling) +- Consideration of SDK/Framework scanning for implicit PackageReference that may be vulnernable. +- Readiness to enable `` to `all` for .NET/VS vNext: + - Customer feedback from .NET 8. + - Satisfaction of direct dependency scanning. + - Noise ratio of transitive dependency scanning (i.e. new warnings) + - Performance/scalability impact of transitive dependency scanning. + - Version resolution to ensure proper vulnerability reporting. + - UI/UX considerations for distinguishing direct/transitive vulnerability warnings. + - Incremental scanning/caching to avoid redundant scans. + - Documentation and education resources for the functionality. + - Prioritization and suppression of severity / advisories. + +Additionally, most of the [`Rationale and alternatives`](#rationale-and-alternatives) are really future possibilities on their own as they are not always exclusive to the current approach. Here's some further possibilities: + +### Suppress advisories + +We can add a way to suppress advisories, either through the NuGet.config, project file or any other configuration file that allows a developer to exclude advisories for various parameters such as a package ID, GHSA ID, or CVE ID. + +An example of how the nuget.config could look like: + +```xml + + + + +``` + +An idea how the project side could look like: +Today, you can suppress warnings by using their warning codes at both the project and the package level. + +Example: + +```xml + + $(NoWarn);NU1901 + + + + + +``` + +We can extend a similar functionality to the advisory urls via their own dedicated property. + +```xml +https://github.com/advisories/GHSA-g3q9-xf95-8hp5 + + + $(NoWarn);https://github.com/advisories/GHSA-g3q9-xf95-8hp5 + + + + + +``` + +The project level and package level metadata are not necessarily a package deal, we can choose to only add one. + +### Allow sources to upstream vulnerability information + +While the NuGet tooling supports multiple sources, not all configurations are going to contain nuget.org, and thus won't easily get the data curated from the [GitHub Advisory Database](https://devblogs.microsoft.com/nuget/how-to-scan-nuget-packages-for-security-vulnerabilities/). + +The [V3 protocol](https://learn.microsoft.com/en-us/nuget/api/overview) and the resource architecture would allow a source to link to a resource that may not be hosted by them. +Not every source would want to setup a pipeline for processing vulnerability information. They can instead just "point" to the nuget.org information. + +For example, an Azure Artifacts source could have this in their index.json: + +```json +{ + "resources" [ + + { + "@id": "https://api.nuget.org/v3/vulnerability.json", + "@type": "VulnerabilityInfo/6.7.0", + "comment": "The base data for vulnerability update periodically" + } + ] +} +``` + +While the nuget.org data only contains vulnerability information about packages on nuget.org, often times an `upstream` source is setup by customers, and while they reference their own private feed, they can still download packages from nuget.org. The vulnerability information is valuable in these scenarios. + +If this upstream approach is taken, it is very likely that the vulnerability checking has a lot of misses, but this is an understood trade-off. + +It is **very important* that if the upstream sources link to the nuget.org vulnerability, the actual nuget.org urls are used wherever possible, as this would allow the client to easily deduplicate the vulnerability information. + +### Command Line Restore output + +Restore output could be modified to provide a vulnerability summary. + +```bash +Found 2 vulnerabilities (0 low, 1 moderate, 0 high, 1 critical) in 2 package(s) + +warning NU1904: Package 'Contoso.Service.APIs' 1.0.3 has a known critical severity vulnerability, https://github.com/advisories/GHSA-1234-5678-9012. +warning NU1902: Package 'Contoso.Forms' 8.4.1 has a known moderate severity vulnerability, https://github.com/advisories/GHSA-1234-5678-9012. +``` + +In cases where no known vulnerabilities are found, restore can provide a normal verbosity message for every project: + +```bash +No known vulnerabilities found for . + +``` + +In addition at normal verbosity, we could log a report for each project whose vulnerabilities were audited. + +```bash +Found 2 vulnerabilities (0 low, 2 moderate, 0 high, 0 critical) in 2 package(s) + +Top-level Package Requested Resolved Severity Advisory URL +> Contoso.Forms 8.4.1 8.4.1 Moderate https://github.com/advisories/GHSA-1234-5678-9012 + +Transitive Package Resolved Severity Advisory URL +> Microsoft.Data.OData 5.2.0 Moderate https://github.com/advisories/GHSA-1234-5678-90XY +``` + +### Providing vulnerability information through a json, remotely or locally + +Other components may want to provide vulnerability information that's not tied to a source. +Whatever approach we take there will be a way to represent the vulnerability information through a json file. + +### Surfacing deprecation information + +Vulnerabilities and deprecation share some similarities. +From a customer point of view, they often also wish to be aware when a package is deprecated. + +However, nuget.org's implementation is that package deprecation information is stored per-version, rather than as ranges, as GitHub's package vulnerability information is. +NuGet.org also has a lot more deprecated package information than vulnerability information. +Therefore, it would be a more significant performance hit. + +At the time of writing, a file containing deprecation information is 140x the size of the vulnerability information. + +### Vulnerabilities in dependencies + +Due to transitive packages, thinking about a package having vulnerabilities is best thought of in the context of a project. +Having vulnerability data at restore time, would allow to potentially gather information about packages that themselves are not vulnerable, but bring in vulnerable packages within their graph. +This information could be a helpful signal for package authors to update their dependency graph. diff --git a/proposed/2023/Add-NoHttpCacheOption.md b/accepted/2023/Add-NoHttpCacheOption.md similarity index 100% rename from proposed/2023/Add-NoHttpCacheOption.md rename to accepted/2023/Add-NoHttpCacheOption.md diff --git a/proposed/2023/Add-dotnet-search.md b/accepted/2023/Add-dotnet-search.md similarity index 100% rename from proposed/2023/Add-dotnet-search.md rename to accepted/2023/Add-dotnet-search.md diff --git a/proposed/2023/InsecureConnectionsDisableCertificateValidation.md b/accepted/2023/InsecureConnectionsDisableCertificateValidation.md similarity index 100% rename from proposed/2023/InsecureConnectionsDisableCertificateValidation.md rename to accepted/2023/InsecureConnectionsDisableCertificateValidation.md diff --git a/proposed/2023/PMUI-Readme-rendering.md b/accepted/2023/PMUI-Readme-rendering.md similarity index 100% rename from proposed/2023/PMUI-Readme-rendering.md rename to accepted/2023/PMUI-Readme-rendering.md diff --git a/proposed/2023/readme-markdown-install-PMUI.md b/accepted/2023/readme-markdown-install-PMUI.md similarity index 100% rename from proposed/2023/readme-markdown-install-PMUI.md rename to accepted/2023/readme-markdown-install-PMUI.md diff --git a/proposed/2023/remove-projects-from-list-package-command.md b/accepted/2023/remove-projects-from-list-package-command.md similarity index 100% rename from proposed/2023/remove-projects-from-list-package-command.md rename to accepted/2023/remove-projects-from-list-package-command.md diff --git a/proposed/archive/AdvancedSearchOnNuGet.md b/accepted/archive/AdvancedSearchOnNuGet.md similarity index 100% rename from proposed/archive/AdvancedSearchOnNuGet.md rename to accepted/archive/AdvancedSearchOnNuGet.md diff --git a/proposed/archive/Deterministic-Pack.md b/accepted/archive/Deterministic-Pack.md similarity index 100% rename from proposed/archive/Deterministic-Pack.md rename to accepted/archive/Deterministic-Pack.md diff --git a/proposed/archive/DotNetSignCommands.md b/accepted/archive/DotNetSignCommands.md similarity index 100% rename from proposed/archive/DotNetSignCommands.md rename to accepted/archive/DotNetSignCommands.md diff --git a/proposed/archive/DotNetSources/Commands.xml b/accepted/archive/DotNetSources/Commands.xml similarity index 100% rename from proposed/archive/DotNetSources/Commands.xml rename to accepted/archive/DotNetSources/Commands.xml diff --git a/proposed/archive/DotNetSources/DotNet-Sources-Support.md b/accepted/archive/DotNetSources/DotNet-Sources-Support.md similarity index 100% rename from proposed/archive/DotNetSources/DotNet-Sources-Support.md rename to accepted/archive/DotNetSources/DotNet-Sources-Support.md diff --git a/proposed/archive/Download-Only-Packages.md b/accepted/archive/Download-Only-Packages.md similarity index 100% rename from proposed/archive/Download-Only-Packages.md rename to accepted/archive/Download-Only-Packages.md diff --git a/proposed/archive/EmbeddedReadmesTechSpec.md b/accepted/archive/EmbeddedReadmesTechSpec.md similarity index 100% rename from proposed/archive/EmbeddedReadmesTechSpec.md rename to accepted/archive/EmbeddedReadmesTechSpec.md diff --git a/proposed/archive/FloatingStableAndPrerelease.md b/accepted/archive/FloatingStableAndPrerelease.md similarity index 100% rename from proposed/archive/FloatingStableAndPrerelease.md rename to accepted/archive/FloatingStableAndPrerelease.md diff --git a/proposed/archive/FloatingVersions-In-PMUI.md b/accepted/archive/FloatingVersions-In-PMUI.md similarity index 100% rename from proposed/archive/FloatingVersions-In-PMUI.md rename to accepted/archive/FloatingVersions-In-PMUI.md diff --git a/proposed/archive/NuGet-ClientCertificates.md b/accepted/archive/NuGet-ClientCertificates.md similarity index 100% rename from proposed/archive/NuGet-ClientCertificates.md rename to accepted/archive/NuGet-ClientCertificates.md diff --git a/proposed/archive/NuGet-FrameworkReference-TransitiveFlow.md b/accepted/archive/NuGet-FrameworkReference-TransitiveFlow.md similarity index 100% rename from proposed/archive/NuGet-FrameworkReference-TransitiveFlow.md rename to accepted/archive/NuGet-FrameworkReference-TransitiveFlow.md diff --git a/proposed/archive/NuGet-FrameworkReference.md b/accepted/archive/NuGet-FrameworkReference.md similarity index 100% rename from proposed/archive/NuGet-FrameworkReference.md rename to accepted/archive/NuGet-FrameworkReference.md diff --git a/proposed/archive/NuGetExtensibility/INuGetProjectServices.md b/accepted/archive/NuGetExtensibility/INuGetProjectServices.md similarity index 100% rename from proposed/archive/NuGetExtensibility/INuGetProjectServices.md rename to accepted/archive/NuGetExtensibility/INuGetProjectServices.md diff --git a/proposed/archive/NuGetExtensibility/NuGetExtensibilityServices.md b/accepted/archive/NuGetExtensibility/NuGetExtensibilityServices.md similarity index 100% rename from proposed/archive/NuGetExtensibility/NuGetExtensibilityServices.md rename to accepted/archive/NuGetExtensibility/NuGetExtensibilityServices.md diff --git a/proposed/archive/NuGetOrgReplicationAPI.md b/accepted/archive/NuGetOrgReplicationAPI.md similarity index 100% rename from proposed/archive/NuGetOrgReplicationAPI.md rename to accepted/archive/NuGetOrgReplicationAPI.md diff --git a/proposed/archive/PMUITabSwitchRefactoring.md b/accepted/archive/PMUITabSwitchRefactoring.md similarity index 100% rename from proposed/archive/PMUITabSwitchRefactoring.md rename to accepted/archive/PMUITabSwitchRefactoring.md diff --git a/proposed/archive/Package-List-Verbosity.md b/accepted/archive/Package-List-Verbosity.md similarity index 100% rename from proposed/archive/Package-List-Verbosity.md rename to accepted/archive/Package-List-Verbosity.md diff --git a/proposed/archive/PackageApplicabilityInNuGetPackageManagerUI.md b/accepted/archive/PackageApplicabilityInNuGetPackageManagerUI.md similarity index 100% rename from proposed/archive/PackageApplicabilityInNuGetPackageManagerUI.md rename to accepted/archive/PackageApplicabilityInNuGetPackageManagerUI.md diff --git a/proposed/archive/PackageIconLicenseDocumentationWithinNupkg.md b/accepted/archive/PackageIconLicenseDocumentationWithinNupkg.md similarity index 100% rename from proposed/archive/PackageIconLicenseDocumentationWithinNupkg.md rename to accepted/archive/PackageIconLicenseDocumentationWithinNupkg.md diff --git a/proposed/archive/PackageReference-AllStable-Normalization.md b/accepted/archive/PackageReference-AllStable-Normalization.md similarity index 100% rename from proposed/archive/PackageReference-AllStable-Normalization.md rename to accepted/archive/PackageReference-AllStable-Normalization.md diff --git a/proposed/archive/PackageReference-Extern-Alias.md b/accepted/archive/PackageReference-Extern-Alias.md similarity index 100% rename from proposed/archive/PackageReference-Extern-Alias.md rename to accepted/archive/PackageReference-Extern-Alias.md diff --git a/proposed/archive/PackageValidation/BuildPropsConventionIsUpheld.md b/accepted/archive/PackageValidation/BuildPropsConventionIsUpheld.md similarity index 100% rename from proposed/archive/PackageValidation/BuildPropsConventionIsUpheld.md rename to accepted/archive/PackageValidation/BuildPropsConventionIsUpheld.md diff --git a/proposed/archive/PackageValidation/DependenciesInNuspecMatchLibRefFolder.md b/accepted/archive/PackageValidation/DependenciesInNuspecMatchLibRefFolder.md similarity index 100% rename from proposed/archive/PackageValidation/DependenciesInNuspecMatchLibRefFolder.md rename to accepted/archive/PackageValidation/DependenciesInNuspecMatchLibRefFolder.md diff --git a/proposed/archive/PackageValidation/FileNameCaseSensitivity.md b/accepted/archive/PackageValidation/FileNameCaseSensitivity.md similarity index 100% rename from proposed/archive/PackageValidation/FileNameCaseSensitivity.md rename to accepted/archive/PackageValidation/FileNameCaseSensitivity.md diff --git a/proposed/archive/PackageValidation/RefAssembliesInNuspecMatchRefFolder.md b/accepted/archive/PackageValidation/RefAssembliesInNuspecMatchRefFolder.md similarity index 100% rename from proposed/archive/PackageValidation/RefAssembliesInNuspecMatchRefFolder.md rename to accepted/archive/PackageValidation/RefAssembliesInNuspecMatchRefFolder.md diff --git a/proposed/archive/Prerelease-Option.md b/accepted/archive/Prerelease-Option.md similarity index 100% rename from proposed/archive/Prerelease-Option.md rename to accepted/archive/Prerelease-Option.md diff --git a/proposed/archive/RefreshMetrics.md b/accepted/archive/RefreshMetrics.md similarity index 100% rename from proposed/archive/RefreshMetrics.md rename to accepted/archive/RefreshMetrics.md diff --git a/proposed/archive/RuntimeJsonFromProject.md b/accepted/archive/RuntimeJsonFromProject.md similarity index 100% rename from proposed/archive/RuntimeJsonFromProject.md rename to accepted/archive/RuntimeJsonFromProject.md diff --git a/proposed/archive/SearchCommandSpec.md b/accepted/archive/SearchCommandSpec.md similarity index 100% rename from proposed/archive/SearchCommandSpec.md rename to accepted/archive/SearchCommandSpec.md diff --git a/proposed/archive/SolutionLoad-CsprojPackageReferenceRestore.md b/accepted/archive/SolutionLoad-CsprojPackageReferenceRestore.md similarity index 100% rename from proposed/archive/SolutionLoad-CsprojPackageReferenceRestore.md rename to accepted/archive/SolutionLoad-CsprojPackageReferenceRestore.md diff --git a/proposed/archive/UserWideConfiguration-AdditionalExtensibilityFolders.md b/accepted/archive/UserWideConfiguration-AdditionalExtensibilityFolders.md similarity index 100% rename from proposed/archive/UserWideConfiguration-AdditionalExtensibilityFolders.md rename to accepted/archive/UserWideConfiguration-AdditionalExtensibilityFolders.md diff --git a/proposed/archive/VisualStudio-PartialRestoreOptimization.md b/accepted/archive/VisualStudio-PartialRestoreOptimization.md similarity index 100% rename from proposed/archive/VisualStudio-PartialRestoreOptimization.md rename to accepted/archive/VisualStudio-PartialRestoreOptimization.md diff --git a/proposed/README.md b/proposed/README.md deleted file mode 100644 index 397830f23..000000000 --- a/proposed/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Proposed - -When a proposal has been `proposed`, it will be reviewed. - -When there is consensus among the NuGet contributors and .NET community of the direction of the proposal, it will go into one of three states. - -- `accepted` - The proposal has been accepted and work will be scheduled to implement it. -- `withdrawn` - The proposal has been rejected or withdrawn by the author. -- `implemented` - The proposal has already been accepted and implemented into the product. - -For more information, see the [NuGet proposal process](../meta#nuget-proposal-process). \ No newline at end of file