nulic 0.0.4
dotnet tool install --global nulic --version 0.0.4
dotnet new tool-manifest
dotnet tool install --local nulic --version 0.0.4
#tool dotnet:?package=nulic&version=0.0.4
nuke :add-package nulic --version 0.0.4
nulic
A .NET global tool that collects and produces a license disclosure package for all NuGet dependencies in a project.
What it does
Given a solution, project, or folder, nulic:
- Enumerates all NuGet packages — direct and transitive
- Downloads or copies the actual license text for each package
- Writes a
third-party-notices/folder next to the solution containing:- One license text file per unique license (shared across packages using the same SPDX id)
- A
nulic-packages.jsonmanifest with full metadata per package
The goal is a complete, shippable artifact — every package gets an actual license file on disk.
Install
dotnet tool install -g nulic
Usage
nulic [<path>] [options]
| Argument / Option | Description |
|---|---|
<path> |
Solution file, project file, or folder. Default: . |
-d, --show-defaults |
Print the default nulic.json to stdout and exit |
-l, --log-level |
Log verbosity: Verbose, Debug, Information (default), Warning, Error |
-m, --merge <dir> |
Merge a third-party-notices/ directory from another nulic-processed project (repeatable) |
-o, --output <dir> |
Output folder for license files and report. Default: <path>/third-party-notices |
Examples
# Run on the current directory (auto-discovers solution)
nulic
# Run on a specific solution
nulic path/to/MyApp.sln
# Only show warnings and errors
nulic --log-level Warning
# Combine licenses from two sub-projects into one disclosure package
nulic MyApp.sln --merge ../firmware/third-party-notices --merge ../safety/third-party-notices
# Write output to a custom folder
nulic MyApp.sln --output D:/artifacts/third-party-notices
nulic.json
On first run, nulic creates a nulic.json next to the solution as a starting template.
Use nulic --show-defaults to print the default config.
{
"exclude": [], // glob patterns for project files to exclude from scanning
"ignore": [], // packages to ignore — id:* or author:* patterns
"allow": [], // SPDX allowlist; non-empty enables allowlist mode (exits 1 on violation)
"overrides": [] // patch metadata or inject packages without a real NuGet entry
}
Ignore patterns
Patterns are glob-style (* = any characters). The id: prefix is optional — a bare pattern also matches against package id.
"ignore": [
"Tyrell.Corp.*", // id glob — id: prefix is optional
"id:*Nexus.Test*", // id: prefix is explicit but equivalent
"author:Rick Deckard", // match on author name (glob)
"developmentDependency", // packages marked developmentDependency in packages.config
"PrivateAssets" // packages with PrivateAssets=all in PackageReference
]
Overrides
Override or inject a package entry — useful for packages with dead license URLs or internal packages.
All fields except id are optional:
"overrides": [
{
// All available fields:
"id": "DeathStar.TurboLaser",
"version": "3.0.0", // pin to a specific version (omit = all versions)
"license": "LicenseRef-Imperial", // SPDX expression or custom LicenseRef
"licenseUrl": "licenses/IMPERIAL_LICENSE.txt", // local path or https://
"authors": ["Emperor Palpatine"],
"projectUrl": "https://empire.gov/deathstar",
"copyright": "Copyright © 19 BBY Galactic Empire. All sectors reserved."
},
{
// Minimal — just fix the license URL for a package with a dead link:
"id": "HanSolo.Kessel",
"licenseUrl": "https://raw.githubusercontent.com/hansolo/kessel/main/LICENSE"
}
]
Allowlist (CI gate)
When allow is non-empty, nulic validates every package against the list and exits with code 1 if any violation is found — suitable for use as a CI gate:
"allow": [
"MIT",
"Apache-2.0",
"BSD-3-Clause",
"WITH LicenseRef-linking-exception" // permits GPL files carrying a linking exception
]
Compound SPDX expressions (e.g. MIT AND LicenseRef-foo) must have every component covered by the allowlist.
NOASSERTION
If nulic cannot obtain or identify a license for a package, the license field in nulic-packages.json is set to NOASSERTION and a warning is printed. Common causes:
- The package has no license metadata and no recognizable license file
- The license URL is dead or returns an unrecognizable format
- The package is not in the local NuGet cache (run
dotnet restorefirst)
Fix with an override:
"overrides": [
{
"id": "Some.Package",
"license": "MIT",
"licenseUrl": "https://raw.githubusercontent.com/org/repo/main/LICENSE"
}
]
Merging projects (--merge)
When a product bundles multiple independently-built components (e.g. a main application together with subsystems from different repos), each component should first be processed by nulic on its own. Then use --merge to produce a combined disclosure package:
# Step 1: process each component independently (in their own CI)
nulic HAL9000/ # produces HAL9000/third-party-notices/
nulic AE35Unit/ # produces AE35Unit/third-party-notices/
# Step 2: produce the combined disclosure for the product
nulic Discovery/ --merge ../HAL9000/third-party-notices --merge ../AE35Unit/third-party-notices
The merge step:
- Reads
nulic-packages.jsonfrom each merged directory - Copies license files into the target
third-party-notices/folder (skips identical files, errors on content mismatch) - Unions all packages, deduplicating by
Id + Version - Validates the combined set against the target project's
allowlist - Regenerates
third-party-notices.mdfrom the combined data
Running nulic on the nulic repo itself produces (abbreviated):
third-party-notices/
MIT.txt # shared — AngleSharp, System.CommandLine, Textify, ...
Apache-2.0.txt # shared — all NuGet.* packages, Serilog, ...
Microsoft.Build.18.6.3/
notices/THIRDPARTYNOTICES.txt # supplementary file from the package
... # one entry per unique package
nulic-packages.json
nulic-packages.json entry (real example from nulic's own dependencies):
{
"id": "AngleSharp",
"version": "1.4.0",
"authors": ["AngleSharp"],
"projectUrl": "https://anglesharp.github.io/",
"copyright": "Copyright 2013-2025, AngleSharp.",
"license": "MIT",
"licenseUrl": "https://licenses.nuget.org/MIT",
"licenseFiles": ["MIT.txt"]
}
Supported project types
| Project type | Package source |
|---|---|
SDK-style .csproj / .fsproj / .vbproj |
obj/project.assets.json (requires dotnet restore) |
Classic .NET Framework .csproj |
packages.config |
Native C++ .vcxproj |
packages.config |
Solutions .sln / .slnx |
All constituent projects |
| Folder | Auto-discovers first .sln / .slnx, then .csproj, etc. |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.4 | 46 | 5/25/2026 |
| 0.0.3 | 42 | 5/25/2026 |
| 0.0.2 | 52 | 5/25/2026 |
| 0.0.1 | 46 | 5/25/2026 |
| 0.0.1-alpha1 | 53 | 5/25/2026 |