Skip to content

Hosted gem redirect writes the Socket source … do block with LF endings into a CRLF Gemfile, leaving it with mixed line endings #1831

Closed

Description

[agent] Found by the scheduled Bundler (RubyGems) bug-hunt routine (ledger #316).

Summary

scan --mode hosted (and get --mode hosted) rewrites the gem declaration of a CRLF Gemfile (a Windows checkout, or core.autocrlf=true) into a Socket source "<index>" do … end block whose lines all end in a bare LF. The lines around it keep CRLF, so the committed Gemfile ends up with mixed line endings.

This is the hosted-mode twin of #1821, which was the same defect in vendored mode and was fixed by #1822 (plan_gemfile_edit now takes the ending of the line it replaces). The hosted planner in patch/redirect/mod.rs didn't get that change. The same thing was fixed for npm's .npmrc append in #1196.

Impact

Low. Bundler parses the mixed file, the converging bundle install and frozen installs pass, a re-scan is a no-op, and rollback / remove restore the user's lines with CRLF. But every hosted redirect on a Windows/autocrlf checkout leaves a Gemfile with mixed endings in the diff (git warns about it, and .gitattributes eol=crlf / editor normalization then churns the file), which vendored mode no longer does after #1822.

Repro

With a real Bundler (2.6.9 or 4.0.23) and the hermetic mock from crates/socket-patch-cli/tests/e2e_redirect_gem_build.rs (redirect_scanned_project(…, Driver::ScanVex)):

  1. Use the fixture Gemfile with CRLF endings: source "<upstream>"\r\n\r\ngem "vuln-gem"\r\n and its bundle installed lock, with no .socket/.
  2. Run socket-patch scan --mode hosted --json --yes --cwd <proj> --api-url <mock> --org <org> --api-token fake.
  3. Read the Gemfile back.

Actual (exit 0, gem redirected):

"source \"http://127.0.0.1:43679/upstream\"\r\nsource \"http://127.0.0.1:43679/patch-registry/gem/<token>/<uuid>/\" do\n  gem \"vuln-gem\", \"1.0.0\"\nend\n"

With a user source … do block (Driver::ScanVexSourceBlock):

"source \"…/upstream\"\r\n\r\nsource \"…/upstream\" do\r\nsource \"…/patch-registry/gem/<token>/<uuid>/\" do\n  gem \"vuln-gem\", \"1.0.0\"\nend\nend\r\n"

The Gemfile.lock keeps CRLF throughout in both cases (CRLF lock in) and stays LF (LF lock in), so only the Gemfile is affected.

Scratch test I used (appended to e2e_redirect_gem_build.rs, not committed): take a fixture from redirect_scanned_project, restore fx.pristine_lock, delete .socket/, write fx.pristine_gemfile with \n → \r\n, run run_hosted_scan, and assert that gemfile.matches("\r\n").count() == gemfile.matches('\n').count(). The assertion fails.

Expected vs actual

Matrix (Linux, Ruby 3.3.6, main b291caa)

Cell Bundler 2.6.9 Bundler 4.0.23
Single-line decl, CRLF Gemfile + LF lock: Gemfile mixed reproduces reproduces (×2)
Single-line decl, CRLF Gemfile + CRLF lock: Gemfile mixed reproduces reproduces (×2)
User source … do block, CRLF Gemfile: Gemfile mixed reproduces reproduces (×2)
Lock endings preserved pass pass
Converging bundle install, same-grant re-scan no-op pass pass
rollback / remove restore the user lines in CRLF pass pass

macOS / Windows weren't probed, but the code path is OS-independent string building.

Suspect code

  • crates/socket-patch-core/src/patch/redirect/mod.rs:8076-8085: the in-place block literal "source \"{}\" do\n gem \"{}\", \"{}\"\nend" is spliced in with gf.replace_range(range, &block).
  • crates/socket-patch-core/src/patch/redirect/mod.rs:8135-8150: the append arm (a transitive gem) computes eol for the separator but still writes the block with \n and a trailing \n (I found this by reading the code, and didn't run a separate repro for it).
  • For comparison, the vendored fix is crates/socket-patch-core/src/vendor/gem.rs plan_gemfile_edit (line_endings::terminator, Fix vendored Gemfile line endings on CRLF (#1821) #1822).

Note: the ledger had earlier listed this as cosmetic. It's filed now because the vendored equivalent (#1821) was accepted and fixed.

Activity

  1. mikolalysenko commented on Oct 29, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming this issue (shared root cause: hosted gem redirect builds the Socket source … do block with hard-coded LF endings). Branch: agent/fix-hosted-gemfile-crlf-block. Claim-ID: 2026-10-29T16:30:43Z-0855ac


    Generated by Claude Code

  2. mikolalysenko commented on Oct 29, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Draft PR: #1841


    Generated by Claude Code

  3. added a commit that references this issue on Oct 29, 2026
    89d5c1d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:triagedbugSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentpm:bundlerBundler (RubyGems)priority:p1

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions