Hosted gem `rollback` / `remove` strips the `DEPENDENCIES` `!` of a gem the user declared inside a `source "https://rubygems.org" do` block, so every frozen install fails after the unwind
メンテナーはふだん 1 日以内に返信
関連するプルリクエストがすでにマージされています。
- #1303 @mikolalysenko による — マージ済み
評価
調査の方向性
crates/socket-patch-core/src/patch/redirect/upstream/gem.rs の354行目付近から確認してください。strip_suffix('!') の呼び出しにはガードが必要です。復元された Gemfile で gem が source ブロック内(または source:/git:/path: オプション付き)に宣言されていない場合に限り、! を削除してください。unwind 中に元の Gemfile のコンテキストがどのように追跡されるかを確認してください。プロジェクトのテストスイートを実行し、issue の再現手順で rollback 後に frozen install が成功することを検証してください。
索引モデルが issue の本文から書いたものです。
説明
[agent] Found by the scheduled Bundler (RubyGems) bug-hunt routine (ledger #316).
Summary
Bundler marks a dependency declared inside a source … do block with ! in the lock's DEPENDENCIES (colorize (= 0.8.1)!), even when that block's source is rubygems.org. The hosted scan of such a gem works: it nests the patch-registry block inside the user's block, and the fresh frozen install gets the patched bytes. The unwind (rollback, or remove <purl>) then restores the Gemfile byte for byte, so the declaration is back inside the user's source "https://rubygems.org" do block. But the unwind always drops the ! from the lock's DEPENDENCIES line. The restored pair no longer matches what Bundler writes, so BUNDLE_FROZEN=true bundle install fails with exit 16 ("Your lockfile needs to be updated, but it can't be because frozen mode is set"). rollback still reports success with hosted.reverted: [pkg:gem/[email protected]].
Impact
After undoing a patch, every CI or deployment (frozen) install of the project breaks until someone runs an unfrozen bundle install and commits the lock. The unwind is supposed to give back the original, installable pair.
Repro (Linux, Ruby 3.3.6, Bundler 4.0.22 or 2.6.9 with bundle lock --add-checksums)
Patch API and patch registry mocked on loopback (the run-13 mock from ledger #316); rubygems.org is the real upstream.
mkdir app && cd app
printf 'source "https://rubygems.org"\n\ngem "rake"\nsource "https://rubygems.org" do\n gem "colorize", "0.8.1"\nend\n' > Gemfile
bundle lock && cp Gemfile.lock /tmp/orig.lock # DEPENDENCIES: colorize (= 0.8.1)!
socket-patch scan --mode hosted --yes --api-url $MOCK --org org --api-token fake
BUNDLE_FROZEN=true BUNDLE_PATH=vb bundle install # exit 0, patched bytes (OK)
socket-patch rollback --api-url $MOCK --org org --api-token fake --patch-server-url $MOCK
diff /tmp/orig.lock Gemfile.lock
# < colorize (= 0.8.1)!
# ---
# > colorize (= 0.8.1)
git diff Gemfile # empty: the Gemfile came back exactly
BUNDLE_FROZEN=true BUNDLE_PATH=vb2 bundle install # exit 16
socket-patch remove pkg:gem/[email protected] leaves the same diff, and a frozen install then fails with exit 16 too.
Expected vs actual
- Expected: CLI_CONTRACT.md's "Hosted unwind coverage" gem row says the unwind undoes the
source "<patch registry>" do … endblock and "the pair comes back". The!should only be dropped when the restored declaration no longer sits in a usersourceblock (the case where hosted mode added it). Here the declaration's own block still pins the source, so the original!must stay, and the lock should come back byte-identical to the pre-scan one. - Actual: the
!is always removed (the row says "theDEPENDENCIESpin loses its!" without exception), which leaves a pair that Bundler's frozen mode rejects.
Matrix
| OS | Ruby | Bundler | Shape | Result |
|---|---|---|---|---|
| Linux | 3.3.6 | 4.0.22 | top-level source + source "https://rubygems.org" do gem … end |
reproduces (×2) |
| Linux | 3.3.6 | 4.0.22 | every gem inside one source "https://rubygems.org" do block |
reproduces |
| Linux | 3.3.6 | 4.0.22 | source … do + nested group :default do |
reproduces |
| Linux | 3.3.6 | 2.6.9 (CHECKSUMS added) | every gem inside one source block |
reproduces |
| Linux | 3.3.6 | 4.0.22 | remove <purl> instead of rollback |
reproduces |
| Linux | 3.3.6 | 4.0.22 | plain top-level declaration (control) | pass (lock byte-restored) |
macOS and Windows weren't probed. The lock surgery is OS-independent.
First bad version
Not bisected. This is current main d47eab3; the v5 upstream restore introduced the hosted unwind.
Suspect code
crates/socket-patch-core/src/patch/redirect/upstream/gem.rs:354: for a non-transitive gem, entry.strip_suffix('!') unconditionally rewrites the DEPENDENCIES line to the unpinned form. It doesn't check whether the restored Gemfile still declares the gem inside a source … do block (or with a source: / git: / path: option), and in that case Bundler keeps the !.
- 主要言語
- Rust
- スター
- 8
- フォーク
- 1
- 平均マージ
- 19時間 1分
- マージ済み PR(30日)
- 473
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
SocketDev/socket-patch のほかの issue
-
agent:triaged bug pm:go priority:p2
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
SocketDev/socket-patch#1409 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
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]対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープンagent:triaged bug bughunt pm:cargo priority:p2
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
SocketDev/socket-patch#651 · コメント 3 件 ·
メンテナーはふだん 1 日以内に返信
-
agent:triaged bench perf-regression pm:nuget priority:p3
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
SocketDev/socket-patch#1425 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
SocketDev/socket-patch の issue をすべて見る
似ている issue
-
area::tern difficulty::easy good first issue kind::cleanup triage::ready
難易度 1/5 1〜3時間 初心者へのやさしさ 88/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
eclipse-zenoh/zenoh#2842 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
中文字符导致软件崩溃オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
Y-ASLant/ElegantClipboard#172 ·
-
bug documentation
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
SaboLabs/soroban-devkit#341 ·
メンテナーはふだん 1 日以内に返信
-
agent:sonnet-high enhancement priority: P2 ready-for-agent
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
shep-pm/shep-kelpie#652 ·
メンテナーはふだん 1 日以内に返信