Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ limits, and required install commands.

### Fixed

- Hosted mode refuses a Yarn Berry project whose root `package.json` mixes CRLF
and LF line endings (`redirect_yarn_berry_mixed_line_endings`), as vendored
mode already did, instead of rewriting every minority line. Both modes now
share one set of berry project gates (line endings, `cacheKey`,
`compressionLevel`).
- Global mode (`-g`) finds npm, yarn, pnpm, bun, RubyGems and Composer on
Windows, where they install as `.cmd` / `.bat` shims, instead of reporting
an empty scan. The yarn and npm-family global lookups no longer run from the
Expand Down
2 changes: 1 addition & 1 deletion crates/socket-patch-cli/CLI_CONTRACT.md

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions crates/socket-patch-cli/src/commands/scan/hosted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1650,8 +1650,8 @@ async fn vendored_takeover(
None
};
// Yarn berry twin of the bun gate: the berry rewriter's project-level
// refusals (mixed line endings, cacheKey, `.yarnrc.yml`
// compressionLevel) must be known before the takeover reverts a
// refusals (mixed yarn.lock / package.json line endings, cacheKey,
// `.yarnrc.yml` compressionLevel) must be known before the takeover reverts a
// vendored berry purl, or the revert strips the live vendored patch
// and the rewriter then refuses the lock. Only entries the
// vendor ledger wired through the yarn-berry backend are gated (the
Expand All @@ -1673,8 +1673,14 @@ async fn vendored_takeover(
)
.await
.ok();
let manifest = socket_patch_core::utils::fs::read_regular_to_string(
&common.cwd.join("package.json"),
)
.await
.ok();
socket_patch_core::patch::redirect::preflight_yarn_berry_hosted(
&lock,
manifest.as_deref(),
yarnrc.as_deref(),
)
.err()
Expand Down
46 changes: 46 additions & 0 deletions crates/socket-patch-cli/tests/in_process_redirect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,52 @@ async fn scan_redirect_refuses_a_mixed_line_ending_yarn_berry_lock() {
);
}

/// #628: the root `package.json` of a berry project is a file the hosted
/// rewrite edits (its `resolutions`), so a manifest mixing CRLF and LF is
/// refused like a mixed lock — the same decision vendored mode takes with
/// `vendor_yarn_berry_mixed_line_endings` — instead of being re-rendered in
/// its majority ending, which rewrote lines the user never touched and
/// left rollback no original bytes to restore. Nothing is written.
#[tokio::test]
#[serial]
async fn scan_redirect_refuses_a_mixed_line_ending_yarn_berry_manifest() {
let server = MockServer::start().await;
mock_discovery(&server).await;
mock_reference_with_berry(&server).await;
mock_view(&server).await;

let tmp = tempfile::tempdir().unwrap();
write_berry_project_spelled(tmp.path(), |t| t.to_string());
let pkg_path = tmp.path().join("package.json");
std::fs::write(
&pkg_path,
format!(
"{{\r\n \"name\": \"consumer\",\n \"version\": \"0.0.0\",\r\n \
\"dependencies\": {{ \"{NAME}\": \"^{VERSION}\" }}\r\n}}\r\n"
),
)
.unwrap();
let lock_path = tmp.path().join("yarn.lock");
let (pkg_before, lock_before) = (
std::fs::read(&pkg_path).unwrap(),
std::fs::read(&lock_path).unwrap(),
);

let env = run_redirect_subprocess(tmp.path(), &server.uri());
assert_eq!(env["redirect"]["redirected"], 0, "{env:#}");
let detail = redirect_warning_detail(&env, "redirect_yarn_berry_mixed_line_endings");
assert!(detail.contains("package.json"), "names the file: {detail}");
assert!(detail.contains("yarn install"), "remedy named: {detail}");
assert_eq!(std::fs::read(&pkg_path).unwrap(), pkg_before, "untouched");
assert_eq!(std::fs::read(&lock_path).unwrap(), lock_before, "untouched");
assert!(
!tmp.path()
.join(".socket/vendor/redirect-state.json")
.exists(),
"no ledger for a refused rewrite"
);
}

/// Classic (v1) yarn.lock with CRLF line endings (Windows `core.autocrlf`
/// checkout): the full hosted chain must repoint the TARGET entry — not
/// whichever entry sorts first — and keep every untouched line CRLF
Expand Down
9 changes: 9 additions & 0 deletions crates/socket-patch-cli/tests/in_process_vendor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1503,6 +1503,15 @@ async fn berry_takeovers_refuse_before_reverting_the_old_mode() {
"yarn.lock",
"redirect_yarn_berry_mixed_line_endings",
),
// #628: hosted mode re-renders the root manifest (its
// `resolutions`), so a mixed one is refused before the revert, the
// same decision the hosted→vendored leg below takes.
(
"mixed package.json",
mix,
"package.json",
"redirect_yarn_berry_mixed_line_endings",
),
(
"compressionLevel",
compression,
Expand Down
Loading
Loading