[agent] Found by the scheduled NuGet / dotnet bug-hunt routine (ledger #320).
Summary
dotnet tool install -g <id> is the .NET way to install a package globally. The SDK restores the tool package into its own packages folder, ~/.dotnet/tools/.store/<id>/<ver>/ (%USERPROFILE%\.dotnet\tools\.store\... on Windows), as <id>/<ver>/<id>.nuspec + tools/<tfm>/any/*.dll. It does not go into ~/.nuget/packages.
socket-patch scan -g only crawls NUGET_PACKAGES / ~/.nuget/packages. So a globally installed .NET tool is never sent to the patch API, never listed, and can't be patched or attested:
scan -g (report-only): the tool's purl is missing from the batch request and the table. Exit 0, no warning.
apply -g with a manifest entry for the tool: 0 of 1 targeted patch applied, ... 1 not found on disk, exit 1. At least this one is loud.
vex -g: omitting pkg:nuget/[email protected] from VEX: the package is not installed (package_not_found).
--global-prefix ~/.dotnet/tools/.store doesn't help either: 0 packages, because each tool is its own nested packages folder (.store/<id>/<ver>/<id>/<ver>/). Only --global-prefix ~/.dotnet/tools/.store/<id>/<ver> (one tool at a time) finds it, and then apply and rollback work.
This is the .NET sibling of #415 (pipx venvs never crawled by scan -g).
Impact
On any machine or CI image with .NET global tools (dotnet-ef, dotnet-format, dotnet-outdated-tool, GitVersion.Tool, Cake.Tool, …), scan -g reports a clean result and never surfaces their patches. The user gets no signal that this location wasn't checked.
Repro (Linux, dotnet SDK 8.0.131, main 2463257)
SP=/path/to/target/release/socket-patch
export SOCKET_NO_CONFIG=1 SOCKET_TELEMETRY_DISABLED=1
dotnet tool install -g dotnetsay --version 3.0.3
ls ~/.dotnet/tools/.store/dotnetsay/3.0.3/dotnetsay/3.0.3/dotnetsay.nuspec # present
ls ~/.nuget/packages/dotnetsay 2>&1 # absent
# run a local stand-in for the public proxy that answers POST /patch/batch with a patch
# for every pkg:nuget purl it receives and logs the request body, then:
$SP scan -g -e nuget --json --proxy-url http://127.0.0.1:8765
# -> the batch body has only the ~/.nuget/packages purls; pkg:nuget/[email protected] is never sent
$SP scan --global-prefix ~/.dotnet/tools/.store -e nuget --json --proxy-url ... # scannedPackages: 0
$SP scan --global-prefix ~/.dotnet/tools/.store/dotnetsay/3.0.3 -e nuget --json --proxy-url ... # finds [email protected]
# with a hand-staged .socket/manifest.json entry for pkg:nuget/[email protected] (README.md):
$SP apply -g --offline # "1 not found on disk", exit 1
$SP vex -g --offline --product pkg:nuget/[email protected] # package_not_found, exit 1
Expected vs actual
- Expected:
scan -g covers every location where NuGet / dotnet installs packages globally. CLI_CONTRACT.md documents --global as "Operate on globally-installed packages", and the report-only --global scan as discovery of the machine tree. For .NET that includes the global tool store. If it's deliberately out of scope, the docs should say so, and scan -g should say it skipped the tool store.
- Actual: only
~/.nuget/packages is crawled (get_nuget_package_paths, crates/socket-patch-core/src/crawlers/nuget_crawler.rs:41-50, nuget_home() at :392). Nothing in README.md, docs/ecosystems.md or CLI_CONTRACT.md mentions .dotnet/tools.
OS × SDK matrix
Probe run: https://github.com/SocketDev/socket-patch/actions/runs/36820498426 (8/8 jobs; real dotnet tool install -g, real dotnet restore).
| OS |
SDK |
tool |
scan -g lists the tool |
apply -g patches the tool |
| Linux (local) |
8.0.131 |
dotnetsay 3.0.3 |
no |
no (rc 1, not found) |
| ubuntu-latest |
6.0.x |
dotnetsay 2.1.7 |
no |
no (rc 1) |
| ubuntu-latest |
9.0.x |
dotnetsay 3.0.3 |
no |
no (rc 1) |
| ubuntu-latest |
10.0.x |
dotnetsay 3.0.3 |
no |
no (rc 1) |
| macos-latest |
8.0.x |
dotnetsay 3.0.3 |
no |
no (rc 1) |
| macos-latest |
9.0.x |
dotnetsay 3.0.3 |
no |
no (rc 1) |
| windows-latest |
8.0.x |
dotnetsay 3.0.3 |
no |
no (rc 1) |
| windows-latest |
9.0.x |
dotnetsay 3.0.3 |
no |
no (rc 1) |
| windows-latest |
10.0.x |
dotnetsay 3.0.3 |
no |
no (rc 1) |
First bad version
Not a regression: v4.0.0 (GitHub release binary) sends the same batch with no tool purl.
Suspect code
crates/socket-patch-core/src/crawlers/nuget_crawler.rs:41-50: the global branch returns [nuget_home()] only. A fix would also enumerate ~/.dotnet/tools/.store/*/*/ (and DOTNET_CLI_HOME if set) as additional packages folders. dotnet tool install --tool-path <dir> installs use <dir>/.store/... with the same layout.
[agent] Found by the scheduled NuGet / dotnet bug-hunt routine (ledger #320).
Summary
dotnet tool install -g <id>is the .NET way to install a package globally. The SDK restores the tool package into its own packages folder,~/.dotnet/tools/.store/<id>/<ver>/(%USERPROFILE%\.dotnet\tools\.store\...on Windows), as<id>/<ver>/<id>.nuspec+tools/<tfm>/any/*.dll. It does not go into~/.nuget/packages.socket-patch scan -gonly crawlsNUGET_PACKAGES/~/.nuget/packages. So a globally installed .NET tool is never sent to the patch API, never listed, and can't be patched or attested:scan -g(report-only): the tool's purl is missing from the batch request and the table. Exit 0, no warning.apply -gwith a manifest entry for the tool:0 of 1 targeted patch applied, ... 1 not found on disk, exit 1. At least this one is loud.vex -g:omitting pkg:nuget/[email protected] from VEX: the package is not installed (package_not_found).--global-prefix ~/.dotnet/tools/.storedoesn't help either: 0 packages, because each tool is its own nested packages folder (.store/<id>/<ver>/<id>/<ver>/). Only--global-prefix ~/.dotnet/tools/.store/<id>/<ver>(one tool at a time) finds it, and then apply and rollback work.This is the .NET sibling of #415 (pipx venvs never crawled by
scan -g).Impact
On any machine or CI image with .NET global tools (
dotnet-ef,dotnet-format,dotnet-outdated-tool,GitVersion.Tool,Cake.Tool, …),scan -greports a clean result and never surfaces their patches. The user gets no signal that this location wasn't checked.Repro (Linux, dotnet SDK 8.0.131, main
2463257)Expected vs actual
scan -gcovers every location where NuGet / dotnet installs packages globally. CLI_CONTRACT.md documents--globalas "Operate on globally-installed packages", and the report-only--globalscan as discovery of the machine tree. For .NET that includes the global tool store. If it's deliberately out of scope, the docs should say so, andscan -gshould say it skipped the tool store.~/.nuget/packagesis crawled (get_nuget_package_paths,crates/socket-patch-core/src/crawlers/nuget_crawler.rs:41-50,nuget_home()at:392). Nothing in README.md, docs/ecosystems.md or CLI_CONTRACT.md mentions.dotnet/tools.OS × SDK matrix
Probe run: https://github.com/SocketDev/socket-patch/actions/runs/36820498426 (8/8 jobs; real
dotnet tool install -g, realdotnet restore).scan -glists the toolapply -gpatches the toolFirst bad version
Not a regression: v4.0.0 (GitHub release binary) sends the same batch with no tool purl.
Suspect code
crates/socket-patch-core/src/crawlers/nuget_crawler.rs:41-50: the global branch returns[nuget_home()]only. A fix would also enumerate~/.dotnet/tools/.store/*/*/(andDOTNET_CLI_HOMEif set) as additional packages folders.dotnet tool install --tool-path <dir>installs use<dir>/.store/...with the same layout.