Skip to content

Commit 20ea2f5

Browse files
committed
fix: correctly return custom npm invocation error messages
1 parent 9ccc4df commit 20ea2f5

File tree

1 file changed

+23
-48
lines changed

1 file changed

+23
-48
lines changed

src/providers/javascript_npm.js

Lines changed: 23 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,40 @@
1-
import { execSync } from "node:child_process"
21
import fs from 'node:fs'
32
import os from "node:os";
4-
import { getCustomPath, handleSpacesInPath } from "../tools.js";
3+
import { getCustomPath, invokeCommand } from "../tools.js";
54
import path from 'node:path'
65
import Sbom from '../sbom.js'
76
import { PackageURL } from 'packageurl-js'
87

9-
export var npmInteractions = {
10-
listing: function runNpmListing(npmListing) {
11-
let npmOutput = execSync(npmListing, err => {
12-
if (err) {
13-
throw new Error('failed to get npmOutput json from npm')
14-
}
15-
});
16-
return npmOutput;
8+
var npmInteractions = {
9+
listing: function runNpmListing(npm, manifestDir, includeAll) {
10+
return invokeCommand(npm, ['ls', includeAll ? '--all' : '', '--omit=dev', '--package-lock-only', '--json', '--prefix', manifestDir], error => {
11+
throw new Error('failed to get npmOutput json from npm', {cause: error})
12+
}).toString()
1713
},
1814
version: function checkNpmVersion(npm) {
19-
execSync(`${handleSpacesInPath(npm)} --version`, err => {
20-
if (err) {
21-
throw new Error('npm is not accessible')
15+
invokeCommand(npm, ['--version'], error => {
16+
if (error.code === 'ENOENT') {
17+
throw new Error(`npm is not accessible at ${npm}`, {})
2218
}
19+
throw new Error('failed to check for npm', {cause: error})
2320
})
2421
},
2522
createPackageLock: function createPackageLock(npm, manifestDir) {
26-
// in windows os, --prefix flag doesn't work, it behaves really weird , instead of installing the package.json fromm the prefix folder,
27-
// it's installing package.json (placed in current working directory of process) into prefix directory, so
23+
// in windows os, --prefix flag doesn't work, it behaves really weird , instead of installing the package.json fromm the prefix folder,
24+
// it's installing package.json (placed in current working directory of process) into prefix directory, so
2825
let originalDir = process.cwd()
2926
if(os.platform() === 'win32') {
3027
process.chdir(manifestDir)
3128
}
32-
execSync(`${handleSpacesInPath(npm)} i --package-lock-only --prefix ${handleSpacesInPath(manifestDir)}`, err => {
33-
if (err) {
34-
throw new Error('failed to create npmOutput list')
35-
}
29+
invokeCommand(npm, ['i', '--package-lock-only', '--prefix', manifestDir], error => {
30+
throw new Error('failed to create npmOutput list', {cause: error})
3631
})
3732
if(os.platform() === 'win32') {
3833
process.chdir(originalDir)
3934
}
4035
}
4136
}
42-
export default { isSupported, validateLockFile, provideComponent, provideStack, npmInteractions }
37+
export default { isSupported, validateLockFile, provideComponent, provideStack }
4338

4439
/** @typedef {import('../provider').Provider} */
4540

@@ -100,22 +95,11 @@ function provideStack(manifest, opts = {}) {
10095
function provideComponent(manifest, opts = {}) {
10196
return {
10297
ecosystem,
103-
content: getSBOM(manifest, opts,false),
98+
content: getSBOM(manifest, opts, false),
10499
contentType: 'application/vnd.cyclonedx+json'
105100
}
106101
}
107102

108-
/**
109-
*
110-
* @param {string} npm the npm binary path
111-
* @param {string }allFilter can be "-all" ( for stack analysis) or empty string ( for component analysis).
112-
* @param {string} manifestDir path to manifest' directory.
113-
* @return {string} returns a string containing the result output.
114-
*/
115-
function getNpmListing(npm, allFilter, manifestDir) {
116-
return `${handleSpacesInPath(npm)} ls${allFilter} --omit=dev --package-lock-only --json --prefix ${manifestDir}`;
117-
}
118-
119103
/**
120104
* Create SBOM json string for npm Package.
121105
* @param {string} manifest - path for package.json
@@ -130,9 +114,7 @@ function getSBOM(manifest, opts = {}, includeTransitive) {
130114
npmInteractions.version(npm);
131115
let manifestDir = path.dirname(manifest)
132116
npmInteractions.createPackageLock(npm, manifestDir);
133-
let allFilter = includeTransitive? " --all" : ""
134-
let npmListing = getNpmListing(npm, allFilter, handleSpacesInPath(manifestDir))
135-
let npmOutput = npmInteractions.listing(npmListing);
117+
let npmOutput = npmInteractions.listing(npm, manifestDir, includeTransitive);
136118
let depsObject = JSON.parse(npmOutput);
137119
let rootName = depsObject["name"]
138120
let rootVersion = depsObject["version"]
@@ -165,16 +147,11 @@ function getSBOM(manifest, opts = {}, includeTransitive) {
165147
*/
166148
function toPurl(name, version) {
167149
let parts = name.split("/");
168-
var pkg
169-
if(parts.length === 2 )
170-
{
171-
pkg = new PackageURL('npm',parts[0],parts[1],version,undefined,undefined);
172-
}
173-
else
174-
{
175-
pkg = new PackageURL('npm',undefined,parts[0],version,undefined,undefined);
150+
if(parts.length === 2) {
151+
return new PackageURL('npm',parts[0],parts[1],version,undefined,undefined);
152+
} else {
153+
return new PackageURL('npm',undefined,parts[0],version,undefined,undefined);
176154
}
177-
return pkg
178155
}
179156

180157
/**
@@ -188,13 +165,11 @@ function addAllDependencies(sbom, from, dependencies) {
188165
Object.entries(dependencies)
189166
.filter(entry => entry[1].version !== undefined)
190167
.forEach(entry => {
191-
let name, artifact ;
192-
[name, artifact] = entry;
168+
let [name, artifact] = entry;
193169
let purl = toPurl(name,artifact.version);
194170
sbom.addDependency(from,purl)
195171
let transitiveDeps = artifact.dependencies
196-
if(transitiveDeps !== undefined)
197-
{
172+
if(transitiveDeps !== undefined) {
198173
addAllDependencies(sbom,sbom.purlToComponent(purl),transitiveDeps)
199174
}
200175
});

0 commit comments

Comments
 (0)