Skip to content
Merged
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
17 changes: 9 additions & 8 deletions tap-snapshots/test/lib/docs.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,10 @@ The value \`private\` is an alias for \`restricted\`.
* Default: false
* Type: Boolean

When running \`npm outdated\` and \`npm ls\`, setting \`--all\` will show all
outdated or installed packages, rather than only those directly depended
upon by the current project.
Show or act on all packages, not just the ones your project directly depends
on. For \`npm outdated\` and \`npm ls\` this lists every outdated or installed
package. For \`npm approve-scripts\` and \`npm deny-scripts\` it selects every
package with pending install scripts.



Expand Down Expand Up @@ -3019,7 +3020,7 @@ Options:
[-a|--all] [--allow-scripts-pending] [--no-allow-scripts-pin] [--json]

-a|--all
When running \`npm outdated\` and \`npm ls\`, setting \`--all\` will show
Show or act on all packages, not just the ones your project directly

--allow-scripts-pending
List packages with install scripts that are not yet covered by the
Expand Down Expand Up @@ -3532,7 +3533,7 @@ Options:
[-a|--all] [--allow-scripts-pending] [--no-allow-scripts-pin] [--json]

-a|--all
When running \`npm outdated\` and \`npm ls\`, setting \`--all\` will show
Show or act on all packages, not just the ones your project directly

--allow-scripts-pending
List packages with install scripts that are not yet covered by the
Expand Down Expand Up @@ -4807,7 +4808,7 @@ Options:
[--workspaces] [--include-workspace-root] [--install-links]

-a|--all
When running \`npm outdated\` and \`npm ls\`, setting \`--all\` will show
Show or act on all packages, not just the ones your project directly

--json
Whether or not to output JSON data, rather than the normal output.
Expand Down Expand Up @@ -4954,7 +4955,7 @@ Options:
[--workspaces] [--include-workspace-root] [--install-links]

-a|--all
When running \`npm outdated\` and \`npm ls\`, setting \`--all\` will show
Show or act on all packages, not just the ones your project directly

--json
Whether or not to output JSON data, rather than the normal output.
Expand Down Expand Up @@ -5103,7 +5104,7 @@ Options:
[--before <date>] [--min-release-age <days>]

-a|--all
When running \`npm outdated\` and \`npm ls\`, setting \`--all\` will show
Show or act on all packages, not just the ones your project directly

--json
Whether or not to output JSON data, rather than the normal output.
Expand Down
4 changes: 3 additions & 1 deletion workspaces/arborist/lib/arborist/isolated-reifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const { join } = require('node:path')
const { depth } = require('treeverse')
const crypto = require('node:crypto')
const { IsolatedNode, IsolatedLink } = require('../isolated-classes.js')
const nameFromFolder = require('@npmcli/name-from-folder')

// generate short hash key based on the dependency tree starting at this node
const getKey = (startNode) => {
Expand Down Expand Up @@ -160,7 +161,8 @@ module.exports = cls => class IsolatedReifier extends cls {
result.id = this.counter++
/* istanbul ignore next - packageName is always set for real packages */
result.name = result.isWorkspace ? (node.packageName || node.name) : node.name
result.packageName = node.packageName || node.name
// strip any path traversal from package.json name fields before they hit path.join below
result.packageName = nameFromFolder(node.packageName || node.path)
result.package = { ...node.package }
result.package.bundleDependencies = undefined

Expand Down
5 changes: 5 additions & 0 deletions workspaces/arborist/lib/isolated-classes.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ class IsolatedNode {
return !!(hasInstallScript || install || preinstall || postinstall)
}

/* istanbul ignore next -- emulate lib/node.js */
get packageName () {
return this.package.name || null
}

get version () {
return this.package.version
}
Expand Down
61 changes: 61 additions & 0 deletions workspaces/arborist/test/arborist/reify.js
Original file line number Diff line number Diff line change
Expand Up @@ -3942,6 +3942,67 @@ t.test('workspace installs retain existing versions with newer package specs', a
'another-cool-package package.json should be updated to abbrev@1.0.4')
})

for (const poisoned of ['../../../escape-target', '@evil/../../../escape-target']) {
t.test(`install strategy linked sanitizes traversal in lockfile name (${poisoned})`, async t => {
// a poisoned lockfile name field would otherwise escape node_modules/.store
const testDir = t.testdir({
'package.json': JSON.stringify({
dependencies: {
abbrev: '1.1.1',
},
}),
'package-lock.json': JSON.stringify({
lockfileVersion: 3,
requires: true,
packages: {
'': {
dependencies: {
abbrev: '1.1.1',
},
},
'node_modules/abbrev': {
name: poisoned,
version: '1.1.1',
resolved: 'https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz',
integrity: 'sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==',
},
},
}),
})

const arb = new Arborist({
path: testDir,
registry: 'https://registry.npmjs.org',
cache: resolve(testDir, 'cache'),
installStrategy: 'linked',
packageLockOnly: true,
})
await arb.reify({ installStrategy: 'linked', packageLockOnly: true })

const external = arb.idealGraph.external
t.equal(external.length, 1, 'one external dep planned')

const pkgName = external[0].packageName
t.notMatch(pkgName, /\.\./, 'packageName has no traversal segments')
t.ok(!pkgName.includes('/') || pkgName.startsWith('@'),
'packageName is a single segment (or @scope/name)')

// joining the sanitized name into the .store layout must not escape
const storePrefix = resolve(testDir, 'node_modules/.store/key/node_modules')
const projected = resolve(storePrefix, pkgName)
t.ok(projected.startsWith(storePrefix), 'projected path stays inside .store')

// belt-and-suspenders: nothing should have been written outside testDir,
// even if a future change starts materializing paths during reify
t.notOk(fs.existsSync(resolve(testDir, '..', 'escape-target')),
'no escape-target leaked one level above testDir')
t.notOk(fs.existsSync(resolve(testDir, '..', '..', 'escape-target')),
'no escape-target leaked two levels above testDir')
t.notOk(fs.existsSync(resolve(testDir, '..', '..', '..', 'escape-target')),
'no escape-target leaked three levels above testDir')
})
}

t.test('externalOptionalDependencies excludes inert optional node with installStrategy linked', async t => {
const testDir = t.testdir({
'package.json': JSON.stringify({
Expand Down
13 changes: 7 additions & 6 deletions workspaces/config/lib/definitions/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,10 @@ const definitions = {
type: Boolean,
short: 'a',
description: `
When running \`npm outdated\` and \`npm ls\`, setting \`--all\` will show
all outdated or installed packages, rather than only those directly
depended upon by the current project.
Show or act on all packages, not just the ones your project directly
depends on. For \`npm outdated\` and \`npm ls\` this lists every outdated
or installed package. For \`npm approve-scripts\` and \`npm deny-scripts\`
it selects every package with pending install scripts.
`,
flatten,
}),
Expand Down Expand Up @@ -2347,13 +2348,13 @@ const definitions = {
If you ask npm to install a package and don't tell it a specific version,
then it will install the specified tag.

It is the tag added to the package@version specified in the
It is the tag added to the package@version specified in the
\`npm dist-tag add\` command, if no explicit tag is given.

When used by the \`npm diff\` command, this is the tag used to fetch the
tarball that will be compared with the local files by default.
If used in the \`npm publish\` command, this is the tag that will be

If used in the \`npm publish\` command, this is the tag that will be
added to the package submitted to the registry.
`,
flatten (key, obj, flatOptions) {
Expand Down
Loading