Repository navigation
Scope project-mode NuGet crawls to the restore's resolved packages (#427) - #1183
Conversation
Assisted-by: Claude Code:claude-opus-5-5
A project-mode scan of a restored .NET project listed every package in ~/.nuget/packages, so agent mode patched, and VEX attested, packages other projects left in the shared cache (#427). When the working directory is a project (.csproj/.fsproj/.vbproj) whose obj/project.assets.json parses, the shared roots (the global packages folder and packageFolders) are now looked up for the restore's resolved libraries instead of walked. Solution roots, unrestored projects, global mode and the project-local packages/ folder keep the walk. Each assets file is parsed once for both its package folders and its libraries. A 3,000-package cache crawl drops from 58 ms to 0.8 ms. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
The scope only read the root project's restore and the one-level-deep ones, so a sub-project deeper down (or one whose assets file has no libraries) lost its packages from the crawl without a warning. The scope now walks the source tree (skipping hidden, symlinked, bin, obj, packages and node_modules dirs, up to 10,000 directories) and unions the libraries of every project directory's restore. Any project without a parsed restore, an unreadable directory or an exhausted budget keeps the whole-cache walk, as on main. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 038042f. Configure here.
|
[agent]
Likely root cause (Windows only). On non-Unix, Proposed fix (outside this PR's scope). On non-Unix, record every read as racy, so I'm re-running the failed job once to confirm. Generated by Claude Code |
|
[agent] The one re-run of This one isn't this PR's either: that test checks wall-clock time for apply-lock acquisition, which this PR doesn't touch, and it passes on Proposed fix (outside this PR's scope). Assert that the acquire never entered the backoff sleep, through a counter or failpoint, instead of comparing elapsed time against a bound. A 116 ms stall on a shared Windows runner doesn't show a sleep. The proposed fix for I've used this PR's one re-run, so I'm leaving CI as is. The PR stays watched. A maintainer can re-run the job, or it will re-run with the next push. Generated by Claude Code |
|
[final reviewer] I merged main into the branch (now Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #427
Summary
A project-mode scan of a restored .NET project used to list every package in the shared NuGet packages folder (
~/.nuget/packages,NUGET_PACKAGES, everypackageFolderskey). Agent mode then patched packages that other projects had left there, and VEX attested them. This PR turns the crawler into a locator for restored projects. Whencwdholds a.csproj/.fsproj/.vbproj, and every project undercwdat any depth has a parsedobj/project.assets.jsonwithlibraries, the shared roots are no longer walked. They are looked up only for the union of those resolvedlibraries(type: "package").Why (leverage)
~/.m2) #265) and Deno children.project.assets.jsonparser (parse_project_assets) serves bothpackageFoldersandlibraries.What changed (
crawlers/nuget_crawler.rsonly)package_rootsbuilds the root list, plus an optional scope.get_nuget_package_paths(same output as before) andcrawl_allboth use it.is_dotnet_projectbecamedotnet_root, which returnsNone,Marker(solution,packages.configor NuGet config) orProject. OnlyProjectroots are scoped.parse_project_assetsparses one assets file intopackageFoldersandlibraries. It replacesparse_project_assets_package_folders.restore_scopewalks the source tree and unions every project directory'slibraries. It returnsNoneif any project is uncovered.locate_librariesprobes<root>/<id lowercased>/<version lowercased>/with the sameverify_nuget_packageandpath_safety::is_safe_name_versionguards asfind_by_purls. It emits the same rows the walk produced for those directories.Deleted
Behavior
cwd, and every project file under it has a parsed assets file withlibraries. The resolved packages come out with the samename,version,purlandpathas before, but inlibrariesorder instead of readdir order.--global/--global-prefix;libraries;packages/folder, which is still walked in full;get_nuget_package_pathsandfind_by_purls.packages.lock.jsonfallback, and thecrawl_unscoped_cachewarning. The warning needsCLI_CONTRACT.md, which open PRs change.Test evidence
New unit tests in
nuget_crawler.rs:restored_project_crawls_only_its_resolved_packageslocated_rows_equal_the_walks_rows_for_resolved_packagessub_project_restores_join_the_scope(a restored sub-project two levels down)an_uncovered_sub_project_keeps_the_walk(review fix: an unrestored sub-project two levels down, and an assets file withoutlibraries)project_local_packages_folder_is_still_walkedsolution_roots_and_unrestored_projects_keep_the_walkglobal_prefix_crawl_is_not_scopedRed → green:
main, the Project-mode NuGet agent scan patches, and VEX attests, packages the project doesn't depend on (the crawler lists the whole ~/.nuget/packages) #427 tests fail. For example, the Project-mode NuGet agent scan patches, and VEX attests, packages the project doesn't depend on (the crawler lists the whole ~/.nuget/packages) #427 test gets[newtonsoft.json@12.0.1, newtonsoft.json@13.0.3, serilog@3.1.1]where it expects[newtonsoft.json@13.0.3].an_uncovered_sub_project_keeps_the_walkfails ona05d7fc, the head before the review fix.038042f.cargo clippy --workspace --all-features -- -D warningsis clean.cargo test -p socket-patch-core --lib: 5805 passed ona05d7fc. Its only 4 failures are the known root-only sandbox ones, which also fail onmain:copy_tree::relax_loop_must_not_traverse_symlinked_rootvlt_heal::an_unremovable_hidden_lock_keeps_every_store_entrypypi_poetry::wire_write_failure_maps_error_and_leaves_lock_untouchedpypi_requirements::wire_failure_rolls_back_already_written_filesOn
038042fI re-ran only the 40crawlers::nugettests, and they pass.crawler_nuget_e2e: 28 passed. CLIe2e_nuget: 21 passed. The NuGet crawler oracle equivalence suite also passes: its trees have nolibraries, so they keep the walk.Timing (release build; I used a throwaway bench and removed it before committing). The fixture is a 3,000-package shared folder and a project that resolves 20 of them:
main: 58.5 ms per crawl, 3,000 packages;No
dotnetin the sandbox, so I didn't run a real restore. The fixtures follow the assets format:librarieskeyed"<Id>/<Version>", withtype: package|project.Risk
Medium.
bin,obj,packagesandnode_modulesdirs, and gives up after 10,000 directories.BaseIntermediateOutputPath, makes the crawl fall back to the whole-cache walk. So a package is dropped only when no project's restore resolves it.cwdthat is referenced by path is covered too, because its packages appear in the referencing project'slibraries.npm/,pypi/,gem/) need no change.🤖 Generated with Claude Code
Generated by Claude Code