From 3a8821c22658bb185df1b556a6030d5b45764e6c Mon Sep 17 00:00:00 2001 From: Sanjays2402 <51058514+Sanjays2402@users.noreply.github.com> Date: Sat, 27 Jun 2026 17:23:12 -0700 Subject: [PATCH 1/2] fix(arborist): skip extraneous orphans in strict-allow-scripts gate An extraneous registry node has no incoming dependency edge and is slated for pruning before reify can run any install script. buildIdealTree drops top-level orphans, but it can retain an orphan nested inside a workspace, in which case the strict-allow-scripts preflight false- positives on it (ESTRICTALLOWSCRIPTS) even though the install script will never execute. Skip extraneous nodes in collectUnreviewedScripts so the strict gate and the on-disk npm install-scripts ls listing agree. Fixes #9680 --- workspaces/arborist/lib/unreviewed-scripts.js | 10 ++++++ .../arborist/test/unreviewed-scripts.js | 31 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/workspaces/arborist/lib/unreviewed-scripts.js b/workspaces/arborist/lib/unreviewed-scripts.js index f7bed387845ec..540f34205cfb4 100644 --- a/workspaces/arborist/lib/unreviewed-scripts.js +++ b/workspaces/arborist/lib/unreviewed-scripts.js @@ -57,6 +57,16 @@ const collectUnreviewedScripts = async ({ // must not be flagged (npm/cli#9562). continue } + if (node.extraneous) { + // Extraneous = the node has no incoming dep edge from a real + // dependency, so it is slated for pruning before reify runs any + // install scripts. buildIdealTree drops top-level orphans, but can + // retain an orphan registry node nested inside a workspace's + // node_modules. In every case the script never executes, so the + // strict-allow-scripts gate must not surface it as unreviewed + // (npm/cli#9680). + continue + } const verdict = isScriptAllowed(node, resolvedPolicy) if (verdict === true || verdict === false) { diff --git a/workspaces/arborist/test/unreviewed-scripts.js b/workspaces/arborist/test/unreviewed-scripts.js index 34e4878b4625a..7dfa64eaeb6e3 100644 --- a/workspaces/arborist/test/unreviewed-scripts.js +++ b/workspaces/arborist/test/unreviewed-scripts.js @@ -29,6 +29,7 @@ const node = ({ isLink = false, inBundle = false, inert = false, + extraneous = false, resolved, } = {}) => ({ name, @@ -41,6 +42,7 @@ const node = ({ isLink, inBundle, inert, + extraneous, isRegistryDependency: true, package: { name, version, scripts }, }) @@ -92,6 +94,35 @@ t.test('collectUnreviewedScripts', async t => { t.strictSame(result, []) }) + t.test('skips extraneous (orphan) registry nodes', async t => { + // An extraneous node has no incoming edges and is slated to be pruned + // before reify runs any install scripts, so it must not gate the install + // under strict-allow-scripts even when the policy neither allows nor + // denies it. Buildup walks the ideal tree and can retain a nested orphan + // when nothing in the workspace depends on it (npm/cli#9680). + const result = await collectUnreviewedScripts({ + tree: tree([ + node({ name: 'orphan', scripts: { install: 'x' }, extraneous: true }), + ]), + policy: null, + }) + t.strictSame(result, []) + }) + + t.test('skips extraneous nodes even when policy denies by name', async t => { + // Same orphan, but the user has a name-only deny entry. An extraneous + // registry node typically has no resolved URL the matcher can verify + // against, so the deny would not match and the node would fall through + // to "unreviewed". It still must not gate the install (npm/cli#9680). + const orphan = node({ name: 'esbuild', scripts: { install: 'x' }, extraneous: true }) + orphan.isRegistryDependency = false + const result = await collectUnreviewedScripts({ + tree: tree([orphan]), + policy: { esbuild: false }, + }) + t.strictSame(result, []) + }) + t.test('skips nodes with no install-relevant scripts', async t => { const result = await collectUnreviewedScripts({ tree: tree([node({ scripts: { test: 'jest' } })]), From 735428d4e1bf45784f945ea68002b62ffaa8511b Mon Sep 17 00:00:00 2001 From: Sanjay Santhanam <51058514+Sanjays2402@users.noreply.github.com> Date: Thu, 2 Jul 2026 10:09:59 -0700 Subject: [PATCH 2/2] fix(arborist): tidy review comments to single-line per feedback Rewrite the extraneous-orphan explanation comments in unreviewed-scripts.js (lib and test) to be more concise and keep each sentence on a single line, addressing review feedback about verbosity and screen-reader-hostile mid-sentence newlines. No logic or test assertion changes. --- workspaces/arborist/lib/unreviewed-scripts.js | 9 ++------- workspaces/arborist/test/unreviewed-scripts.js | 13 ++++--------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/workspaces/arborist/lib/unreviewed-scripts.js b/workspaces/arborist/lib/unreviewed-scripts.js index 540f34205cfb4..1513a7fe347aa 100644 --- a/workspaces/arborist/lib/unreviewed-scripts.js +++ b/workspaces/arborist/lib/unreviewed-scripts.js @@ -58,13 +58,8 @@ const collectUnreviewedScripts = async ({ continue } if (node.extraneous) { - // Extraneous = the node has no incoming dep edge from a real - // dependency, so it is slated for pruning before reify runs any - // install scripts. buildIdealTree drops top-level orphans, but can - // retain an orphan registry node nested inside a workspace's - // node_modules. In every case the script never executes, so the - // strict-allow-scripts gate must not surface it as unreviewed - // (npm/cli#9680). + // Extraneous nodes are orphans pruned before reify runs any install script, so their scripts never execute. + // buildIdealTree drops top-level orphans but can retain one nested in a workspace's node_modules, so this gate must skip them (npm/cli#9680). continue } diff --git a/workspaces/arborist/test/unreviewed-scripts.js b/workspaces/arborist/test/unreviewed-scripts.js index 7dfa64eaeb6e3..db11680ec0688 100644 --- a/workspaces/arborist/test/unreviewed-scripts.js +++ b/workspaces/arborist/test/unreviewed-scripts.js @@ -95,11 +95,7 @@ t.test('collectUnreviewedScripts', async t => { }) t.test('skips extraneous (orphan) registry nodes', async t => { - // An extraneous node has no incoming edges and is slated to be pruned - // before reify runs any install scripts, so it must not gate the install - // under strict-allow-scripts even when the policy neither allows nor - // denies it. Buildup walks the ideal tree and can retain a nested orphan - // when nothing in the workspace depends on it (npm/cli#9680). + // An extraneous orphan is pruned before reify runs any install script, so it must not gate the install even when the policy neither allows nor denies it (npm/cli#9680). const result = await collectUnreviewedScripts({ tree: tree([ node({ name: 'orphan', scripts: { install: 'x' }, extraneous: true }), @@ -110,10 +106,9 @@ t.test('collectUnreviewedScripts', async t => { }) t.test('skips extraneous nodes even when policy denies by name', async t => { - // Same orphan, but the user has a name-only deny entry. An extraneous - // registry node typically has no resolved URL the matcher can verify - // against, so the deny would not match and the node would fall through - // to "unreviewed". It still must not gate the install (npm/cli#9680). + // Same orphan, but with a name-only deny entry. + // An extraneous registry node usually has no resolved URL for the matcher to verify, so the deny misses and it falls through to "unreviewed". + // It still must not gate the install (npm/cli#9680). const orphan = node({ name: 'esbuild', scripts: { install: 'x' }, extraneous: true }) orphan.isRegistryDependency = false const result = await collectUnreviewedScripts({