Repository navigation
Fix gem source block after a ; on the line (#1531) - #1537
Merged
Mikola Lysenko (mikolalysenko) merged 4 commits intoOct 14, 2026
Merged
Mikola Lysenko (mikolalysenko) merged 4 commits into
Mikola Lysenko (mikolalysenko) merged 4 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
`rollback` and `remove` dropped the `!` source pin from a gem's DEPENDENCIES line when its `source "..." do` block followed another statement and a `;` on the same line (`zz = 1; source "..." do`). Bundler 4.0.19+ then failed every frozen install with exit 16. The Gemfile block scanner only checked for a `source` call at the start of a line. It now checks each top-level `;` statement too, so the gem is seen as inside its source block and keeps its pin. Fixes #1531 Assisted-by: Claude Code:claude-opus-5-5
The first fix only looked for `source` right after a `;`. Bundler also runs a source block opened after `then`, `=` and other expression starts, so rollback could still drop the gem's `!` pin there. The scanner now treats `source` as a call wherever a keyword would start an expression, skips `source = ...` assignments, ends a call made inside a brace block when that block closes, and takes a restored gem's indent from the line its source statement is on. Refs #1531 Assisted-by: Claude Code:claude-opus-5-5
Mikola Lysenko (mikolalysenko)
marked this pull request as ready for review
October 14, 2026 15:30
Collaborator
Author
|
BugBot review Generated by Claude Code |
Tanmay Singla (Tanmay182003)
approved these changes
Oct 14, 2026
A `source` call or `do` block inside the brace block of a source
call's own arguments (`source ENV.fetch("S") { source "y" } do`)
took over the outer call, so its real `do` block was not seen as a
source block and rollback could drop the gem's `!` pin. Only a block
opened at the call's own brace level now belongs to it.
Refs #1531
Assisted-by: Claude Code:claude-opus-5-5
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 6fff5ae. Configure here.
Collaborator
Author
|
Tanmay Singla (@Tanmay182003) one commit landed after your approval (on c51944e), so I'm holding this out of the merge queue until you take another look:
I reproduced the original bug independently before this commit landed. CI is running on the new head. Once you re-approve, it can go into the queue. Generated by Claude Code |
Tanmay Singla (Tanmay182003)
approved these changes
Oct 14, 2026
Mikola Lysenko (mikolalysenko)
deleted the
agent/fix-gem-source-block-after-semicolon
branch
October 14, 2026 17:00
This was referenced Oct 14, 2026
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 #1531
What users saw
With a Gemfile like this:
Bundler locks
vuln-gem (= 1.0.0)!. Afterscan --mode hosted,bundle install, and thenrollbackorremove, socket-patch restored the Gemfile byte for byte but wrote theDEPENDENCIESline without the!. On Bundler 4.0.19+ every frozen install (BUNDLE_FROZEN=true, deployment, CI) then failed with exit 16 until someone ran an unfrozenbundle installby hand.Root cause
block_stackincrates/socket-patch-core/src/patch/redirect/upstream/gem.rsis the Gemfile scanner behindin_source_block. It only recognised asourcecall at the very start of a line. In themasked.split(';')loop it resetsource_pendingtofalsefor every later statement, without checking whether that statement was itself asourcecall. Sozz = 1; source "…" dowas read as a plaindoblock, and the unwind choseUnpinfor the gem.Fix
The scanner already treats keywords (
if,case, …) as openers wherever they start an expression (#1476).sourcenow gets the same treatment: it is a call whereverstarts_expressionholds at depth 0, including after;,=,thenand so on. In detail:source = …andsource == …are not calls (source_call_args)..source,:sourceandsource:were already excluded byruby_words.source_pendingnow records how many brace blocks were open around the call. A}that closes a block the call sat inside ends the call (urls.each { |u| source u }.then dois not a source block). A;inside a brace block within the call's own arguments no longer ends it (source ENV.fetch("S") { warn "x"; "https://x" } do).sourcecall ordoblock inside the brace block of an outer call's own arguments doesn't replace that call. Only adoor{at the call's brace level is its block (take_source, from Bugbot's review).;starts a new statement, sostatement_linemoves to that line. A restored declaration then takes its indent from the line the source statement is on, even when the earlier statement started on a previous line.No wrapper changes:
npm/,pypi/andgem/only dispatch to the Rust binary.Tests
source_block_opener_mid_line(unit, core): 14 opener shapes × inside/after the block, plus 9 non-call shapesFAILED. 3 passed; 1 failedsource_block_declaration_keeps_its_bang_through_restore(unit, full restore round-trip):zz = 1; source … doand the continued-line casegem_hosted_unwind_keeps_a_source_block_bang(e2e, real Bundler 4.0.21): newScanVexSourceBlockAfterSemicolondriver,rollbackandremovevuln-gem (= 1.0.0)without!Commands run locally (Ruby 3.3.6, Bundler 4.0.21 as in the CI leg):
cargo fmt --all -- --check: okcargo clippy --workspace --all-features -- -D warnings: okcargo test -p socket-patch-core --all-features --lib gem: 358 passedBUNDLER_VERSION=4.0.21 SOCKET_PATCH_BUNDLER_E2E_VERSION=4.0.21 SOCKET_PATCH_BUNDLER_E2E_REQUIRED=1 cargo test -p socket-patch-cli --all-features --test e2e_redirect_gem_build --test e2e_vendor_gem_build -- --include-ignored: 51 + 43 passedcargo test --workspace --all-features --no-fail-fast: 246 binaries ok. 13 tests failed, all for sandbox reasons in code this PR doesn't touch. The sandbox runs as root, so thechmod 0o555write-failure tests (vendor/reconcile/revert state writes, unremovable lock files,copy_treesymlink root, vlt heal, poetry/requirements wire failures, repair cleanup) can't fail.e2e_bun_lockb::binary_shared_bundled_record_hosted_pin_is_managedneedspatches-api.socket.dev, which the sandbox can't reach. CI runs these as non-root with network access.Code review
I ran
/code-review highon the first fix and folded every finding into the second commit except one:vex/discover/gem.rsparse_source_block_declshas its own, much simpler source-block grammar. It has never handled the Hosted gemrollback/removestill strip the DEPENDENCIES!when the user'ssource … doblock holds an assignment-formv = if/case/begin … end, so frozen installs fail on Bundler 4.0.19+ #1476 or Hosted gemrollback/removestrip the DEPENDENCIES!when the user's source block opener spans lines or uses braces, so frozen installs fail on Bundler 4.0.19+ #1509 shapes either, so it already disagreed withblock_stackbefore this PR. Moving discovery ontoblock_stackis a separate refactor and belongs in its own issue, not in this bug fix.🤖 Generated with Claude Code
https://claude.ai/code/session_01JMZecNRUYcZ8pNUFxKbrhB
Generated by Claude Code