Title image of Nuget restoring the wrong package from the wrong source

Nuget restoring the wrong package from the wrong source

25 June 2023

·
C#

This has been an annoying problem for a long time when using Nuget.

The typical scenario is this:

Your project is set up to look at one or more private Nuget feeds and the Nuget public feed. All is going well until someone publishes a package to the public Nuget feed with the same name and version as one of your internal packages. Now when you build the project it restores the random public package instead of your internal package which breaks everything.

It’s super annoying, especially when you have a complex internal package dependency tree and this happens to one of your base libraries. Suddenly your entire code base isn’t building and you need to spend a week changing dependencies.

💡

The actual name for this is dependency confusion. It’s also considered a serious security flaw as malicious actors can trick package managers to inject malicious code into your application.

So how do we fix it?

For a long time, our only option was to change our package to a new unique name + version combination and update all of the dependencies. This is very labour-intensive and doesn’t permanently fix the problem (A new public package could be created and break everything again). Thankfully Microsoft has added a better way to fix it: package source maps.

Package source maps give us “fine-grained control of where your packages come”. We can explicitly set which feed to use for packages instead of leaving it up to Nuget.

This feature is new so it’s only available on the latest tooling: Visual Studio 2022, .Net SDK 6.0+ and Nuget 6.0+

Fixing individual packages

Setting up the package source mappings happens in the Nuget.config.

Add a packageSourceMapping section to the config directly underneath the packageSources section. In this new section we can define package name patterns to specify which packages can come from each source. Importantly, the patterns support wildcard values (*).

If a package matches multiple patterns the most specific one will be used. In the example below, the “Logger” package is explicitly mapped to the “MyFeed” package source. Though “Logger” also matches the wildcard pattern (*) of the “Nuget.org” source, it comes from “MyFeed” because the pattern is more specific.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <config>
    <add key="repositoryPath" value="packages" />
  </config>

  <packageSources>
    <clear />
    <add key="MyFeed" value="https://MyCompany.pkgs.visualstudio.com/_packaging/MyCompany@Local/nuget/v3/index.json" />
    <add key="NuGet.org" value="https://api.nuget.org/v3/index.json" />
  </packageSources>

  <packageSourceMapping>
    <packageSource key="MyFeed">
      <package pattern="Logger" />
      <package pattern="*" />
    </packageSource> 
     
    <packageSource key="NuGet.org">
      <package pattern="*" /> 
     </packageSource>
  </packageSourceMapping>
</configuration>

This is much better than the previous fix of changing all your package names and versions. But even this can become annoying if it happens to many of your packages. Let’s see what we can do to specify all our packages with a single config line…

Strategy to fix all your packages

Source mappings become even more powerful if we implement a naming strategy to our packages. Prefixing all internal package names with your organization name allows us to group up our packages. With one mapping all prefixed internal packages are mapped to the internal package source:

  <packageSource key="MyFeed">
		<!-- All packages prefixed with MyCompany. -->
    <package pattern="MyCompany.*" />
    <package pattern="*" />
  </packageSource>

No more restoring the wrong package 🙂