Repository navigation
Fix gem restore of Bundler 4.1 override targets (#1989) - #1991
Mikola Lysenko (mikolalysenko) merged 4 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
With Bundler 4.1, `override "other", with: "gem", in: "parent"` records the replacement only in the lock's OVERRIDES section and keeps parent's original edge in the specs. Hosted rollback and remove then treated the gem as directly declared and wrote a new exact `gem "gem", "x.y.z"` pin into the Gemfile, which blocked the project from updating past the vulnerable version. The restore now counts an OVERRIDES `with:` target as a dependency of another spec, so it drops the appended Socket block and its DEPENDENCIES entry and gives back the original pair byte for byte. Fixes #1989 Assisted-by: Claude Code:claude-opus-5-5
Cover the two other OVERRIDES shapes Bundler 4.1 writes: a replacement with a version requirement (which holds a comma) and `with: nil`. Assisted-by: Claude Code:claude-opus-5-5
630dd19 to
26062a3
Compare
Assisted-by: Claude Code:claude-opus-5-5
|
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 927fa4c. Configure here.
There was a problem hiding this comment.
[agent] Reviewed 927fa4ccdf118bf8a01e1164112f8de68d318980. Checked Bundler OVERRIDES target recognition and restore ownership; the exact-head override_target round-trip test passed locally (1 test). No major correctness issues found. Validation: The focused core override_target round-trip test passed locally (1 test). Source and regression-test review plus available exact-head CI checks; broader local suites were not run.
|
Burn-down agent: labeled Ready for review.
Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1989
Summary
Hosted gem
rollback/removeno longer turn a gem reached only through a Bundler 4.1override "other", with: "gem", in: "parent"into a new exact top-level pin. The Gemfile and Gemfile.lock now come back byte for byte, as they do for an ordinary transitive gem. Before this fix, the straygem "vuln-gem", "1.0.0"pin blocked the project from updating past the vulnerable version.Root cause
restore_one(crates/socket-patch-core/src/patch/redirect/upstream/gem.rs) only treats the appended Socket block as a transitive gem's whenis_subdependencyfinds another locked spec depending on the gem. It checked only 6-space spec sub-lines. A Bundler 4.1 dependency override keeps the parent's original edge in the specs (parent (1.0.0)→other-dep) and records the replacement only in the lock's newOVERRIDESsection. No sub-line names the gem, so the restore took theDecl::Directarm.Change
is_subdependencyalso counts thewith:target of anyOVERRIDESentry, via a smalloverride_targetsreader.Override#to_lockjoinsinspected values with,). That coversversion:requirements containing,, andwith: nilyields no target.npm/,pypi/,gem/) changes are needed.Test evidence
override_target_redirect_round_trips_through_restore(hosted rewrite →restore_oneon a Bundler 4.1 OVERRIDES pair)gem "rails", "7.0.0"an_overrides_with_target_is_a_subdependency(argument order,version:with a comma,with: nil, name as target/parent/prefix, section scoping)OVERRIDESshape was checked against a real lock written bybundle _4.1.0.beta3_ lockfor the issue's Gemfile. It has the same section position and entry format.cargo fmt --all -- --check: clean.cargo clippy --workspace --all-features -- -D warnings: clean.cargo test -p socket-patch-core --all-features --lib: 6997 passed, 4 failed. The 4 also fail on unmodifiedmainin this sandbox, because it runs as root (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_…; same as Build: share one test RNG across randomized tests (#1868) #1882 and Build: share one test env guard in core (#1889) #1891).cargo test -p socket-patch-cli --all-features --lib --bins: 940 passed.cargo test -p socket-patch-cli --all-features --test e2e_redirect_gem_build --test e2e_vendor_gem_build -- --ignoredwith real Ruby 3.3.6 and Bundler: 37 + 11 passed.cargo test --workspaceran out of this sandbox's disk allowance while linking the ~100 CLI integration binaries, so CI covers the rest.Review findings not fixed (
/code-review high)Override#to_lockis[target.inspect, "with: #{op.inspect}", "in: #{from.inspect}", ...].join(", "), and its ownLOCK_LINEparser accepts only that form.in:parent still counts": the existing sub-line rule takes the same risk. Both are only a secondary guard behindprovably_appended(an option-less block after a blank line that the in-place rewrite cannot produce).overridewithoutin:": Bundler rejectswith:withoutin:(add_dependency_overrideraises).Follow-ups
zz_parent_unwindscenario belongs ine2e_redirect_gem_build.Note
Medium Risk
Changes transitive-vs-direct classification during gem restore; wrong parsing could drop real declarations or leave stray pins, but behavior is gated by existing
provably_appendedchecks and only extends dependency detection.Overview
Fixes hosted gem rollback/remove (#1989) when a patched gem is wired only through Bundler 4.1’s
override "…", with: "<gem>", in: "<parent>". Those locks keep the parent’s original spec edge and record the swap inOVERRIDES, so the gem never appears on a 6-space sub-line. Restore used to treat it as direct and injectgem "<name>", "<version>", blocking updates past the pinned version.is_subdependencyingem.rsnow also treats thewith:gem name from lockOVERRIDESentries (via newoverride_targetsparser) as “another spec depends on this,” alongside existing sub-line checks. That letsrestore_oneclassify the hosted append as transitive again—drop the Socket block andDEPENDENCIESentry instead of adding an exact pin—so Gemfile / Gemfile.lock round-trip byte-for-byte like ordinary transitive redirects.Docs and unit/async tests cover argument order,
version:clauses with commas,with: nil, and full rewrite → restore for an override-onlyrailsfixture.Reviewed by Cursor Bugbot for commit 927fa4c. Configure here.
Generated by Claude Code