Summary
docs/inventory-sources.md currently lists NuGet (packages.lock.json) under "Not currently covered". This issue requests read-only NuGet package inventory support so .NET developer endpoints can be included in the same supply-chain exposure checks as npm, PyPI, Go, RubyGems, and Composer.
Motivation
NuGet is the primary package manager for .NET. Without NuGet coverage, Bumblebee cannot answer whether a .NET-heavy developer machine has exposure to a known compromised or vulnerable package version.
Proposed sources
Bumblebee should not execute dotnet, nuget, MSBuild, or any package-manager command. It can get useful coverage by reading existing metadata files:
| Source |
Why it matters |
project.assets.json under obj/ |
Broadest PackageReference coverage; written by restore and contains resolved package libraries such as PackageName/1.0.0. Skip libraries entries where type != "package". |
packages.lock.json |
Highest-confidence lock file when present; opt-in via RestorePackagesWithLockFile. Dependencies are grouped per TFM/RID and include package type and resolved version. Treat NuGet package Direct/Transitive entries as direct/transitive; skip project-reference entries. |
packages.config |
Legacy XML format; contains <package id="..." version="..." />. |
~/.nuget/packages/<id>/<version>/<id>.nuspec |
User global package cache; useful for the baseline profile. Parse <id> and <version> from <metadata>. |
Suggested priority: project.assets.json for project-profile coverage, packages.lock.json when available for lock-file confidence, .nuspec cache entries for baseline inventory, and packages.config for legacy projects.
Expected records
Use Bumblebee's existing package record shape:
ecosystem: nuget.
- Note: OSV uses
NuGet as the ecosystem spelling; lowercase nuget matches Bumblebee's current local style (npm, pypi, rubygems, etc.).
package_name: NuGet package id, preserving observed casing.
normalized_name: lowercase package id, because NuGet package ids are case-insensitive.
version: resolved version string.
install_scope: direct / transitive where known from packages.lock.json.
source_type: for example nuget-assets, nuget-lockfile, nuget-packages-config, nuget-cache.
Current code touchpoints
Based on the current main branch:
internal/model/model.go: add EcosystemNuGet = "nuget" and register it in supportedEcosystems / supportedEcosystemOrder.
internal/scanner/scanner.go: add NuGet scanner dispatch for project.assets.json, packages.lock.json, packages.config, and guarded .nuspec files.
cmd/bumblebee/roots.go: add filepath.Join(home, ".nuget", "packages") to baselineHomeCandidates() with model.RootKindUserPackage.
internal/walk/walk.go: no walker exclude change appears necessary; obj/ and .nuget are not currently excluded.
A .nuspec path-shape guard similar to rubygems.IsInstalledGemspec would avoid treating arbitrary vendored .nuspec files as installed global-cache packages. The expected cache shape is <global-packages-root>/<package-id-lowercase>/<version>/<package-id>.nuspec.
References
Summary
docs/inventory-sources.mdcurrently lists NuGet (packages.lock.json) under "Not currently covered". This issue requests read-only NuGet package inventory support so .NET developer endpoints can be included in the same supply-chain exposure checks as npm, PyPI, Go, RubyGems, and Composer.Motivation
NuGet is the primary package manager for .NET. Without NuGet coverage, Bumblebee cannot answer whether a .NET-heavy developer machine has exposure to a known compromised or vulnerable package version.
Proposed sources
Bumblebee should not execute
dotnet,nuget, MSBuild, or any package-manager command. It can get useful coverage by reading existing metadata files:project.assets.jsonunderobj/PackageName/1.0.0. Skiplibrariesentries wheretype != "package".packages.lock.jsonRestorePackagesWithLockFile. Dependencies are grouped per TFM/RID and include packagetypeand resolved version. Treat NuGet packageDirect/Transitiveentries as direct/transitive; skip project-reference entries.packages.config<package id="..." version="..." />.~/.nuget/packages/<id>/<version>/<id>.nuspecbaselineprofile. Parse<id>and<version>from<metadata>.Suggested priority:
project.assets.jsonfor project-profile coverage,packages.lock.jsonwhen available for lock-file confidence,.nuspeccache entries for baseline inventory, andpackages.configfor legacy projects.Expected records
Use Bumblebee's existing package record shape:
ecosystem:nuget.NuGetas the ecosystem spelling; lowercasenugetmatches Bumblebee's current local style (npm,pypi,rubygems, etc.).package_name: NuGet package id, preserving observed casing.normalized_name: lowercase package id, because NuGet package ids are case-insensitive.version: resolved version string.install_scope:direct/transitivewhere known frompackages.lock.json.source_type: for examplenuget-assets,nuget-lockfile,nuget-packages-config,nuget-cache.Current code touchpoints
Based on the current
mainbranch:internal/model/model.go: addEcosystemNuGet = "nuget"and register it insupportedEcosystems/supportedEcosystemOrder.internal/scanner/scanner.go: add NuGet scanner dispatch forproject.assets.json,packages.lock.json,packages.config, and guarded.nuspecfiles.cmd/bumblebee/roots.go: addfilepath.Join(home, ".nuget", "packages")tobaselineHomeCandidates()withmodel.RootKindUserPackage.internal/walk/walk.go: no walker exclude change appears necessary;obj/and.nugetare not currently excluded.A
.nuspecpath-shape guard similar torubygems.IsInstalledGemspecwould avoid treating arbitrary vendored.nuspecfiles as installed global-cache packages. The expected cache shape is<global-packages-root>/<package-id-lowercase>/<version>/<package-id>.nuspec.References
packages.lock.jsonproject.assets.json.nuspecreference