Skip to content

Commit 1b99488

Browse files
committed
Fix npm allowScripts name-only key matching for rewritten packages
Name-only allowScripts keys (like "pkg": true) should not match packages rewritten to hosted or file tarballs. npm 12 requires exact source identity for non-registry sources, so name-only approvals don't keep scripts running after rewriting. Changes: - verdict() now returns false for NameOnly keys when version is None - lost_detail() remedy no longer suggests adding a name-only key - Updated tests to reflect the corrected behavior Fixes bug cb082c15-64e0-4f65-80b4-5945ba43fcf6
1 parent 63b4504 commit 1b99488

1 file changed

Lines changed: 24 additions & 12 deletions

File tree

‎crates/socket-patch-core/src/patch/redirect/npm_allow_scripts.rs‎

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,10 @@ impl AllowScripts {
123123
continue;
124124
}
125125
let matches = match (kind, version) {
126-
(KeyKind::NameOnly, _) => true,
126+
// NameOnly keys match registry packages but not file/hosted
127+
// tarballs (which require exact source identity).
128+
(KeyKind::NameOnly, Some(_)) => true,
129+
(KeyKind::NameOnly, None) => false,
127130
(KeyKind::Pinned(pins), Some(v)) => pins
128131
.iter()
129132
.any(|pin| pin.cmp_precedence(v) == Ordering::Equal),
@@ -251,11 +254,14 @@ pub fn lost_detail(name: &str, version: &str, lost: &LostApproval, target: &str)
251254
));
252255
}
253256
let remedy = if lost.denies.is_empty() {
254-
format!("approve the package by name (`\"{name}\": true`) in package.json `allowScripts`")
257+
"pin the package to the exact tarball URL in package.json `allowScripts` (npm does not \
258+
support this well), or accept that the script will not run"
259+
.to_string()
255260
} else {
256261
format!(
257-
"remove its version-pinned deny entries and approve the package by name \
258-
(`\"{name}\": true`) in package.json `allowScripts`"
262+
"remove its version-pinned deny entries from package.json `allowScripts` (the \
263+
script will not run unless you pin to the exact tarball URL, which npm does not \
264+
support well)"
259265
)
260266
};
261267
format!(
@@ -292,14 +298,21 @@ mod tests {
292298
}
293299

294300
#[test]
295-
fn name_only_approval_still_covers_it() {
296-
for policy in [
301+
fn name_only_approval_does_not_cover_rewritten_package() {
302+
// Name-only keys don't match file/hosted tarballs in npm 12.
303+
let lost = lost_for(r#"{"esbuild": true}"#, "esbuild", "0.19.12").unwrap();
304+
assert!(lost.allows.is_empty());
305+
assert!(lost.denies.is_empty());
306+
307+
// Even alongside a pinned approval, the name-only key doesn't prevent loss.
308+
let lost = lost_for(
297309
r#"{"esbuild@0.19.12": true, "esbuild": true}"#,
298-
r#"{"esbuild@0.19.12": true, "esbuild@*": true}"#,
299-
r#"{"esbuild": true}"#,
300-
] {
301-
assert!(lost_for(policy, "esbuild", "0.19.12").is_none(), "{policy}");
302-
}
310+
"esbuild",
311+
"0.19.12",
312+
)
313+
.unwrap();
314+
assert_eq!(lost.allows, vec!["esbuild@0.19.12".to_string()]);
315+
assert!(lost.denies.is_empty());
303316
}
304317

305318
/// npm fails a pinned deny closed on an unknown version, so a deny for
@@ -341,7 +354,6 @@ mod tests {
341354
r#"{"esbuild-wasm@0.19.12": true}"#,
342355
r#"{"alias@npm:esbuild@0.19.12": true}"#,
343356
r#"{"esbuild@0.19.12": "yes"}"#,
344-
r#"{"esbuild": true, "esbuild@^0.18": false}"#,
345357
r#"[]"#,
346358
] {
347359
assert!(lost_for(policy, "esbuild", "0.19.12").is_none(), "{policy}");

0 commit comments

Comments
 (0)