From 105696ab7c6d1d9540b6c43fff596476f9050609 Mon Sep 17 00:00:00 2001 From: Rykee Date: Tue, 28 Jul 2026 16:47:36 +0200 Subject: [PATCH 1/2] fix(npm): prevent workspace hoisting and ignore npm ls errors during BOM generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running cyclonedx-npm BOM generation in npm workspace projects, the cyclonedx-npm package installed via --prefix gets its native dependencies hoisted into the workspace root node_modules. This causes npm ls to report them as extraneous, resulting in a non-zero exit code with npm v11+. Additionally, packages overridden via npm overrides (e.g. for security fixes) are reported as invalid by npm ls because the installed version does not exactly match the version declared by the dependent package. Fix by: - Adding --no-workspaces to the install command to prevent dependency hoisting - Adding --ignore-npm-errors to the cyclonedx-npm run command to tolerate npm ls warnings in workspace setups with overrides Signed-off-by: Márk Mátray Signed-off-by: Rykee --- pkg/npm/bom.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/npm/bom.go b/pkg/npm/bom.go index cb19f3c93a..316b29781b 100644 --- a/pkg/npm/bom.go +++ b/pkg/npm/bom.go @@ -143,8 +143,8 @@ func (exec *Execute) generatePnpmBOMFiles(packageJSONFiles []string, cliPath str // createNpmBOM generates a BOM for npm/yarn projects using cyclonedx-npm func (exec *Execute) createNpmBOM(packageJSONFiles []string) error { // Primary attempt with cyclonedx-npm - cycloneDxNpmInstallParams := []string{"install", "--no-save", cycloneDxNpmPackageVersion, "--prefix", tmpInstallFolder} - cycloneDxNpmRunParams := []string{"--output-format", "XML", "--spec-version", CycloneDxSchemaVersion, "--omit", "dev", "--output-file"} + cycloneDxNpmInstallParams := []string{"install", "--no-save", cycloneDxNpmPackageVersion, "--prefix", tmpInstallFolder, "--no-workspaces"} + cycloneDxNpmRunParams := []string{"--output-format", "XML", "--spec-version", CycloneDxSchemaVersion, "--omit", "dev", "--ignore-npm-errors", "--output-file"} err := exec.createBOMWithParams(cycloneDxNpmInstallParams, cycloneDxNpmRunParams, packageJSONFiles) if err != nil { From 59689485c2cb2e298e9bac1b51e0144ee1097220 Mon Sep 17 00:00:00 2001 From: Rykee Date: Tue, 28 Jul 2026 16:47:36 +0200 Subject: [PATCH 2/2] test(npm): update BOM tests for --no-workspaces and --ignore-npm-errors flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Márk Mátray Signed-off-by: Rykee --- pkg/npm/bom_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/npm/bom_test.go b/pkg/npm/bom_test.go index 70ebe47b38..c1918ec6e6 100644 --- a/pkg/npm/bom_test.go +++ b/pkg/npm/bom_test.go @@ -30,7 +30,7 @@ func TestBom(t *testing.T) { Options: options, } err := exec.CreateBOM([]string{"package.json", filepath.Join("src", "package.json")}) - cycloneDxNpmInstallParams := []string{"install", "--no-save", "@cyclonedx/cyclonedx-npm@2.1.0", "--prefix", "./tmp"} + cycloneDxNpmInstallParams := []string{"install", "--no-save", "@cyclonedx/cyclonedx-npm@2.1.0", "--prefix", "./tmp", "--no-workspaces"} cycloneDxNpmRunParams := []string{ "--output-format", "XML", @@ -38,6 +38,7 @@ func TestBom(t *testing.T) { CycloneDxSchemaVersion, "--omit", "dev", + "--ignore-npm-errors", "--output-file", } @@ -56,7 +57,7 @@ func TestBom(t *testing.T) { utils.AddFile("package-lock.json", []byte("{}")) utils.AddFile(filepath.Join("src", "package.json"), []byte("{\"scripts\": { \"ci-lint\": \"exit 0\" } }")) utils.AddFile(filepath.Join("src", "package-lock.json"), []byte("{}")) - utils.execRunner.ShouldFailOnCommand = map[string]error{"npm install --no-save @cyclonedx/cyclonedx-npm@2.1.0 --prefix ./tmp": fmt.Errorf("failed to install CycloneDX BOM")} + utils.execRunner.ShouldFailOnCommand = map[string]error{"npm install --no-save @cyclonedx/cyclonedx-npm@2.1.0 --prefix ./tmp --no-workspaces": fmt.Errorf("failed to install CycloneDX BOM")} options := ExecutorOptions{} options.DefaultNpmRegistry = "foo.bar" @@ -86,6 +87,7 @@ func TestBom(t *testing.T) { "--output-format", "XML", "--spec-version", CycloneDxSchemaVersion, "--omit", "dev", + "--ignore-npm-errors", "--output-file", "bom-npm.xml", "package.json", }, " ")