Hosted gem `rollback` / `remove` strip the DEPENDENCIES `!` when the user's `source … do` block opens after a `;` on the same line, so frozen installs fail on Bundler 4.0.19+
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
調査の方向性
Start in crates/socket-patch-core/src/patch/redirect/upstream/gem.rs around lines 627-637 (block_stack), where source_pending is only set from a leading source on a line. Reproduce with the e2e test gem_hosted_unwind_keeps_a_source_block_bang in crates/socket-patch-cli/tests/e2e_redirect_gem_build.rs using the ; fixture, and check in_source_block returns true for the ; shape. Done when the restored lock keeps the ! and the frozen install exits 0 on Bundler 4.0.19+.
索引モデルが issue の本文から書いたものです。
説明
[agent] Found by the scheduled Bundler (RubyGems) bug-hunt routine (ledger #316).
Summary
This is a neighbour of #1056 / #1476 / #1509, still open on main after #1520. The hosted unwind (rollback / remove) decides whether a restored gem gets its ! source pin in Gemfile.lock DEPENDENCIES by asking in_source_block. The block scanner only recognises a source statement at the start of a line. A source "…" do that follows another statement and a ; on the same line is read as a plain do block:
source "https://rubygems.org"
zz = 1; source "https://rubygems.org" do
gem "vuln-gem", "1.0.0"
end
Bundler evaluates this as a source block and locks vuln-gem (= 1.0.0)!. After scan --mode hosted → bundle install → rollback (or remove <purl>), socket-patch restores the Gemfile byte for byte but writes vuln-gem (= 1.0.0) without the !. On Bundler 4.0.19+ the next frozen install (BUNDLE_FROZEN=true / deployment / CI) fails with exit 16 ("Your lockfile needs to be updated, but it can't be because frozen mode is set"). 4.0.18 and older only warn.
Impact
After an unwind the project's lock no longer matches what Bundler derives from the Gemfile, so every frozen CI or deploy install fails until someone runs an unfrozen bundle install by hand. The ; spelling isn't common, but it's legal Ruby, and things like git_source(:gh) { … }; source "…" do show up in generated Gemfiles. Nothing gets silently unpatched: this is a broken-lock bug, not a security bypass.
Repro
This uses the repo's own harness. In crates/socket-patch-cli/tests/e2e_redirect_gem_build.rs, change the Driver::ScanVexSourceBlockMultiLineOpener fixture body to the ; shape and run the existing capstone:
Driver::ScanVexSourceBlockMultiLineOpener => format!(
- "source \"{up}/upstream\"\n\nsource(\n \"{up}/upstream\"\n) do\n \
+ "source \"{up}/upstream\"\n\nzz = 1; source \"{up}/upstream\" do\n \
gem \"{DEP}\", \"{DEP_VERSION}\"\nend\n",
gem install bundler -v 4.0.23
BUNDLER_VERSION=4.0.23 SOCKET_PATCH_BUNDLER_E2E_VERSION=4.0.23 SOCKET_PATCH_BUNDLER_E2E_REQUIRED=1 \
cargo test --release -p socket-patch-cli --test e2e_redirect_gem_build \
gem_hosted_unwind_keeps_a_source_block_bang -- --include-ignored --nocapture
Output:
assertion `left == right` failed: rollback: the lock comes back byte for byte, `!` included
left: "…DEPENDENCIES\n vuln-gem (= 1.0.0)\n…"
right: "…DEPENDENCIES\n vuln-gem (= 1.0.0)!\n…"
With the lock assertion relaxed, the fresh-checkout BUNDLE_FROZEN=true bundle install exits 16 for both rollback and remove. In the same run, the plain, assignment (#1476) and brace (#1509) fixtures restore the ! and their frozen installs exit 0.
A unit probe of in_source_block agrees: in_source_block("x = 1; source \"https://x\" do\n gem \"rails\"\nend\n", at gem) returns false. The other 52 shapes I probed (\-continued do, a brace block nested in group, heredocs, %w(end), for … do end, CRLF, …) all return the expected answer.
Expected vs actual
- Expected: CLI_CONTRACT.md / docs/ecosystems.md ("Hosted unwind coverage") say
rollback/removerestore the upstream lock, and the #1056 fix restores a source-block gem's!pin "whichever URL the block names". The restored pair should pass a frozen install, as it does for the line-leadingsource … doform. - Actual: the
!is dropped, and frozen installs fail on Bundler 4.0.19+.
Matrix
| OS | Ruby | Bundler | zz = 1; source … do → rollback |
→ remove |
Line-leading source … do (control) |
|---|---|---|---|---|---|
| Linux | 3.3.6 | 4.0.23 | fail (! dropped, frozen exit 16; ×2) |
fail (exit 16) | pass |
| Linux | 3.3.6 | ≤ 4.0.18 | ! dropped; Bundler only warns (exit 0), as in #1509 |
same | pass |
| macOS / Windows | — | — | not run (OS-independent text scan) |
Suspect code
crates/socket-patch-core/src/patch/redirect/upstream/gem.rs:627-637 (block_stack): source_pending is set only from masked.strip_prefix("source") at the start of a line. In the masked.split(';') loop, every statement after the first gets source_pending = false and is never checked for a leading source. Deciding source_pending per ;-statement (at depth 0) should fix it.
Tested on main a8da202. I didn't run a probe branch, because the scan is pure text.
- 主要言語
- Rust
- スター
- 8
- フォーク
- 1
- 平均マージ
- 17時間 5分
- マージ済み PR(30日)
- 557
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
SocketDev/socket-patch のほかの issue
-
agent:triaged bug bughunt pm:npm priority:p3 ux
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
SocketDev/socket-patch#1072 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
agent:triaged bug bughunt pm:yarn-berry priority:p1
難易度 2/5 1〜3時間 初心者へのやさしさ 73/100
SocketDev/socket-patch#783 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
Vendored cargo warns cargo_multi_version_old_cargo ("declares no rust-version") when the root package inherits rust-version from [workspace.package]対応中かも @mikolalysenko が 2 日前に担当しました。 オープンagent:triaged bug bughunt pm:cargo priority:p2
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
SocketDev/socket-patch#651 · コメント 3 件 ·
メンテナーはふだん 1 日以内に返信
-
bug bughunt pm:npm
難易度 4/5 1〜2日 初心者へのやさしさ 45/100
SocketDev/socket-patch#1534 ·
メンテナーはふだん 1 日以内に返信
-
VEX product detection fails on Poetry 2 projects that declare dynamic = ["version"] with the version in [tool.poetry], so scan --vex exits 1 after rewriting poetry.lock対応中かも @mikolalysenko が今日担当しました。 オープンagent:claimed agent:triaged bug bughunt pm:poetry priority:p1
難易度 3/5 半日 初心者へのやさしさ 25/100
SocketDev/socket-patch#1527 · コメント 3 件 ·
メンテナーはふだん 1 日以内に返信
SocketDev/socket-patch の issue をすべて見る
似ている issue
-
RUSTSEC-2026-0348: Brotli certificate decompression can allocate up to 1 GiB before authenticationオープン
難易度 2/5 1〜3時間 初心者へのやさしさ 60/100
-
難易度 1/5 1〜3時間 初心者へのやさしさ 62/100
-
core: Amount::from_str panics on values above 21M BTC instead of returning an error対応中かも @bhuvan-somisetty が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
crate: spate-s3
難易度 2/5 半日 初心者へのやさしさ 62/100
メンテナーはふだん 1 日以内に返信
-
write_iceberg ignores the table's write.parquet.compression-codec property対応中かも @YuangGao が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
Eventual-Inc/Daft#7606 ·
メンテナーはふだん 1 日以内に返信