Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

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,531 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

已经有一个关联 PR 被合并了。

  • #1537 来自 @mikolalysenko —— 已合并

评估

难度
4/5
预计耗时
3-5 天
新手友好度
35/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
ruby, rust
领域
backend

调研方向

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:triaged bug bughunt pm:bundler priority:p1

[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 / remove restore 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-leading source … do form.
  • 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
平均合并
16 小时 18 分钟
30 天内合并 PR
587

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

SocketDev/socket-patch 的其他 Issue

查看 SocketDev/socket-patch 的全部 Issue

相似的 Issue

更多 Rust Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。