Repository navigation
Fix gem stale-install guard home selection (#1001, #729) - #1002
Conversation
Assisted-by: Claude Code:claude-opus-5-5
The hosted stale-install guard needs to know which gem homes `bundle install` installs into or reuses, and which of those belong to the project. The crawler's flat get_gem_paths list can't say: it keeps the `gem env` homes for apply's default-gem fallback even when the project sets its own Bundler `path`, and it gives relative dirs for the default `--cwd .`. Record in BundleStoreDiscovery whether an explicit install path is configured (app config, env BUNDLE_PATH or global config), and add RubyCrawler::bundler_install_homes. It returns the install stores, the refused out-of-tree config root, and the `gem env` homes only when Bundler uses system gems. Each home is tagged project-local by comparing absolute, normalized paths. Assisted-by: Claude Code:claude-opus-5-5
`scan --mode hosted` flagged an unpatched copy in the machine's gem home as stale even when the project sets a Bundler `path`. Bundler never reuses that copy, but the warning dropped the gem from the same run's VEX, so `scan --mode hosted --vex` failed with no_applicable_patches on every fresh checkout (#1001). With the default `--cwd .`, a stale copy in the project's own vendor/bundle was called a "shared gem home" with a remedy that does nothing, and the committed vendor/cache archive was left out of the delete list (#729). The guard now uses RubyCrawler::bundler_install_homes, so it judges only the homes Bundler uses and takes the project-local tag from the crawler instead of a lexical starts_with(cwd). Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
The stale-install guard skipped the machine's gem homes whenever any tier set a Bundler install path. But Bundler takes `path`, `path.system` and `disable_shared_gems` from the first tier (local, env, global) that sets any of them. So a local `path.system: true` puts Bundler back on system gems even when BUNDLE_PATH is set in the environment. In that setup a stale system copy wasn't warned about, and the same run's VEX could attest it. Decide this the way Bundler's Settings#path does, with bundler_sets_explicit_path, and drop the discovery flag that ignored tier order. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
Resolve ruby_crawler.rs by keeping the tests from both sides. Main's #916 added bundler_truthy, Bundler's to_bool coercion, so bundler_sets_explicit_path now reads path.system and disable_shared_gems through it ("1" and "yes" count as true, "no" and "0" as false), the same as #916's path.system tier check. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
The digest guard test is red on main: #955 added crawlers/gradle_cache.rs, patch/jvm_jar.rs and patch/sidecars/maven.rs to the pending list, and #690 had already moved them onto the utils::digest helpers. This ports the same three-line change as #1016, so it becomes a no-op once #1016 lands. Assisted-by: Claude Code:claude-opus-5-5
|
[agent] Generated by Claude Code |
|
BugBot review Generated by Claude Code |
|
[agent] Blocked: waiting on CI to finish on d65c5c4 and on #1016 to merge.
Generated by Claude Code |
|
Ready for review (burn-down agent). Head Generated by Claude Code |
Head branch was modified
|
bugbot run Generated by Claude Code |
|
[agent] Blocked: waiting on CI for aa42c4a.
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 aa42c4a. Configure here.
|
[agent] Ready for review at
Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1001
Fixes #729
Summary
scan --mode hosted(andget --mode hosted) now judges stale gem installs only in the gem homesbundle installactually installs into or reuses, and it decides whether a home belongs to the project the same way however--cwdis spelled.paththat isn't installed yet, soscan --mode hosted --vexfails withno_applicable_patcheson fresh checkouts #1001: a project that sets a Bundler installpath(in.bundle/config, envBUNDLE_PATHor the global config) but hasn't installed into it yet no longer gets a falseredirect_gem_stale_installfor an unrelated copy in the machine'sgem envhome. That copy is no longer dropped from the same run's--vex, soscan --mode hosted --vexattests the patch (exit 0) instead of failing withno_applicable_patcheson fresh checkouts.vendor/bundlea "shared gem home" when--cwdis left at its default (or relative), so it gives the wrong remedy and drops the committed cache archive from the delete list #729: with the default--cwd ., a stale copy in the project's ownvendor/bundlegets the project-local delete-list remedy instead of the "shared gem home" caveat, and the committedvendor/cachearchive is folded into that warning's delete list.Root cause
The guard (
gem_stale_install_warningsincrates/socket-patch-cli/src/commands/scan/hosted.rs) answered two questions with lexical tests onRubyCrawler::get_gem_paths, a flat path list built for agentapply:get_gem_pathsappends thegem envhomes whenever the defaultvendor/bundlehas no store.applyneeds that for default gems. But with an explicitpath, Bundler'suse_system_gems?is false: it fetches non-default gems into the path and never reuses a system copy.dir.starts_with(cwd)against the raw--cwd. The crawler hands backvendor/bundle/...for the default., andPath::starts_with(".")doesn't match that.Fix
bundler_sets_explicit_pathfollows Bundler'sSettings#path. The first tier (app config, env, global config) that setspath,path.systemordisable_shared_gemsdecides alone, and its path is explicit only when it's non-empty,path.systemisn't true anddisable_shared_gemsisn't false. Both flags go through Bundler'sto_bool(bundler_truthy, from Fix gem crawl ignoring Bundler path.system (#915) #916). A higher tier'spath.system: truetherefore beats a lower tier's path (a Bugbot finding, fixed in 5ed25cd). An empty path counts as not explicit, so when it's unclear the system homes are still judged.RubyCrawler::bundler_install_homesreturns the install stores, the refused out-of-tree config root (Hosted gem VEX attestsnot_affectedfor an unpatched install when.bundle/configsets an out-of-treepath(absolute or~/…), because the skipped bundle root counts as "nothing installed" #709), and thegem envhomes only when Bundler uses system gems, i.e. no deployment store and no explicit path. Each home comes back tagged project-local bybundler_gem_homes_from, which compares absolute, lexically normalized paths, as the containment guard already does.get_gem_pathsandapplyare unchanged.No wrapper (
npm/,pypi/,gem/) changes are needed. This is Rust-side discovery logic.Tests (red → green)
e2e_redirect_gem_stale_install::gem_hosted_explicit_bundle_path_ignores_system_home_copy(local config and envBUNDLE_PATH; fakegemon PATH points at a home holding an unpatched copy)redirect_gem_stale_installfor the system copy,no_applicable_patchesgem_hosted_system_install_still_flags_system_home_copy(nopathset)ruby_crawler::tests::bundler_sets_explicit_path_follows_settings_tiers(14 tier and to_bool combinations)gem_hosted_system_install_still_flags_system_home_copy, arm with a localpath.system: trueover envBUNDLE_PATHgem_hosted_default_cwd_keeps_project_local_remedy(no--cwd, and--cwd ., with a committedvendor/cachearchive)ruby_crawler::tests::bundler_gem_homes_from_tags_project_local_by_absolute_pathCommands run locally
On d6a1466 (
mainmerged in, 33 commits including #916; d65c5c4 only adds the digest-list port, and the digest tests pass):cargo clippy --workspace --all-features -- -D warnings: clean.cargo test --workspace --all-features --lib: CLI 861/861. Core 5559 passed, 5 failed: the same root-only permission tests and thedigestguard listed below, none in files this PR touches.e2e_redirect_gem_stale_install: 35/35.e2e_redirect_gem_build --include-ignoredwith real Bundler 4.0.18: 31/31.e2e_gem --include-ignored(the live-API smoke suite): 3 tests fail only because this sandbox can't reachpatches-api.socket.dev(tunnel error). CI runs it with network.Earlier, the full suite on 9dd72b4 (CI was green on that head in every workflow):
cargo clippy --workspace --all-features -- -D warnings: clean.cargo fmt --all -- --check: every hunk this PR touches is clean.mainitself isn't rustfmt-clean with the pinned 1.93.1 toolchain (122 files differ), and CI doesn't run a fmt check, so I left the unrelated files alone.cargo test --workspace --all-features, run in batches of 10 test binaries because one full build exceeds this sandbox's disk:e2e_redirect_gem_stale_installtests pass, plus every other suite, except as noted below;socket-patch-core --lib: 5247 passed, 5 failed. 4 are permission-injection tests (copy_tree,vlt_heal,pypi_poetry,pypi_requirements) that can't fail a write when the sandbox runs as root. The 5th isutils::digest::tests::production_digests_go_through_the_helpers, the knownmainfailure that Route Gradle digests through utils::digest #878 fixes;covgap_commands_vendor(3),in_process_redirect(3) andrepair(2): all write- or remove-failure injection tests, also defeated by running as root. None of them touch gem code.SOCKET_PATCH_BUNDLER_E2E_REQUIRED=1 SOCKET_PATCH_BUNDLER_E2E_VERSION=4.0.18 cargo test -p socket-patch-cli --all-features --test e2e_redirect_gem_build -- --ignored(real Ruby 3.3.6 / Bundler 4.0.18): 16/16 pass.Notes
d65c5c4 ports Fix main CI red on stale digest pending-list entries #1016's three-line fix to the
utils::digestpending list. That guard is red onmain, and the change becomes a no-op once Fix main CI red on stale digest pending-list entries #1016 lands.Bugbot's second finding (that a falsy
disable_shared_gemshides the path) is a false positive. Bundler 2.5.22 and 4.0.18 both folddisable_shared_gems == falseintosystem_path, whichuse_system_gems?checks beforeexplicit_path. Evidence is in the review thread.Fix gem crawler missing Bundler .bundle root (#967) #968 (open) also changes
discover_bundle_stores_impl, so whichever of the two lands second will need a small merge. Fix gem crawl ignoring Bundler path.system (#915) #916 has since merged, and this branch now includes it (merge commit d6a1466).🤖 Generated with Claude Code
Note
Medium Risk
Changes hosted scan/VEX behavior for Ruby projects with Bundler path settings—fewer false stale warnings but different warning text and VEX inclusion when system gem copies are ignored.
Overview
Hosted-mode gem stale-install probing no longer walks every path from agent
apply'sget_gem_paths(which always includedgem envhomes). It now usesRubyCrawler::bundler_install_homes, which limits checks to stores Bundler actually installs into or reuses, and only adds machinegem envhomes when Bundler is on system gems (no explicit installpath/ deployment store), via newbundler_sets_explicit_pathtier logic aligned with Bundler'sSettings#path.Each home is tagged project-local vs shared with
bundler_gem_homes_from(absolute, normalized containment), so default--cwd .still treatsvendor/bundleas project-local and picks the delete-list remedy instead of the shared-home caveat.CLI_CONTRACT.mddocuments the rules; e2e and ruby_crawler unit tests cover explicitBUNDLE_PATH,path.systemprecedence, and default-cwd behavior.Reviewed by Cursor Bugbot for commit aa42c4a. Configure here.
Generated by Claude Code