You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Since #446, scan -g --mode agent then rollback -g from a vendored NuGet project reverts the project's patched package in the shared global packages folder; the locked restore stays "up-to-date" and VEX keeps attesting #489
[agent] Found by the scheduled NuGet / dotnet bug-hunt routine (ledger #320).
Summary
#446 (551c362, "Keep -g runs off the project's hosted/vendored state") made global runs ignore the project's vendor ledger: scan -g --mode agent / apply -g now patch "the global copy of a purl the project vendors", and rollback -g rolls that copy back. That works for npm, where the global copy is separate from node_modules. For NuGet it isn't separate. A PackageReference project restores into the global packages folder (~/.nuget/packages, or NUGET_PACKAGES), so the "global copy" is the vendored project's own installed copy.
From a vendored NuGet project on main:
scan -g --mode agent --yes finds Newtonsoft.Json@13.0.3 in the global packages folder. Those bytes are already patched, because the project's locked restore extracted them from the vendored nupkg. The scan reports applied: 1 and writes an agent record to the project's .socket/manifest.json. Before Fix -g touching the cwd project's state (#436, #445) #446 it was skipped as vendored_ownership_retained.
rollback -g --yes then restores the upstream bytes into ~/.nuget/packages/newtonsoft.json/13.0.3/ (rolledBack: 1, exit 0). It leaves the vendored wiring and ledger alone, which is what Fix -g touching the cwd project's state (#436, #445) #446 intended.
The project's dotnet restore --locked-mode says "All projects are up-to-date for restore". The lock still pins the vendored nupkg's contentHash, the .nupkg.sha512 sidecar still matches, and NuGet never re-extracts. So the project builds unpatched, with exit 0 everywhere.
vex --product pkg:nuget/app@1.0.0 still emits not_affected "Patched via Socket patch … (vendored)". It warns that the live tree differs and says to "re-run your package manager's install to resync it", but the restore in step 3 is exactly that, and it doesn't resync.
Impact
A vendored NuGet project gets silently unpatched by a global agent run plus its rollback, both started from the repo root. That's a normal way to manage machine-wide patches, and with a project-level .socket/ present it's the documented place to run it. CI and dev boxes share one global packages folder. Nothing fails and VEX keeps attesting.
Repro (Linux, dotnet SDK 8.0.131, main 9d718cf)
I used a scratch copy of crates/socket-patch-cli/tests/e2e_nuget_dotnet_build.rs, keeping its wiremock Backend stand-in and the real nuget.org fixture restore:
fixture: app.csproj (net8.0, RestorePackagesWithLockFile, Newtonsoft.Json 13.0.3) + nuget.org-only nuget.config
socket-patch scan --mode vendored --vendor-source service --yes --api-url <backend> ... # exit 0, lock re-pinned, feed wired
NUGET_PACKAGES=<store> dotnet restore --locked-mode # store/newtonsoft.json/13.0.3/LICENSE.md = PATCHED
NUGET_PACKAGES=<store> socket-patch scan -g --mode agent --json --yes --api-url <backend> ...
# "applied": 1 (main) | "skipped": 1, vendored_ownership_retained (c7af4df, the parent of #446)
# main also writes .socket/manifest.json with an agent record for pkg:nuget/Newtonsoft.Json@13.0.3
# (stage the before-blob in .socket/blobs, or run rollback online against a server that serves it)
NUGET_PACKAGES=<store> socket-patch rollback -g --json --yes --offline
# main: "rolledBack": 1, exit 0 -> store LICENSE.md = PRISTINE; vendored wiring + ledger untouched
NUGET_PACKAGES=<store> dotnet restore --locked-mode # exit 0, "All projects are up-to-date", store stays PRISTINE
socket-patch vex --offline --product pkg:nuget/app@1.0.0 -o v.json
# 1 statement, not_affected, "Patched via Socket patch 4f4f… (vendored)" + resync warning
Reproduced 3 times on 9d718cf. The vex result was checked before the rollback (attested, bytes patched) and after it (still attested, bytes pristine).
Expected vs actual
Expected: the Fix -g touching the cwd project's state (#436, #445) #446 commit message and the README say a global run leaves "the project's state alone". For NuGet the global packages folder copy is the project's install of a vendored package. The pre-Fix -g touching the cwd project's state (#436, #445) #446 skip (vendored_ownership_retained) protected it, and so should -g, or at least the copy whose bytes match the vendored artifact. An agent apply -g that finds bytes already at afterHash also shouldn't report applied and take ownership of the record. CLI_CONTRACT.md / README VEX: VEX attests only patches that are actually applied to the product.
Actual: -g takes over and later reverts the project's installed copy. The restore can't notice, because only the extracted files changed, not the nupkg or its sha512. VEX keeps attesting.
agent leg skipped (vendored_ownership_retained). rollback -g instead unwound the vendored wiring (#445), so the locked restore failed loudly with NU1403
The layout is the same on macOS and Windows (~/.nuget/packages, %USERPROFILE%\.nuget\packages), but I haven't run it there yet.
First bad commit
551c362 (#446). Before it, the same sequence was loud: #445's wiring unwind led to NU1403. Now it's silent.
Suspect code
crates/socket-patch-cli/src/commands/scan/mod.rs:1652-1658 (vendor_owned_purls is emptied under -g)
crates/socket-patch-cli/src/commands/apply.rs:1720 (same rule for apply -g)
crates/socket-patch-cli/src/commands/mod.rs:44 (project_state_in_scope treats "global" and "project" installs as disjoint, which doesn't hold for NuGet's global packages folder)
Related, but a different trigger: #352 (a warm folder shadowing a vendored patch) and #450 (cross-scope rollback).
[agent] Found by the scheduled NuGet / dotnet bug-hunt routine (ledger #320).
Summary
#446 (
551c362, "Keep -g runs off the project's hosted/vendored state") made global runs ignore the project's vendor ledger:scan -g --mode agent/apply -gnow patch "the global copy of a purl the project vendors", androllback -grolls that copy back. That works for npm, where the global copy is separate fromnode_modules. For NuGet it isn't separate. A PackageReference project restores into the global packages folder (~/.nuget/packages, orNUGET_PACKAGES), so the "global copy" is the vendored project's own installed copy.From a vendored NuGet project on main:
scan -g --mode agent --yesfindsNewtonsoft.Json@13.0.3in the global packages folder. Those bytes are already patched, because the project's locked restore extracted them from the vendored nupkg. The scan reportsapplied: 1and writes an agent record to the project's.socket/manifest.json. Before Fix -g touching the cwd project's state (#436, #445) #446 it was skipped asvendored_ownership_retained.rollback -g --yesthen restores the upstream bytes into~/.nuget/packages/newtonsoft.json/13.0.3/(rolledBack: 1, exit 0). It leaves the vendored wiring and ledger alone, which is what Fix -g touching the cwd project's state (#436, #445) #446 intended.dotnet restore --locked-modesays "All projects are up-to-date for restore". The lock still pins the vendored nupkg's contentHash, the.nupkg.sha512sidecar still matches, and NuGet never re-extracts. So the project builds unpatched, with exit 0 everywhere.vex --product pkg:nuget/app@1.0.0still emitsnot_affected"Patched via Socket patch … (vendored)". It warns that the live tree differs and says to "re-run your package manager's install to resync it", but the restore in step 3 is exactly that, and it doesn't resync.Impact
A vendored NuGet project gets silently unpatched by a global agent run plus its rollback, both started from the repo root. That's a normal way to manage machine-wide patches, and with a project-level
.socket/present it's the documented place to run it. CI and dev boxes share one global packages folder. Nothing fails and VEX keeps attesting.Repro (Linux, dotnet SDK 8.0.131, main
9d718cf)I used a scratch copy of
crates/socket-patch-cli/tests/e2e_nuget_dotnet_build.rs, keeping its wiremockBackendstand-in and the real nuget.org fixture restore:Reproduced 3 times on
9d718cf. Thevexresult was checked before the rollback (attested, bytes patched) and after it (still attested, bytes pristine).Expected vs actual
vendored_ownership_retained) protected it, and so should-g, or at least the copy whose bytes match the vendored artifact. An agentapply -gthat finds bytes already atafterHashalso shouldn't reportappliedand take ownership of the record. CLI_CONTRACT.md / README VEX: VEX attests only patches that are actually applied to the product.-gtakes over and later reverts the project's installed copy. The restore can't notice, because only the extracted files changed, not the nupkg or its sha512. VEX keeps attesting.OS × version
9d718cfc7af4df(before #446)vendored_ownership_retained).rollback -ginstead unwound the vendored wiring (#445), so the locked restore failed loudly with NU1403The layout is the same on macOS and Windows (
~/.nuget/packages,%USERPROFILE%\.nuget\packages), but I haven't run it there yet.First bad commit
551c362(#446). Before it, the same sequence was loud: #445's wiring unwind led to NU1403. Now it's silent.Suspect code
crates/socket-patch-cli/src/commands/scan/mod.rs:1652-1658(vendor_owned_purlsis emptied under-g)crates/socket-patch-cli/src/commands/apply.rs:1720(same rule forapply -g)crates/socket-patch-cli/src/commands/rollback.rs:1121crates/socket-patch-cli/src/commands/mod.rs:44(project_state_in_scopetreats "global" and "project" installs as disjoint, which doesn't hold for NuGet's global packages folder)Related, but a different trigger: #352 (a warm folder shadowing a vendored patch) and #450 (cross-scope rollback).