@cyclonedx/cdxgen 11.1.8 → 11.1.10
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/bin/cdxgen.js +48 -1
- package/lib/cli/index.js +195 -18
- package/lib/helpers/logger.js +52 -0
- package/lib/helpers/utils.js +298 -272
- package/lib/helpers/utils.test.js +5 -5
- package/lib/helpers/validator.js +26 -1
- package/package.json +4 -3
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/helpers/logger.d.ts +4 -0
- package/types/lib/helpers/logger.d.ts.map +1 -0
- package/types/lib/helpers/utils.d.ts +1 -4
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/helpers/validator.d.ts.map +1 -1
package/bin/cdxgen.js
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
printSummary,
|
|
22
22
|
printTable,
|
|
23
23
|
} from "../lib/helpers/display.js";
|
|
24
|
+
import { thoughtEnd, thoughtLog } from "../lib/helpers/logger.js";
|
|
24
25
|
import {
|
|
25
26
|
ATOM_DB,
|
|
26
27
|
dirNameStr,
|
|
@@ -397,6 +398,7 @@ if (!args.projectName) {
|
|
|
397
398
|
args.projectName = basename(resolve(filePath));
|
|
398
399
|
}
|
|
399
400
|
}
|
|
401
|
+
thoughtLog(`Let's try to generate a CycloneDX BOM for the path '${filePath}'`);
|
|
400
402
|
if (
|
|
401
403
|
filePath.includes(" ") ||
|
|
402
404
|
filePath.includes("\r") ||
|
|
@@ -412,6 +414,9 @@ if (
|
|
|
412
414
|
// Support for obom/cbom aliases
|
|
413
415
|
if (process.argv[1].includes("obom") && !args.type) {
|
|
414
416
|
args.type = "os";
|
|
417
|
+
thoughtLog(
|
|
418
|
+
"Ok, the user wants to generate an Operations Bill-of-Materials (OBOM).",
|
|
419
|
+
);
|
|
415
420
|
}
|
|
416
421
|
|
|
417
422
|
/**
|
|
@@ -428,14 +433,28 @@ const options = Object.assign({}, args, {
|
|
|
428
433
|
? resolve(join(filePath, args.output))
|
|
429
434
|
: args.output,
|
|
430
435
|
});
|
|
431
|
-
|
|
436
|
+
// Filter duplicate types. Eg: -t gradle -t gradle
|
|
437
|
+
if (options.projectType && Array.isArray(options.projectType)) {
|
|
438
|
+
options.projectType = Array.from(new Set(options.projectType));
|
|
439
|
+
}
|
|
440
|
+
if (!options.projectType) {
|
|
441
|
+
thoughtLog(
|
|
442
|
+
"Ok, the user wants me to identify all the project types and generate a consolidated BOM document.",
|
|
443
|
+
);
|
|
444
|
+
}
|
|
432
445
|
if (process.argv[1].includes("cbom")) {
|
|
446
|
+
thoughtLog(
|
|
447
|
+
"Ok, the user wants to generate Cryptographic Bill-of-Materials (CBOM).",
|
|
448
|
+
);
|
|
433
449
|
options.includeCrypto = true;
|
|
434
450
|
options.evidence = true;
|
|
435
451
|
options.specVersion = 1.6;
|
|
436
452
|
options.deep = true;
|
|
437
453
|
}
|
|
438
454
|
if (process.argv[1].includes("cdxgen-secure")) {
|
|
455
|
+
thoughtLog(
|
|
456
|
+
"Ok, the user wants cdxgen to run in secure mode by default. Let's try and use the permissions api.",
|
|
457
|
+
);
|
|
439
458
|
console.log(
|
|
440
459
|
"NOTE: Secure mode only restricts cdxgen from performing certain activities such as package installation. It does not provide security guarantees in the presence of malicious code.",
|
|
441
460
|
);
|
|
@@ -446,6 +465,9 @@ if (options.standard) {
|
|
|
446
465
|
options.specVersion = 1.6;
|
|
447
466
|
}
|
|
448
467
|
if (options.includeFormulation) {
|
|
468
|
+
thoughtLog(
|
|
469
|
+
"Wait, the user wants to include formulation information. Let's warn about accidentally disclosing sensitive data via the BOM files.",
|
|
470
|
+
);
|
|
449
471
|
console.log(
|
|
450
472
|
"NOTE: Formulation section could include sensitive data such as emails and secrets.\nPlease review the generated SBOM before distribution.\n",
|
|
451
473
|
);
|
|
@@ -456,6 +478,13 @@ if (options.includeFormulation) {
|
|
|
456
478
|
* @param {object} options CLI options
|
|
457
479
|
*/
|
|
458
480
|
const applyAdvancedOptions = (options) => {
|
|
481
|
+
if (options?.profile !== "generic") {
|
|
482
|
+
thoughtLog(`BOM profile to use is '${options.profile}'.`);
|
|
483
|
+
} else {
|
|
484
|
+
thoughtLog(
|
|
485
|
+
"The user hasn't specified a profile. Should I suggest one to optimize the BOM for a specific use case or persona 🤔?",
|
|
486
|
+
);
|
|
487
|
+
}
|
|
459
488
|
switch (options.profile) {
|
|
460
489
|
case "appsec":
|
|
461
490
|
options.deep = true;
|
|
@@ -508,6 +537,11 @@ const applyAdvancedOptions = (options) => {
|
|
|
508
537
|
default:
|
|
509
538
|
break;
|
|
510
539
|
}
|
|
540
|
+
if (options.lifecycle) {
|
|
541
|
+
thoughtLog(
|
|
542
|
+
`BOM must be generated for the lifecycle '${options.lifecycle}'.`,
|
|
543
|
+
);
|
|
544
|
+
}
|
|
511
545
|
switch (options.lifecycle) {
|
|
512
546
|
case "pre-build":
|
|
513
547
|
options.installDeps = false;
|
|
@@ -728,7 +762,9 @@ const checkPermissions = (filePath, options) => {
|
|
|
728
762
|
options.usagesSlicesFile = `${options.projectName}-usages.json`;
|
|
729
763
|
}
|
|
730
764
|
prepareEnv(filePath, options);
|
|
765
|
+
thoughtLog("Getting ready to generate the BOM ⚡️.");
|
|
731
766
|
let bomNSData = (await createBom(filePath, options)) || {};
|
|
767
|
+
thoughtLog("Tweaking the generated BOM data. Nearly there.");
|
|
732
768
|
// Add extra metadata and annotations with post processing
|
|
733
769
|
bomNSData = postProcess(bomNSData, options);
|
|
734
770
|
if (
|
|
@@ -748,6 +784,13 @@ const checkPermissions = (filePath, options) => {
|
|
|
748
784
|
} else {
|
|
749
785
|
jsonPayload = JSON.stringify(bomNSData.bomJson, null, null);
|
|
750
786
|
fs.writeFileSync(jsonFile, jsonPayload);
|
|
787
|
+
if (jsonFile.endsWith("bom.json")) {
|
|
788
|
+
thoughtLog(
|
|
789
|
+
`Let's save the file to "${jsonFile}". Should I suggest the '.cdx.json' file extension for better semantics?`,
|
|
790
|
+
);
|
|
791
|
+
} else {
|
|
792
|
+
thoughtLog(`Let's save the file to "${jsonFile}".`);
|
|
793
|
+
}
|
|
751
794
|
}
|
|
752
795
|
if (
|
|
753
796
|
jsonPayload &&
|
|
@@ -843,6 +886,7 @@ const checkPermissions = (filePath, options) => {
|
|
|
843
886
|
jsonFile,
|
|
844
887
|
JSON.stringify(bomJsonUnsignedObj, null, null),
|
|
845
888
|
);
|
|
889
|
+
thoughtLog(`Signing the BOM file "${jsonFile}".`);
|
|
846
890
|
if (publicKeyFile) {
|
|
847
891
|
// Verifying this signature
|
|
848
892
|
const signatureVerification = jws.verify(
|
|
@@ -929,10 +973,13 @@ const checkPermissions = (filePath, options) => {
|
|
|
929
973
|
}
|
|
930
974
|
// Perform automatic validation
|
|
931
975
|
if (options.validate) {
|
|
976
|
+
thoughtLog("Wait, let's check the generated BOM file for any issues.");
|
|
932
977
|
if (!validateBom(bomNSData.bomJson)) {
|
|
933
978
|
process.exit(1);
|
|
934
979
|
}
|
|
980
|
+
thoughtLog("BOM file looks valid. Thank you for using cdxgen!");
|
|
935
981
|
}
|
|
982
|
+
thoughtEnd();
|
|
936
983
|
// Automatically submit the bom data
|
|
937
984
|
// biome-ignore lint/suspicious/noDoubleEquals: yargs passes true for empty values
|
|
938
985
|
if (options.serverUrl && options.serverUrl != true && options.apiKey) {
|
package/lib/cli/index.js
CHANGED
|
@@ -30,6 +30,8 @@ import {
|
|
|
30
30
|
gitTreeHashes,
|
|
31
31
|
listFiles,
|
|
32
32
|
} from "../helpers/envcontext.js";
|
|
33
|
+
import { thoughtLog } from "../helpers/logger.js";
|
|
34
|
+
|
|
33
35
|
import {
|
|
34
36
|
CARGO_CMD,
|
|
35
37
|
CLJ_CMD,
|
|
@@ -1344,11 +1346,22 @@ export async function createJavaBom(path, options) {
|
|
|
1344
1346
|
`${options.multiProject ? "**/" : ""}pom.xml`,
|
|
1345
1347
|
options,
|
|
1346
1348
|
);
|
|
1349
|
+
// gradle
|
|
1350
|
+
const gradleFiles = getAllFiles(
|
|
1351
|
+
path,
|
|
1352
|
+
`${options.multiProject ? "**/" : ""}build.gradle*`,
|
|
1353
|
+
options,
|
|
1354
|
+
);
|
|
1347
1355
|
let bomJsonFiles = [];
|
|
1348
1356
|
if (
|
|
1349
1357
|
pomFiles?.length &&
|
|
1350
1358
|
isPackageManagerAllowed("maven", ["bazel", "sbt", "gradle"], options)
|
|
1351
1359
|
) {
|
|
1360
|
+
if (gradleFiles.length) {
|
|
1361
|
+
thoughtLog(
|
|
1362
|
+
`Is this a Gradle project? I recommend invoking cdxgen with the "-t gradle" option if you're encountering build errors.`,
|
|
1363
|
+
);
|
|
1364
|
+
}
|
|
1352
1365
|
if (!isQuarkus) {
|
|
1353
1366
|
// Quarkus projects require special treatment. To detect quarkus, we parse the first 3 maven file to look for a hit
|
|
1354
1367
|
for (const pf of pomFiles.slice(0, 3)) {
|
|
@@ -1367,6 +1380,9 @@ export async function createJavaBom(path, options) {
|
|
|
1367
1380
|
let result = undefined;
|
|
1368
1381
|
let mvnArgs;
|
|
1369
1382
|
if (isQuarkus) {
|
|
1383
|
+
thoughtLog(
|
|
1384
|
+
"This appears to be a quarkus project. Let's use the right maven plugin.",
|
|
1385
|
+
);
|
|
1370
1386
|
// disable analytics. See: https://quarkus.io/usage/
|
|
1371
1387
|
mvnArgs = [
|
|
1372
1388
|
"-fn",
|
|
@@ -1438,6 +1454,7 @@ export async function createJavaBom(path, options) {
|
|
|
1438
1454
|
}
|
|
1439
1455
|
// Use the cyclonedx maven plugin if there is no preference for maven deps tree
|
|
1440
1456
|
if (!useMavenDepsTree) {
|
|
1457
|
+
thoughtLog("The user wants me to use the cyclonedx-maven plugin.");
|
|
1441
1458
|
console.log(
|
|
1442
1459
|
`Executing '${mavenCmd} ${mvnArgs.join(" ")}' in`,
|
|
1443
1460
|
basePath,
|
|
@@ -1488,6 +1505,9 @@ export async function createJavaBom(path, options) {
|
|
|
1488
1505
|
// For the first pom alone, we need to execute first in non-recursive mode to capture
|
|
1489
1506
|
// the parent component. Then, we execute all of them in recursive mode
|
|
1490
1507
|
if (f === firstPom) {
|
|
1508
|
+
thoughtLog(
|
|
1509
|
+
"What is the parent component here? Let's use maven command to find out.",
|
|
1510
|
+
);
|
|
1491
1511
|
result = spawnSync(
|
|
1492
1512
|
"mvn",
|
|
1493
1513
|
["dependency:tree", "-N", `-DoutputFile=${tempMvnParentTree}`],
|
|
@@ -1510,10 +1530,22 @@ export async function createJavaBom(path, options) {
|
|
|
1510
1530
|
tmpParentComponent.type = "application";
|
|
1511
1531
|
parentComponent = tmpParentComponent;
|
|
1512
1532
|
parentComponent.components = [];
|
|
1533
|
+
if (parentComponent.name) {
|
|
1534
|
+
thoughtLog(
|
|
1535
|
+
`Parent component is called ${parentComponent.name}!`,
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1513
1538
|
}
|
|
1514
1539
|
}
|
|
1515
1540
|
}
|
|
1516
|
-
|
|
1541
|
+
thoughtLog(
|
|
1542
|
+
`**MAVEN**: Let's use Maven to collect packages from ${basePath}.`,
|
|
1543
|
+
);
|
|
1544
|
+
if (DEBUG_MODE) {
|
|
1545
|
+
console.log(
|
|
1546
|
+
`Executing 'mvn ${mvnTreeArgs.join(" ")}' in ${basePath}`,
|
|
1547
|
+
);
|
|
1548
|
+
}
|
|
1517
1549
|
// Prefer the built-in maven
|
|
1518
1550
|
result = spawnSync(
|
|
1519
1551
|
PREFER_MAVEN_DEPS_TREE ? "mvn" : mavenCmd,
|
|
@@ -1577,6 +1609,9 @@ export async function createJavaBom(path, options) {
|
|
|
1577
1609
|
console.log(
|
|
1578
1610
|
"\nFalling back to parsing pom.xml files. Only direct dependencies would get included!",
|
|
1579
1611
|
);
|
|
1612
|
+
thoughtLog(
|
|
1613
|
+
"**MAVEN**: There appear to be build errors, so the SBOM will be incomplete.",
|
|
1614
|
+
);
|
|
1580
1615
|
const dlist = parsePom(f);
|
|
1581
1616
|
if (dlist?.length) {
|
|
1582
1617
|
pkgList = pkgList.concat(dlist);
|
|
@@ -1693,19 +1728,17 @@ export async function createJavaBom(path, options) {
|
|
|
1693
1728
|
}
|
|
1694
1729
|
}
|
|
1695
1730
|
if (possible_misses) {
|
|
1696
|
-
if (
|
|
1731
|
+
if (gradleFiles.length) {
|
|
1732
|
+
console.log(
|
|
1733
|
+
"Is this a gradle project? Try running cdxgen with `-t gradle`.",
|
|
1734
|
+
);
|
|
1735
|
+
} else if (!DEBUG_MODE) {
|
|
1697
1736
|
console.warn(
|
|
1698
1737
|
"Multiple errors occurred while building this project with maven. The SBOM is therefore incomplete!",
|
|
1699
1738
|
);
|
|
1700
1739
|
}
|
|
1701
1740
|
}
|
|
1702
1741
|
}
|
|
1703
|
-
// gradle
|
|
1704
|
-
const gradleFiles = getAllFiles(
|
|
1705
|
-
path,
|
|
1706
|
-
`${options.multiProject ? "**/" : ""}build.gradle*`,
|
|
1707
|
-
options,
|
|
1708
|
-
);
|
|
1709
1742
|
const allProjects = [];
|
|
1710
1743
|
const allProjectsAddedPurls = [];
|
|
1711
1744
|
const rootDependsOn = new Set();
|
|
@@ -1923,9 +1956,14 @@ export async function createJavaBom(path, options) {
|
|
|
1923
1956
|
"from this gradle project. De-duping this list ...",
|
|
1924
1957
|
);
|
|
1925
1958
|
} else {
|
|
1926
|
-
|
|
1927
|
-
"
|
|
1959
|
+
thoughtLog(
|
|
1960
|
+
"**GRADLE:** SBOM is incomplete. I recommend troubleshooting the issue to improve the BOM precision.",
|
|
1928
1961
|
);
|
|
1962
|
+
if (!DEBUG_MODE) {
|
|
1963
|
+
console.log(
|
|
1964
|
+
"No packages found. Set the environment variable 'CDXGEN_DEBUG_MODE=debug' to troubleshoot any gradle related errors.",
|
|
1965
|
+
);
|
|
1966
|
+
}
|
|
1929
1967
|
options.failOnError && process.exit(1);
|
|
1930
1968
|
}
|
|
1931
1969
|
// Should we attempt to resolve class names
|
|
@@ -2367,16 +2405,14 @@ export async function createNodejsBom(path, options) {
|
|
|
2367
2405
|
`${options.multiProject ? "**/" : ""}package.json`,
|
|
2368
2406
|
options,
|
|
2369
2407
|
);
|
|
2370
|
-
const yarnLockFile = getAllFiles(path, "yarn.lock", options);
|
|
2371
|
-
const pnpmLockFile = getAllFiles(path, "pnpm-lock.yaml", options);
|
|
2372
2408
|
const npmInstallCount = Number.parseInt(process.env.NPM_INSTALL_COUNT) || 2;
|
|
2373
2409
|
// Automatic npm install logic.
|
|
2374
2410
|
// Only perform npm install for smaller projects (< 2 package.json) without the correct number of lock files
|
|
2375
2411
|
if (
|
|
2376
2412
|
(pkgJsonLockFiles?.length === 0 ||
|
|
2377
2413
|
pkgJsonLockFiles?.length < pkgJsonFiles?.length) &&
|
|
2378
|
-
|
|
2379
|
-
|
|
2414
|
+
yarnLockFiles?.length === 0 &&
|
|
2415
|
+
pnpmLockFiles?.length === 0 &&
|
|
2380
2416
|
pkgJsonFiles?.length <= npmInstallCount &&
|
|
2381
2417
|
options.installDeps
|
|
2382
2418
|
) {
|
|
@@ -3317,6 +3353,9 @@ export async function createPythonBom(path, options) {
|
|
|
3317
3353
|
}
|
|
3318
3354
|
// Fallback to parsing manually
|
|
3319
3355
|
if (!pkgList.length || !frozen) {
|
|
3356
|
+
thoughtLog(
|
|
3357
|
+
`Manually parsing ${f}. The result would include only direct dependencies.`,
|
|
3358
|
+
);
|
|
3320
3359
|
if (DEBUG_MODE) {
|
|
3321
3360
|
console.log(
|
|
3322
3361
|
`Manually parsing ${f}. The result would include only direct dependencies.`,
|
|
@@ -4005,10 +4044,12 @@ export async function createRustBom(path, options) {
|
|
|
4005
4044
|
}
|
|
4006
4045
|
}
|
|
4007
4046
|
// After running cargo check, .d files would get created
|
|
4008
|
-
const makeDFiles = getAllFiles(path, "target/**/*.d", options);
|
|
4009
4047
|
let pkgFilesMap = {};
|
|
4010
|
-
|
|
4011
|
-
|
|
4048
|
+
if (options.deep || ["build", "post-build"].includes(options.lifecycle)) {
|
|
4049
|
+
const makeDFiles = getAllFiles(path, "target/**/*.d", options);
|
|
4050
|
+
for (const dfile of makeDFiles) {
|
|
4051
|
+
pkgFilesMap = { ...pkgFilesMap, ...parseMakeDFile(dfile) };
|
|
4052
|
+
}
|
|
4012
4053
|
}
|
|
4013
4054
|
const cargoLockFiles = getAllFiles(
|
|
4014
4055
|
path,
|
|
@@ -6205,7 +6246,16 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6205
6246
|
);
|
|
6206
6247
|
if (DEBUG_MODE) {
|
|
6207
6248
|
console.log(
|
|
6208
|
-
|
|
6249
|
+
`**OS**: Found ${osPackages.length} OS packages at ${options.allLayersExplodedDir}`,
|
|
6250
|
+
);
|
|
6251
|
+
}
|
|
6252
|
+
if (osPackages.length) {
|
|
6253
|
+
thoughtLog(
|
|
6254
|
+
`I found ${osPackages.length} OS packages at ${options.allLayersExplodedDir}`,
|
|
6255
|
+
);
|
|
6256
|
+
} else {
|
|
6257
|
+
thoughtLog(
|
|
6258
|
+
`I couldn't find any OS packages at ${options.allLayersExplodedDir}. Perhaps the binary plugin wasn't available, or the architecture is unsupported.`,
|
|
6209
6259
|
);
|
|
6210
6260
|
}
|
|
6211
6261
|
if (allTypes?.length) {
|
|
@@ -6230,6 +6280,11 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6230
6280
|
if (DEBUG_MODE) {
|
|
6231
6281
|
console.log(`Found ${bomData.bomJson.components.length} OS components`);
|
|
6232
6282
|
}
|
|
6283
|
+
if (bomData.bomJson.components.length) {
|
|
6284
|
+
thoughtLog(
|
|
6285
|
+
`I found ${bomData.bomJson.components.length} OS packages 😎.`,
|
|
6286
|
+
);
|
|
6287
|
+
}
|
|
6233
6288
|
components = components.concat(bomData.bomJson.components);
|
|
6234
6289
|
}
|
|
6235
6290
|
}
|
|
@@ -6237,10 +6292,19 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6237
6292
|
if (DEBUG_MODE) {
|
|
6238
6293
|
console.log("Scanning", path);
|
|
6239
6294
|
}
|
|
6295
|
+
if (pathList.length > 2) {
|
|
6296
|
+
thoughtLog(`Let's thoroughly check the path ${path}.`);
|
|
6297
|
+
}
|
|
6240
6298
|
// Node.js
|
|
6241
6299
|
if (hasAnyProjectType(["oci", "js"], options)) {
|
|
6300
|
+
thoughtLog(
|
|
6301
|
+
"**JS**: Now looking for JavaScript projects (npm, yarn, pnpm) and files.",
|
|
6302
|
+
);
|
|
6242
6303
|
bomData = await createNodejsBom(path, options);
|
|
6243
6304
|
if (bomData?.bomJson?.components?.length) {
|
|
6305
|
+
thoughtLog(
|
|
6306
|
+
`I found ${bomData.bomJson.components.length} npm packages. Let's keep looking.`,
|
|
6307
|
+
);
|
|
6244
6308
|
if (DEBUG_MODE) {
|
|
6245
6309
|
console.log(
|
|
6246
6310
|
`Found ${bomData.bomJson.components.length} npm packages at ${path}`,
|
|
@@ -6268,8 +6332,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6268
6332
|
}
|
|
6269
6333
|
// Java
|
|
6270
6334
|
if (hasAnyProjectType(["oci", "java"], options)) {
|
|
6335
|
+
thoughtLog(
|
|
6336
|
+
"**JAVA**: Looking for Java projects (e.g., Maven, Gradle, SBT). I hope all configurations—from Java version to individual build settings—are correctly aligned.",
|
|
6337
|
+
);
|
|
6271
6338
|
bomData = await createJavaBom(path, options);
|
|
6272
6339
|
if (bomData?.bomJson?.components?.length) {
|
|
6340
|
+
thoughtLog(
|
|
6341
|
+
`I found ${bomData.bomJson.components.length} java packages.`,
|
|
6342
|
+
);
|
|
6273
6343
|
if (DEBUG_MODE) {
|
|
6274
6344
|
console.log(
|
|
6275
6345
|
`Found ${bomData.bomJson.components.length} java packages at ${path}`,
|
|
@@ -6291,6 +6361,9 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6291
6361
|
if (bomData.parentComponent.components?.length) {
|
|
6292
6362
|
let bomSubComponents = bomData.parentComponent.components;
|
|
6293
6363
|
if (["true", "1"].includes(process.env.GRADLE_RESOLVE_FROM_NODE)) {
|
|
6364
|
+
thoughtLog(
|
|
6365
|
+
"Wait, the user wants me to resolve gradle projects from npm.",
|
|
6366
|
+
);
|
|
6294
6367
|
const allRefs = components.map((c) => c["bom-ref"]);
|
|
6295
6368
|
const duplicateComponents = bomSubComponents.filter((c) =>
|
|
6296
6369
|
allRefs.includes(c["bom-ref"]),
|
|
@@ -6309,8 +6382,19 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6309
6382
|
}
|
|
6310
6383
|
}
|
|
6311
6384
|
if (hasAnyProjectType(["oci", "py"], options)) {
|
|
6385
|
+
thoughtLog(
|
|
6386
|
+
"**PYTHON**: Looking for Python projects with package managers such as pip, poetry, uv, etc. Wish me good luck!",
|
|
6387
|
+
);
|
|
6388
|
+
if (process.env?.CDXGEN_IN_CONTAINER !== "true") {
|
|
6389
|
+
thoughtLog(
|
|
6390
|
+
"I'm running in a non-container environment. Let's hope the correct build tools are available ✌️.",
|
|
6391
|
+
);
|
|
6392
|
+
}
|
|
6312
6393
|
bomData = await createPythonBom(path, options);
|
|
6313
6394
|
if (bomData?.bomJson?.components?.length) {
|
|
6395
|
+
thoughtLog(
|
|
6396
|
+
`I found ${bomData.bomJson.components.length} python packages.`,
|
|
6397
|
+
);
|
|
6314
6398
|
if (DEBUG_MODE) {
|
|
6315
6399
|
console.log(
|
|
6316
6400
|
`Found ${bomData.bomJson.components.length} python packages at ${path}`,
|
|
@@ -6330,8 +6414,12 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6330
6414
|
}
|
|
6331
6415
|
}
|
|
6332
6416
|
if (hasAnyProjectType(["oci", "go"], options)) {
|
|
6417
|
+
thoughtLog(
|
|
6418
|
+
"**GO**: Looking for go projects. I need to be cautious about purl namespaces and potential failures with the 'go list' command.",
|
|
6419
|
+
);
|
|
6333
6420
|
bomData = await createGoBom(path, options);
|
|
6334
6421
|
if (bomData?.bomJson?.components?.length) {
|
|
6422
|
+
thoughtLog(`I found ${bomData.bomJson.components.length} go packages.`);
|
|
6335
6423
|
if (DEBUG_MODE) {
|
|
6336
6424
|
console.log(
|
|
6337
6425
|
`Found ${bomData.bomJson.components.length} go packages at ${path}`,
|
|
@@ -6351,8 +6439,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6351
6439
|
}
|
|
6352
6440
|
}
|
|
6353
6441
|
if (hasAnyProjectType(["oci", "rust"], options)) {
|
|
6442
|
+
thoughtLog(
|
|
6443
|
+
"**RUST**: Let's search for Cargo/Rust projects. Should I warn the user that we don't support Cargo 'features' and native dependencies, which may lead to both false positives and false negatives? 🤔?",
|
|
6444
|
+
);
|
|
6354
6445
|
bomData = await createRustBom(path, options);
|
|
6355
6446
|
if (bomData?.bomJson?.components?.length) {
|
|
6447
|
+
thoughtLog(
|
|
6448
|
+
`I found ${bomData.bomJson.components.length} rust packages.`,
|
|
6449
|
+
);
|
|
6356
6450
|
if (DEBUG_MODE) {
|
|
6357
6451
|
console.log(
|
|
6358
6452
|
`Found ${bomData.bomJson.components.length} rust packages at ${path}`,
|
|
@@ -6379,8 +6473,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6379
6473
|
}
|
|
6380
6474
|
}
|
|
6381
6475
|
if (hasAnyProjectType(["oci", "php"], options)) {
|
|
6476
|
+
thoughtLog(
|
|
6477
|
+
"**PHP**: About to search for Composer-based projects. I hope lock files are available; otherwise, the 'composer install' command might fail for various reasons.",
|
|
6478
|
+
);
|
|
6382
6479
|
bomData = createPHPBom(path, options);
|
|
6383
6480
|
if (bomData?.bomJson?.components?.length) {
|
|
6481
|
+
thoughtLog(
|
|
6482
|
+
`I found ${bomData.bomJson.components.length} php packages.`,
|
|
6483
|
+
);
|
|
6384
6484
|
if (DEBUG_MODE) {
|
|
6385
6485
|
console.log(
|
|
6386
6486
|
`Found ${bomData.bomJson.components.length} php packages at ${path}`,
|
|
@@ -6407,8 +6507,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6407
6507
|
}
|
|
6408
6508
|
}
|
|
6409
6509
|
if (hasAnyProjectType(["oci", "ruby"], options)) {
|
|
6510
|
+
thoughtLog(
|
|
6511
|
+
"**RUBY**: Are there any Ruby projects in this path? There's only one way to know.",
|
|
6512
|
+
);
|
|
6410
6513
|
bomData = await createRubyBom(path, options);
|
|
6411
6514
|
if (bomData?.bomJson?.components?.length) {
|
|
6515
|
+
thoughtLog(
|
|
6516
|
+
`We got ${bomData.bomJson.components.length} ruby packages.`,
|
|
6517
|
+
);
|
|
6412
6518
|
if (DEBUG_MODE) {
|
|
6413
6519
|
console.log(
|
|
6414
6520
|
`Found ${bomData.bomJson.components.length} ruby packages at ${path}`,
|
|
@@ -6436,8 +6542,12 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6436
6542
|
}
|
|
6437
6543
|
}
|
|
6438
6544
|
if (hasAnyProjectType(["oci", "csharp"], options)) {
|
|
6545
|
+
thoughtLog("**CSHARP**: What about csharp and fsharp projects?");
|
|
6439
6546
|
bomData = await createCsharpBom(path, options);
|
|
6440
6547
|
if (bomData?.bomJson?.components?.length) {
|
|
6548
|
+
thoughtLog(
|
|
6549
|
+
`There are ${bomData.bomJson.components.length} csharp packages.`,
|
|
6550
|
+
);
|
|
6441
6551
|
if (DEBUG_MODE) {
|
|
6442
6552
|
console.log(
|
|
6443
6553
|
`Found ${bomData.bomJson.components.length} csharp packages at ${path}`,
|
|
@@ -6464,8 +6574,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6464
6574
|
}
|
|
6465
6575
|
}
|
|
6466
6576
|
if (hasAnyProjectType(["oci", "dart"], options)) {
|
|
6577
|
+
thoughtLog(
|
|
6578
|
+
"**DART**: Looking for Dart projects. These are rare ones. Should I inform the user that they can pass the types argument via the command-line to speed things up?",
|
|
6579
|
+
);
|
|
6467
6580
|
bomData = await createDartBom(path, options);
|
|
6468
6581
|
if (bomData?.bomJson?.components?.length) {
|
|
6582
|
+
thoughtLog(
|
|
6583
|
+
`I found ${bomData.bomJson.components.length} pub packages.`,
|
|
6584
|
+
);
|
|
6469
6585
|
if (DEBUG_MODE) {
|
|
6470
6586
|
console.log(
|
|
6471
6587
|
`Found ${bomData.bomJson.components.length} pub packages at ${path}`,
|
|
@@ -6485,8 +6601,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6485
6601
|
}
|
|
6486
6602
|
}
|
|
6487
6603
|
if (hasAnyProjectType(["oci", "haskell"], options)) {
|
|
6604
|
+
thoughtLog(
|
|
6605
|
+
"**HASKELL**: Looking for Haskell projects. They're rarely encountered.",
|
|
6606
|
+
);
|
|
6488
6607
|
bomData = createHaskellBom(path, options);
|
|
6489
6608
|
if (bomData?.bomJson?.components?.length) {
|
|
6609
|
+
thoughtLog(
|
|
6610
|
+
`I found ${bomData.bomJson.components.length} hackage packages.`,
|
|
6611
|
+
);
|
|
6490
6612
|
if (DEBUG_MODE) {
|
|
6491
6613
|
console.log(
|
|
6492
6614
|
`Found ${bomData.bomJson.components.length} hackage packages at ${path}`,
|
|
@@ -6506,8 +6628,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6506
6628
|
}
|
|
6507
6629
|
}
|
|
6508
6630
|
if (hasAnyProjectType(["oci", "elixir"], options)) {
|
|
6631
|
+
thoughtLog(
|
|
6632
|
+
"**ELIXIR**: Looking for Elixir projects—they're quite rare as well.",
|
|
6633
|
+
);
|
|
6509
6634
|
bomData = createElixirBom(path, options);
|
|
6510
6635
|
if (bomData?.bomJson?.components?.length) {
|
|
6636
|
+
thoughtLog(
|
|
6637
|
+
`I found ${bomData.bomJson.components.length} mix packages.`,
|
|
6638
|
+
);
|
|
6511
6639
|
if (DEBUG_MODE) {
|
|
6512
6640
|
console.log(
|
|
6513
6641
|
`Found ${bomData.bomJson.components.length} mix packages at ${path}`,
|
|
@@ -6527,8 +6655,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6527
6655
|
}
|
|
6528
6656
|
}
|
|
6529
6657
|
if (hasAnyProjectType(["oci", "c"], options)) {
|
|
6658
|
+
thoughtLog(
|
|
6659
|
+
"**C/C++**: Looking for C/C++ projects. Should I warn the user that the generated SBOM might have low accuracy and contain errors?",
|
|
6660
|
+
);
|
|
6530
6661
|
bomData = createCppBom(path, options);
|
|
6531
6662
|
if (bomData?.bomJson?.components?.length) {
|
|
6663
|
+
thoughtLog(
|
|
6664
|
+
`I found ${bomData.bomJson.components.length} cpp packages.`,
|
|
6665
|
+
);
|
|
6532
6666
|
if (DEBUG_MODE) {
|
|
6533
6667
|
console.log(
|
|
6534
6668
|
`Found ${bomData.bomJson.components.length} cpp packages at ${path}`,
|
|
@@ -6548,8 +6682,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6548
6682
|
}
|
|
6549
6683
|
}
|
|
6550
6684
|
if (hasAnyProjectType(["oci", "clojure"], options)) {
|
|
6685
|
+
thoughtLog(
|
|
6686
|
+
"**CLOJURE**: Looking for Clojure projects. Should I warn the user that the purl namespace 'clojars' isn't widely supported by tools like Dependency-Track?",
|
|
6687
|
+
);
|
|
6551
6688
|
bomData = createClojureBom(path, options);
|
|
6552
6689
|
if (bomData?.bomJson?.components?.length) {
|
|
6690
|
+
thoughtLog(
|
|
6691
|
+
`I found ${bomData.bomJson.components.length} clojure packages.`,
|
|
6692
|
+
);
|
|
6553
6693
|
if (DEBUG_MODE) {
|
|
6554
6694
|
console.log(
|
|
6555
6695
|
`Found ${bomData.bomJson.components.length} clojure packages at ${path}`,
|
|
@@ -6569,8 +6709,12 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6569
6709
|
}
|
|
6570
6710
|
}
|
|
6571
6711
|
if (hasAnyProjectType(["oci", "github"], options)) {
|
|
6712
|
+
thoughtLog("**GITHUB**: Looking for any github packages and workflows.");
|
|
6572
6713
|
bomData = createGitHubBom(path, options);
|
|
6573
6714
|
if (bomData?.bomJson?.components?.length) {
|
|
6715
|
+
thoughtLog(
|
|
6716
|
+
`I found ${bomData.bomJson.components.length} github action packages as well. Should I convert these to formulation instead 🤔`,
|
|
6717
|
+
);
|
|
6574
6718
|
if (DEBUG_MODE) {
|
|
6575
6719
|
console.log(
|
|
6576
6720
|
`Found ${bomData.bomJson.components.length} GitHub action packages at ${path}`,
|
|
@@ -6590,8 +6734,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6590
6734
|
}
|
|
6591
6735
|
}
|
|
6592
6736
|
if (hasAnyProjectType(["oci", "cloudbuild"], options)) {
|
|
6737
|
+
thoughtLog(
|
|
6738
|
+
"**CLOUDBUILD**: Let's check for CloudBuild configuration files that include package dependencies.",
|
|
6739
|
+
);
|
|
6593
6740
|
bomData = createCloudBuildBom(path, options);
|
|
6594
6741
|
if (bomData?.bomJson?.components?.length) {
|
|
6742
|
+
thoughtLog(
|
|
6743
|
+
`I found ${bomData.bomJson.components.length} cloudbuild packages.`,
|
|
6744
|
+
);
|
|
6595
6745
|
if (DEBUG_MODE) {
|
|
6596
6746
|
console.log(
|
|
6597
6747
|
`Found ${bomData.bomJson.components.length} CloudBuild configuration at ${path}`,
|
|
@@ -6611,8 +6761,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6611
6761
|
}
|
|
6612
6762
|
}
|
|
6613
6763
|
if (hasAnyProjectType(["oci", "swift"], options)) {
|
|
6764
|
+
thoughtLog(
|
|
6765
|
+
"**SWIFT**: Now checking for Swift projects. We don't support CocoaPods, Objective-C, or pure Xcode projects, so the SBOM will be incomplete.",
|
|
6766
|
+
);
|
|
6614
6767
|
bomData = await createSwiftBom(path, options);
|
|
6615
6768
|
if (bomData?.bomJson?.components?.length) {
|
|
6769
|
+
thoughtLog(
|
|
6770
|
+
`I found ${bomData.bomJson.components.length} swift packages here.`,
|
|
6771
|
+
);
|
|
6616
6772
|
if (DEBUG_MODE) {
|
|
6617
6773
|
console.log(
|
|
6618
6774
|
`Found ${bomData.bomJson.components.length} Swift packages at ${path}`,
|
|
@@ -6632,8 +6788,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6632
6788
|
}
|
|
6633
6789
|
}
|
|
6634
6790
|
if (hasAnyProjectType(["oci", "jar", "war", "ear"], options)) {
|
|
6791
|
+
thoughtLog(
|
|
6792
|
+
"**JAR**: Let's check for any bundled jar/war/ear files to improve the SBOM accuracy.",
|
|
6793
|
+
);
|
|
6635
6794
|
bomData = await createJarBom(path, options);
|
|
6636
6795
|
if (bomData?.bomJson?.components?.length) {
|
|
6796
|
+
thoughtLog(
|
|
6797
|
+
`I found ${bomData.bomJson.components.length} jar packages as well.`,
|
|
6798
|
+
);
|
|
6637
6799
|
if (DEBUG_MODE) {
|
|
6638
6800
|
console.log(
|
|
6639
6801
|
`Found ${bomData.bomJson.components.length} jar packages at ${path}`,
|
|
@@ -6654,8 +6816,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6654
6816
|
}
|
|
6655
6817
|
// Collect any crypto keys
|
|
6656
6818
|
if (options.specVersion >= 1.6 && options.includeCrypto) {
|
|
6819
|
+
thoughtLog(
|
|
6820
|
+
"**CBOM**: Wait, the user wants me to look for cryptographic assets. Let's check thoroughly.",
|
|
6821
|
+
);
|
|
6657
6822
|
bomData = await createCryptoCertsBom(path, options);
|
|
6658
6823
|
if (bomData?.bomJson?.components?.length) {
|
|
6824
|
+
thoughtLog(
|
|
6825
|
+
`I found ${bomData.bomJson.components.length} crypto assets.`,
|
|
6826
|
+
);
|
|
6659
6827
|
if (DEBUG_MODE) {
|
|
6660
6828
|
console.log(
|
|
6661
6829
|
`Found ${bomData.bomJson.components.length} crypto assets at ${path}`,
|
|
@@ -6693,6 +6861,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6693
6861
|
}
|
|
6694
6862
|
// Retain the components of parent component
|
|
6695
6863
|
if (parentSubComponents.length) {
|
|
6864
|
+
thoughtLog("**METADATA**: Tweaking the parent component hierarchy.");
|
|
6696
6865
|
if (!parentComponent || !Object.keys(parentComponent).length) {
|
|
6697
6866
|
parentComponent = parentSubComponents[0];
|
|
6698
6867
|
}
|
|
@@ -7196,9 +7365,17 @@ export async function createBom(path, options) {
|
|
|
7196
7365
|
projectType = ["java"];
|
|
7197
7366
|
}
|
|
7198
7367
|
if (projectType.length > 1) {
|
|
7368
|
+
thoughtLog(
|
|
7369
|
+
`The user has specified multiple project types: projectType.join(", "). Let's focus on the types one at a time.`,
|
|
7370
|
+
);
|
|
7199
7371
|
console.log("Generate BOM for project types:", projectType.join(", "));
|
|
7200
7372
|
return await createMultiXBom(path, options);
|
|
7201
7373
|
}
|
|
7374
|
+
if (projectType.length === 1) {
|
|
7375
|
+
thoughtLog(
|
|
7376
|
+
`The user wants me to focus on a single type, '${projectType}'. Could there be an issue with auto-detection, or might they use another tool like cyclonedx-cli to merge all the generated BOMs later?`,
|
|
7377
|
+
);
|
|
7378
|
+
}
|
|
7202
7379
|
// Use the project type alias to return any singular BOM
|
|
7203
7380
|
if (PROJECT_TYPE_ALIASES["java"].includes(projectType[0])) {
|
|
7204
7381
|
return await createJavaBom(path, options);
|