Skip to content

Commit 54bd233

Browse files
committed
bundler: 2026-11-15 run 2 (#2089, #2090, #2091)
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011f9aeRNUGKGmXEf5TfCKqU
1 parent ed44d0e commit 54bd233

3 files changed

Lines changed: 51 additions & 11 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[agent] 2026-11-15: Bundler (RubyGems) bug-hunt run
2+
3+
**Tested:** main `63f791d` (5.1.0; same SHA as the last two runs, so the run went to the backlog). Linux. Ruby 3.3.6 with Bundler 4.0.18, 2.6.9 and 2.5.22; Ruby 3.2.6 with 2.4.19.
4+
5+
**Harness:** a `rails new` app (Rails 7.1.6, 81 gems, 8-platform lock, bootsnap boot, `Bundler.require(*Rails.groups)`) with seven mock patches: rack and rails-html-sanitizer (transitive), puma and bootsnap (direct, native), web-console and capybara (in `group … do` blocks), nokogiri (precompiled). The Python mock was rebuilt from the state file's notes; each patched gem is the upstream `.gem` with one Ruby file changed and `checksums.yaml.gz` recomputed.
6+
7+
**Re-triage:** main has not moved, so nothing to re-check. #1109 is `agent:needs-human`.
8+
9+
**Cells**
10+
11+
| Cell | Result |
12+
| --- | --- |
13+
| Hosted, Rails app: scan, dev / test boot, frozen install, lock stable, `vex`, deployment clone with `BUNDLE_WITHOUT=development:test`, production boot, rollback, `pristine` | pass on 4.0.18, 2.6.9 and 2.5.22, pair byte-exact; nokogiri refused as documented |
14+
| Hosted, Rails app: `bundle cache`, then a `--local` deployment install from `vendor/cache` | pass on 4.0.18 (the cache holds the patched archives) |
15+
| Hosted lock written by one Bundler, installed by another (2.5.22 and 2.6.9 locks on 4.0.18; 4.0.18 lock on 2.5.22): deployment, plain install, `vex`, re-scan | pass (only `BUNDLED WITH` and Bundler's own lines change) |
16+
| Agent, Rails app with a warm bootsnap cache: scan, boot, frozen install, `apply --check`, `vex` | pass on 4.0.18 |
17+
| Agent, CI clone with `BUNDLE_DEPLOYMENT` and `BUNDLE_WITHOUT`: `apply`, boot, `apply --check`, `vex` | pass on 4.0.18 (the two group gems are skipped with a note, exit 0) |
18+
| Agent and hosted common path, 2-gem project | pass on 2.4.19 |
19+
| Switching agent to hosted | **fail #2089** on 4.0.18 and 2.6.9 (with CHECKSUMS), 2.6.9 and 2.5.22 (without) |
20+
| Switching hosted to agent: scan, `apply`, `pristine`, `vex`, rollback | pass on 4.0.18 (clear `hosted wiring live` warning, pair byte-exact after rollback) |
21+
| Vendored, Rails app: scan, frozen install, boot, `vex`, rollback | 2 of 7 vendored, pair byte-exact after rollback; messages **fail #2091** |
22+
| Vendored, group gems rewritten as top-level `gem "x", group: :test`: scan, deployment clone without the groups | pass on 4.0.18 |
23+
| Vendored then hosted on one project (mixed): frozen install, boot, `vex` | pass on 4.0.18 (6 gems attested) |
24+
| Mixed vendored + hosted: `rollback`, `remove <vendored purl>`, `vendor --revert` | **fail #2090** on 4.0.18, 2.6.9 and 2.5.22 |
25+
26+
**Filed**
27+
- https://github.com/SocketDev/socket-patch/issues/2089: a hosted scan over an agent-patched project leaves the upstream `.gem` in `vendor/bundle/…/cache` under a lock that pins the patched sha256, with no warning. `bundle pristine` / `--redownload` exit 37, remove the gem, and every later `bundle install` exits 37 too. Without CHECKSUMS they reinstall the unpatched gem.
28+
- https://github.com/SocketDev/socket-patch/issues/2090: reverting a vendored gem while another gem is hosted puts its spec into the hosted gem's `GEM` section (`record_gem_section` takes the first one). A fresh `bundle install` exits 7 and `rollback` then refuses both gems. `remove` exits 0 while doing it.
29+
- https://github.com/SocketDev/socket-patch/issues/2091 (`ux`): on the stock Rails Gemfile vendored mode fails 5 of 7 gems and no error names a remedy; top-level `group:` and `--mode hosted` both work.
30+
31+
**Commented / closed:** nothing.
32+
33+
**Ruled out**
34+
- `vex` in a CI clone that leaves out `development:test` attests the hosted group gems from the lock pin. Already listed (documented rule).
35+
- A hosted lock installed by another Bundler gets a new `BUNDLED WITH` (and 2.5.22 drops the `bundler` CHECKSUMS line of a 4.0 lock). That is Bundler.
36+
- After agent to hosted, `list` shows each gem twice (manifest record and hosted pin) and step 2 says to reinstall. Noted in #2089, not filed separately.
37+
- `rollback` after agent to hosted (without a `pristine` in between) restores the pair, the files and the manifest.

‎known-non-bugs/bundler.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,6 @@ Documented limitations and verified false positives. One bullet each. Search thi
165165
- `scan --mode vendored` over a hosted project with a native gem exits 1, vendors the pure-Ruby gems and leaves the native one hosted. Documented refusal (`native_extensions_unsupported`); the mixed state lists, attests and rolls back correctly (2026-11-14).
166166
- `gem "x", force_ruby_platform: true`, or `bundle config set force_ruby_platform true` plus `bundle lock` over the existing lock, keep every platform variant in a Bundler 4.0.18 lock, so hosted mode still refuses the gem (`redirect_gem_platform_unsupported`). Only a new lock or `bundle lock --remove-platform` gives a `ruby`-only lock. Bundler's behavior, documented refusal; the `vex` problem after the switch is #2087 (2026-11-15).
167167
- Hosted `rollback` / `remove` without `--gem-refresh-shared` leave the patched copy in a shared gem home and warn. That part is documented; the remedy that fails afterwards is #2086 (2026-11-15).
168+
- A hosted lock installed by a different Bundler than wrote it changes only `BUNDLED WITH` (and Bundler 2.5.22 drops the `bundler` CHECKSUMS line of a 4.0 lock); the hosted sections, the patched installs and `vex` are unaffected. That is Bundler (2026-11-15).
169+
- Vendored mode refusing `group … do` gems, native-extension gems and precompiled platform gems on a Rails Gemfile is by design (#340); only the missing remedy in the messages is filed (#2091). Top-level `gem "x", group: :test` is accepted (2026-11-15).
170+
- `scan --mode agent` over a hosted project keeps the hosted wiring and warns ("left the hosted wiring live"); `apply` reports the copies as already patched. By design (2026-11-15).

‎state/bundler.md‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
[agent] Progress ledger for the scheduled Bundler (RubyGems) bug-hunt routine (label pm:bundler).
22

3-
Last run: 2026-11-15, main `63f791d`, release 5.1.0, newest Bundler 4.0.24 stable and 4.1.0.beta3 prerelease (tested so far: 2.3.27, 2.4.19, 2.5.22/23, 2.6.9, 4.0.18, 4.0.24, 4.1.0.beta3). Ruby 3.1.6, 3.2.6 and 3.3.6.
3+
Last run: 2026-11-15, main `63f791d`, release 5.1.0, newest Bundler 4.0.24 stable and 4.1.0.beta3 prerelease (tested so far: 2.3.27, 2.4.19, 2.5.22/23, 2.6.9, 4.0.18, 4.0.24, 4.1.0.beta3). Ruby 3.1.6, 3.2.6 and 3.3.6. Second run of 11-15.
44

55
The ledger was reset on 2026-11-13. The old 97 KB ledger is in this branch's history (`git show ec2d4516f:state/bundler.md`); search it with `git grep`, don't copy it back.
66

7-
Harness notes: the sandbox reaches rubygems.org but not the Socket patch API. A standalone mock of the patch API and patch registry works for all three modes (endpoints: `POST …/patches/batch`, `GET …/patches/by-package/<purl>`, `POST …/patches/package`, `GET …/patches/view/<uuid>` with `blobContent`, and a compact index under `/patch-registry/gem/<token>/<uuid>/`; copy the `/info` line from rubygems.org and swap the checksum). Build the patched gem by repacking the upstream `.gem` with its `metadata.gz` unchanged, and pass `--api-url <mock> --proxy-url <mock> --patch-server-url <mock>` to every command (without a token the CLI calls the proxy URL). For vendored mode the grant's `tarball` artifact needs `integrity.sha512` (SRI) and a second artifact `{"kind":"gem-stub-gemspec"}` serving `gem spec <patched.gem> --ruby`. Give test repos a `**/vendor/bundle/` ignore line. `--api-token fake --org test` works in place of the proxy route. For a gem with precompiled builds, `nokogiri 1.16.0` compiles from source in under a minute here. rbenv Rubies are in `/opt/ruby-3.1.6` (Bundler 2.3.27, 2.6.9), `/opt/ruby-3.2.6` (2.4.19, 4.0.18), `/opt/ruby-3.3.6` (2.5.22, 4.0.18); `gem install bundler -v 4.0.24` / `4.1.0.beta3` works there.
7+
Harness notes: the sandbox reaches rubygems.org but not the Socket patch API. A standalone mock of the patch API and patch registry works for all three modes (endpoints: `POST …/patches/batch`, `GET …/patches/by-package/<purl>`, `POST …/patches/package`, `GET …/patches/view/<uuid>` with `blobContent`, and a compact index under `/patch-registry/gem/<token>/<uuid>/`; copy the `/info` line from rubygems.org and swap the checksum). Build the patched gem by repacking the upstream `.gem` with its `metadata.gz` unchanged, and pass `--api-url <mock> --proxy-url <mock> --patch-server-url <mock>` to every command (without a token the CLI calls the proxy URL). For vendored mode the grant's `tarball` artifact needs `integrity.sha512` (SRI) and a second artifact `{"kind":"gem-stub-gemspec"}` serving `gem spec <patched.gem> --ruby`. Give test repos a `**/vendor/bundle/` ignore line. `--api-token fake --org test` works in place of the proxy route. For a gem with precompiled builds, `nokogiri 1.16.0` compiles from source in under a minute here. rbenv Rubies are in `/opt/ruby-3.1.6` (Bundler 2.3.27, 2.6.9), `/opt/ruby-3.2.6` (2.4.19, 4.0.18), `/opt/ruby-3.3.6` (2.5.22, 4.0.18); `gem install bundler -v 4.0.24` / `4.1.0.beta3` works there (2.6.9 on 3.3.6 too). A patched gem can also be made without Ruby: copy the upstream `.gem`, change one file in `data.tar.gz` and recompute `checksums.yaml.gz`. A realistic project: `gem install rails -v 7.1.5` into a scratch `GEM_HOME`, then `rails new app --skip-git --skip-bundle --skip-javascript --skip-hotwire --skip-asset-pipeline --skip-docker` (81 gems, installs in 30 s); patch rack, rails-html-sanitizer, puma, bootsnap, web-console, capybara.
88

99
## Coverage matrix
1010

1111
Linux only. A cell is `pass` with the Bundler versions and the date, `fail #N`, `n/a`, or `untested`.
1212

1313
| Workflow | Agent | Vendored | Hosted |
1414
| --- | --- | --- | --- |
15-
| Common path: scan, patch, fresh `bundle install`, app loads patched code, `vex`, rollback, `bundle install` again | pass 2.5.22, 2.6.9, 4.0.18 (11-15) | pass 2.5.22, 2.6.9, 4.0.18, 4.1.0.beta3, CRLF pair too (11-15); `vex` warning fail #2076 | pass 2.3.27 to 4.0.24, 4.1.0.beta3 (11-14) |
15+
| Common path: scan, patch, fresh `bundle install`, app loads patched code, `vex`, rollback, `bundle install` again | pass 2.4.19, 2.5.22, 2.6.9, 4.0.18; Rails 7.1 app with bootsnap and a CI clone without groups on 4.0.18 (11-15) | pass 2.5.22, 2.6.9, 4.0.18, 4.1.0.beta3, CRLF pair too (11-15); `vex` warning fail #2076; on a Rails Gemfile 5 of 7 gems are refused with no remedy, fail #2091 | pass 2.3.27 to 4.0.24, 4.1.0.beta3 (11-14); Rails 7.1 app on 2.5.22, 2.6.9, 4.0.18, cross-Bundler installs and `bundle cache` too (11-15) |
1616
| System or user gem home (no `BUNDLE_PATH`) | pass 4.0.18, 2.5.22 with `GEM_HOME` (11-15) | fail #2075 (2.6.9, 4.0.18) | pass 4.0.18: warning, `scan` and `rollback` with `--gem-refresh-shared` (11-15); the remedy after a plain rollback / remove fail #2086 |
1717
| `bundle config set path vendor/bundle` | pass 2.6.9 (11-13) | pass 4.0.18 (11-14) | pass 2.3.27 to 4.0.18 (11-14) |
1818
| Deployment and frozen installs (`BUNDLE_DEPLOYMENT`, `BUNDLE_FROZEN`, `.bundle/config`) | pass frozen 2.6.9, 4.0.18 (11-13) | pass frozen and deployment clone, with `BUNDLE_WITHOUT` too, 4.0.18 (11-14) | pass frozen on all, deployment clone 2.5.22, 2.6.9, 4.0.18 (11-14) |
@@ -28,22 +28,22 @@ Linux only. A cell is `pass` with the Bundler versions and the date, `fail #N`,
2828
| Monorepo: several Gemfiles, nested projects, scan from the repo root | untested (agent scans one project by design) | untested | pass 4.0.18: scan, `list`, rollback from the root (11-14) |
2929
| `setup` and the Bundler plugin it installs | n/a: `setup` and the plugin were removed in v5 (CLI_CONTRACT "…no longer published"); only `gem_bundler_plugin_stale` detection is left, untested | n/a | n/a |
3030
| Re-runs (idempotency) and `--json` output | pass 4.0.18 (11-14) | re-scan pass 2.6.9, 4.0.18 (apart from #2075) | pass 4.0.18 (11-14) |
31-
| Switching modes on one project | untested | hosted to vendored: pair and mixed state pass 4.0.24; rollback afterwards leaves patched installs, fail #2083 | vendored to hosted refused by design (not re-run) |
31+
| Switching modes on one project | hosted to agent pass 4.0.18 (11-15); agent to hosted leaves the upstream archive, `pristine` / `--redownload` fail #2089 | hosted to vendored: pair and mixed state pass 4.0.24; rollback afterwards leaves patched installs, fail #2083 | hosted beside vendored gems (mixed) installs and attests 4.0.18 (11-15); any revert of the vendored gem then corrupts the lock, fail #2090 |
3232
| Bundler 4.1 prerelease | untested | pass 4.1.0.beta3 (11-14); `OVERRIDES` / `CONTENT ADDRESSES` sections not produced, untested | pass 4.1.0.beta3 (11-14); same sections untested |
3333
| Bundler 1.x refused where the docs say so | untested | untested | untested |
3434

3535
## Backlog
3636

37-
1. Friction pass as a first-time user following only the CLI's messages and `docs/usage.md`. Known candidates: `redirect_gem_no_checksums_section` says "bundler < 2.6 does not write one" on a 2.6.9 lock (its remedy works); vendored mode refuses every gem inside a `group do` block, which is most Rails Gemfiles (by design, #340: is the message's remedy clear?); `scan --mode vendored` exits 1 whenever one patched gem is native (is the hint to use hosted for it clear?); `remove <gem>` from a monorepo root doesn't name the sub-projects that pin it; `apply --check` says "Run `socket-patch apply` to regenerate them" for a gem `apply` refuses (`native_extensions_unsupported`); the hosted next step says "a plain `bundle install` keeps the gems it already has" when the stale copy is a platform build the lock no longer names.
38-
2. A realistic Rails-sized project (a Rails 7 or 8 Gemfile with groups, bootsnap, a `Bundler.require` boot) through hosted mode end to end, on Bundler 2.5, 2.6 and 4.0.
39-
3. Vendored mode, the rest: `remove` / `vendor --revert` after a hosted to vendored takeover (#2083 covers `rollback` only), `scan --prune`.
40-
4. Agent mode, the rest: Bundler 2.4, the system gem home under `/opt/ruby-*` itself, switching agent to hosted and back, `apply --dry-run` starts no Ruby, a relative crawl root (#2048), an interrupted rebuild, a monorepo.
41-
5. Other flags the nested apply of `scan --mode agent` may drop (same cause as #2069: `nested_apply_args_from_params` fills `GlobalArgs` from defaults).
42-
6. Hosted shared gem home, the rest: `--gem-refresh-shared` with two projects pinning the same gem version (the documented cost), `remove` of one gem out of several, `SOCKET_GEM_REFRESH_SHARED=1`.
37+
1. Mixed and switched states, the rest (#2089 and #2090 came from here): agent to hosted with a native gem or a shared gem home; agent to vendored and back; hosted first and then `vendor <one purl>`; `scan --prune` and `repair` on a mixed project; a re-scan when a newer patch supersedes one of a mixed pair.
38+
2. Friction pass, the rest. Still open candidates: `redirect_gem_no_checksums_section` says "bundler < 2.6 does not write one" on a 2.6.9 lock (its remedy works); `scan --mode vendored` exits 1 whenever one patched gem is refused, with next steps that read like success (noted in #2091); `remove <gem>` from a monorepo root doesn't name the sub-projects that pin it; `apply --check` says "Run `socket-patch apply` to regenerate them" for a gem `apply` refuses; the hosted next step says "a plain `bundle install` keeps the gems it already has" when the stale copy is a platform build the lock no longer names; `docs/usage.md` never mentions Ruby.
39+
3. The Rails app, the rest: a Rails 8 Gemfile (kamal, thruster, solid_*), the default dev setup with a shared rbenv gem home, `bin/setup`, a Dockerfile-style `BUNDLE_PATH=/usr/local/bundle` install, `bundle update` / `bundle update rails` with hosted pins (beyond #2070), Dependabot-style `bundle lock --update <gem>`.
40+
4. Vendored mode, the rest: `remove` / `vendor --revert` after a hosted to vendored takeover (#2083 covers `rollback` only), `scan --prune`.
41+
5. Agent mode, the rest: the system gem home under `/opt/ruby-*` itself, `apply --dry-run` starts no Ruby, a relative crawl root (#2048), an interrupted rebuild, a monorepo. Other flags the nested apply of `scan --mode agent` may drop (same cause as #2069).
42+
6. Hosted shared gem home, the rest: `--gem-refresh-shared` with two projects pinning the same gem version, `remove` of one gem out of several, `SOCKET_GEM_REFRESH_SHARED=1`.
4343
7. Bundler 4.1 lock sections `OVERRIDES` and `CONTENT ADDRESSES`: find which Gemfile or setting makes 4.1.0.beta3 write them, then hosted and vendored. Ruby 3.4 is not in the sandbox.
4444
8. Deployment mode and `.bundle/config` shapes around the stale-install guard. #1109 is open and waiting on a maintainer decision; don't re-file it.
4545
9. Bundler 1.x refused where the docs say so (needs a Ruby that still runs Bundler 1.17; none in the sandbox).
46-
10. Re-check #2069, #2070, #2075, #2076, #2083, #2084, #2086 and #2087 once fixed.
46+
10. Re-check #2069, #2070, #2075, #2076, #2083, #2084, #2086, #2087, #2089, #2090 and #2091 once fixed.
4747

4848
## Known non-bugs
4949

0 commit comments

Comments
 (0)