npm / npm/cli

[BUG] cleaning up failed optional dep removes bins that were never linked by that dep

Open
#4,362 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug Priority 2 Release 8.x
Dominant language
JavaScript
Stars
10.1k
Forks
4.7k
Avg merge
2d 2h
Merged PRs (30d)
19

Description

Is there an existing issue for this?
  • I have searched the existing issues
This issue exists in the latest npm version
  • I am using the latest npm
Current Behavior

Consider a package like this:

{
  "name": "@tier.run/sdk",
  "version": "1.2.3",
  "optionalDependencies": {
    "@tier.run/cli-darwin-amd64": "~0.0.0-0 || 0 || 1",
    "@tier.run/cli-darwin-arm64": "~0.0.0-0 || 0 || 1",
    "@tier.run/cli-linux-amd64": "~0.0.0-0 || 0 || 1",
    "@tier.run/cli-linux-arm64": "~0.0.0-0 || 0 || 1",
    "@tier.run/cli-windows-amd64": "~0.0.0-0 || 0 || 1",
    "@tier.run/cli-windows-arm64": "~0.0.0-0 || 0 || 1"
  }
}

Each of these @tier.run/cli-... packages has a single binary as their bin, named tier, and a cpu and os requirement. For example:

{
  "name": "@tier.run/cli-darwin-arm64",
  "version": "0.0.0-2022-02-02-14-38-04",
  "bin": { "tier": "./tier" },
  "files": ["tier"],
  "os": ["darwin"],
  "cpu": ["arm64"]
}

The intention is that at most one of these packages will be installable, and have its tier binary linked to node_modules/.bin/tier.

However, this doesn't work! What happens is that Arborist adds the other 5 mismatched optional deps to the this[_trashList] along with their bins, and then deletes the tier binary from the package that actually was installed.

I'm not sure what the right answer is here, but it seems like:

  • Nodes that were never reified should not have their bins removed, that seems obvious, but it's of course much less obvious to know how to determine that at trash collection time.
  • Maybe it should track the Node that was the source of the bin (updating as each Node has its bins linked, in the case of clobbering), and only remove it if it's still to that node being removed?
  • Maybe the _trashList should somehow track "only delete if it's a symlink to ${path}, otherwise ignore"?

This also could be not quite a security issue, but definitely an annoying issue if a module were to add an optional dep with "os":["this-does-not-exist"],"bin":{"express":"x","babel":"x","jest":"x",...} in its package.json. The OS would never match, and then arborist would delete all the bins.

Expected Behavior

When multiple optional deps are installed which would all write to the same bin, and only one of them survives the os/cpu checks, the bin should end up linked from the working optional dep.

Steps To Reproduce

described above

Environment
  • npm: 8.4.0
  • Node.js: any version
  • OS Name: Darwin
  • System Model Name: Darwin moxy.lan 21.2.0 Darwin Kernel Version 21.2.0: Sun Nov 28 20:28:41 PST 2021; root:xnu-8019.61.5~1/RELEASE_ARM64_T6000 arm64
  • npm config:
; "user" config from /Users/isaacs/.npmrc

access = "public" 
foo = "baz" 
script-shell = "bash" 
sign-git-commit = true 
sign-git-tag = true 

; node bin location = /usr/local/bin/node
; cwd = /Users/isaacs/dev/tierdev/node-sdk
; HOME = /Users/isaacs
; Run `npm config ls -l` to show all defaults.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing Arborist's this[_trashList] handling and the bin-linking and cleanup paths described in the issue. Reproduce the package setup with platform-specific optional dependencies that share the tier bin. Done means the surviving optional dependency's bin remains linked and bins from mismatched dependencies do not remove it.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, nodejs
Domain
cli, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.