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
71 changes: 71 additions & 0 deletions crates/socket-patch-cli/tests/in_process_redirect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,77 @@ async fn scan_redirect_rewrites_yarn_berry_lock() {
);
}

/// 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
/// byte-identical. Regression: `split("\n\n")` never split a CRLF lock, so
/// the whole file was one block and the leftmost `resolved`/`integrity` (the
/// decoy's) were rewritten, then confirmed and ledgered as the target's.
#[tokio::test]
#[serial]
async fn scan_redirect_rewrites_correct_entry_in_crlf_classic_lock() {
let server = MockServer::start().await;
mock_discovery(&server).await;
mock_reference(&server).await;

let tmp = tempfile::tempdir().unwrap();
std::fs::write(
tmp.path().join("package.json"),
format!(
r#"{{ "name": "consumer", "version": "0.0.0", "dependencies": {{ "{NAME}": "{VERSION}" }} }}"#
),
)
.unwrap();
let pkg = tmp.path().join("node_modules").join(NAME);
std::fs::create_dir_all(&pkg).unwrap();
std::fs::write(
pkg.join("package.json"),
format!(r#"{{ "name": "{NAME}", "version": "{VERSION}" }}"#),
)
.unwrap();
let decoy_resolved = "https://registry.yarnpkg.com/aaa-decoy/-/aaa-decoy-1.0.0.tgz#aaaa";
let lock_lf = format!(
"# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.\n\
# yarn lockfile v1\n\n\n\
aaa-decoy@^1.0.0:\n version \"1.0.0\"\n resolved \"{decoy_resolved}\"\n \
integrity sha512-DECOYdecoy==\n\n\
{NAME}@{VERSION}:\n version \"{VERSION}\"\n \
resolved \"https://registry.yarnpkg.com/{NAME}/-/{NAME}-{VERSION}.tgz#bbbb\"\n \
integrity sha512-UPSTREAMupstream==\n"
);
std::fs::write(tmp.path().join("yarn.lock"), lock_lf.replace('\n', "\r\n")).unwrap();

let code = run(redirect_args(tmp.path(), server.uri())).await;
assert_eq!(code, 0, "scan --redirect (classic CRLF) should succeed");

let lock = std::fs::read_to_string(tmp.path().join("yarn.lock")).unwrap();
assert!(
lock.contains(&format!("resolved \"{decoy_resolved}\"\r\n"))
&& lock.contains("integrity sha512-DECOYdecoy==\r\n"),
"the decoy entry must stay byte-identical: {lock}"
);
assert!(
lock.contains(&format!("resolved \"{HOSTED_URL}\"\r\n"))
&& lock.contains(&format!("integrity {PATCHED_SHA512}\r\n")),
"the target entry must pin the hosted patch: {lock}"
);
assert!(
!lock.contains("integrity sha512-UPSTREAMupstream=="),
"the target's upstream integrity must be gone: {lock}"
);
assert_eq!(
lock.matches('\n').count(),
lock.matches("\r\n").count(),
"every line must keep its CRLF ending: {lock}"
);
assert!(
tmp.path()
.join(".socket/vendor/redirect-state.json")
.is_file(),
"a redirect ledger should be written"
);
}

/// Write a project whose only lockfile is a text `bun.lock` (registry 4-tuple).
fn write_bun_project(root: &Path) {
std::fs::write(
Expand Down
Loading
Loading