-
Notifications
You must be signed in to change notification settings - Fork 4.4k
fix: recognize allowScripts for local link targets #9490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: latest
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -97,6 +97,37 @@ const matches = (node, key) => { | |
| } | ||
| } | ||
|
|
||
| const resolvedSourceSpecs = (node) => { | ||
| const specs = [] | ||
| const seen = new Set() | ||
| const add = (spec) => { | ||
| if (typeof spec !== 'string' || spec === '' || seen.has(spec)) { | ||
| return | ||
| } | ||
| seen.add(spec) | ||
| specs.push(spec) | ||
| } | ||
|
|
||
| add(node?.resolved) | ||
|
|
||
| if (node?.linksIn && typeof node.linksIn[Symbol.iterator] === 'function') { | ||
| for (const link of node.linksIn) { | ||
| add(link.resolved) | ||
| } | ||
|
|
||
| // Link targets for local directory deps are separate inventory nodes | ||
| // whose own `resolved` is null. The incoming Link carries the saved spec | ||
| // (for example `file:../pkg`, relative to node_modules), while policy | ||
| // entries written by hand often use the dependency spec from package.json | ||
| // (for example `file:pkg`, resolved by npa to this target path). Include | ||
| // the real target paths so both forms can match the same local dep. | ||
| add(node.realpath) | ||
| add(node.path) | ||
|
Comment on lines
+124
to
+125
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 to @owlstronaut. The guard on line 113 is always true since Can we gate the paths on the real link-target case, e.g. only add them when |
||
| } | ||
|
|
||
| return specs | ||
| } | ||
|
|
||
| const matchRegistry = (node, parsed) => { | ||
| // If this node is not a registry dep, refuse the match. A registry-style | ||
| // key (`pkg`, `pkg@1`, `pkg@1 || 2`) must not match a tarball or git node | ||
|
|
@@ -282,17 +313,13 @@ const matchGit = (node, parsed) => { | |
| } | ||
|
|
||
| const matchFileOrDir = (node, parsed) => { | ||
| if (!node.resolved) { | ||
| return false | ||
| } | ||
| return node.resolved === parsed.saveSpec || node.resolved === parsed.fetchSpec | ||
| return resolvedSourceSpecs(node) | ||
| .some(resolved => resolved === parsed.saveSpec || resolved === parsed.fetchSpec) | ||
| } | ||
|
|
||
| const matchRemote = (node, parsed) => { | ||
| if (!node.resolved) { | ||
| return false | ||
| } | ||
| return node.resolved === parsed.fetchSpec || node.resolved === parsed.saveSpec | ||
| return resolvedSourceSpecs(node) | ||
| .some(resolved => resolved === parsed.fetchSpec || resolved === parsed.saveSpec) | ||
| } | ||
|
|
||
| const isRegistryNode = (node) => { | ||
|
|
@@ -337,4 +364,5 @@ module.exports = isScriptAllowed | |
| module.exports.isScriptAllowed = isScriptAllowed | ||
| module.exports.isExactVersionDisjunction = isExactVersionDisjunction | ||
| module.exports.getTrustedRegistryIdentity = getTrustedRegistryIdentity | ||
| module.exports.resolvedSourceSpecs = resolvedSourceSpecs | ||
| module.exports.trustedDisplay = trustedDisplay | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -118,6 +118,25 @@ t.test('file path — exact resolved match', t => { | |
| t.end() | ||
| }) | ||
|
|
||
| t.test('file path — link target matches incoming link source', t => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add a negative case here? A registry node (resolved = tarball URL, empty |
||
| const targetPath = require('node:path').resolve('local-pkg') | ||
| const target = node({ | ||
| name: 'local-pkg', | ||
| packageName: 'local-pkg', | ||
| version: '1.0.0', | ||
| }) | ||
| target.resolved = null | ||
| target.path = targetPath | ||
| target.realpath = targetPath | ||
| target.linksIn = new Set([{ resolved: 'file:../local-pkg' }]) | ||
|
|
||
| t.equal(isScriptAllowed(target, { 'file:../local-pkg': true }), true) | ||
| t.equal(isScriptAllowed(target, { 'file:local-pkg': true }), true) | ||
| t.equal(isScriptAllowed(target, { 'file:../local-pkg': false }), false) | ||
| t.equal(isScriptAllowed(target, { 'file:../other': true }), null) | ||
| t.end() | ||
| }) | ||
|
|
||
| t.test('directory key — npa parses absolute paths as type=directory', t => { | ||
| // npa treats absolute paths as { type: 'directory' }, which the | ||
| // matcher shares with the 'file' case. path.resolve produces a | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same root cause leaks into the writer. If a link target has an empty
linksIn(soresolvedis null),resolvedSourceSpecs(node)[0]isnode.realpath, an absolute path.versionedKeyFor/nameKeyForthen take thestartsWith('/')branch and write something like/proj/node_modules/AintoallowScriptsinstead offile:../A. Better to prefer afile:candidate over a bare path, or return null so we don't persist a machine-specific key. Fixing comment 1 with thesize > 0guard mostly covers this too.