Skip to content

Commit daca7bd

Browse files
committed
Test node lookup for the dependency check
Covers the hoisted, bundled and pnpm-isolated layouts, optional dependencies, copies outside node_modules and unsafe dependency names. Refs #1462 Assisted-by: Claude Code:claude-opus-5-5
1 parent 5e9277b commit daca7bd

1 file changed

Lines changed: 60 additions & 0 deletions

File tree

‎crates/socket-patch-core/src/vex/verify.rs‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,6 +1946,66 @@ mod tests {
19461946
dir
19471947
}
19481948

1949+
/// #1462: node's lookup from an installed copy finds a bundled,
1950+
/// hoisted or pnpm-sibling dependency; an optional one may be absent,
1951+
/// and a copy outside `node_modules` or an unsafe name is no evidence.
1952+
#[tokio::test]
1953+
async fn unresolved_npm_dependency_follows_node_lookup() {
1954+
let tmp = tempfile::tempdir().unwrap();
1955+
let root = tmp.path();
1956+
let put = |rel: &str, text: &str| {
1957+
let path = root.join(rel);
1958+
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
1959+
std::fs::write(path, text).unwrap();
1960+
};
1961+
let manifest = r#"{"name":"lp","dependencies":{"a":"1","@s/b":"1","opt":"1",
1962+
"../../escape":"1"},"optionalDependencies":{"opt":"1"}}"#;
1963+
1964+
// Hoisted layout: `a` and `@s/b` at the root; `@s/b` missing first.
1965+
put("node_modules/lp/package.json", manifest);
1966+
put("node_modules/a/package.json", "{}");
1967+
let hoisted = root.join("node_modules/lp");
1968+
assert_eq!(
1969+
unresolved_npm_dependency(&hoisted).await.as_deref(),
1970+
Some("@s/b")
1971+
);
1972+
// Bundled inside the package itself.
1973+
put("node_modules/lp/node_modules/@s/b/package.json", "{}");
1974+
assert_eq!(unresolved_npm_dependency(&hoisted).await, None);
1975+
1976+
// pnpm's isolated store: dependencies are siblings of the package.
1977+
let store = "node_modules/.pnpm/lp@1.0.0/node_modules";
1978+
put(&format!("{store}/lp/package.json"), manifest);
1979+
put(&format!("{store}/a/package.json"), "{}");
1980+
let isolated = root.join(store).join("lp");
1981+
assert_eq!(
1982+
unresolved_npm_dependency(&isolated).await.as_deref(),
1983+
Some("@s/b")
1984+
);
1985+
put(&format!("{store}/@s/b/package.json"), "{}");
1986+
assert_eq!(unresolved_npm_dependency(&isolated).await, None);
1987+
1988+
// Not in a node_modules tree: never evidence.
1989+
put("unplugged/lp/package.json", manifest);
1990+
assert_eq!(
1991+
unresolved_npm_dependency(&root.join("unplugged/lp")).await,
1992+
None
1993+
);
1994+
1995+
for (name, plain) in [
1996+
("a", true),
1997+
("@s/b", true),
1998+
("@/b", false),
1999+
("s/b", false),
2000+
("../x", false),
2001+
("@s/..", false),
2002+
("a\\b", false),
2003+
("", false),
2004+
] {
2005+
assert_eq!(plain_npm_name(name), plain, "{name}");
2006+
}
2007+
}
2008+
19492009
fn hosted_ctx(purl: &str, copies: HostedCopies) -> VendorContext {
19502010
VendorContext {
19512011
hosted: [(purl.to_string(), copies)].into_iter().collect(),

0 commit comments

Comments
 (0)