Repository navigation
Gem VEX judges an unused system gem-home copy when the project sets a Bundler path, so standalone vex never attests #1098
Description
Activity
- addedbugSomething isn't workingSomething isn't workingpm:bundlerBundler (RubyGems)Bundler (RubyGems)arch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)Filed by a scheduled architecture audit routine (see the architecture review discussion)
on Oct 8, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Re-checked on main @
f3c6313(architecture audit, ecosystems and formats). This still holds, and the two answers are unchanged:get_gem_pathsstill appends everygem envhome whenever the default root has no store and a Bundler manifest exists (ruby_crawler.rs#L135-L141),`` whateverbundler_sets_explicit_pathsays.bundler_install_homes(#L644) is still used only by the hosted stale guard (scan/hosted.rs#L368).
The comment above the fallback gives a reason to keep the system homes: default gems (
rexml,json) ship only there. So the fix should keep the default-gem homes and drop only the non-defaultgem envhomes under an explicitpath, rather than reusebundler_install_homeswholesale.
Generated by Claude Code
- addedv5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.Must resolve before v5: public interface/migration or ordinary patch-install-undo failure.and removed
on Oct 9, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actionsv5 release blocker (P1). VEX must inspect the Bundler home actually used by an ordinary project with an explicit install path, not reject it because of unrelated system gems.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue (with #1109; shared root cause: the gem crawler has no single model of whether Bundler uses system gems, so
deployment/.bundle-default projects and standalonevexstill judge unusedgem envhomes). Branch: agent/fix-gem-bundler-system-homes. Claim-ID: 2026-10-09T15:21:58Z-105ae7
Generated by Claude Code
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions
[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: register comment.
Kind: bug (inconsistent logic within one ecosystem). Source: new finding; register E90.
Problem
The question "which gem homes does Bundler load this project's gems from" now has two answers on main @
e61a845:RubyCrawler::get_gem_paths(ruby_crawler.rs#L43-L58).It appends every `gem env` home whenever the default `vendor/bundle` holds no store ([`#L136-L143`](https://github.com/SocketDev/socket-patch/blob/e61a8458651f78a8d42e4aad437e66a9f9894f6b/crates/socket-patch-core/src/crawlers/ruby_crawler.rs#L136-L143)).`` It does this even when the project sets an explicit Bundlerpath, where Bundler disables shared gems. This list feeds scan discovery, agentapply, andvex's installed-copy lookup (ecosystem_dispatch.rs#L618-L660).``RubyCrawler::bundler_install_homes(#L645-L690).`` It was added by Fix gem stale-install guard home selection (#1001, #729) #1002 for Hosted gem stale-install guard flags an unused system gem-home copy when the project sets a Bundlerpaththat isn't installed yet, soscan --mode hosted --vexfails withno_applicable_patcheson fresh checkouts #1001 and counts thegem envhomes only when Bundler uses system gems: no deployment store, and no explicit `path` according to `bundler_sets_explicit_path`. Only the hosted stale-install guard uses it (`scan/hosted.rs#L379`).For a hosted gem purl,
vexrequires every copy in list 1 to verify (vex_consumed.rs#L28,vex.rs#L624-L630). #1002 fixed the #1001 symptom forscan --mode hosted --vex, but the standalonevexcommand still has it.Proved by execution. I ran a throwaway test twice on
e61a845. It reuses the harness ofe2e_redirect_gem_stale_install.rs:stage_system_home_copyprovides a fakegem env gemdirhome holding the unpatchedstale-probe-gem-1.0.0, plus the mock API. The steps were:.bundle/configsetsBUNDLE_PATH;scan --mode hosted --vexexits 0, with no stale warning, as Hosted gem stale-install guard flags an unused system gem-home copy when the project sets a Bundlerpaththat isn't installed yet, soscan --mode hosted --vexfails withno_applicable_patcheson fresh checkouts #1001 intends;GEMsection);vexruns with the samePATH.vexBUNDLE_PATH: vendor/bundle(nothing installed yet)not_applied("the patched files still hold the original content"),no_applicable_patchesBUNDLE_PATH: gems, with the patched copy ingems/ruby/3.3.0/gems/not_appliedverified,not_affectedIn both failing cases, Bundler never loads the system-home copy (the premise of #1001 and #1002). The project is patched, or about to be, yet
vexrefuses it on every run. On the fresh checkout, the unused copy also prevents the hosted lockfile basis from applying, because the copy counts as "installed".The agent
applypath reads the same list 1. In an explicit-path project, it therefore also writes to (androllbackrestores) a same-version copy in the shared gem home, which Bundler doesn't load for that project. I found this by reading the code; I didn't execute it.Symptoms
paththat isn't installed yet, soscan --mode hosted --vexfails withno_applicable_patcheson fresh checkouts #1001 / Fix gem stale-install guard home selection (#1001, #729) #1002: the same defect in the stale guard, fixed there only.gem "x", "~> 1.0"to the older patched"0.8.1", so the prescribedbundle installdowngrades the project's locked gem #1055: also shared-gem-home state leaking into a project's answer (version selection; different path).Impact: fail-closed (no false attestation), but a false negative. Any developer or CI machine whose system gem home holds an old copy of a patched gem never gets
vexoutput for that gem, in projects that setpath(common in CI caches,bundle config set --local path vendor/bundle). Size: one model function plus three call sites.Proposed change
bundler_install_homes(or oneBundlerHomes { loaded, default_gem_homes }value built once) the single answer to "which homes does Bundler load for this project".vexinstalled lookup (find_manifest_package_copies_reusingandhosted_consumed_copies) judge only those homes.get_gem_pathswith only its documented default-gem reason for keeping thegem envhomes under an explicit path. Either restrict those homes to gems whose spec is underspecifications/default/, or keep them for apply only. The PR decides which and documents it in CLI_CONTRACT's gem section.bundler_install_homesre-reads the app, env and global tiers thatdiscover_bundle_stores_implhas already resolved.BundleStoreDiscoveryshould carryexplicit_pathso the rule lives in one place.Size and scope
crawlers/ruby_crawler.rs,ecosystem_dispatch.rs(the gem branch) andcommands/vex_consumed.rs(the gem row), plus tests.applywrite targets beyond the default-gem rule, and Hosted gem scan pins a version that only another project installed into the shared gem home, rewritinggem "x", "~> 1.0"to the older patched"0.8.1", so the prescribedbundle installdowngrades the project's locked gem #1055's version selection.Acceptance criteria
vexattests the gem in both failing rows above, and in eachBUNDLE_PATHspelling (env,.bundle/config, global config). Add a regression e2e test besidegem_hosted_explicit_bundle_path_ignores_system_home_copy.path(system gems), an unpatchedgem envcopy still blocks attestation (not_applied), and so doespath.system: trueoutranking envBUNDLE_PATH. This mirrorsgem_hosted_system_install_still_flags_system_home_copy.not_affectedfor an unpatched install when.bundle/configsets an out-of-treepath(absolute or~/…), because the skipped bundle root counts as "nothing installed" #709's out-of-tree config root is still read for verification.vextake the home list from the same function: a unit test asserts that they agree on each tier combination.e2e_redirect_gem_stale_install, the ruby crawler unit tests and the gem VEX discovery tests stay green.Dependencies
BUNDLE_GEMFILE=gemfiles/x.gemfilemovesBundler.root, so a relative bundle path resolves to the wrong dir,applypatches the system copy andvexattestsnot_affectedwhile Bundler loads the unpatchedgemfiles/vendor/bundlecopy #952 (BUNDLE_GEMFILEandBundler.root) and PR Fix hosted gem pinning a version the lock doesn't resolve (#1055) #1060 (Hosted gem scan pins a version that only another project installed into the shared gem home, rewritinggem "x", "~> 1.0"to the older patched"0.8.1", so the prescribedbundle installdowngrades the project's locked gem #1055). Rebase on whichever lands first.Backlog review — 2026-10-08
Priority: P1 → P2. An unused system gem copy makes VEX reject a correctly patched Bundler path; false negative.