`npm audit` fails to audit packages with a local dependency in npm v6.9.0


(Chris Topher) #1

What I Wanted to Do

I wanted to run npm audit in a package using a local dependency with a version starting with file:.

What Happened Instead

npm audit failed with the following obscure message.

npm ERR! code ENOAUDIT
npm ERR! audit Your configured registry (https://registry.npmjs.org/) does not support audit requests, or the audit endpoint is temporarily unavailable.

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2019-03-10T16_20_05_686Z-debug.log

Reproduction Steps

To reproduce, create the following two files:

 * workspace/package-a/package.json
 * workspace/package-b/package.json

The contents of workspace/package-a/package.json are:

{
  "name": "package-a",
  "version": "0.0.0",
  "dependencies": {
    "async": "2.6.2"
  }
}

The contents of workspace/package-b/package.json are:

{
  "name": "package-b",
  "version": "0.0.0",
  "dependencies": {
    "package-a": "file:../package-a"
  }
}

While in the workspace directory, run the following commands:

docker run -it --rm --volume `pwd`:/home/node/workspace --workdir /home/node/workspace node:10.15.1-alpine sh
npm install -g npm@6.9.0
cd package-a
npm install
cd ../package-b
npm install 
npm audit

Details

npm audit fails when a dependency appears in package-lock.json with the requires property:

  "dependencies": {
    "package-a": {
      "version": "file:../package-a",
      "requires": {
        "async": "2.6.2"
      }
    }
  }

Removing the requires property from package-lock.json avoids the error.

To solve this problem, npm audit should ignore or correctly process the requires property for dependencies with a version that begins with file:. Alternatively, npm install could leave out the requires property for dependencies with a version that begins with file:.

After executing the steps to reproduce, the resultant package-lock.json for package-b is:

{
  "name": "package-b",
  "version": "0.0.0",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "package-a": {
      "version": "file:../package-a",
      "requires": {
        "async": "2.6.2"
      }
    }
  }
}

If we remove the requires property and run again, npm audit succeeds:

{
  "name": "package-b",
  "version": "0.0.0",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "package-a": {
      "version": "file:../package-a"
    }
  }
}

When npm audit fails, here is the corresponding log file at ~/.npm/_logs/:

0 info it worked if it ends with ok
1 verbose cli [ '/usr/local/bin/node', '/usr/local/bin/npm', 'audit' ]
2 info using npm@6.9.0
3 info using node@v10.15.1
4 verbose npm-session 52f98ef74b86d7eb
5 http fetch POST 400 https://registry.npmjs.org/-/npm/v1/security/audits 600ms
6 verbose stack Error: Your configured registry (https://registry.npmjs.org/) does not support audit requests, or the audit endpoint is temporarily unavailable.
6 verbose stack     at Bluebird.all.spread.then.catch (/usr/local/lib/node_modules/npm/lib/audit.js:201:18)
6 verbose stack     at tryCatcher (/usr/local/lib/node_modules/npm/node_modules/bluebird/js/release/util.js:16:23)
6 verbose stack     at Promise._settlePromiseFromHandler (/usr/local/lib/node_modules/npm/node_modules/bluebird/js/release/promise.js:512:31)
6 verbose stack     at Promise._settlePromise (/usr/local/lib/node_modules/npm/node_modules/bluebird/js/release/promise.js:569:18)
6 verbose stack     at Promise._settlePromise0 (/usr/local/lib/node_modules/npm/node_modules/bluebird/js/release/promise.js:614:10)
6 verbose stack     at Promise._settlePromises (/usr/local/lib/node_modules/npm/node_modules/bluebird/js/release/promise.js:690:18)
6 verbose stack     at _drainQueueStep (/usr/local/lib/node_modules/npm/node_modules/bluebird/js/release/async.js:138:12)
6 verbose stack     at _drainQueue (/usr/local/lib/node_modules/npm/node_modules/bluebird/js/release/async.js:131:9)
6 verbose stack     at Async._drainQueues (/usr/local/lib/node_modules/npm/node_modules/bluebird/js/release/async.js:147:5)
6 verbose stack     at Immediate.Async.drainQueues [as _onImmediate] (/usr/local/lib/node_modules/npm/node_modules/bluebird/js/release/async.js:17:14)
6 verbose stack     at runCallback (timers.js:705:18)
6 verbose stack     at tryOnImmediate (timers.js:676:5)
6 verbose stack     at processImmediate (timers.js:658:5)
7 verbose cwd /home/node/workspace/package-b
8 verbose Linux 4.9.125-linuxkit
9 verbose argv "/usr/local/bin/node" "/usr/local/bin/npm" "audit"
10 verbose node v10.15.1
11 verbose npm  v6.9.0
12 error code ENOAUDIT
13 error audit Your configured registry (https://registry.npmjs.org/) does not support audit requests, or the audit endpoint is temporarily unavailable.
14 verbose exit [ 1, true ]

Platform Info

$ npm --versions
{ 'package-b': '0.0.0',
  npm: '6.9.0',
  ares: '1.15.0',
  cldr: '33.1',
  http_parser: '2.8.0',
  icu: '62.1',
  modules: '64',
  napi: '3',
  nghttp2: '1.34.0',
  node: '10.15.1',
  openssl: '1.1.0j',
  tz: '2018e',
  unicode: '11.0',
  uv: '1.23.2',
  v8: '6.8.275.32-node.12',
  zlib: '1.2.11' }
$ node -p process.platform
linux

(Robert Rothermel) #2

We discovered the same problem yesterday, and a different workaround. If you clone the Facebook Flux repo, you can duplicate the original error by running:

cd flux/examples/flux-jest-container
npm install # or npm install --package-lock-only
npm audit

In the package.json file for the example code, it lists the root directory of the project as a dependency:

"dependencies": {
  "flux": "../../."
}

As the original post mentioned, removing the requires block from the package-lock.json file allows npm audit to run successfully. Alternatively, symlinking the parent directory into the example directory and updating the path in package.json to not include a ../ also allows npm audit to complete:

cd flux/examples/flux-jest-container
ln -s ../../. flux
npm install ./flux
# after this step, the package.json dependency reads { "flux": "file:flux" }
# alternatively, manually entering { "flux": "./flux" } also works
npm audit # succeeds

In this case we see the issue is related to referencing a local path in a parent directory (using file:../), and moving the local path into a child of the current directory resolves the issue.

If you compare the request sent to /-/npm/v1/security/audits from an audit with a parent local path and a child local path (failing vs working), the difference seems to be whether or not the dependencies property is populated for the local path: