@cyclonedx/cdxgen 12.3.3 → 12.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -25
- package/bin/audit.js +21 -7
- package/bin/cdxgen.js +270 -127
- package/bin/convert.js +34 -15
- package/bin/hbom.js +495 -0
- package/bin/repl.js +592 -37
- package/bin/validate.js +31 -4
- package/bin/verify.js +18 -5
- package/data/README.md +298 -25
- package/data/component-tags.json +6 -0
- package/data/crypto-oid.json +16 -0
- package/data/cyclonedx-2.0-bundled.schema.json +7182 -0
- package/data/predictive-audit-allowlist.json +11 -0
- package/data/queries-darwin.json +12 -1
- package/data/queries-win.json +7 -1
- package/data/queries.json +39 -2
- package/data/rules/ai-agent-governance.yaml +16 -0
- package/data/rules/asar-archives.yaml +150 -0
- package/data/rules/chrome-extensions.yaml +8 -0
- package/data/rules/ci-permissions.yaml +42 -18
- package/data/rules/container-risk.yaml +14 -7
- package/data/rules/dependency-sources.yaml +11 -0
- package/data/rules/hbom-compliance.yaml +325 -0
- package/data/rules/hbom-performance.yaml +307 -0
- package/data/rules/hbom-security.yaml +248 -0
- package/data/rules/host-topology.yaml +165 -0
- package/data/rules/mcp-servers.yaml +18 -3
- package/data/rules/obom-runtime.yaml +907 -22
- package/data/rules/package-integrity.yaml +14 -0
- package/data/rules/rootfs-hardening.yaml +179 -0
- package/data/rules/vscode-extensions.yaml +9 -0
- package/lib/audit/index.js +210 -8
- package/lib/audit/index.poku.js +332 -0
- package/lib/audit/reporters.js +222 -0
- package/lib/audit/targets.js +146 -1
- package/lib/audit/targets.poku.js +186 -0
- package/lib/cli/asar.poku.js +328 -0
- package/lib/cli/index.js +527 -99
- package/lib/cli/index.poku.js +1469 -212
- package/lib/evinser/evinser.js +14 -9
- package/lib/helpers/analyzer.js +1406 -29
- package/lib/helpers/analyzer.poku.js +342 -0
- package/lib/helpers/analyzerScope.js +712 -0
- package/lib/helpers/asarutils.js +1556 -0
- package/lib/helpers/asarutils.poku.js +443 -0
- package/lib/helpers/auditCategories.js +12 -0
- package/lib/helpers/auditCategories.poku.js +32 -0
- package/lib/helpers/bomUtils.js +155 -1
- package/lib/helpers/bomUtils.poku.js +79 -1
- package/lib/helpers/cbomutils.js +271 -1
- package/lib/helpers/cbomutils.poku.js +248 -5
- package/lib/helpers/display.js +291 -1
- package/lib/helpers/display.poku.js +149 -0
- package/lib/helpers/evidenceUtils.js +58 -0
- package/lib/helpers/evidenceUtils.poku.js +54 -0
- package/lib/helpers/exportUtils.js +9 -0
- package/lib/helpers/gtfobins.js +142 -8
- package/lib/helpers/gtfobins.poku.js +24 -1
- package/lib/helpers/hbom.js +710 -0
- package/lib/helpers/hbom.poku.js +496 -0
- package/lib/helpers/hbomAnalysis.js +268 -0
- package/lib/helpers/hbomAnalysis.poku.js +249 -0
- package/lib/helpers/hbomLoader.js +35 -0
- package/lib/helpers/hostTopology.js +803 -0
- package/lib/helpers/hostTopology.poku.js +363 -0
- package/lib/helpers/inventoryStats.js +69 -0
- package/lib/helpers/inventoryStats.poku.js +86 -0
- package/lib/helpers/lolbas.js +19 -1
- package/lib/helpers/lolbas.poku.js +23 -0
- package/lib/helpers/osqueryTransform.js +47 -0
- package/lib/helpers/osqueryTransform.poku.js +47 -0
- package/lib/helpers/plugins.js +350 -0
- package/lib/helpers/plugins.poku.js +57 -0
- package/lib/helpers/protobom.js +209 -45
- package/lib/helpers/protobom.poku.js +183 -5
- package/lib/helpers/protobomLoader.js +43 -0
- package/lib/helpers/protobomLoader.poku.js +31 -0
- package/lib/helpers/remote/dependency-track.js +36 -3
- package/lib/helpers/remote/dependency-track.poku.js +44 -0
- package/lib/helpers/source.js +24 -0
- package/lib/helpers/source.poku.js +32 -0
- package/lib/helpers/utils.js +1438 -93
- package/lib/helpers/utils.poku.js +846 -4
- package/lib/managers/binary.e2e.poku.js +367 -0
- package/lib/managers/binary.js +2293 -353
- package/lib/managers/binary.poku.js +1699 -1
- package/lib/managers/docker.js +201 -79
- package/lib/managers/docker.poku.js +337 -12
- package/lib/server/server.js +4 -28
- package/lib/stages/postgen/annotator.js +38 -0
- package/lib/stages/postgen/annotator.poku.js +107 -1
- package/lib/stages/postgen/auditBom.js +121 -18
- package/lib/stages/postgen/auditBom.poku.js +1366 -31
- package/lib/stages/postgen/hostTopologyAudit.poku.js +186 -0
- package/lib/stages/postgen/postgen.js +406 -8
- package/lib/stages/postgen/postgen.poku.js +484 -0
- package/lib/stages/postgen/ruleEngine.js +116 -0
- package/lib/stages/pregen/envAudit.js +14 -3
- package/lib/validator/bomValidator.js +90 -38
- package/lib/validator/bomValidator.poku.js +90 -0
- package/lib/validator/complianceRules.js +4 -2
- package/lib/validator/index.poku.js +14 -0
- package/package.json +23 -21
- package/types/bin/hbom.d.ts +3 -0
- package/types/bin/hbom.d.ts.map +1 -0
- package/types/bin/repl.d.ts +1 -1
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts +44 -0
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/audit/reporters.d.ts +16 -0
- package/types/lib/audit/reporters.d.ts.map +1 -1
- package/types/lib/audit/targets.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts +16 -0
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +4 -0
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/helpers/analyzer.d.ts +33 -0
- package/types/lib/helpers/analyzer.d.ts.map +1 -1
- package/types/lib/helpers/analyzerScope.d.ts +11 -0
- package/types/lib/helpers/analyzerScope.d.ts.map +1 -0
- package/types/lib/helpers/asarutils.d.ts +34 -0
- package/types/lib/helpers/asarutils.d.ts.map +1 -0
- package/types/lib/helpers/auditCategories.d.ts +5 -0
- package/types/lib/helpers/auditCategories.d.ts.map +1 -1
- package/types/lib/helpers/bomUtils.d.ts +10 -0
- package/types/lib/helpers/bomUtils.d.ts.map +1 -1
- package/types/lib/helpers/cbomutils.d.ts +3 -2
- package/types/lib/helpers/cbomutils.d.ts.map +1 -1
- package/types/lib/helpers/display.d.ts.map +1 -1
- package/types/lib/helpers/evidenceUtils.d.ts +8 -0
- package/types/lib/helpers/evidenceUtils.d.ts.map +1 -0
- package/types/lib/helpers/exportUtils.d.ts.map +1 -1
- package/types/lib/helpers/gtfobins.d.ts +8 -0
- package/types/lib/helpers/gtfobins.d.ts.map +1 -1
- package/types/lib/helpers/hbom.d.ts +49 -0
- package/types/lib/helpers/hbom.d.ts.map +1 -0
- package/types/lib/helpers/hbomAnalysis.d.ts +76 -0
- package/types/lib/helpers/hbomAnalysis.d.ts.map +1 -0
- package/types/lib/helpers/hbomLoader.d.ts +7 -0
- package/types/lib/helpers/hbomLoader.d.ts.map +1 -0
- package/types/lib/helpers/hostTopology.d.ts +12 -0
- package/types/lib/helpers/hostTopology.d.ts.map +1 -0
- package/types/lib/helpers/inventoryStats.d.ts +11 -0
- package/types/lib/helpers/inventoryStats.d.ts.map +1 -0
- package/types/lib/helpers/lolbas.d.ts.map +1 -1
- package/types/lib/helpers/osqueryTransform.d.ts +3 -0
- package/types/lib/helpers/osqueryTransform.d.ts.map +1 -1
- package/types/lib/helpers/plugins.d.ts +58 -0
- package/types/lib/helpers/plugins.d.ts.map +1 -0
- package/types/lib/helpers/protobom.d.ts +5 -4
- package/types/lib/helpers/protobom.d.ts.map +1 -1
- package/types/lib/helpers/protobomLoader.d.ts +17 -0
- package/types/lib/helpers/protobomLoader.d.ts.map +1 -0
- package/types/lib/helpers/remote/dependency-track.d.ts +10 -3
- package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -1
- package/types/lib/helpers/source.d.ts.map +1 -1
- package/types/lib/helpers/utils.d.ts +45 -8
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +5 -0
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/server/server.d.ts +2 -1
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
- package/types/lib/stages/postgen/auditBom.d.ts +26 -1
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts +2 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/node.d.ts +23 -0
- package/types/lib/third-party/arborist/lib/node.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/complianceRules.d.ts.map +1 -1
- package/data/spdx-model-v3.0.1.jsonld +0 -15999
package/bin/repl.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import process from "node:process";
|
|
@@ -21,14 +21,35 @@ import {
|
|
|
21
21
|
printTable,
|
|
22
22
|
printVulnerabilities,
|
|
23
23
|
} from "../lib/helpers/display.js";
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
formatHbomHardwareClassSummary,
|
|
26
|
+
getHbomSummary,
|
|
27
|
+
isHbomLikeBom,
|
|
28
|
+
} from "../lib/helpers/hbomAnalysis.js";
|
|
29
|
+
import {
|
|
30
|
+
getPropertyValue,
|
|
31
|
+
getSourceDerivedCryptoComponents,
|
|
32
|
+
getUnpackagedExecutableComponents,
|
|
33
|
+
getUnpackagedSharedLibraryComponents,
|
|
34
|
+
} from "../lib/helpers/inventoryStats.js";
|
|
35
|
+
import {
|
|
36
|
+
importProtobomModule,
|
|
37
|
+
isProtoBomPath,
|
|
38
|
+
} from "../lib/helpers/protobomLoader.js";
|
|
25
39
|
import {
|
|
26
40
|
getProvenanceComponents,
|
|
27
41
|
getTrustedComponents,
|
|
28
42
|
} from "../lib/helpers/provenanceUtils.js";
|
|
29
43
|
import { toCycloneDxLikeBom } from "../lib/helpers/spdxUtils.js";
|
|
30
44
|
import { table } from "../lib/helpers/table.js";
|
|
31
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
getTmpDir,
|
|
47
|
+
isDryRun,
|
|
48
|
+
safeExistsSync,
|
|
49
|
+
safeMkdirSync,
|
|
50
|
+
safeMkdtempSync,
|
|
51
|
+
safeWriteSync,
|
|
52
|
+
} from "../lib/helpers/utils.js";
|
|
32
53
|
import { getBomWithOras } from "../lib/managers/oci.js";
|
|
33
54
|
import { validateBom } from "../lib/validator/bomValidator.js";
|
|
34
55
|
|
|
@@ -55,7 +76,7 @@ const cdxArt = `
|
|
|
55
76
|
|
|
56
77
|
console.log(cdxArt);
|
|
57
78
|
|
|
58
|
-
if (process.env
|
|
79
|
+
if (process.env.CDXGEN_NODE_OPTIONS) {
|
|
59
80
|
process.env.NODE_OPTIONS = `${process.env.NODE_OPTIONS || ""} ${process.env.CDXGEN_NODE_OPTIONS}`;
|
|
60
81
|
}
|
|
61
82
|
|
|
@@ -63,6 +84,23 @@ if (process.env?.CDXGEN_NODE_OPTIONS) {
|
|
|
63
84
|
let sbom;
|
|
64
85
|
const getInteractiveBom = () => toCycloneDxLikeBom(sbom);
|
|
65
86
|
|
|
87
|
+
function getContainerRegistryHost(reference) {
|
|
88
|
+
const trimmedReference = `${reference || ""}`.trim().toLowerCase();
|
|
89
|
+
if (!trimmedReference) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
const slashIndex = trimmedReference.indexOf("/");
|
|
93
|
+
if (slashIndex <= 0) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
return trimmedReference.slice(0, slashIndex).replace(/:\d+$/, "");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function isSupportedSbomRegistryReference(reference) {
|
|
100
|
+
const registryHost = getContainerRegistryHost(reference);
|
|
101
|
+
return registryHost === "ghcr.io" || registryHost === "docker.io";
|
|
102
|
+
}
|
|
103
|
+
|
|
66
104
|
function unescapeAnnotationText(value) {
|
|
67
105
|
return String(value || "")
|
|
68
106
|
.replace(/<br>/g, "\n")
|
|
@@ -143,11 +181,15 @@ function printAuditTable(title, rows) {
|
|
|
143
181
|
);
|
|
144
182
|
}
|
|
145
183
|
|
|
146
|
-
function
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
184
|
+
function printKeyValueTable(title, entries) {
|
|
185
|
+
const rows = [["Field", "Value"]];
|
|
186
|
+
entries.forEach(([field, value]) => {
|
|
187
|
+
if (value === undefined || value === null || value === "") {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
rows.push([field, `${value}`]);
|
|
191
|
+
});
|
|
192
|
+
printAuditTable(title, rows);
|
|
151
193
|
}
|
|
152
194
|
|
|
153
195
|
function isLikelyObom(bom) {
|
|
@@ -158,6 +200,10 @@ function isLikelyObom(bom) {
|
|
|
158
200
|
);
|
|
159
201
|
}
|
|
160
202
|
|
|
203
|
+
function isLikelyHbom(bom) {
|
|
204
|
+
return isHbomLikeBom(bom);
|
|
205
|
+
}
|
|
206
|
+
|
|
161
207
|
function isLikelyCargoBom(bom) {
|
|
162
208
|
const formulation = Array.isArray(bom?.formulation)
|
|
163
209
|
? bom.formulation
|
|
@@ -221,11 +267,94 @@ function getCargoFormulationEntries(bom) {
|
|
|
221
267
|
return matchingEntries;
|
|
222
268
|
}
|
|
223
269
|
|
|
270
|
+
const HBOM_FIRMWARE_PROPERTIES = Object.freeze([
|
|
271
|
+
"cdx:hbom:protocol",
|
|
272
|
+
"cdx:hbom:flags",
|
|
273
|
+
"cdx:hbom:guids",
|
|
274
|
+
"cdx:hbom:instanceIds",
|
|
275
|
+
"cdx:hbom:createdEpoch",
|
|
276
|
+
"cdx:hbom:firmwareDate",
|
|
277
|
+
]);
|
|
278
|
+
|
|
279
|
+
const HBOM_BUS_SECURITY_PROPERTIES = Object.freeze([
|
|
280
|
+
"cdx:hbom:securityLevel",
|
|
281
|
+
"cdx:hbom:iommuProtection",
|
|
282
|
+
"cdx:hbom:policy",
|
|
283
|
+
"cdx:hbom:authorized",
|
|
284
|
+
"cdx:hbom:usbVersion",
|
|
285
|
+
"cdx:hbom:usbClassName",
|
|
286
|
+
"cdx:hbom:usbInterfaceClasses",
|
|
287
|
+
"cdx:hbom:pciClass",
|
|
288
|
+
"cdx:hbom:pciClassCode",
|
|
289
|
+
"cdx:hbom:displayConnectorType",
|
|
290
|
+
"cdx:hbom:contentProtection",
|
|
291
|
+
"cdx:hbom:drmNode",
|
|
292
|
+
]);
|
|
293
|
+
|
|
294
|
+
const HBOM_POWER_PROPERTIES = Object.freeze([
|
|
295
|
+
"cdx:hbom:designCapacityPercent",
|
|
296
|
+
"cdx:hbom:energyNow",
|
|
297
|
+
"cdx:hbom:energyFull",
|
|
298
|
+
"cdx:hbom:energyFullDesign",
|
|
299
|
+
"cdx:hbom:chargeNow",
|
|
300
|
+
"cdx:hbom:chargeFull",
|
|
301
|
+
"cdx:hbom:chargeFullDesign",
|
|
302
|
+
"cdx:hbom:powerNow",
|
|
303
|
+
"cdx:hbom:voltageNow",
|
|
304
|
+
"cdx:hbom:currentNow",
|
|
305
|
+
"cdx:hbom:warningLevel",
|
|
306
|
+
]);
|
|
307
|
+
|
|
308
|
+
function getInteractiveHbomOrWarn(replContext) {
|
|
309
|
+
const interactiveBom = getInteractiveBom();
|
|
310
|
+
if (!interactiveBom) {
|
|
311
|
+
console.log(
|
|
312
|
+
"⚠ No BOM is loaded. Use .import command to import an existing BOM",
|
|
313
|
+
);
|
|
314
|
+
replContext.displayPrompt();
|
|
315
|
+
return undefined;
|
|
316
|
+
}
|
|
317
|
+
if (!isLikelyHbom(interactiveBom)) {
|
|
318
|
+
console.log(
|
|
319
|
+
"This BOM does not look like an HBOM. Import an HBOM generated with 'cdxgen -t hbom' to use this view.",
|
|
320
|
+
);
|
|
321
|
+
replContext.displayPrompt();
|
|
322
|
+
return undefined;
|
|
323
|
+
}
|
|
324
|
+
return interactiveBom;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function filterHbomComponentsByProperties(
|
|
328
|
+
bom,
|
|
329
|
+
propertyNames,
|
|
330
|
+
hardwareClasses = [],
|
|
331
|
+
) {
|
|
332
|
+
return (bom?.components || []).filter((component) => {
|
|
333
|
+
const hardwareClass = getPropertyValue(component, "cdx:hbom:hardwareClass");
|
|
334
|
+
if (hardwareClasses.includes(hardwareClass)) {
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
return propertyNames.some((propertyName) =>
|
|
338
|
+
Boolean(getPropertyValue(component, propertyName)),
|
|
339
|
+
);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function getDiagnosticDisplayDetail(diagnostic) {
|
|
344
|
+
return (
|
|
345
|
+
diagnostic.installHint ||
|
|
346
|
+
diagnostic.privilegeHint ||
|
|
347
|
+
diagnostic.message ||
|
|
348
|
+
diagnostic.code ||
|
|
349
|
+
"-"
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
224
353
|
let historyFile;
|
|
225
354
|
const historyConfigDir = join(homedir(), ".config", ".cdxgen");
|
|
226
|
-
if (!process.env.CDXGEN_REPL_HISTORY && !
|
|
355
|
+
if (!process.env.CDXGEN_REPL_HISTORY && !safeExistsSync(historyConfigDir)) {
|
|
227
356
|
try {
|
|
228
|
-
|
|
357
|
+
safeMkdirSync(historyConfigDir, { recursive: true });
|
|
229
358
|
historyFile = join(historyConfigDir, ".repl_history");
|
|
230
359
|
} catch (_e) {
|
|
231
360
|
// ignore
|
|
@@ -234,10 +363,15 @@ if (!process.env.CDXGEN_REPL_HISTORY && !fs.existsSync(historyConfigDir)) {
|
|
|
234
363
|
historyFile = join(historyConfigDir, ".repl_history");
|
|
235
364
|
}
|
|
236
365
|
|
|
237
|
-
export const importSbom = (sbomOrPath) => {
|
|
238
|
-
|
|
366
|
+
export const importSbom = async (sbomOrPath) => {
|
|
367
|
+
const importTarget = String(sbomOrPath || "").trim();
|
|
368
|
+
if (!importTarget) {
|
|
369
|
+
console.log("⚠ An SBOM path or image reference is required.");
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (importTarget.endsWith(".json") && safeExistsSync(importTarget)) {
|
|
239
373
|
try {
|
|
240
|
-
sbom = JSON.parse(
|
|
374
|
+
sbom = JSON.parse(readFileSync(importTarget, "utf-8"));
|
|
241
375
|
let bomType = "SBOM";
|
|
242
376
|
if (isSpdxJsonLd(sbom)) {
|
|
243
377
|
bomType = "SPDX";
|
|
@@ -245,8 +379,13 @@ export const importSbom = (sbomOrPath) => {
|
|
|
245
379
|
if (sbom?.vulnerabilities && Array.isArray(sbom.vulnerabilities)) {
|
|
246
380
|
bomType = "VDR";
|
|
247
381
|
}
|
|
248
|
-
console.log(`✅ ${bomType} imported successfully from ${
|
|
382
|
+
console.log(`✅ ${bomType} imported successfully from ${importTarget}`);
|
|
249
383
|
printSummary(sbom);
|
|
384
|
+
if (isLikelyHbom(sbom)) {
|
|
385
|
+
console.log(
|
|
386
|
+
"💭 HBOM detected. Try .hbomsummary, .hbomevidence, .hbomdiagnostics, or .hbomtips",
|
|
387
|
+
);
|
|
388
|
+
}
|
|
250
389
|
if (isLikelyObom(sbom)) {
|
|
251
390
|
console.log(
|
|
252
391
|
"💭 OBOM detected. Try .osinfocategories, .obomtips, .processes, or .services_snapshot",
|
|
@@ -263,56 +402,66 @@ export const importSbom = (sbomOrPath) => {
|
|
|
263
402
|
);
|
|
264
403
|
}
|
|
265
404
|
} catch (e) {
|
|
266
|
-
console.log(
|
|
405
|
+
console.log(
|
|
406
|
+
`⚠ Unable to import the BOM from ${importTarget} due to ${e}`,
|
|
407
|
+
);
|
|
267
408
|
}
|
|
268
|
-
} else if (
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
409
|
+
} else if (isProtoBomPath(importTarget) && safeExistsSync(importTarget)) {
|
|
410
|
+
const { readBinary } = await importProtobomModule(
|
|
411
|
+
"cdxi",
|
|
412
|
+
"protobuf BOM input",
|
|
413
|
+
);
|
|
414
|
+
sbom = readBinary(importTarget, true);
|
|
273
415
|
printSummary(sbom);
|
|
274
|
-
} else if (
|
|
275
|
-
sbomOrPath.startsWith("ghcr.io") ||
|
|
276
|
-
sbomOrPath.startsWith("docker.io")
|
|
277
|
-
) {
|
|
416
|
+
} else if (isSupportedSbomRegistryReference(importTarget)) {
|
|
278
417
|
try {
|
|
279
|
-
sbom = getBomWithOras(
|
|
418
|
+
sbom = getBomWithOras(importTarget);
|
|
280
419
|
if (sbom) {
|
|
281
420
|
printSummary(sbom);
|
|
282
421
|
} else {
|
|
283
422
|
console.log(
|
|
284
|
-
`cyclonedx sbom attachment was not found within ${
|
|
423
|
+
`cyclonedx sbom attachment was not found within ${importTarget}`,
|
|
285
424
|
);
|
|
286
425
|
}
|
|
287
426
|
} catch (e) {
|
|
288
|
-
console.log(
|
|
427
|
+
console.log(
|
|
428
|
+
`⚠ Unable to import the BOM from ${importTarget} due to ${e}`,
|
|
429
|
+
);
|
|
289
430
|
}
|
|
290
431
|
} else {
|
|
291
|
-
console.log(`⚠ ${
|
|
432
|
+
console.log(`⚠ ${importTarget} is invalid.`);
|
|
292
433
|
}
|
|
293
434
|
};
|
|
294
435
|
// Load any sbom passed from the command line
|
|
295
436
|
if (process.argv.length > 2) {
|
|
296
|
-
importSbom(process.argv[process.argv.length - 1]);
|
|
437
|
+
await importSbom(process.argv[process.argv.length - 1]);
|
|
297
438
|
console.log("💭 Type .print to view the BOM as a table");
|
|
298
439
|
console.log("💭 Type .trusted to list components with trusted publishing.");
|
|
299
440
|
console.log(
|
|
300
441
|
"💭 Type .provenance to list components with registry provenance evidence.",
|
|
301
442
|
);
|
|
443
|
+
if (isLikelyHbom(sbom)) {
|
|
444
|
+
console.log(
|
|
445
|
+
"💭 Type .hbomsummary to review the host profile, evidence coverage, hardware-class mix, and collector diagnostics.",
|
|
446
|
+
);
|
|
447
|
+
}
|
|
302
448
|
if (getAuditAnnotations().length) {
|
|
303
449
|
console.log(
|
|
304
450
|
"💭 Type .auditfindings to review cdx-audit and bom-audit annotations.",
|
|
305
451
|
);
|
|
306
452
|
}
|
|
307
|
-
} else if (
|
|
453
|
+
} else if (safeExistsSync("bom.json")) {
|
|
308
454
|
// If the current directory has a bom.json load it
|
|
309
|
-
importSbom("bom.json");
|
|
455
|
+
await importSbom("bom.json");
|
|
310
456
|
} else {
|
|
311
457
|
console.log("💭 Use .create <path> to create an SBOM for the given path.");
|
|
312
458
|
console.log("💭 Use .import <json> to import an existing BOM.");
|
|
313
459
|
console.log(
|
|
314
460
|
"💭 For OBOM investigations, try .obomtips after importing an OBOM.",
|
|
315
461
|
);
|
|
462
|
+
console.log(
|
|
463
|
+
"💭 For HBOM investigations, try .hbomtips after importing an HBOM.",
|
|
464
|
+
);
|
|
316
465
|
console.log("💭 Type .exit or press ctrl+d to close.");
|
|
317
466
|
}
|
|
318
467
|
|
|
@@ -333,7 +482,7 @@ cdxgenRepl.defineCommand("create", {
|
|
|
333
482
|
help: "create an SBOM for the given path",
|
|
334
483
|
async action(sbomOrPath) {
|
|
335
484
|
this.clearBufferedCommand();
|
|
336
|
-
const tempDir =
|
|
485
|
+
const tempDir = safeMkdtempSync(join(getTmpDir(), "cdxgen-repl-"));
|
|
337
486
|
const bomFile = join(tempDir, "bom.json");
|
|
338
487
|
const bomNSData = await createBom(sbomOrPath, {
|
|
339
488
|
multiProject: true,
|
|
@@ -350,6 +499,11 @@ cdxgenRepl.defineCommand("create", {
|
|
|
350
499
|
console.log(
|
|
351
500
|
"💭 Type .provenance to list components with registry provenance evidence.",
|
|
352
501
|
);
|
|
502
|
+
if (isLikelyHbom(sbom)) {
|
|
503
|
+
console.log(
|
|
504
|
+
"💭 Type .hbomsummary or .hbomdiagnostics for focused hardware inventory and collector-diagnostic summaries.",
|
|
505
|
+
);
|
|
506
|
+
}
|
|
353
507
|
if (getAuditAnnotations().length) {
|
|
354
508
|
console.log(
|
|
355
509
|
"💭 Type .auditfindings to review cdx-audit and bom-audit annotations.",
|
|
@@ -368,9 +522,9 @@ cdxgenRepl.defineCommand("create", {
|
|
|
368
522
|
});
|
|
369
523
|
cdxgenRepl.defineCommand("import", {
|
|
370
524
|
help: "import an existing BOM",
|
|
371
|
-
action(sbomOrPath) {
|
|
525
|
+
async action(sbomOrPath) {
|
|
372
526
|
this.clearBufferedCommand();
|
|
373
|
-
importSbom(sbomOrPath);
|
|
527
|
+
await importSbom(sbomOrPath);
|
|
374
528
|
this.displayPrompt();
|
|
375
529
|
},
|
|
376
530
|
});
|
|
@@ -387,6 +541,293 @@ cdxgenRepl.defineCommand("summary", {
|
|
|
387
541
|
this.displayPrompt();
|
|
388
542
|
},
|
|
389
543
|
});
|
|
544
|
+
cdxgenRepl.defineCommand("hbomsummary", {
|
|
545
|
+
help: "summarize HBOM host metadata, evidence coverage, and hardware-class mix",
|
|
546
|
+
action() {
|
|
547
|
+
const interactiveBom = getInteractiveBom();
|
|
548
|
+
if (!interactiveBom) {
|
|
549
|
+
console.log(
|
|
550
|
+
"⚠ No BOM is loaded. Use .import command to import an existing BOM",
|
|
551
|
+
);
|
|
552
|
+
this.displayPrompt();
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
if (!isLikelyHbom(interactiveBom)) {
|
|
556
|
+
console.log(
|
|
557
|
+
"This BOM does not look like an HBOM. Import an HBOM generated with 'cdxgen -t hbom' to use this view.",
|
|
558
|
+
);
|
|
559
|
+
this.displayPrompt();
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
const hbomSummary = getHbomSummary(interactiveBom);
|
|
563
|
+
printKeyValueTable("HBOM summary", [
|
|
564
|
+
["Host", hbomSummary.metadataName],
|
|
565
|
+
["Component type", hbomSummary.metadataType],
|
|
566
|
+
["Manufacturer", hbomSummary.manufacturer],
|
|
567
|
+
["Platform", hbomSummary.platform],
|
|
568
|
+
["Architecture", hbomSummary.architecture],
|
|
569
|
+
["Collector profile", hbomSummary.collectorProfile],
|
|
570
|
+
["Identifier policy", hbomSummary.identifierPolicy],
|
|
571
|
+
["Component count", hbomSummary.componentCount],
|
|
572
|
+
["Hardware class count", hbomSummary.hardwareClassCount],
|
|
573
|
+
[
|
|
574
|
+
"Top hardware classes",
|
|
575
|
+
formatHbomHardwareClassSummary(hbomSummary.hardwareClassCounts),
|
|
576
|
+
],
|
|
577
|
+
["Command evidence count", hbomSummary.evidenceCommandCount],
|
|
578
|
+
["Observed file count", hbomSummary.evidenceFileCount],
|
|
579
|
+
]);
|
|
580
|
+
this.displayPrompt();
|
|
581
|
+
},
|
|
582
|
+
});
|
|
583
|
+
cdxgenRepl.defineCommand("hbomclasses", {
|
|
584
|
+
help: "show HBOM component counts by hardware class",
|
|
585
|
+
action() {
|
|
586
|
+
const interactiveBom = getInteractiveBom();
|
|
587
|
+
if (!interactiveBom) {
|
|
588
|
+
console.log(
|
|
589
|
+
"⚠ No BOM is loaded. Use .import command to import an existing BOM",
|
|
590
|
+
);
|
|
591
|
+
this.displayPrompt();
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
if (!isLikelyHbom(interactiveBom)) {
|
|
595
|
+
console.log(
|
|
596
|
+
"This BOM does not look like an HBOM. Import an HBOM generated with 'cdxgen -t hbom' to use this view.",
|
|
597
|
+
);
|
|
598
|
+
this.displayPrompt();
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
const hbomSummary = getHbomSummary(interactiveBom);
|
|
602
|
+
if (!hbomSummary.hardwareClassCounts.length) {
|
|
603
|
+
console.log(
|
|
604
|
+
"No HBOM hardware classes were found on the loaded BOM. Check whether the document includes cdx:hbom:hardwareClass properties.",
|
|
605
|
+
);
|
|
606
|
+
this.displayPrompt();
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
printAuditTable("HBOM hardware classes", [
|
|
610
|
+
["Hardware class", "Count"],
|
|
611
|
+
...hbomSummary.hardwareClassCounts.map(({ hardwareClass, count }) => [
|
|
612
|
+
hardwareClass,
|
|
613
|
+
`${count}`,
|
|
614
|
+
]),
|
|
615
|
+
]);
|
|
616
|
+
this.displayPrompt();
|
|
617
|
+
},
|
|
618
|
+
});
|
|
619
|
+
cdxgenRepl.defineCommand("hbomevidence", {
|
|
620
|
+
help: "show HBOM collector profile plus command and observed-file evidence",
|
|
621
|
+
action() {
|
|
622
|
+
const interactiveBom = getInteractiveBom();
|
|
623
|
+
if (!interactiveBom) {
|
|
624
|
+
console.log(
|
|
625
|
+
"⚠ No BOM is loaded. Use .import command to import an existing BOM",
|
|
626
|
+
);
|
|
627
|
+
this.displayPrompt();
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
if (!isLikelyHbom(interactiveBom)) {
|
|
631
|
+
console.log(
|
|
632
|
+
"This BOM does not look like an HBOM. Import an HBOM generated with 'cdxgen -t hbom' to use this view.",
|
|
633
|
+
);
|
|
634
|
+
this.displayPrompt();
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
const hbomSummary = getHbomSummary(interactiveBom);
|
|
638
|
+
printKeyValueTable("HBOM evidence overview", [
|
|
639
|
+
["Collector profile", hbomSummary.collectorProfile],
|
|
640
|
+
["Command evidence count", hbomSummary.evidenceCommandCount],
|
|
641
|
+
["Observed file count", hbomSummary.evidenceFileCount],
|
|
642
|
+
]);
|
|
643
|
+
if (hbomSummary.evidenceCommands.length) {
|
|
644
|
+
printAuditTable("HBOM command evidence", [
|
|
645
|
+
["Command #", "Evidence"],
|
|
646
|
+
...hbomSummary.evidenceCommands.map((command, index) => [
|
|
647
|
+
`${index + 1}`,
|
|
648
|
+
command,
|
|
649
|
+
]),
|
|
650
|
+
]);
|
|
651
|
+
}
|
|
652
|
+
if (hbomSummary.evidenceFiles.length) {
|
|
653
|
+
printAuditTable("HBOM observed files", [
|
|
654
|
+
["File #", "Path"],
|
|
655
|
+
...hbomSummary.evidenceFiles.map((filePath, index) => [
|
|
656
|
+
`${index + 1}`,
|
|
657
|
+
filePath,
|
|
658
|
+
]),
|
|
659
|
+
]);
|
|
660
|
+
}
|
|
661
|
+
this.displayPrompt();
|
|
662
|
+
},
|
|
663
|
+
});
|
|
664
|
+
cdxgenRepl.defineCommand("hbomdiagnostics", {
|
|
665
|
+
help: "show parsed HBOM command diagnostics, issue counts, and install or privilege guidance",
|
|
666
|
+
action() {
|
|
667
|
+
const interactiveBom = getInteractiveHbomOrWarn(this);
|
|
668
|
+
if (!interactiveBom) {
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
const hbomSummary = getHbomSummary(interactiveBom);
|
|
672
|
+
if (!hbomSummary.commandDiagnosticCount) {
|
|
673
|
+
console.log(
|
|
674
|
+
"No HBOM command diagnostics were found. This usually means the collector completed without recording missing-command or permission-denied enrichments.",
|
|
675
|
+
);
|
|
676
|
+
this.displayPrompt();
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
printKeyValueTable("HBOM diagnostic overview", [
|
|
680
|
+
["Diagnostic count", hbomSummary.commandDiagnosticCount],
|
|
681
|
+
["Actionable diagnostics", hbomSummary.actionableDiagnosticCount],
|
|
682
|
+
["Missing commands", hbomSummary.missingCommandCount],
|
|
683
|
+
["Permission denied", hbomSummary.permissionDeniedCount],
|
|
684
|
+
["Partial support", hbomSummary.partialSupportCount],
|
|
685
|
+
["Timeouts", hbomSummary.timeoutCount],
|
|
686
|
+
["Other command errors", hbomSummary.commandErrorCount],
|
|
687
|
+
["Diagnostic issues", hbomSummary.diagnosticIssues.join(", ")],
|
|
688
|
+
["Missing command IDs", hbomSummary.missingCommandIds.join(", ")],
|
|
689
|
+
["Permission-denied IDs", hbomSummary.permissionDeniedIds.join(", ")],
|
|
690
|
+
["Install hint count", hbomSummary.installHintCount],
|
|
691
|
+
["Privilege hint count", hbomSummary.privilegeHintCount],
|
|
692
|
+
[
|
|
693
|
+
"Requires privileged rerun",
|
|
694
|
+
hbomSummary.requiresPrivilegedEnrichment ? "yes" : "no",
|
|
695
|
+
],
|
|
696
|
+
]);
|
|
697
|
+
printAuditTable("HBOM command diagnostics", [
|
|
698
|
+
["Issue", "Diagnostic ID", "Command", "Hint / Message"],
|
|
699
|
+
...hbomSummary.commandDiagnostics.map((diagnostic) => [
|
|
700
|
+
diagnostic.issue || "unknown",
|
|
701
|
+
diagnostic.id || "-",
|
|
702
|
+
diagnostic.command || "-",
|
|
703
|
+
getDiagnosticDisplayDetail(diagnostic),
|
|
704
|
+
]),
|
|
705
|
+
]);
|
|
706
|
+
this.displayPrompt();
|
|
707
|
+
},
|
|
708
|
+
});
|
|
709
|
+
cdxgenRepl.defineCommand("hbomfirmware", {
|
|
710
|
+
help: "show firmware, board, TPM, and update-managed HBOM components plus host firmware provenance",
|
|
711
|
+
action() {
|
|
712
|
+
const interactiveBom = getInteractiveHbomOrWarn(this);
|
|
713
|
+
if (!interactiveBom) {
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
const metadataComponent = interactiveBom.metadata?.component;
|
|
717
|
+
const firmwareComponents = filterHbomComponentsByProperties(
|
|
718
|
+
interactiveBom,
|
|
719
|
+
HBOM_FIRMWARE_PROPERTIES,
|
|
720
|
+
["firmware", "board", "tpm"],
|
|
721
|
+
);
|
|
722
|
+
const metadataEntries = [
|
|
723
|
+
[
|
|
724
|
+
"Board vendor",
|
|
725
|
+
getPropertyValue(metadataComponent, "cdx:hbom:boardVendor"),
|
|
726
|
+
],
|
|
727
|
+
["Board name", getPropertyValue(metadataComponent, "cdx:hbom:boardName")],
|
|
728
|
+
[
|
|
729
|
+
"BIOS vendor",
|
|
730
|
+
getPropertyValue(metadataComponent, "cdx:hbom:biosVendor"),
|
|
731
|
+
],
|
|
732
|
+
[
|
|
733
|
+
"BIOS version",
|
|
734
|
+
getPropertyValue(metadataComponent, "cdx:hbom:biosVersion"),
|
|
735
|
+
],
|
|
736
|
+
[
|
|
737
|
+
"Firmware date",
|
|
738
|
+
getPropertyValue(metadataComponent, "cdx:hbom:firmwareDate"),
|
|
739
|
+
],
|
|
740
|
+
[
|
|
741
|
+
"Device-tree revision",
|
|
742
|
+
getPropertyValue(metadataComponent, "cdx:hbom:deviceTreeRevision"),
|
|
743
|
+
],
|
|
744
|
+
];
|
|
745
|
+
const hasMetadataProvenance = metadataEntries.some(([, value]) =>
|
|
746
|
+
Boolean(value),
|
|
747
|
+
);
|
|
748
|
+
if (!firmwareComponents.length && !hasMetadataProvenance) {
|
|
749
|
+
console.log(
|
|
750
|
+
"No focused firmware or board provenance pivots were found. Import an HBOM from a host that exposes board, TPM, or firmware-management metadata to use this view.",
|
|
751
|
+
);
|
|
752
|
+
this.displayPrompt();
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
if (hasMetadataProvenance) {
|
|
756
|
+
printKeyValueTable("HBOM host firmware provenance", metadataEntries);
|
|
757
|
+
}
|
|
758
|
+
if (firmwareComponents.length) {
|
|
759
|
+
printTable(
|
|
760
|
+
{ components: firmwareComponents, dependencies: [] },
|
|
761
|
+
undefined,
|
|
762
|
+
undefined,
|
|
763
|
+
`Found ${firmwareComponents.length} firmware, board, TPM, or update-managed component(s).`,
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
this.displayPrompt();
|
|
767
|
+
},
|
|
768
|
+
});
|
|
769
|
+
cdxgenRepl.defineCommand("hbombuses", {
|
|
770
|
+
help: "show bus, connector, USB, PCI, and external-expansion HBOM components with security or topology metadata",
|
|
771
|
+
action() {
|
|
772
|
+
const interactiveBom = getInteractiveHbomOrWarn(this);
|
|
773
|
+
if (!interactiveBom) {
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
const busComponents = filterHbomComponentsByProperties(
|
|
777
|
+
interactiveBom,
|
|
778
|
+
HBOM_BUS_SECURITY_PROPERTIES,
|
|
779
|
+
[
|
|
780
|
+
"bus",
|
|
781
|
+
"usb-device",
|
|
782
|
+
"pci-device",
|
|
783
|
+
"display-adapter",
|
|
784
|
+
"display-connector",
|
|
785
|
+
],
|
|
786
|
+
);
|
|
787
|
+
if (!busComponents.length) {
|
|
788
|
+
console.log(
|
|
789
|
+
"No bus or connector components with focused security or topology metadata were found.",
|
|
790
|
+
);
|
|
791
|
+
this.displayPrompt();
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
printTable(
|
|
795
|
+
{ components: busComponents, dependencies: [] },
|
|
796
|
+
undefined,
|
|
797
|
+
undefined,
|
|
798
|
+
`Found ${busComponents.length} bus, USB, PCI, or display-link component(s) with bus-security or topology pivots.`,
|
|
799
|
+
);
|
|
800
|
+
this.displayPrompt();
|
|
801
|
+
},
|
|
802
|
+
});
|
|
803
|
+
cdxgenRepl.defineCommand("hbompower", {
|
|
804
|
+
help: "show HBOM power and battery components with detailed design-capacity and runtime telemetry",
|
|
805
|
+
action() {
|
|
806
|
+
const interactiveBom = getInteractiveHbomOrWarn(this);
|
|
807
|
+
if (!interactiveBom) {
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
const powerComponents = filterHbomComponentsByProperties(
|
|
811
|
+
interactiveBom,
|
|
812
|
+
HBOM_POWER_PROPERTIES,
|
|
813
|
+
["power"],
|
|
814
|
+
);
|
|
815
|
+
if (!powerComponents.length) {
|
|
816
|
+
console.log(
|
|
817
|
+
"No focused power or battery telemetry components were found on the loaded HBOM.",
|
|
818
|
+
);
|
|
819
|
+
this.displayPrompt();
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
printTable(
|
|
823
|
+
{ components: powerComponents, dependencies: [] },
|
|
824
|
+
undefined,
|
|
825
|
+
undefined,
|
|
826
|
+
`Found ${powerComponents.length} power or battery component(s) with detailed runtime telemetry.`,
|
|
827
|
+
);
|
|
828
|
+
this.displayPrompt();
|
|
829
|
+
},
|
|
830
|
+
});
|
|
390
831
|
cdxgenRepl.defineCommand("exit", {
|
|
391
832
|
help: "exit",
|
|
392
833
|
action() {
|
|
@@ -447,7 +888,7 @@ cdxgenRepl.defineCommand("search", {
|
|
|
447
888
|
console.log(e);
|
|
448
889
|
}
|
|
449
890
|
} else {
|
|
450
|
-
console.log(
|
|
891
|
+
console.log('⚠ Specify the search string. Eg: .search "search string"');
|
|
451
892
|
}
|
|
452
893
|
} else {
|
|
453
894
|
console.log(
|
|
@@ -596,6 +1037,90 @@ cdxgenRepl.defineCommand("cryptos", {
|
|
|
596
1037
|
this.displayPrompt();
|
|
597
1038
|
},
|
|
598
1039
|
});
|
|
1040
|
+
cdxgenRepl.defineCommand("sourcecryptos", {
|
|
1041
|
+
help: "show source-derived cryptographic assets detected from JS AST analysis",
|
|
1042
|
+
action() {
|
|
1043
|
+
const interactiveBom = getInteractiveBom();
|
|
1044
|
+
if (!interactiveBom?.components) {
|
|
1045
|
+
console.log("⚠ No BOM is loaded. Use .import command to import an SBOM");
|
|
1046
|
+
this.displayPrompt();
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
const sourceCryptoComponents = getSourceDerivedCryptoComponents(
|
|
1050
|
+
interactiveBom.components,
|
|
1051
|
+
);
|
|
1052
|
+
if (!sourceCryptoComponents.length) {
|
|
1053
|
+
console.log(
|
|
1054
|
+
"No source-derived crypto assets found. Generate a CBOM or SBOM with source crypto analysis to use this view.",
|
|
1055
|
+
);
|
|
1056
|
+
this.displayPrompt();
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
printTable(
|
|
1060
|
+
{ components: sourceCryptoComponents, dependencies: [] },
|
|
1061
|
+
["cryptographic-asset"],
|
|
1062
|
+
undefined,
|
|
1063
|
+
`Found ${sourceCryptoComponents.length} source-derived cryptographic asset component(s).`,
|
|
1064
|
+
);
|
|
1065
|
+
this.displayPrompt();
|
|
1066
|
+
},
|
|
1067
|
+
});
|
|
1068
|
+
cdxgenRepl.defineCommand("unpackagedbins", {
|
|
1069
|
+
help: "show executable file components that were not matched to OS package ownership",
|
|
1070
|
+
action() {
|
|
1071
|
+
const interactiveBom = getInteractiveBom();
|
|
1072
|
+
if (!interactiveBom?.components) {
|
|
1073
|
+
console.log("⚠ No BOM is loaded. Use .import command to import an SBOM");
|
|
1074
|
+
this.displayPrompt();
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
const unpackagedExecutables = getUnpackagedExecutableComponents(
|
|
1078
|
+
interactiveBom.components,
|
|
1079
|
+
);
|
|
1080
|
+
if (!unpackagedExecutables.length) {
|
|
1081
|
+
console.log(
|
|
1082
|
+
"No unpackaged executable file components found. Import a container or rootfs BOM with native file inventory to use this view.",
|
|
1083
|
+
);
|
|
1084
|
+
this.displayPrompt();
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
printTable(
|
|
1088
|
+
{ components: unpackagedExecutables, dependencies: [] },
|
|
1089
|
+
["file"],
|
|
1090
|
+
undefined,
|
|
1091
|
+
`Found ${unpackagedExecutables.length} executable file component(s) that were not traced to OS package ownership.`,
|
|
1092
|
+
);
|
|
1093
|
+
this.displayPrompt();
|
|
1094
|
+
},
|
|
1095
|
+
});
|
|
1096
|
+
cdxgenRepl.defineCommand("unpackagedlibs", {
|
|
1097
|
+
help: "show shared library file components that were not matched to OS package ownership",
|
|
1098
|
+
action() {
|
|
1099
|
+
const interactiveBom = getInteractiveBom();
|
|
1100
|
+
if (!interactiveBom?.components) {
|
|
1101
|
+
console.log("⚠ No BOM is loaded. Use .import command to import an SBOM");
|
|
1102
|
+
this.displayPrompt();
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
const unpackagedSharedLibraries = getUnpackagedSharedLibraryComponents(
|
|
1106
|
+
interactiveBom.components,
|
|
1107
|
+
);
|
|
1108
|
+
if (!unpackagedSharedLibraries.length) {
|
|
1109
|
+
console.log(
|
|
1110
|
+
"No unpackaged shared library file components found. Import a container or rootfs BOM with native file inventory to use this view.",
|
|
1111
|
+
);
|
|
1112
|
+
this.displayPrompt();
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
printTable(
|
|
1116
|
+
{ components: unpackagedSharedLibraries, dependencies: [] },
|
|
1117
|
+
["file"],
|
|
1118
|
+
undefined,
|
|
1119
|
+
`Found ${unpackagedSharedLibraries.length} shared library file component(s) that were not traced to OS package ownership.`,
|
|
1120
|
+
);
|
|
1121
|
+
this.displayPrompt();
|
|
1122
|
+
},
|
|
1123
|
+
});
|
|
599
1124
|
cdxgenRepl.defineCommand("frameworks", {
|
|
600
1125
|
help: "print the components of type framework as a table",
|
|
601
1126
|
action() {
|
|
@@ -660,7 +1185,14 @@ cdxgenRepl.defineCommand("save", {
|
|
|
660
1185
|
if (!saveToFile) {
|
|
661
1186
|
saveToFile = "bom.json";
|
|
662
1187
|
}
|
|
663
|
-
|
|
1188
|
+
if (isDryRun) {
|
|
1189
|
+
console.log(
|
|
1190
|
+
`⚠ Dry run mode blocks saving the BOM to ${saveToFile}. Disable --dry-run or CDXGEN_DRY_RUN to persist it.`,
|
|
1191
|
+
);
|
|
1192
|
+
this.displayPrompt();
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
safeWriteSync(saveToFile, JSON.stringify(sbom, null, 2));
|
|
664
1196
|
console.log(`BOM saved successfully to ${saveToFile}`);
|
|
665
1197
|
} else {
|
|
666
1198
|
console.log(
|
|
@@ -1049,6 +1581,25 @@ cdxgenRepl.defineCommand("obomtips", {
|
|
|
1049
1581
|
this.displayPrompt();
|
|
1050
1582
|
},
|
|
1051
1583
|
});
|
|
1584
|
+
cdxgenRepl.defineCommand("hbomtips", {
|
|
1585
|
+
help: "show analyst tips and useful commands for HBOM investigations",
|
|
1586
|
+
action() {
|
|
1587
|
+
console.log("HBOM analyst quick guide:");
|
|
1588
|
+
console.log("1. .hbomsummary");
|
|
1589
|
+
console.log("2. .hbomclasses");
|
|
1590
|
+
console.log("3. .hbomevidence");
|
|
1591
|
+
console.log("4. .hbomdiagnostics");
|
|
1592
|
+
console.log("5. .hbomfirmware / .hbombuses / .hbompower");
|
|
1593
|
+
console.log(
|
|
1594
|
+
"6. .auditfindings to review hbom-security, hbom-performance, and hbom-compliance findings",
|
|
1595
|
+
);
|
|
1596
|
+
console.log("7. .search <hardwareClass or device name>");
|
|
1597
|
+
console.log(
|
|
1598
|
+
'Tip: .query components[properties[name="cdx:hbom:hardwareClass" and value="storage"]] filters directly by hardware class.',
|
|
1599
|
+
);
|
|
1600
|
+
this.displayPrompt();
|
|
1601
|
+
},
|
|
1602
|
+
});
|
|
1052
1603
|
cdxgenRepl.defineCommand("licenses", {
|
|
1053
1604
|
help: "visualize license distribution",
|
|
1054
1605
|
async action() {
|
|
@@ -1249,6 +1800,7 @@ cdxgenRepl.defineCommand("tagcloud", {
|
|
|
1249
1800
|
"docker_volumes",
|
|
1250
1801
|
"etc_hosts",
|
|
1251
1802
|
"firefox_addons",
|
|
1803
|
+
"gatekeeper",
|
|
1252
1804
|
"vscode_extensions",
|
|
1253
1805
|
"homebrew_packages",
|
|
1254
1806
|
"installed_applications",
|
|
@@ -1265,8 +1817,10 @@ cdxgenRepl.defineCommand("tagcloud", {
|
|
|
1265
1817
|
"portage_packages",
|
|
1266
1818
|
"process_events",
|
|
1267
1819
|
"processes",
|
|
1820
|
+
"secureboot_certificates",
|
|
1268
1821
|
"privilege_transitions",
|
|
1269
1822
|
"privileged_listening_ports",
|
|
1823
|
+
"npm_packages",
|
|
1270
1824
|
"python_packages",
|
|
1271
1825
|
"rpm_packages",
|
|
1272
1826
|
"scheduled_tasks",
|
|
@@ -1291,6 +1845,7 @@ cdxgenRepl.defineCommand("tagcloud", {
|
|
|
1291
1845
|
"npm_packages",
|
|
1292
1846
|
"opera_extensions",
|
|
1293
1847
|
"pipes_snapshot",
|
|
1848
|
+
"process_open_handles_snapshot",
|
|
1294
1849
|
"process_open_sockets",
|
|
1295
1850
|
"safari_extensions",
|
|
1296
1851
|
"scheduled_tasks",
|