Skip to content

Commit 2473e74

Browse files
authored
fix: correctly return custom golang invocation error messages (#180)
1 parent 5a4f868 commit 2473e74

File tree

2 files changed

+42
-70
lines changed

2 files changed

+42
-70
lines changed

src/providers/golang_gomodules.js

Lines changed: 34 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
// import {exec} from "child_process";
2-
import { execSync } from "node:child_process"
31
import fs from 'node:fs'
42
import { EOL } from "os";
5-
import { getCustom, getCustomPath, handleSpacesInPath } from "../tools.js";
3+
import { getCustom, getCustomPath, invokeCommand } from "../tools.js";
64
import path from 'node:path'
75
import Sbom from '../sbom.js'
86
import { PackageURL } from 'packageurl-js'
@@ -64,10 +62,6 @@ function provideComponent(manifest, opts = {}) {
6462
}
6563
}
6664

67-
function getGoGraphCommand(goBin) {
68-
return `${handleSpacesInPath(goBin)} mod graph `;
69-
}
70-
7165
/**
7266
*
7367
* @param {string} edge containing an edge of direct graph of source dependency (parent) and target dependency (child)
@@ -85,36 +79,21 @@ function getChildVertexFromEdge(edge) {
8579
return edge.split(" ")[1];
8680
}
8781

88-
89-
function getGoModGraph(goGraphCommand, options) {
90-
return execSync(goGraphCommand, options).toString()
91-
//
92-
// let result = ""
93-
// return new Promise((resolveF => {
94-
// child.stdout.on("data", (x) => result+=x)
95-
// child.stderr.on("data", (x) => result+=x)
96-
// child.on("exit", () => resolveF(result))
97-
// }))
98-
}
99-
10082
/**
10183
*
10284
* @param line one row from go.mod file
10385
* @return {boolean} whether line from go.mod should be considered as ignored or not
10486
*/
10587
function ignoredLine(line) {
10688
let result = false
107-
if(line.match(".*exhortignore.*"))
108-
{
109-
if(line.match(".+//\\s*exhortignore") || line.match(".+//\\sindirect (//)?\\s*exhortignore"))
110-
{
89+
if(line.match(".*exhortignore.*")) {
90+
if(line.match(".+//\\s*exhortignore") || line.match(".+//\\sindirect (//)?\\s*exhortignore")) {
11191
let trimmedRow = line.trim()
11292
if(!trimmedRow.startsWith("module ") && !trimmedRow.startsWith("go ") && !trimmedRow.startsWith("require (") && !trimmedRow.startsWith("require(")
11393
&& !trimmedRow.startsWith("exclude ") && !trimmedRow.startsWith("replace ") && !trimmedRow.startsWith("retract ") && !trimmedRow.startsWith("use ")
11494
&& !trimmedRow.includes("=>"))
11595
{
116-
if( trimmedRow.startsWith("require ") || trimmedRow.match("^[a-z.0-9/-]+\\s{1,2}[vV][0-9]\\.[0-9](\\.[0-9]){0,2}.*"))
117-
{
96+
if( trimmedRow.startsWith("require ") || trimmedRow.match("^[a-z.0-9/-]+\\s{1,2}[vV][0-9]\\.[0-9](\\.[0-9]){0,2}.*")) {
11897
result = true
11998
}
12099
}
@@ -266,32 +245,34 @@ function getSBOM(manifest, opts = {}, includeTransitive) {
266245
// get custom goBin path
267246
let goBin = getCustomPath('go', opts)
268247
// verify goBin is accessible
269-
execSync(`${handleSpacesInPath(goBin)} version`, err => {
270-
if (err) {
271-
throw new Error('go binary is not accessible')
248+
try {
249+
invokeCommand(goBin, ['version'])
250+
} catch(error) {
251+
if (error.code === 'ENOENT') {
252+
throw new Error(`go binary is not accessible at "${goBin}"`)
272253
}
273-
})
254+
throw new Error(`failed to check for go binary`, {cause: error})
255+
}
274256
let manifestDir = path.dirname(manifest)
275-
let goGraphCommand = getGoGraphCommand(goBin)
276-
let options = {cwd: manifestDir}
277-
let goGraphOutput
278-
goGraphOutput = getGoModGraph(goGraphCommand, options);
257+
try {
258+
var goGraphOutput = invokeCommand(goBin, ['mod', 'graph'], {cwd: manifestDir}).toString()
259+
} catch(error) {
260+
throw new Error('failed to invoke go binary for module graph', {cause: error})
261+
}
279262
let ignoredDeps = getIgnoredDeps(manifest);
280263
let allIgnoredDeps = ignoredDeps.map((dep) => dep.toString())
281264
let sbom = new Sbom();
282265
let rows = goGraphOutput.split(getLineSeparatorGolang());
283266
let root = getParentVertexFromEdge(rows[0])
284-
let matchManifestVersions = getCustom("MATCH_MANIFEST_VERSIONS","false",opts);
267+
let matchManifestVersions = getCustom("MATCH_MANIFEST_VERSIONS", "false", opts);
285268
if(matchManifestVersions === "true") {
286-
{
287-
performManifestVersionsCheck(root, rows, manifest)
288-
}
269+
performManifestVersionsCheck(root, rows, manifest)
289270
}
290-
let mainModule = toPurl(root, "@", undefined)
271+
272+
const mainModule = toPurl(root, "@", undefined)
291273
sbom.addRoot(mainModule)
292-
let exhortGoMvsLogicEnabled = getCustom("EXHORT_GO_MVS_LOGIC_ENABLED","false",opts)
293-
if(includeTransitive && exhortGoMvsLogicEnabled === "true")
294-
{
274+
const exhortGoMvsLogicEnabled = getCustom("EXHORT_GO_MVS_LOGIC_ENABLED", "false", opts)
275+
if(includeTransitive && exhortGoMvsLogicEnabled === "true") {
295276
rows = getFinalPackagesVersionsForModule(rows,manifest,goBin)
296277
}
297278
if (includeTransitive) {
@@ -341,22 +322,16 @@ function getSBOM(manifest, opts = {}, includeTransitive) {
341322
function toPurl(dependency, delimiter, qualifiers) {
342323
let lastSlashIndex = dependency.lastIndexOf("/");
343324
let pkg
344-
if (lastSlashIndex === -1)
345-
{
325+
if (lastSlashIndex === -1) {
346326
let splitParts = dependency.split(delimiter);
347327
pkg = new PackageURL(ecosystem,undefined,splitParts[0],splitParts[1],qualifiers,undefined)
348-
}
349-
else
350-
{
328+
} else {
351329
let namespace = dependency.slice(0,lastSlashIndex)
352330
let dependencyAndVersion = dependency.slice(lastSlashIndex+1)
353331
let parts = dependencyAndVersion.split(delimiter);
354-
if(parts.length === 2 )
355-
{
332+
if(parts.length === 2 ) {
356333
pkg = new PackageURL(ecosystem,namespace,parts[0],parts[1],qualifiers,undefined);
357-
}
358-
else
359-
{
334+
} else {
360335
pkg = new PackageURL(ecosystem,namespace,parts[0],defaultMainModuleVersion,qualifiers,undefined);
361336
}
362337
}
@@ -373,8 +348,14 @@ function toPurl(dependency, delimiter, qualifiers) {
373348
function getFinalPackagesVersionsForModule(rows,manifestPath,goBin) {
374349
let manifestDir = path.dirname(manifestPath)
375350
let options = {cwd: manifestDir}
376-
execSync(`${handleSpacesInPath(goBin)} mod download`, options)
377-
let finalVersionsForAllModules = execSync(`${handleSpacesInPath(goBin)} list -m all`, options).toString()
351+
// TODO: determine whether this is necessary
352+
try {
353+
invokeCommand(goBin, ['mod', 'download'], options)
354+
var finalVersionsForAllModules = invokeCommand(goBin, ['list', '-m', 'all'], options).toString()
355+
} catch(error) {
356+
throw new Error('failed to list all modules', {cause: error})
357+
}
358+
378359
let finalVersionModules = new Map()
379360
finalVersionsForAllModules.split(getLineSeparatorGolang()).filter(string => string.trim()!== "")
380361
.filter(string => string.trim().split(" ").length === 2)
@@ -418,12 +399,3 @@ function getLineSeparatorGolang() {
418399
let reg = /\n|\r\n/
419400
return reg
420401
}
421-
422-
// /**
423-
// *
424-
// * @param {string} fullPackage - full package with its name and version-
425-
// * @return {string} package version only
426-
// */
427-
// function getVersionOfPackage(fullPackage) {
428-
// return fullPackage.split("@")[1]
429-
// }

test/providers/golang_gomodules.test.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ suite('testing the golang-go-modules data provider', () => {
2424
"go_mod_with_all_ignore"
2525
].forEach(testCase => {
2626
let scenario = testCase.replace('go_mod_', '').replaceAll('_', ' ')
27-
test(`verify go.mod sbom provided for stack analysis with scenario ${scenario}`, async () => {
27+
test(`verify go.mod sbom provided for stack analysis with scenario ${scenario}`, () => {
2828
// load the expected graph for the scenario
29-
let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/golang/${testCase}/expected_sbom_stack_analysis.json`,).toString()
29+
let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/golang/${testCase}/expected_sbom_stack_analysis.json`).toString()
3030
expectedSbom = JSON.stringify(JSON.parse(expectedSbom),null, 4)
3131
// invoke sut stack analysis for scenario manifest
32-
let providedDataForStack = await golangGoModules.provideStack(`test/providers/tst_manifests/golang/${testCase}/go.mod`)
32+
let providedDataForStack = golangGoModules.provideStack(`test/providers/tst_manifests/golang/${testCase}/go.mod`)
3333
// new(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date
3434

3535
// providedDataForStack.content = providedDataForStack.content.replaceAll("\"timestamp\":\"[a-zA-Z0-9\\-\\:]+\"","")
@@ -40,12 +40,12 @@ suite('testing the golang-go-modules data provider', () => {
4040
// these test cases takes ~2500-2700 ms each pr >10000 in CI (for the first test-case)
4141
}).timeout(process.env.GITHUB_ACTIONS ? 30000 : 10000)
4242

43-
test(`verify go.mod sbom provided for component analysis with scenario ${scenario}`, async () => {
43+
test(`verify go.mod sbom provided for component analysis with scenario ${scenario}`, () => {
4444
// load the expected list for the scenario
45-
let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/golang/${testCase}/expected_sbom_component_analysis.json`,).toString().trimEnd()
45+
let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/golang/${testCase}/expected_sbom_component_analysis.json`).toString().trimEnd()
4646
expectedSbom = JSON.stringify(JSON.parse(expectedSbom),null, 4)
4747
// invoke sut stack analysis for scenario manifest
48-
let providedDataForComponent = await golangGoModules.provideComponent(`test/providers/tst_manifests/golang/${testCase}/go.mod`)
48+
let providedDataForComponent = golangGoModules.provideComponent(`test/providers/tst_manifests/golang/${testCase}/go.mod`)
4949
// verify returned data matches expectation
5050
expect(providedDataForComponent.ecosystem).equal('golang')
5151
expect(providedDataForComponent.contentType).equal('application/vnd.cyclonedx+json')
@@ -60,12 +60,12 @@ suite('testing the golang-go-modules data provider', () => {
6060

6161
].forEach(testCase => {
6262
let scenario = testCase.replace('go_mod_', '').replaceAll('_', ' ')
63-
test(`verify go.mod sbom provided for stack analysis with scenario ${scenario}`, async () => {
63+
test(`verify go.mod sbom provided for stack analysis with scenario ${scenario}`, () => {
6464
// load the expected graph for the scenario
6565
let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/golang/${testCase}/expected_sbom_stack_analysis.json`,).toString()
6666
// expectedSbom = JSON.stringify(JSON.parse(expectedSbom))
6767
// invoke sut stack analysis for scenario manifest
68-
let providedDataForStack = await golangGoModules.provideStack(`test/providers/tst_manifests/golang/${testCase}/go.mod`,{"EXHORT_GO_MVS_LOGIC_ENABLED" : "true"})
68+
let providedDataForStack = golangGoModules.provideStack(`test/providers/tst_manifests/golang/${testCase}/go.mod`,{"EXHORT_GO_MVS_LOGIC_ENABLED" : "true"})
6969
// new(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date
7070

7171
// providedDataForStack.content = providedDataForStack.content.replaceAll("\"timestamp\":\"[a-zA-Z0-9\\-\\:]+\"","")

0 commit comments

Comments
 (0)