GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — Hosted gem redirect appends a second declaration when the gem is declared through `eval_gemfile` or a loop, so every `bundle install` fails with "You cannot specify the same gem twice" · Issue #482 · SocketDev/socket-patch Closed Labels agent:triagedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentpm:bundlerBundler (RubyGems)Bundler (RubyGems)priority:p1 Description[agent] Found by the scheduled Bundler (RubyGems) bug-hunt routine (ledger #316). Summary
In both cases the rewriter appends a top-level Impact
ReproThis uses the hermetic fixture from mkdir proj && cd proj bundle config set --local path vendor/bundle printf 'source "%s/upstream"\n\neval_gemfile "Gemfile.shared"\n' "$MOCK" > Gemfile printf 'gem "vuln-gem"\n' > Gemfile.shared bundle install # ok socket-patch scan --mode hosted --json --yes --cwd "$PWD" \ --api-url "$MOCK" --org test-org --api-token fake # exit 0, redirected: 1 tail -3 Gemfile # source "<MOCK>/patch-registry/gem/<token>/<uuid>/" do # gem "vuln-gem", "1.0.0" # end bundle install # [!] There was an error parsing `Gemfile`: You cannot specify the same gem twice with # different version requirements. # You specified: vuln-gem (>= 0) and vuln-gem (= 1.0.0). Bundler cannot continue. (exit 4) If Expected vs actual
Matrix (Linux, Ruby 3.3.6, socket-patch main
|
| Bundler | eval_gemfile, gem "x" |
eval_gemfile, gem "x", "1.0.0" |
eval_gemfile, "= 1.0.0", require: false |
%w[x].each { gem g } |
|---|---|---|---|---|
| 4.0.17 (CHECKSUMS lock) | fail (exit 4) | fail (exit 4) | fail (exit 4) | fail (exit 4) |
| 2.6.9 (no CHECKSUMS) | fail (exit 4) | untested | untested | untested |
| 2.4.22 | fail (exit 4) | untested | untested | untested |
Control: a real transitive dependency (gem "parent-gem" → vuln-gem), with a CRLF Gemfile or a Gemfile with no trailing newline, appends correctly and installs the patched bytes with a frozen install.
The rewrite doesn't depend on the OS, so macOS and Windows weren't probed.
First bad release: v4.0.0 (the published npm binary) behaves the same, so this isn't a v5 regression.
crates/socket-patch-core/src/patch/redirect/mod.rs:5105: the "Genuinely undeclared (a transitive dep): append a block" branch, which is reached whenever declared_re (:4986) misses.crates/socket-patch-core/src/vendor/gem.rs:1304 appends a managed gem "x", "<v>", path: … block when no line in the Gemfile declares the gem. I didn't verify this end to end. v5 vendoring needs a service artifact my sandbox can't serve.No probe runs: everything above was reproduced on Linux with the real bundler.
[agent] Triaged as priority:p1 (Bundler). Confirmed on main: the hosted rewriter's append branch in redirect/mod.rs runs whenever declared_re misses a declaration in the root Gemfile text. It never checks the lock's DEPENDENCIES section, so a direct gem declared through eval_gemfile or a loop gets appended a second time. No open or merged PR covers this. #340 also touches this rewriter, but it's a different defect: #340 mis-edits a declaration the rewriter does find, while this one misses the declaration entirely. So I haven't clustered them.
Generated by Claude Code
[agent] Bundler bug-hunt (ledger #316): the vendored arm is now verified end to end with a real install on main 61cfb9b, Linux, Ruby 3.3.6. I drove it through a copy of e2e_vendor_gem_build.rs, whose prebuilt-artifact fixture serves the service artifact.
Repro: start from staged_rack_project. Rewrite the Gemfile to source "https://rubygems.org" + eval_gemfile "Gemfile.common", put gem "rack", "~> 3.1" in Gemfile.common, then run bundle install (ok) and socket-patch vendor --json --offline --cwd ..
vendor exits 0 with "status": "success" and applied: 1. The lock gains the PATH section and the rack (= 3.2.7)! pin. Gemfile gets an appended fenced block (crates/socket-patch-core/src/vendor/gem.rs:1367):
# >>> socket-patch vendor (managed) >>>
gem "rack", "3.2.7", path: ".socket/vendor/gem/<uuid>/rack-3.2.7"
# <<< socket-patch vendor (managed) <<<
bundle install (frozen and unfrozen) and every bundle exec exits 4: You cannot specify the same gem twice with different version requirements. You specified: rack (~> 3.1) and rack (= 3.2.7).| Bundler | vendor |
Next bundle install (frozen / unfrozen) |
|---|---|---|
| 4.0.17 (×2) | exit 0, applied 1 | exit 4 / exit 4 |
| 2.6.9 | exit 0, applied 1 | exit 4 / exit 4 |
| 2.4.22 | exit 0, applied 1 | exit 4 / exit 4 |
The "declared at all?" gate at vendor/gem.rs:1352 only scans the top-level Gemfile text. It has the same blind spot as the hosted declared_re, so a fix probably needs to cover both rewriters. A pre-vendor lock listing rack under DEPENDENCIES already marks it as a direct dependency.
Generated by Claude Code
[agent] Shares root cause with #548: the hosted Gemfile rewriter chooses between "rewrite" and "append" from a single regex probe of the root Gemfile text. It never counts every declaration Bundler will actually see, so it misses the eval_gemfile/loop declaration here and the second literal line in #548, and it never checks the lock's DEPENDENCIES. Will be fixed together. The vendored gate at vendor/gem.rs:1352 has the same blind spot and belongs in the same fix.
Generated by Claude Code
[agent] Claiming this issue (with #548; shared root cause: the Gemfile rewriters pick rewrite or append from one regex probe of the root Gemfile instead of counting every declaration Bundler sees). Branch: agent/fix-gemfile-declaration-census. Claim-ID: 2026-10-02T11:21:53Z-e56953
Generated by Claude Code