Fix gem lock readers ignoring gems.locked (#736) - #750
Open
Mikola Lysenko (mikolalysenko) wants to merge 5 commits into
Open
Mikola Lysenko (mikolalysenko) wants to merge 5 commits into
Mikola Lysenko (mikolalysenko) wants to merge 5 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
A gems.rb project's gems.locked was invisible to the lock inventory, ledger recovery read only Gemfile.lock, and VEX discovery read both locks. A leftover redirected Gemfile.lock beside gems.rb + gems.locked therefore made vex attest not_affected while bundle install installed the unpatched gem from gems.locked. Add one resolver for the lock Bundler loads (honouring BUNDLE_GEMFILE and the app config) and route the inventory, gem_remotes, VEX discovery and the hosted engine through it. VEX still reads the ignored twin, but any Socket wiring there is diagnosed as unattributable instead of attested. Fixes #736 Assisted-by: Claude Code:claude-opus-5-5
Mikola Lysenko (mikolalysenko)
force-pushed
the
agent/fix-gem-loaded-lock-readers
branch
from
October 4, 2026 04:41
9ea1929 to
4834b26
Compare
Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
Mikola Lysenko (mikolalysenko)
marked this pull request as ready for review
October 4, 2026 05:10
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 b519ef6. Configure here.
This was referenced Oct 4, 2026
Collaborator
Author
|
Ready for review — burn-down agent.
Reviewers should focus on the twin-lock handling in Slack announcement: not sent. This session's Slack connector has no send tool, so the next run will retry. Generated by Claude Code |
Mikola Lysenko (mikolalysenko)
pushed a commit
that referenced
this pull request
Oct 4, 2026
Assisted-by: Claude Code:claude-opus-5-5
This was referenced Oct 4, 2026
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 #736
Summary
socket-patch now reads the gem lock Bundler actually loads. Before this, a
gems.rbproject'sgems.lockedwas invisible to the lock inventory (scan's lockfile supplement, the in-memory hosted engine, VEX ledger liveness), and ledger recovery read onlyGemfile.lock. VEX discovery read both locks, so a leftover redirectedGemfile.lockbesidegems.rb+gems.lockedmadevexattestnot_affectedwhilebundle installinstalled the unpatched gem fromgems.locked. That repro is in the #736 comments, on real Bundler 2.6.9 and 4.0.17.Root cause
Bundler loads one manifest/lock pair:
gems.rb+gems.lockedwhen the root holds agems.rb, otherwiseGemfile+Gemfile.lock, unlessBUNDLE_GEMFILE(env or.bundle/config) says otherwise.LoadedManifest::pairalready models this, and the writers use it (#341, #390). The readers each chose their own lock: they hard-codedGemfile.lock, or read both.Change
crawlers/ruby_crawler.rs:bundler_loaded_manifest_in(view): on disk or a snapshot, the ambient env plus the app config; in a memory view, its own.bundle/config. This logic moved out of the hosted engine.bundler_loaded_lock_in(view): the lock of that pair, orNonefor an unsupportedBUNDLE_GEMFILE.lock_inventory/gem.rs:inventory_gemfile_lock_raw_inandgem_remotesread only the loaded lock.vex/discover/gem.rs: only the loaded lock yields refs. The twin Bundler ignores is still read through the guarded reader, so its Socket uuids stay recognized (rule 11) and a ledger claim can't attest them. Each ref the twin would have yielded becomes apatched_ref_unattributablediagnostic that names the lock Bundler loads. Bundler picks one pair deterministically, so rule 1 ("read every lock") applies only within that pair here, and the module docs now say so.hosted/engine.rs:keep_bundler_loaded_gem_filesreuses the shared resolver. Its behavior is unchanged.polyglot_project_discovers_the_union_of_every_package_managerused to add a vendoredgems.lockednext to the bundler fixture'sGemfile.lockwith nogems.rb. Bundler never reads that file, so it is now an ignored twin. The test keeps its vendored coverage through thePipfile.lockwheel, and gem coverage through the hosted bundler fixture.Per-issue checklist (#736 acceptance criteria)
inventory_projectongems.rb+gems.lockedreturns its gems:lock_inventory::tests::gem_inventory_reads_the_lock_bundler_loadsGemfile.lockbesidegems.rb+gems.locked: inventory, every-lock inventory and VEX discovery read onlygems.locked: same test, plusvex::discover::gem::tests::only_the_lock_bundler_loads_is_readanda_stale_redirected_gemfile_lock_beside_gems_rb_is_not_attested(the issue-comment repro).bundle/configBUNDLE_GEMFILE: Gemfilebeside agems.rbreadsGemfile.lockon disk and in memory:gem_inventory_reads_the_lock_bundler_loads,gem_inventory_memory_view_reads_the_lock_bundler_loadsgems.rbproject yields a gem candidate, with or without a stale twin:hosted_memory_engine::gems_rb_project_yields_its_gem_candidatesgem_remotes_reads_the_lock_bundler_loadsgems.rb, a straygems.lockedis ignored:gem_inventory_ignores_gems_locked_without_gems_rbTest evidence
gem_inventory_reads…,…memory_view…,gem_remotes_reads…,only_the_lock_bundler_loads_is_read,a_stale_redirected…). The engine test failed withleft: 0, right: 1(no candidate) when onlylock_inventory/gem.rswas reverted.cargo clippy --workspace --all-features -- -D warnings: clean.--all-targetsreports only pre-existing hits onmain, none in the touched files.cargo test --workspace --all-features --no-fail-fast: 214 test binaries ok. 12 tests fail locally, and every one is a permission-injection test (chmod 0o555/ unremovable-file write failures incovgap_commands_vendor,copy_tree,vlt_heal,pypi_poetry,pypi_requirements,repair_invariants). They can't fail as root (the sandbox runs as uid 0), and none touches gem code. CI runs as non-root.e2e_redirect_gem_build -- --ignored(11 passed),e2e_vendor_gem_build -- --ignored(6 passed),e2e_vex_lockfile gem(9 passed).e2e_vendor_jvm_buildmaven_reactor failure on the superseded head 71e4564 was a Maven Central HTTP 429 during fixture warm-up, and it passed on b519ef6.cargo fmt --all -- --checkisn't usable as a gate here:mainitself isn't rustfmt-clean, and CI doesn't run it. The touched hunks are rustfmt-formatted.npm/,pypi/,gem/only dispatch to the binary).🤖 Generated with Claude Code
https://claude.ai/code/session_012Ao6g9qAnawPfNxv11f3wM
Note
Medium Risk
Changes which lock drives scan inventory and VEX attestation for Ruby projects with twin lockfiles; behavior becomes stricter (fewer false
not_affectedclaims) but may surface new diagnostics where stale locks held old redirects.Overview
Fixes incorrect gem lock selection so
vex, scan’s lockfile supplement, and the in-memory hosted engine use the same lock Bundler loads (gems.lockedforgems.rbprojects, otherwiseGemfile.lock, honoringBUNDLE_GEMFILE/.bundle/config).A shared resolver (
bundler_loaded_manifest_in,bundler_loaded_lock_in) replaces ad hocGemfile.lockreads and the hosted engine’s duplicated manifest logic. Lock inventory and ledger GEM-remote recovery now inventory only that file. VEX discovery attributes patches only from the loaded lock; wiring in an ignored twin (e.g. stale redirectedGemfile.lockbesidegems.rb+gems.locked) still recognizes Socket UUIDs but emitspatched_ref_unattributableinstead of attestingnot_affectedwhile Bundler installs unpatched gems.Tests cover
gems.rblayouts, config overrides, memory-hosted redirects, and the polyglot union test no longer treats an ignoredgems.lockedas a second vendored source.Reviewed by Cursor Bugbot for commit b519ef6. Configure here.
Generated by Claude Code