cli icon indicating copy to clipboard operation
cli copied to clipboard

[BUG] `npm ci` erroneously installs optional OS-constrained transitive dependency through direct shrinkwrap dependency

Open restjohn opened this issue 7 months ago • 2 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

This issue exists in the latest npm version

  • [X] I am using the latest npm

Current Behavior

Consider a package, lib1, with the following characteristics.

  • has an optionalDependency, with an OS constraint, such as fsevents package.json
    { ... "os": [ "darwin" ] ... }
    
  • published with a shrinkwrap package descriptor
  • shrinkwrap was generated on the platform compatible with the OS-constrained dependency

Developer A creates another package, app1, which depends on lib1, and generates app1's package-lock.json with npm install also on the platform matching said OS constraint.

Developer B, OR a CI process, on a different platform from said OS constraint, runs npm ci to install app1's dependencies. npm ci produces an error like the following.

[.../app1> npm ci
npm error code EBADPLATFORM
npm error notsup Unsupported platform for [email protected]: wanted {"os":"darwin"} (current: {"os":"linux"})
npm error notsup Valid os:  darwin
npm error notsup Actual os: linux
npm error A complete log of this run can be found in: /root/.npm/_logs/2024-07-02T12_41_06_204Z-debug-0.log

Examining app1's package-lock.json reveals that npm does not include an "optional": true entry in the package-lock block for lib1's fsevents dependency.

Expected Behavior

npm ci should retain the optional nature of the platform-specific dependency and proceed with a successful clean install of app1's dependencies regardless of the dependencies.

Steps To Reproduce

  1. On a linux platform, clone the demo repository: https://github.com/restjohn/issues.npm.shrinkwrap_optional_dep.
  2. Use npm 10.8.1, latest at the time of this writing.
  3. cd app1
  4. npm ci
  5. npm should produce an error as in the Current Behavior section above.

Please see the README in the demo repository for quite a bit more detail about the nuances of this behavior.

Also note that the demo repository package lib1.shrinkwrap references the fsevents package through a devDependency, and npm should not be attempting to install lib1.shrinkwrap devDependencies from the app1 package anyway.

Environment

  • npm: 10.8.1
  • Node.js: 20.15.0
  • OS Name: Debian GNU/Linux 12 (bookworm)
  • System Model Name: Node 20 Slim Docker image
  • npm config:
; node bin location = /usr/local/bin/node
; node version = v20.15.0
; npm local prefix = /npm_transitive_os_dep/app1
; npm version = 10.8.1
; cwd = /npm_transitive_os_dep/app1
; HOME = /root
; Run `npm config ls -l` to show all defaults.

restjohn avatar Jul 02 '24 13:07 restjohn