Fix Bundler settings resolution order (#483, #507) - #532
Open
Mikola Lysenko (mikolalysenko) wants to merge 3 commits into
Open
Mikola Lysenko (mikolalysenko) wants to merge 3 commits into
Mikola Lysenko (mikolalysenko) wants to merge 3 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
This was referenced Oct 2, 2026
When BUNDLE_GEMFILE was set both in .bundle/config and in the environment, socket-patch followed the environment. Bundler does the reverse: local app config outranks ENV. A dual-boot project with `gemfile Gemfile.next` committed and BUNDLE_GEMFILE=Gemfile exported got its Gemfile rewired and attested while bundler installed Gemfile.next unpatched. The app config value now wins, unless the environment names a manifest in another directory (that moves bundler's root, so the project's config is never read). Add one app-config reader shared by every Bundler key, and a resolver for bundler's cache dir (cache_path / BUNDLE_CACHE_PATH, default vendor/cache) in the same priority. Refs #507, #483 Assisted-by: Claude Code:claude-opus-5-5
The hosted gem stale-install guard only looked for committed archives in vendor/cache. With `bundle config set --local cache_path vendor/gems` (or BUNDLE_CACHE_PATH), a committed unpatched archive there gave no warning, the same run's VEX attested the gem, and bundle install then installed the unpatched bytes. Both guard flavors now use bundler's configured cache dir, so the stale archive warns, joins the delete-list remedy, and keeps the purl out of the in-run attestation. Fixes #483 Fixes #507 Assisted-by: Claude Code:claude-opus-5-5
Mikola Lysenko (mikolalysenko)
marked this pull request as ready for review
October 2, 2026 06:08
Collaborator
Author
|
BugBot review Generated by Claude Code |
Collaborator
Author
|
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 477aae9. Configure here.
Collaborator
Author
|
Ready for review at head
Generated by Claude Code |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
LLM Description written by Claude Code:claude-opus-5-5
Fixes #483
Fixes #507
Summary
Gem modes now read Bundler settings in Bundler's own priority, with the local app config over the environment.
BUNDLE_GEMFILEenv var override.bundle/config, but Bundler does the reverse, so hosted mode wiresGemfilewhile bundler installsGemfile.nextunpatched and VEX attests it #507: WhenBUNDLE_GEMFILEis set in both.bundle/configand the environment, the.bundle/configvalue now wins, as it does in Bundler. Before, a dual-boot project (bundle config set --local gemfile Gemfile.next) with an exportedBUNDLE_GEMFILE=Gemfilehad itsGemfilerewired and attested, while Bundler installedGemfile.nextunpatched. That project now getsredirect_gem_bundle_gemfile_unsupported, nothing is redirected, and nothing is attested. Vendored mode uses the same resolver (vendor/gem.rs→bundler_loaded_manifest), so it is fixed too.vendor/cache, so a committed cache at a configuredcache_pathgets no warning, the in-run VEX attests it, and Bundler 2.4 installs the unpatched gem #483: The hosted gem stale-install guard now looks for the committed archive in Bundler's configured cache dir (BUNDLE_CACHE_PATHin the app config, then the env var, elsevendor/cache) instead of alwaysvendor/cache. Both flavors use it: the standalone warning and the folded delete-list remedy. A stale archive there now warns and keeps the same run's VEX from attesting the purl.Root cause
socket-patch read Bundler settings one key at a time, with no resolver that follows
Bundler::Settingspriority (local app config$BUNDLE_APP_CONFIG/config/.bundle/configfirst, thenENV):gemfile:formats/gem/manifest.rs::classifychecked the environment before the app config, which is the reverse of Bundler's order. A unit test even pinned the inverted order.cache_path: never read.scan/hosted.rshard-coded<cwd>/vendor/cachein both guard flavors.Changes
crawlers/ruby_crawler.rs: addedbundle_config_setting(contents, key), one exact-key app-config reader thatconfig_gemfilenow uses. Addedbundler_app_cache_dir[_with_env], which resolvescache_pathin Bundler's priority (relative to the project root, absolute stands alone, read-only use so no containment needed).formats/gem/manifest.rs::classify: the app config value now outranks the env. The one exception: an envBUNDLE_GEMFILEnaming a file in another directory still decides alone. That value movesBundler.root, so Bundler reads that root's config and never the project's. The run still refuses, now naming the env var. The inverted unit test is replaced.scan/hosted.rs: both stale-guard flavors use the resolved cache dir, and the warning text now says "its cache dir".redirect_gem_bundle_gemfile_unsupportedandredirect_gem_stale_installrows), docs/ecosystems.md, and CHANGELOG[Unreleased] / Fixed.npm/,pypi/,gem/only dispatch to the binary).Per-issue checklist
BUNDLE_GEMFILEenv var override.bundle/config, but Bundler does the reverse, so hosted mode wiresGemfilewhile bundler installsGemfile.nextunpatched and VEX attests it #507, each test red onmainand green here:formats::gem::manifest::tests::config_wins_over_env_like_bundler_settings: configGemfile.next+ envGemfilegivesUnsupported{AppConfig}and the remedy namesbundle config unset --local gemfile. Both directions of the supported-spelling conflict are covered too.formats::gem::manifest::tests::env_gemfile_in_another_directory_is_never_overridden_by_project_configcrawlers::ruby_crawler::tests::loaded_manifest_app_config_beats_the_environment(on disk)e2e_redirect_gem_build::gem_hosted_bundle_gemfile_config_outranks_env_redirects_nothing(ScanVexDualBoot+BUNDLE_GEMFILE=Gemfileexported to socket-patch). Onmainit fails with exactly the reported envelope:"redirected":1,"rewrittenFiles":["Gemfile"],"vex":{"statements":1}.vendor/cache, so a committed cache at a configuredcache_pathgets no warning, the in-run VEX attests it, and Bundler 2.4 installs the unpatched gem #483, each test red onmainand green here:commands::scan::hosted::tests::gem_stale_probe_follows_the_configured_bundle_cache_path: covers the standalone warning, thestale_purlsVEX exclusion, the folded delete list, and that a leftovervendor/cachearchive is ignored oncecache_pathmoves it.e2e_redirect_gem_stale_install::gem_hosted_stale_archive_at_configured_cache_path_warns_and_is_not_attested, for both the app-config andBUNDLE_CACHE_PATH-env arms. Onmainit fails with the reported symptom: noredirect_gem_stale_install,vex.statements: 1.crawlers::ruby_crawler::tests::app_cache_dir_follows_bundler_settings_priorityandbundle_config_setting_matches_the_exact_key(new helpers)Test evidence (Linux, Ruby 3.3.6, Bundler 4.0.17)
cargo clippy --workspace --all-features -- -D warnings: clean.cargo test -p socket-patch-core --all-features --lib: 4720 passed, 4 failed. The 4 failures (copy_tree::relax_loop_must_not_traverse_symlinked_root,vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry,pypi_poetry::wire_write_failure_…,pypi_requirements::wire_failure_rolls_back_…) fail identically onorigin/main. They are permission tests that root bypasses in this sandbox, and they are unrelated to this change.cargo test -p socket-patch-cli --all-features --lib: 830 passed.--test e2e_redirect_gem_stale_install(25),in_process_gem_apply(11),in_process_gem_multi_platform(7),covgap_commands_scan_hosted(50),hosted_memory_parity(31), corecrawler_ruby_e2e(25): all pass.--test e2e_redirect_gem_build -- --ignored(9/9) and--test e2e_vendor_gem_build -- --ignored(5/5), both with real Bundler: all pass, and the non-ignored halves pass too.cargo fmt --all -- --check:mainitself is not rustfmt-clean (460 diffs with the pinned 1.93.1 rustfmt, and CI doesn't gate it), so I formatted only this PR's own hunks.cargo test --workspace --all-features: building every integration-test binary used up the sandbox's disk allowance. CI covers it.Follow-ups
~/.bundle/config(priority below ENV) is still not consulted for any key. That was already true and is unchanged here.🤖 Generated with Claude Code
https://claude.ai/code/session_01MWt5CXPnmqVEUZe4wnCfgX
Note
Medium Risk
Changes gem hosted redirect manifest selection and stale-install/VEX exclusion logic; mis-resolution previously could patch or attest the wrong manifest or miss stale committed cache archives.
Overview
Gem hosted and vendored flows now resolve
BUNDLE_GEMFILEandcache_paththe same way Bundler does:.bundle/configbeats the environment, with a narrow exception when env points at a Gemfile outside the project root.#507: Dual-boot setups (
bundle config set --local gemfile Gemfile.nextplus exportedBUNDLE_GEMFILE=Gemfile) no longer rewrite and attest the ignoredGemfile. The run refuses withredirect_gem_bundle_gemfile_unsupportedinstead.#483: The hosted gem stale-install probe checks committed
.gemarchives under Bundler's configured cache dir (BUNDLE_CACHE_PATHin app config, then env, elsevendor/cache), not alwaysvendor/cache. Stale archives there triggerredirect_gem_stale_installand exclude the purl from same-run--vexattestation.Shared plumbing adds
bundle_config_settingandbundler_app_cache_dirinruby_crawler;manifest::classifyinverts gemfile precedence and documents when env-only wins.Reviewed by Cursor Bugbot for commit 477aae9. Configure here.
Generated by Claude Code