PackageGuard 1.4.1

dotnet tool install --global PackageGuard --version 1.4.1
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local PackageGuard --version 1.4.1
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=PackageGuard&version=1.4.1
                    
nuke :add-package PackageGuard --version 1.4.1
                    

About

What's this?

PackageGuard is a fully open-source tool to scan the NuGet dependencies of your .NET solutions against a deny- or allowlist to control the open-source licenses that you want to allow or certain versions of certain packages you want to enforce or avoid.

What's so special about that?

I've noticed that the commercial solutions for this are usually very expensive and have functionality that smaller companies may not need. Hopefully this little tools fills the gap between tools like GitHub's Dependabot and expensive commercial products like Blackduck, SNYK and others.

Who created this?

My name is Dennis Doomen and I'm a Microsoft MVP and Principal Consultant at Aviva Solutions with 28 years of experience under my belt. As a software architect and/or lead developer, I specialize in designing full-stack enterprise solutions based on .NET as well as providing coaching on all aspects of designing, building, deploying and maintaining software systems. I'm the author of several open-source projects such as Fluent Assertions, Reflectify, Liquid Projections, and I've been maintaining coding guidelines for C# since 2001.

Contact me through Email, Bluesky, Twitter/X or Mastadon

How do I configure it?

First, you need to create a JSON configuration file listing the packages and/or licenses you want to allow/deny list. By default, this file is called config.json and loaded from the working directory, but you can override that using the --configpath CLI parameter. The config file needs to have the following format:

{
    "settings": {
        "allow": {
          "licenses": [
              "Apache-2.0", // Uses SPDX naming
              "MIT",
          ],
          "packages": [
              "MyPackage/[7.0.0,8.0.0)"
          ]            
        },
        "deny": {
          "licenses": [],
          "packages": [
            "ProhibitedPackage"
          ]
        },
        "ignoredFeeds": [
          "https://pkgs.dev.azure.com/somecompany/project/_packaging/myfeed/nuget/v3/index.json"
        ]
    }
}

In this example, only NuGet packages with the MIT or Apache 2.0 licenses are allowed, the use of the package ProhibitedPackage is prohibited, and MyPackage should stick to version 7 only. Both the allow and deny sections support the licenses and packages properties. But licenses and packages listed under allow have precedence over those under the deny section.

License names are case-insensitive and follow the SPDX identifier naming conventions, but we have special support for certain proprietary Microsoft licenses such as used by the Microsoft.AspNet.WebApi* packages. For those, we support using the license name Microsoft .NET Library License.

Package names can include just the NuGet ID but may also include a NuGet-compatible version (range) separated by /. Here's a summary of the possible notations:

Notation Valid versions
"Package/1.0" 1.0
"Package/[1.0,)" v ≥ 1.0
"Package/(1.0,)" v > 1.0
"Package/[1.0]" v == 1.0
"Package/(,1.0]" v ≤ 1.0
"Package/(,1.0)" v < 1.0
"Package/[1.0,2.0]" 1.0 ≤ v ≤ 2.0
"Package/(1.0,2.0)" 1.0 < v < 2.0
"Package/[1.0,2.0)" 1.0 ≤ v < 2.0

You can also tell PackageGuard to allow all packages from a particular feed, even if a package on that feed doesn't meet the licenses or packages listed under allow. Just add the element feeds under the allow element and specify a wildcard pattern that matches the name or URL of the feed.

{
    "settings": {
        "allow": {
            "feeds": ["*dev.azure.com*"]
        }
    }
}

And in case you want to prevent PackageGuard from trying to access a particular feed altogether, add them to the ignoredFeeds element. Notice that PackageGuard may still trigger a dotnet restore call if the package lock file (project.assets.json) doesn't exist yet, unless you use the SkipRestore option, that will use all available NuGet feeds.

How do I use it?

With this configuration in place, simply invoke PackageGuard like this

packageguard --configpath <path-to-config-file> <path-to-solution-file-or-project>

If you pass a directory, PackageGuard will try to find the .sln files there. But you can also specify a specific .csproj to scan.

If everything was configured correctly, you'll get something like:

alternate text is missing from this package README image

The exit code indicates either 0 for success or 1 for failure.

Additional notes

Speeding up the analysis using caching

One of the most expensive operations that PackageGuard needs to do is to download find the license information from GitHub or other sources. You can significantly speed-up the analysis process by using the --use-caching flag.

By default, this will cause PackageGuard to persist the license information it retrieved to a binary file under .packageguard\cache.bin. You can commit this file to source control so successive runs can reuse the license information it collected during a previous run.

If PackageGuard finds new packages in your project or solution that did not exist during the previous run, then it will update the cache after the analysis is completed.

Github rate limiting issues

If you're running into errors from GitHub like

Response status code does not indicate success: 403 (rate limit exceeded).

it means PackageGuard has ran into the rate limits of api.github.com while trying to fetch license information from certain repositories. You can solve that by either waiting an hour or creating a GitHub Personal Access Token with the public_repo scope. You can find more information about those tokens here.

After having generated such a token, pass it to PackageGuard through its github-api-key option or set-up an environment variable named GITHUB_API_KEY.

Versioning

This library uses Semantic Versioning to give meaning to the version numbers. For the versions available, see the tags on this repository.

Credits

This library wouldn't have been possible without the following tools, packages and companies:

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
1.4.1 299 7/13/2025
1.3.1 1,192 6/10/2025
1.3.0 188 6/7/2025
1.2.0 493 5/27/2025
1.1.0 165 5/22/2025
1.0.1 573 4/9/2025
1.0.0 153 4/8/2025