Skip to content

Commit 87ed9c9

Browse files
authored
Adds new vulnerabilities command to the repl (#1120)
* Adds new vulnerabilities command to the repl Signed-off-by: Prabhu Subramanian <[email protected]> * Tweaks to bom type Signed-off-by: Prabhu Subramanian <[email protected]> --------- Signed-off-by: Prabhu Subramanian <[email protected]>
1 parent 72a5929 commit 87ed9c9

File tree

4 files changed

+68
-8
lines changed

4 files changed

+68
-8
lines changed

bin/repl.js

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
printOccurrences,
1515
printServices,
1616
printTable,
17+
printVulnerabilities,
1718
} from "../display.js";
1819
import { createBom } from "../index.js";
1920
import { validateBom } from "../validator.js";
@@ -61,9 +62,13 @@ export const importSbom = (sbomOrPath) => {
6162
if (sbomOrPath?.endsWith(".json") && fs.existsSync(sbomOrPath)) {
6263
try {
6364
sbom = JSON.parse(fs.readFileSync(sbomOrPath, "utf-8"));
64-
console.log(`✅ SBOM imported successfully from ${sbomOrPath}`);
65+
let bomType = "SBOM";
66+
if (sbom?.vulnerabilities && Array.isArray(sbom.vulnerabilities)) {
67+
bomType = "VDR";
68+
}
69+
console.log(`✅ ${bomType} imported successfully from ${sbomOrPath}`);
6570
} catch (e) {
66-
console.log(`⚠ Unable to import the SBOM from ${sbomOrPath} due to ${e}`);
71+
console.log(`⚠ Unable to import the BOM from ${sbomOrPath} due to ${e}`);
6772
}
6873
} else {
6974
console.log(`⚠ ${sbomOrPath} is invalid.`);
@@ -72,13 +77,13 @@ export const importSbom = (sbomOrPath) => {
7277
// Load any sbom passed from the command line
7378
if (process.argv.length > 2) {
7479
importSbom(process.argv[process.argv.length - 1]);
75-
console.log("💭 Type .print to view the SBOM as a table");
80+
console.log("💭 Type .print to view the BOM as a table");
7681
} else if (fs.existsSync("bom.json")) {
7782
// If the current directory has a bom.json load it
7883
importSbom("bom.json");
7984
} else {
8085
console.log("💭 Use .create <path> to create an SBOM for the given path.");
81-
console.log("💭 Use .import <json> to import an existing SBOM.");
86+
console.log("💭 Use .import <json> to import an existing BOM.");
8287
console.log("💭 Type .exit or press ctrl+d to close.");
8388
}
8489

@@ -302,7 +307,7 @@ cdxgenRepl.defineCommand("validate", {
302307
if (sbom) {
303308
const result = validateBom(sbom);
304309
if (result) {
305-
console.log("SBOM is valid!");
310+
console.log("BOM is valid!");
306311
}
307312
} else {
308313
console.log(
@@ -426,7 +431,7 @@ cdxgenRepl.defineCommand("services", {
426431
let services = await expression.evaluate(sbom);
427432
if (!services) {
428433
console.log(
429-
"No services found. Use evinse command to generate an SBOM with evidence.",
434+
"No services found. Use evinse command to generate a SaaSBOM with evidence.",
430435
);
431436
} else {
432437
if (!Array.isArray(services)) {
@@ -439,12 +444,38 @@ cdxgenRepl.defineCommand("services", {
439444
}
440445
} else {
441446
console.log(
442-
"⚠ No SBOM is loaded. Use .import command to import an evinse SBOM",
447+
"⚠ No SaaSBOM is loaded. Use .import command to import a SaaSBOM",
443448
);
444449
}
445450
this.displayPrompt();
446451
},
447452
});
453+
cdxgenRepl.defineCommand("vulnerabilities", {
454+
help: "view vulnerabilities",
455+
async action() {
456+
if (sbom) {
457+
try {
458+
const expression = jsonata("vulnerabilities");
459+
let vulnerabilities = await expression.evaluate(sbom);
460+
if (!vulnerabilities) {
461+
console.log(
462+
"No vulnerabilities found. Use depscan to generate a VDR file with vulnerabilities.",
463+
);
464+
} else {
465+
if (!Array.isArray(vulnerabilities)) {
466+
vulnerabilities = [vulnerabilities];
467+
}
468+
printVulnerabilities(vulnerabilities);
469+
}
470+
} catch (e) {
471+
console.log(e);
472+
}
473+
} else {
474+
console.log("⚠ No BOM is loaded. Use .import command to import a VDR");
475+
}
476+
this.displayPrompt();
477+
},
478+
});
448479
cdxgenRepl.defineCommand("osinfocategories", {
449480
help: "view the category names for the OS info from the obom",
450481
async action() {

display.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,3 +340,31 @@ export const printReachables = (sliceArtefacts) => {
340340
console.log(table(data, config));
341341
}
342342
};
343+
344+
export function printVulnerabilities(vulnerabilities) {
345+
if (!vulnerabilities) {
346+
return;
347+
}
348+
const data = [["Ref", "Ratings", "State", "Justification"]];
349+
for (const avuln of vulnerabilities) {
350+
const arow = [
351+
avuln["bom-ref"],
352+
`${avuln?.ratings
353+
.map((r) => r?.severity?.toUpperCase())
354+
.join("\n")}\n${avuln?.ratings.map((r) => r?.score).join("\n")}`,
355+
avuln?.analysis?.state || "",
356+
avuln?.analysis?.justification || "",
357+
];
358+
data.push(arow);
359+
}
360+
const config = {
361+
header: {
362+
alignment: "center",
363+
content: "Vulnerabilities\nGenerated with \u2665 by cdxgen",
364+
},
365+
};
366+
if (data.length > 1) {
367+
console.log(table(data, config));
368+
}
369+
console.log(`${vulnerabilities.length} vulnerabilities found.`);
370+
}

types/display.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export function printVulnerabilities(vulnerabilities: any): void;
12
export function printTable(bomJson: any, filterTypes?: any): void;
23
export function printOSTable(bomJson: any): void;
34
export function printServices(bomJson: any): void;

types/display.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)