Hosted gem scan of a Gemfile with no lock still pins shared-gem-home versions: `gem "x", "~> 2.0"` becomes the older patched `"1.0.0"`, and a gem the project never declared is appended as a new dependency
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
調査の方向性
crates/socket-patch-core/src/patch/redirect/mod.rs の6098~6445行付近を確認してください。6205行のガードは locked が None の場合にバイパスされます。ロックなしプロジェクトがGemのピン留めや追加をスキップするようにチェックを追加してください。e2e_redirect_gem_build.rs のフィクスチャを使用して、Gemfileのみのスキャンでマニフェストが変更されないことを検証してください。
索引モデルが issue の本文から書いたものです。
説明
[agent] Found by the scheduled Bundler (RubyGems) bug-hunt routine (ledger #316).
Summary
#1060 (the fix for #1055) skips a crawled gem version that the project's lock doesn't resolve (redirect_gem_version_not_locked). The check only runs when a lock exists, though: let locked = files.get(lock_name).map(...) is None for a project with a Gemfile / gems.rb and no Gemfile.lock / gems.locked, and if let Some(specs) = &locked then skips the guard completely. Library repos usually don't commit their lock, so this is the normal state of a fresh clone before bundle install.
In that state, a hosted scan on a machine whose shared gem home holds another project's copy of a patched gem does what #1055 described, and adds one more failure:
- The constraint is overwritten.
gem "vuln-gem", "~> 2.0"is rewritten tosource "<patch registry>" do gem "vuln-gem", "1.0.0" end. The nextbundle installinstalls 1.0.0, where the untouched Gemfile installs 2.0.0. - An unrelated gem is added. A Gemfile that never mentions
vuln-gem(gem "tiny-dep"only) gets a newsource … do gem "vuln-gem", "1.0.0" endblock appended through the "genuinely undeclared (a transitive dep)" branch. The nextbundle installaddsvuln-gem (= 1.0.0)!to the project's dependencies. Without the scan the project installs onlytiny-dep.
Both runs exit 0 and report redirected: 1 / action: "pinned". The only warning is redirect_gem_stale_install about the shared-home copy, which doesn't say that the project's declared dependencies changed. rollback / remove can't undo it either: a Gemfile-only pin isn't a reference without a lock (CLI_CONTRACT.md "Lockless pins"), so the user has to edit the Gemfile by hand.
Impact
- The project's dependencies change silently: it downgrades below the user's constraint, or it picks up a gem it never used.
- With
--vex, the scan exits 1 because of the stale warning, but plainscan --mode hosted/ CI runs exit 0 and leave the rewritten Gemfile for the user to commit.
Repro (real Bundler; hermetic mock upstream + patch registry, the e2e_redirect_gem_build.rs fixtures)
# upstream mock serves tiny-dep 1.0.0 and vuln-gem 1.0.0 + 2.0.0; the patch registry serves patched vuln-gem 1.0.0
export GEM_HOME=$TMP/shared-home GEM_PATH=$TMP/shared-home:<system gem dir>
# project A (another project on the same machine) puts vuln-gem 1.0.0 into the shared home
(cd a && printf 'source "<upstream>"\ngem "vuln-gem", "1.0.0"\n' > Gemfile && bundle install)
# project B: fresh clone, Gemfile only, no lock
cd b && printf 'source "<upstream>"\n\ngem "vuln-gem", "~> 2.0"\n' > Gemfile
socket-patch scan --mode hosted --json --yes --api-url <mock> --org test-org --api-token fake
# exit 0, redirect.patches = [{purl: pkg:gem/[email protected], action: pinned}]
cat Gemfile
# source "<upstream>"
# source "<patch registry>/" do
# gem "vuln-gem", "1.0.0"
# end
bundle install # → Gemfile.lock: vuln-gem (1.0.0) / DEPENDENCIES vuln-gem (= 1.0.0)!
# control: the same Gemfile without the scan → "Installing vuln-gem 2.0.0"
# project C: Gemfile declares only `gem "tiny-dep"`, no lock
socket-patch scan --mode hosted … # exit 0; appends `source "<patch registry>" do gem "vuln-gem", "1.0.0" end`
bundle install # DEPENDENCIES gains `vuln-gem (= 1.0.0)!`; the control installs only tiny-dep
Expected vs actual
- Expected (CLI_CONTRACT.md,
redirect_gem_version_not_locked): hosted mode "re-points the version the lock resolves; it never picks a version", and "the user's declared constraint and the locked version are never overwritten". With no lock there's nothing resolved to re-point. The scan should skip these gems with a warning (the way cargo refuses a lockless project withredirect_cargo_lockless_dependents), or at least never append a gem the manifest doesn't declare and never replace a declared requirement that the crawled version doesn't satisfy. - Actual: the crawled shared-home version is pinned as an exact top-level requirement in both shapes, and the scan reports success.
Matrix
| OS | Ruby | Bundler | Shape | Result |
|---|---|---|---|---|
| Linux | 3.3.6 | 2.5.22 | lockless ~> 2.0 declaration |
fails (downgrade to 1.0.0) |
| Linux | 3.3.6 | 2.5.22 | lockless, gem not declared | fails (gem appended and installed) |
| Linux | 3.3.6 | 4.0.18 | both shapes | fails (same, CHECKSUMS lock written by the install) |
| Linux | 3.3.6 | 4.0.18 | same shapes with a lock (the #1055 control) | pass (redirect_gem_version_not_locked, repo e2e suite) |
| macOS / Windows | — | — | — | untested; the logic is OS-independent |
Main b96a785, which includes #1060. Both shapes were reproduced twice, on two Bundler versions. I didn't bisect: the lockless path is outside the #1060 change, so this predates it.
Suspect code
crates/socket-patch-core/src/patch/redirect/mod.rs:6098:lockedisNonewithout a lock.crates/socket-patch-core/src/patch/redirect/mod.rs:6205:if let Some(specs) = &locked, so the #1055 guard is skipped when there's no lock.crates/socket-patch-core/src/patch/redirect/mod.rs:6387(in-place rewrite to the exact version) and:6445(the "genuinely undeclared (a transitive dep): append a block" branch, which without a lock can't tell a transitive dep from an unrelated shared-home gem).
No probe runs: found and confirmed on Linux only.
- 主要言語
- Rust
- スター
- 8
- フォーク
- 0
- 平均マージ
- 1日 1時間
- マージ済み PR(30日)
- 257
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
SocketDev/socket-patch のほかの issue
-
agent:triaged bug bughunt pm:npm priority:p1
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
SocketDev/socket-patch#1127 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
agent:triaged bug bughunt pm:pipenv priority:p1
難易度 2/5 1時間未満 初心者へのやさしさ 85/100
SocketDev/socket-patch#1122 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
agent:triaged bug bughunt pm:npm priority:p1
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
SocketDev/socket-patch#1072 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
agent:triaged arch-audit bug priority:p3
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
SocketDev/socket-patch#1062 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
agent:triaged bug bughunt pm:bundler priority:p1
難易度 2/5 1〜3時間 初心者へのやさしさ 80/100
SocketDev/socket-patch#1056 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
SocketDev/socket-patch の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
-
documentation enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
adorsys/status-list-server#619 ·
メンテナーはふだん 2 日以内に返信
-
batch-backport only backports the first 30 matching PRs対応中かも @DvirDukhan が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 5 日以内に返信
-
Configuration-level resource: `Allocate` rejects the kubelet's re-offer of the same device for a later container of the same Pod ("Unable to claim slot")対応中かも @fang80913 が 38 日前に担当しました。 オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
project-akri/akri#854 ·
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 77/100
メンテナーはふだん 1 日以内に返信