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
{{ message }}
Repository navigation
Hosted gem stale-install guard flags an unused system gem-home copy when the project sets a Bundler path that isn't installed yet, so scan --mode hosted --vex fails with no_applicable_patches on fresh checkouts #1001
[agent] Found by the scheduled Bundler (RubyGems) bug-hunt routine (ledger #316).
Summary
Take a project that sets a Bundler install path (bundle config set --local path vendor/bundle, or env BUNDLE_PATH=vendor/bundle) but has nothing installed there yet. That's every fresh clone and every cold-cache CI run. If the same gem@version also sits in the machine's gem env home, scan --mode hosted flags that system copy as stale with redirect_gem_stale_install. That copy belongs to another project or to Ruby's bundled gems.
The warning says "bundle install reuses it without refetching". That's false. With an explicit path, Bundler ignores non-default gems in the system home and fetches the hosted patch into vendor/bundle. The warning's remedy ("prefer switching this project to a project-local bundle path (bundle config set --local path vendor/bundle)") tells the user to set what's already set. The stale flag also drops the purl from the same run's --vex set, so scan --mode hosted --vex … exits 1 with no_applicable_patches and writes no VEX, even though the next bundle install installs the patched bytes.
Impact
A false, alarming warning, with a remedy that is already in effect, on every fresh checkout or CI run of a path-configured project whenever the runner's system gem home has the same version. Ruby's bundled gems (rexml, net-imap, rake, …) are regular gems in the system home, so a patch for one of them hits this on stock images.
The in-run VEX fails closed (exit 1, no document), which breaks a scan --mode hosted --vex CI step.
The failure is noisy rather than silent, but it's a refusal that fires when it shouldn't.
Repro (Linux, Ruby 3.3.6, real bundle install)
The patch API and patch registry are mocked on loopback (the run-13 mock from ledger #316: a rebuilt colorize-0.8.1 with a marker line served from a compact index; the upstream is real rubygems.org).
gem install colorize -v 0.8.1 # a system copy exists (another project, or a bundled gem)
mkdir proj &&cd proj
printf'source "https://rubygems.org"\n\ngem "colorize", "~> 0.8.1"\n'> Gemfile
bundle _4.0.22_ config set --local path vendor/bundle
bundle _4.0.22_ install && bundle _4.0.22_ lock --add-checksums
rm -rf vendor # = a fresh clone / cold CI cache
socket-patch scan --mode hosted --json --yes --api-url $MOCK --org org --api-token fake \
--vex out.vex.json --vex-product pkg:gem/app@1.0.0
# exit 1, status "error", error.code "no_applicable_patches"# redirect.warnings[0]: redirect_gem_stale_install "… a stale UNPATCHED install is materialized in the shared gem home at# /opt/rbenv/versions/3.3.6/lib/ruby/gems/3.3.0/gems/colorize-0.8.1 — `bundle install` reuses it without refetching …# prefer switching this project to a project-local bundle path (`bundle config set --local path vendor/bundle`…"# Fresh checkout of the rewritten Gemfile + Gemfile.lock + .bundle/config:
BUNDLE_FROZEN=true bundle _4.0.22_ install # exit 0
bundle _4.0.22_ exec ruby -e 'p Gem.loaded_specs["colorize"].full_gem_path'# => …/vendor/bundle/ruby/3.3.0/gems/colorize-0.8.1 (patched marker present: the warning was wrong)
Bundler-side check, with no socket-patch involved: with path vendor/bundle set, bundle install of rexml 3.3.9 prints "Fetching rexml 3.3.9 / Installing" and loads vendor/bundle/ruby/3.3.0/gems/rexml-3.3.9, even though rexml-3.3.9 is already installed in the system gem home.
Expected vs actual
Expected: CLI_CONTRACT.md, "Gem stale-install guard": the guard exists because "a gem ALREADY materialized under the project's bundle paths keeps its upstream bytes — the next bundle install prints Using <gem> and never refetches". When the deciding Bundler tier sets an explicit path (config or env), the gem env homes aren't where bundle install takes non-default gems from. A copy there shouldn't be judged stale or pulled out of the in-run VEX. Default gems never have files under gems/<name>-<ver>, so skipping those homes loses nothing for the guard.
Actual: the guard reuses RubyCrawler::get_gem_paths. It appends the gem env homes whenever the default vendor/bundle root holds no store, which is right for agent apply's default-gem fallback, so the guard judges a copy Bundler will never use.
OS × version matrix
OS
Ruby
Bundler
Shape
Result
Linux
3.3.6
4.0.22
local path vendor/bundle, not installed, system copy present
fail (×3 on main)
Linux
3.3.6
2.6.9
same
fail
Linux
3.3.6
4.0.22
env BUNDLE_PATH=vendor/bundle, not installed
fail
Linux
3.3.6
4.0.22
gem pulled in transitively by a git: gem, same config
fail (same warning)
Linux
3.3.6
4.0.22
same config, no system copy (control)
pass (exit 0, VEX written, install patched)
Linux
3.3.6
4.0.22
no path (system install), system copy unpatched (control)
pass (a correct warning; Bundler really does reuse it)
Release: v4.0.0 also emits the warning (and exits 1), so this isn't a regression.
crates/socket-patch-core/src/crawlers/ruby_crawler.rs:132: if !discovery.default_root_has_stores && has_bundler_manifest appends gem_env_gems_dirs() even when the deciding tier set an explicit path. For the stale guard, those homes should only be probed when Bundler would actually use system gems (no explicit path, or a truthy path.system).
[agent] Found by the scheduled Bundler (RubyGems) bug-hunt routine (ledger #316).
Summary
Take a project that sets a Bundler install path (
bundle config set --local path vendor/bundle, or envBUNDLE_PATH=vendor/bundle) but has nothing installed there yet. That's every fresh clone and every cold-cache CI run. If the samegem@versionalso sits in the machine'sgem envhome,scan --mode hostedflags that system copy as stale withredirect_gem_stale_install. That copy belongs to another project or to Ruby's bundled gems.The warning says "
bundle installreuses it without refetching". That's false. With an explicitpath, Bundler ignores non-default gems in the system home and fetches the hosted patch intovendor/bundle. The warning's remedy ("prefer switching this project to a project-local bundle path (bundle config set --local path vendor/bundle)") tells the user to set what's already set. The stale flag also drops the purl from the same run's--vexset, soscan --mode hosted --vex …exits 1 withno_applicable_patchesand writes no VEX, even though the nextbundle installinstalls the patched bytes.Impact
path-configured project whenever the runner's system gem home has the same version. Ruby's bundled gems (rexml,net-imap,rake, …) are regular gems in the system home, so a patch for one of them hits this on stock images.scan --mode hosted --vexCI step.Repro (Linux, Ruby 3.3.6, real
bundle install)The patch API and patch registry are mocked on loopback (the run-13 mock from ledger #316: a rebuilt
colorize-0.8.1with a marker line served from a compact index; the upstream is real rubygems.org).Bundler-side check, with no socket-patch involved: with
path vendor/bundleset,bundle installofrexml 3.3.9prints "Fetching rexml 3.3.9 / Installing" and loadsvendor/bundle/ruby/3.3.0/gems/rexml-3.3.9, even thoughrexml-3.3.9is already installed in the system gem home.Expected vs actual
bundle installprintsUsing <gem>and never refetches". When the deciding Bundler tier sets an explicitpath(config or env), thegem envhomes aren't wherebundle installtakes non-default gems from. A copy there shouldn't be judged stale or pulled out of the in-run VEX. Default gems never have files undergems/<name>-<ver>, so skipping those homes loses nothing for the guard.RubyCrawler::get_gem_paths. It appends thegem envhomes whenever the defaultvendor/bundleroot holds no store, which is right for agentapply's default-gem fallback, so the guard judges a copy Bundler will never use.OS × version matrix
path vendor/bundle, not installed, system copy presentBUNDLE_PATH=vendor/bundle, not installedgit:gem, same configpath(system install), system copy unpatched (control)25e3ca6) doesn't change it; it keeps thegem envfallback on for explicit roots.Suspect code
crates/socket-patch-cli/src/commands/scan/hosted.rs:371:gem_stale_install_warningstakescrawler.get_gem_paths(&options)verbatim.crates/socket-patch-core/src/crawlers/ruby_crawler.rs:132:if !discovery.default_root_has_stores && has_bundler_manifestappendsgem_env_gems_dirs()even when the deciding tier set an explicitpath. For the stale guard, those homes should only be probed when Bundler would actually use system gems (no explicitpath, or a truthypath.system).Tested on main
9c43dfc.