包源映射

包源映射是一款工具,可用于提升供应链安全性,尤其如果是混用公共和私有包源时。

默认情况下,NuGet 会在需要下载包时搜索所有配置的包源。 如果多个源上都存在某个包时,则可能无法确定从哪个源下载包。 使用包源映射可以筛选包,告诉 NuGet 要搜索哪个(些)源。

此外,我们还提供其他最佳做法建议,帮助你增强供应链抵御攻击的能力。

NuGet 6.0 中新增了包源映射。 从 Visual Studio 17.5 开始,可以使用 Visual Studio 选项对话框添加和删除包源映射。

Visual Studio 支持

Visual Studio 包源映射 工具中的支持 -> 选项 包管理器 UI 中的支持
17.0 - 17.4 ✅有空 ❌ 不可用 ❌ 不可用
17.5 ✅有空 ✅有空 ❌ 不可用
17.7 预览版 3 ✅有空 ✅有空 ✅ 显示的状态

此功能适用于所有 NuGet 集成工具。

较旧的工具将忽略包源映射配置。 若要使用此功能,请确保你所有的生成环境都使用兼容的工具版本。

只要使用了兼容的工具,包源映射就会应用于所有项目类型(包括 .NET Framework)。

视频演练

若要通过视频简要了解包源映射功能,请考虑观看 YouTube 上的使用包源映射保护 NuGet 包视频。

启用包源映射

要选择启用此功能,必须具有 nuget.config 文件。 在存储库的根目录中有一个 nuget.config 被视为最佳做法。 有关详细信息,请参阅 nuget.config 文档

使用 Visual Studio 选项对话框启用

  1. 在 Visual Studio 中打开解决方案。
  2. 导航到 Package Source Mappings 选项对话框。

从包管理器 UI

  • 从列表中选择一个包,以在“详细信息”窗格中显示。
  • Configure 按钮打开“包源映射”选项页。

The NuGet Package Manager window in Visual Studio showing a selected package, and a highlight around the

从 Visual Studio 选项对话框

  • 转到 Visual Studio 主工具栏中的 Tools 菜单,然后选择 NuGet Package Manager ->Package Manager Settings
  • 导航到 页Package Source Mappings

The Visual Studio Package Source Mappings Options Dialog showing no package source mappings, with an Add button to create a new mapping.

  1. Package Source Mappings 页面中的 Add 按钮,打开 Add Package Source Mappings 对话框。

The Add Package Source Mappings dialog 4. 输入包 ID 或包模式,然后通过切换所需源的复选框选择一个或多个包源。

The Add Package Source Mappings dialog with a filled package pattern and selected package source.

  1. Package Source Mapping 选项页将显示新建的源映射。

The Package Source Mapping options page showing the newly created source mapping

  1. 按“选项”对话框中的 OK,保存对适用 nuget.config 的更改。
  2. NuGet 包管理器窗口将刷新并反映所选包的源映射的新状态。 The NuGet Package Manager window in Visual Studio showing a selected package with the

通过手动编辑 nuget.config 启用

  • nuget.config 文件中声明所需的包源。
  • 在源声明之后,添加 <packageSourceMapping> 元素,它指定每个源的所需映射。
  • 为每个正在使用的源声明一个 packageSource 元素。
    • 根据需要添加任意数量的模式。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <!-- Define the package sources, nuget.org and contoso.com. -->
  <!-- `clear` ensures no additional sources are inherited from another config file. -->
  <packageSources>
    <clear />
    <!-- `key` can be any identifier for your source. -->
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
    <add key="contoso.com" value="https://contoso.com/packages/" />
  </packageSources>
  
  <!-- Define mappings by adding package patterns beneath the target source. -->
  <!-- Contoso.* packages and NuGet.Common will be restored from contoso.com,
       everything else from nuget.org. -->
  <packageSourceMapping>
    <!-- key value for <packageSource> should match key values from <packageSources> element -->
    <packageSource key="nuget.org">
      <package pattern="*" />
    </packageSource>
    <packageSource key="contoso.com">
      <package pattern="Contoso.*" />
      <package pattern="NuGet.Common" />
    </packageSource>
  </packageSourceMapping>
</configuration>

如果存在不同级别(计算机级别、用户级别、存储库级别)的多个 nuget.config 文件,请按照 nuget.config 优先规则应用包源映射设置。

包源映射规则

为了获得最大的灵活性和控制,NuGet 要求所有包通过定义明确的优先级来匹配包模式。

包模式要求

所有请求的包必须通过匹配一个定义的包模式映射到一个或多个源。 换句话说,定义 packageSourceMapping 元素后,必须显式定义每个包(包括可传递包)应从哪个源还原。

  • 顶级包和可传递包都必须匹配定义的模式。 不要求顶级包及其依赖项来自同一个源。
  • 可以在多个源上定义同一 ID 模式,从而允许匹配要从定义该模式的任何源中还原的包 ID。 但是,不建议这样做,因为这会对还原可预测性(给定包可能来自多个源)产生影响。 如果你信任所有各自的来源,这可能是有效的配置。

包模式语法

模式 示例语法 说明
包前缀模式 *NuGet.* 必须以 * 结尾 ,其中 * 匹配 0 个或多个字符。 * 是允许的最短前缀模式,匹配所有包 ID。
包 ID 模式 NuGet.CommonContoso.Contracts 确切的包 ID。

包模式优先级

当多个唯一模式与包 ID 匹配时,将首选最具有针对性的模式。 包 ID 模式始终具有最高优先级,而泛型 * 始终具有最低优先级。 对于包前缀模式,最长的前缀具有优先权。

Package Pattern Precedence Examples

设置默认源

* 模式可用于声明实际的默认源,这意味着任何与其他指定模式不匹配的包都将从该源还原,而不会引发错误。 如果你主要使用 nuget.org 中的包,并且只有几个内部包,或者对所有内部包(如 Contoso.*)都使用标准前缀,则此配置非常有利。

如果你的团队没有对内部包 ID 使用标准前缀或在安装之前审查 nuget.org 包,则将专用源设置为默认源将更好地满足你的需求。

注意

如果请求的包已存在于全局包文件夹中,则不会发生源查找,并且将忽略映射。 请考虑声明存储库的全局包文件夹,以获得此功能的全面安全性优势。 计划在下一次迭代中改进默认全局包文件夹的体验。 若要详细了解包安装的工作原理,请参阅概念性文档。

开始使用

可通过 2 种方式完全载入存储库,手动或使用 NuGet.PackageSourceMapper 工具

手动载入

对于手动载入,可以执行以下步骤:

  1. 声明一个新的存储库的全局包文件夹
  2. 运行 dotnet restore 还原依赖项。
  3. 运行 dotnet list package --include-transitive 以查看解决方案中的所有顶级包和可传递包。
    • 对于使用 packages.config 的 .NET Framework 项目,packages.config 文件将包含所有直接包和可传递包的简单列表。
  4. 定义映射,使解决方案中的每个包 ID(包括可传递包)与目标源的模式匹配。
  5. 运行 dotnet nuget locals global-packages -c 以清除全局包目录。
  6. 运行还原以验证是否正确配置了映射。 如果映射没有完全涵盖解决方案中每个包 ID,错误消息将帮助你确定问题。
  7. 还原成功后,就完成了! 可以选择考虑:

使用工具自动载入

许多存储库具有大量包,手动执行工作可能很耗时。 NuGet.PackageSourceMapper 工具可以根据项目的已知包和源自动生成 NuGet.config。

包源映射器工具需要你已成功完成一个包还原,它将读取作为生成的一部分生成的每个 .nupkg.metadata 文件,以最好地了解你如何映射各个包和源。 工具不仅涵盖主要依赖项,它还在生成映射时考虑所有可传递的依赖项。

工具有多种选项,可根据需要生成映射模式,请查看博客文章和工具的自述文件说明以获取更多详细信息。

若要了解源映射可能是什么样子,请参阅示例存储库

注意

  • 没有用于管理包源映射配置的 nuget.exe 或 dotnet.exe 命令,请参阅 NuGet/Home#10735
  • 在安装包时无法映射包,请参阅 NuGet/Home#10730
  • 使用 DotNetCoreCLI@2 Azure Pipelines 任务时存在一个限制,可通过在源映射配置中使用 feed- 前缀来绕过此限制。 不过,建议使用 NuGetAuthenticate 来满足身份验证需求,并直接从脚本任务调用 dotnet cli。 请参阅 microsoft/azure-pipelines-tasks#15542