CycloneDX / CycloneDX/cyclonedx-node-npm
[BUG] `--omit=dev` and `--omit=optional` flags don't exclude `devOptional` dependencies, causing misleading output
- Dominant language
- JavaScript
- Stars
- 150
- Forks
- 29
- Avg merge
- 1h 3m
- Merged PRs (30d)
- 1
Description
## Describe the bug
With #1307, dependency tree resolution is mainly based on the `npm ls` output. The `npm ls` command's `--omit=dev` and `--omit=optional` flags are misleading when dealing with `devOptional` dependencies. These dependencies are not excluded by either flag individually or in combination, despite their development-oriented nature.
[npm documentation states](https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json):
> dev, optional, devOptional: If the package is strictly part of the devDependencies tree, then dev will be true. If it is strictly part of the optionalDependencies tree, then optional will be set. If it is both a dev dependency and an optional dependency of a non-dev dependency, then devOptional will be set. (An optional dependency of a dev dependency will have both dev and optional set.)
Following this logic, I'd expect, using `--omit=dev` and `--omit=optional` at the same time, would also omit `devOptional`s but it does not.
## To Reproduce
Scanning [cyclonedx-node-npm](https://github.com/CycloneDX/cyclonedx-node-npm) includes the `devOptional` dependency `@isaacs/cliui@8.0.2`:
- `git clone https://github.com/CycloneDX/cyclonedx-node-npm`
- `pushd cyclonedx-node-npm`
- `npm install`
- `popd`
- `npx @cyclonedx/cyclonedx-npm@4.0.0 --verbose --verbose --verbose --flatten-components --short-PURLs --spec-version 1.6 --output-format JSON --output-file - --omit dev --omit optional -- cyclonedx-node-npm/package.json > cyclonedx-node-npm/cyclonedx-node-npm-4.cdx.json`
Produces the [cyclonedx-node-npm-4.cdx.json](https://github.com/user-attachments/files/21403017/cyclonedx-node-npm-4.cdx.json) file with the following `cliui@8.0.2` entry:
```json5
{
// ...
"components": [
// ...
{
"type": "library",
"name": "cliui",
"group": "@isaacs",
"version": "8.0.2",
"bom-ref": "@cyclonedx/cyclonedx-npm@4.0.0|@isaacs/cliui@8.0.2",
"author": "Ben Coe",
"description": "easily create complex multi-column command-line-interfaces",
"licenses": ...,
"purl": "pkg:npm/%40isaacs/cliui@8.0.2",
"externalReferences": ...
"properties": [
{
"name": "cdx:npm:package:development",
"value": "true"
},
{
"name": "cdx:npm:package:path",
"value": "node_modules/@isaacs/cliui"
}
]
},
// ...
"dependencies": [
// ...
{
"ref": "@cyclonedx/cyclonedx-npm@4.0.0|jackspeak@3.4.3",
"dependsOn": [
"@cyclonedx/cyclonedx-npm@4.0.0|@isaacs/cliui@8.0.2",
"@cyclonedx/cyclonedx-npm@4.0.0|@pkgjs/parseargs@0.11.0"
]
},
// ...
}
```
## Expected behavior
Analyzing the whole dependency path for `@isaacs/cliui`,
```text
@cyclonedx/cyclonedx-npm (root package)
└── @cyclonedx/cyclonedx-library@8.5.0
└── libxmljs2@0.37.0 (optional dependency)
└── node-gyp@11.2.0
└── make-fetch-happen@14.0.3
└── cacache@19.0.1
└── glob@10.4.5
└── jackspeak@3.4.3
└── @isaacs/cliui@8.0.2
```
shows that, `@isaacs/cliui` has been pulled through a long tail of dependencies, but mainly by `libxmljs2@0.37.0` optional dependency of the `@cyclonedx/cyclonedx-library@8.5.0`. I'd expect that it would not show up after all.
## Screenshots or output-paste
CLI output of the `npx @cyclonedx/cyclonedx-npm@4.0.0 --verbose --verbose --verbose --flatten-components --short-PURLs --spec-version 1.6 --output-format JSON --output-file - --omit dev --omit optional -- cyclonedx-node-npm/package.json > cyclonedx-node-npm/cyclonedx-node-npm-4.cdx.json` given above is:
```text
DEBUG | options: {"ignoreNpmErrors":false,"packageLockOnly":false,"omit":["dev","optional"],"workspace":[],"workspaces":true,"gatherLicenseTexts":false,"flattenComponents":true,"shortPURLs":true,"specVersion":"1.6","outputFormat":"JSON","outputFile":"-","mcType":"application","verbose":3}
DEBUG | makeNpmRunner caused execFileSync "/opt/homebrew/Cellar/node@22/22.17.1/bin/node" with "-- /opt/homebrew/Cellar/node@22/22.17.1/lib/node_modules/npm/bin/npm-cli.js"
DEBUG | found NPM version "10.9.2"
DEBUG | packageFile: /Users/addiha5/work/cyclonedx-node-npm/package.json
INFO | projectDir: /Users/addiha5/work/cyclonedx-node-npm
INFO | detected a `node_modules` dir
LOG | gathering BOM data ...
INFO | gathering dependency tree ...
DEBUG | npm-ls: run npm with ["ls","--json","--long","--all","--omit=dev","--omit=optional"] in "/Users/addiha5/work/cyclonedx-node-npm"
INFO | building BOM ...
LOG | serializing BOM ...
LOG | try validating BOM result ...
INFO | BOM result appears valid
LOG | writing BOM to -
INFO | wrote 366448 bytes to -
```
Indicating that `npm ls --json --long --all --omit=dev --omit=optional` has been called under the hood.
Calling `npm ls --json --long --all --omit=dev --omit=optional > npm-ls-no-dev-op.json` would give me [npm-ls-no-dev-op.json](https://github.com/user-attachments/files/21402999/npm-ls-no-dev-op.json).
## Environment
- _@cyclonedx/cyclonedx-npm_ version: v4.0.0
- NPM version: 10.9.2
- Node version: v22.17.1
- OS: macOS 15.5
## Additional context
Add any other context about the problem here.
## Contribution
- [x] I am willing to provide a fix (given that someone give some pointers to the right direction)
- [ ] I will wait until somebody else fixes it
Contributor guide
Assessment
This issue has not been assessed yet.