@cyclonedx/cdxgen 10.5.2 → 10.6.2
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 +31 -14
- package/analyzer.js +1 -1
- package/bin/cdxgen.js +10 -2
- package/display.js +22 -0
- package/index.js +241 -129
- package/package.json +19 -13
- package/server.js +18 -6
- package/types/display.d.ts +1 -0
- package/types/display.d.ts.map +1 -1
- package/types/evinser.d.ts +6 -6
- package/types/index.d.ts +6 -1
- package/types/index.d.ts.map +1 -1
- package/types/server.d.ts.map +1 -1
- package/types/utils.d.ts +17 -10
- package/types/utils.d.ts.map +1 -1
- package/utils.js +220 -48
- package/utils.test.js +87 -11
package/index.js
CHANGED
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
FETCH_LICENSE,
|
|
36
36
|
LEIN_CMD,
|
|
37
37
|
MAX_BUFFER,
|
|
38
|
+
PREFER_MAVEN_DEPS_TREE,
|
|
38
39
|
SWIFT_CMD,
|
|
39
40
|
TIMEOUT_MS,
|
|
40
41
|
addEvidenceForDotnet,
|
|
@@ -66,6 +67,7 @@ import {
|
|
|
66
67
|
getSwiftPackageMetadata,
|
|
67
68
|
getTimestamp,
|
|
68
69
|
includeMavenTestScope,
|
|
70
|
+
isValidIriReference,
|
|
69
71
|
parseBazelActionGraph,
|
|
70
72
|
parseBazelSkyframe,
|
|
71
73
|
parseBdistMetadata,
|
|
@@ -726,7 +728,9 @@ function addExternalReferences(opkg) {
|
|
|
726
728
|
}
|
|
727
729
|
}
|
|
728
730
|
}
|
|
729
|
-
return externalReferences
|
|
731
|
+
return externalReferences
|
|
732
|
+
.map((reference) => ({ ...reference, url: reference.url.trim() }))
|
|
733
|
+
.filter((reference) => isValidIriReference(reference.url));
|
|
730
734
|
}
|
|
731
735
|
|
|
732
736
|
/**
|
|
@@ -1185,6 +1189,7 @@ export async function createJavaBom(path, options) {
|
|
|
1185
1189
|
// Support for tracking all the tools that created the BOM
|
|
1186
1190
|
// For java, this would correctly include the cyclonedx maven plugin.
|
|
1187
1191
|
let tools = undefined;
|
|
1192
|
+
let possible_misses = false;
|
|
1188
1193
|
// war/ear mode
|
|
1189
1194
|
if (path.endsWith(".war") || path.endsWith(".jar")) {
|
|
1190
1195
|
// Check if the file exists
|
|
@@ -1225,11 +1230,16 @@ export async function createJavaBom(path, options) {
|
|
|
1225
1230
|
pomFiles?.length &&
|
|
1226
1231
|
!["scala", "sbt", "gradle"].includes(options.projectType)
|
|
1227
1232
|
) {
|
|
1233
|
+
let result = undefined;
|
|
1228
1234
|
const cdxMavenPlugin =
|
|
1229
1235
|
process.env.CDX_MAVEN_PLUGIN ||
|
|
1230
1236
|
"org.cyclonedx:cyclonedx-maven-plugin:2.8.0";
|
|
1231
1237
|
const cdxMavenGoal = process.env.CDX_MAVEN_GOAL || "makeAggregateBom";
|
|
1232
|
-
let mvnArgs = [
|
|
1238
|
+
let mvnArgs = [
|
|
1239
|
+
"-fn",
|
|
1240
|
+
`${cdxMavenPlugin}:${cdxMavenGoal}`,
|
|
1241
|
+
"-DoutputName=bom",
|
|
1242
|
+
];
|
|
1233
1243
|
if (includeMavenTestScope) {
|
|
1234
1244
|
mvnArgs.push("-DincludeTestScope=true");
|
|
1235
1245
|
}
|
|
@@ -1247,6 +1257,7 @@ export async function createJavaBom(path, options) {
|
|
|
1247
1257
|
if (options.specVersion === 1.4) {
|
|
1248
1258
|
mvnArgs = mvnArgs.concat("-DschemaVersion=1.4");
|
|
1249
1259
|
}
|
|
1260
|
+
const firstPom = pomFiles.length ? pomFiles[0] : undefined;
|
|
1250
1261
|
for (const f of pomFiles) {
|
|
1251
1262
|
const basePath = dirname(f);
|
|
1252
1263
|
const settingsXml = join(basePath, "settings.xml");
|
|
@@ -1268,44 +1279,97 @@ export async function createJavaBom(path, options) {
|
|
|
1268
1279
|
jarNSMapping = { ...jarNSMapping, ...tmpjarNSMapping };
|
|
1269
1280
|
}
|
|
1270
1281
|
}
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
cwd: basePath,
|
|
1274
|
-
shell: true,
|
|
1275
|
-
encoding: "utf-8",
|
|
1276
|
-
timeout: TIMEOUT_MS,
|
|
1277
|
-
maxBuffer: MAX_BUFFER,
|
|
1278
|
-
});
|
|
1279
|
-
// Check if the cyclonedx plugin created the required bom.json file
|
|
1280
|
-
// Sometimes the plugin fails silently for complex maven projects
|
|
1281
|
-
bomJsonFiles = getAllFiles(path, "**/target/*.json", options);
|
|
1282
|
-
// Check if the bom json files got created in a directory other than target
|
|
1283
|
-
if (!bomJsonFiles.length) {
|
|
1284
|
-
bomJsonFiles = getAllFiles(path, "**/bom*.json", options);
|
|
1285
|
-
}
|
|
1286
|
-
const bomGenerated = bomJsonFiles.length;
|
|
1287
|
-
if (!bomGenerated || result.status !== 0 || result.error) {
|
|
1288
|
-
const tempDir = mkdtempSync(join(tmpdir(), "cdxmvn-"));
|
|
1289
|
-
const tempMvnTree = join(tempDir, "mvn-tree.txt");
|
|
1290
|
-
let mvnTreeArgs = ["dependency:tree", `-DoutputFile=${tempMvnTree}`];
|
|
1291
|
-
if (process.env.MVN_ARGS) {
|
|
1292
|
-
const addArgs = process.env.MVN_ARGS.split(" ");
|
|
1293
|
-
mvnTreeArgs = mvnTreeArgs.concat(addArgs);
|
|
1294
|
-
}
|
|
1282
|
+
// Use the cyclonedx maven plugin if there is no preference for maven deps tree
|
|
1283
|
+
if (!PREFER_MAVEN_DEPS_TREE) {
|
|
1295
1284
|
console.log(
|
|
1296
|
-
`
|
|
1285
|
+
`Executing '${mavenCmd} ${mvnArgs.join(" ")}' in`,
|
|
1286
|
+
basePath,
|
|
1297
1287
|
);
|
|
1298
|
-
result = spawnSync(mavenCmd,
|
|
1288
|
+
result = spawnSync(mavenCmd, mvnArgs, {
|
|
1299
1289
|
cwd: basePath,
|
|
1300
1290
|
shell: true,
|
|
1301
1291
|
encoding: "utf-8",
|
|
1302
1292
|
timeout: TIMEOUT_MS,
|
|
1303
1293
|
maxBuffer: MAX_BUFFER,
|
|
1304
1294
|
});
|
|
1295
|
+
// Check if the cyclonedx plugin created the required bom.json file
|
|
1296
|
+
// Sometimes the plugin fails silently for complex maven projects
|
|
1297
|
+
bomJsonFiles = getAllFiles(path, "**/target/*.json", options);
|
|
1298
|
+
// Check if the bom json files got created in a directory other than target
|
|
1299
|
+
if (!bomJsonFiles.length) {
|
|
1300
|
+
bomJsonFiles = getAllFiles(
|
|
1301
|
+
path,
|
|
1302
|
+
"target/**/*{cdx,bom}*.json",
|
|
1303
|
+
options,
|
|
1304
|
+
);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
// Also check if the user has a preference for maven deps tree command
|
|
1308
|
+
if (
|
|
1309
|
+
PREFER_MAVEN_DEPS_TREE ||
|
|
1310
|
+
!bomJsonFiles.length ||
|
|
1311
|
+
result?.status !== 0 ||
|
|
1312
|
+
result?.error
|
|
1313
|
+
) {
|
|
1314
|
+
const tempDir = mkdtempSync(join(tmpdir(), "cdxmvn-"));
|
|
1315
|
+
const tempMvnTree = join(tempDir, "mvn-tree.txt");
|
|
1316
|
+
const tempMvnParentTree = join(tempDir, "mvn-parent-tree.txt");
|
|
1317
|
+
let mvnTreeArgs = ["dependency:tree", `-DoutputFile=${tempMvnTree}`];
|
|
1318
|
+
if (process.env.MVN_ARGS) {
|
|
1319
|
+
const addArgs = process.env.MVN_ARGS.split(" ");
|
|
1320
|
+
mvnTreeArgs = mvnTreeArgs.concat(addArgs);
|
|
1321
|
+
}
|
|
1322
|
+
// Automatically use settings.xml to improve the success for fallback
|
|
1323
|
+
if (existsSync(settingsXml)) {
|
|
1324
|
+
mvnTreeArgs.push("-s");
|
|
1325
|
+
mvnTreeArgs.push(settingsXml);
|
|
1326
|
+
}
|
|
1327
|
+
// For the first pom alone, we need to execute first in non-recursive mode to capture
|
|
1328
|
+
// the parent component. Then, we execute all of them in recursive mode
|
|
1329
|
+
if (f === firstPom) {
|
|
1330
|
+
result = spawnSync(
|
|
1331
|
+
"mvn",
|
|
1332
|
+
["dependency:tree", "-N", `-DoutputFile=${tempMvnParentTree}`],
|
|
1333
|
+
{
|
|
1334
|
+
cwd: basePath,
|
|
1335
|
+
shell: true,
|
|
1336
|
+
encoding: "utf-8",
|
|
1337
|
+
timeout: TIMEOUT_MS,
|
|
1338
|
+
maxBuffer: MAX_BUFFER,
|
|
1339
|
+
},
|
|
1340
|
+
);
|
|
1341
|
+
if (result.status === 0) {
|
|
1342
|
+
if (existsSync(tempMvnParentTree)) {
|
|
1343
|
+
const mvnTreeString = readFileSync(tempMvnParentTree, {
|
|
1344
|
+
encoding: "utf-8",
|
|
1345
|
+
});
|
|
1346
|
+
const parsedList = parseMavenTree(mvnTreeString, f);
|
|
1347
|
+
const dlist = parsedList.pkgList;
|
|
1348
|
+
const tmpParentComponent = dlist.splice(0, 1)[0];
|
|
1349
|
+
tmpParentComponent.type = "application";
|
|
1350
|
+
parentComponent = tmpParentComponent;
|
|
1351
|
+
parentComponent.components = [];
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
console.log(`Executing 'mvn ${mvnTreeArgs.join(" ")}' in ${basePath}`);
|
|
1356
|
+
// Prefer the built-in maven
|
|
1357
|
+
result = spawnSync(
|
|
1358
|
+
PREFER_MAVEN_DEPS_TREE ? "mvn" : mavenCmd,
|
|
1359
|
+
mvnTreeArgs,
|
|
1360
|
+
{
|
|
1361
|
+
cwd: basePath,
|
|
1362
|
+
shell: true,
|
|
1363
|
+
encoding: "utf-8",
|
|
1364
|
+
timeout: TIMEOUT_MS,
|
|
1365
|
+
maxBuffer: MAX_BUFFER,
|
|
1366
|
+
},
|
|
1367
|
+
);
|
|
1305
1368
|
if (result.status !== 0 || result.error) {
|
|
1369
|
+
possible_misses = true;
|
|
1306
1370
|
// Our approach to recursively invoking the maven plugin for each sub-module is bound to result in failures
|
|
1307
1371
|
// These could be due to a range of reasons that are covered below.
|
|
1308
|
-
if (pomFiles.length === 1 || DEBUG_MODE) {
|
|
1372
|
+
if (pomFiles.length === 1 || DEBUG_MODE || PREFER_MAVEN_DEPS_TREE) {
|
|
1309
1373
|
console.error(result.stdout, result.stderr);
|
|
1310
1374
|
console.log("The above build errors could be due to:\n");
|
|
1311
1375
|
if (
|
|
@@ -1319,7 +1383,10 @@ export async function createJavaBom(path, options) {
|
|
|
1319
1383
|
} else if (
|
|
1320
1384
|
result.stdout &&
|
|
1321
1385
|
(result.stdout.includes("Could not resolve dependencies") ||
|
|
1322
|
-
result.stdout.includes("no dependency information available")
|
|
1386
|
+
result.stdout.includes("no dependency information available") ||
|
|
1387
|
+
result.stdout.includes(
|
|
1388
|
+
"The following artifacts could not be resolved",
|
|
1389
|
+
))
|
|
1323
1390
|
) {
|
|
1324
1391
|
console.log(
|
|
1325
1392
|
"1. Try building the project with 'mvn package -Dmaven.test.skip=true' using the correct version of Java and maven before invoking cdxgen.",
|
|
@@ -1358,95 +1425,120 @@ export async function createJavaBom(path, options) {
|
|
|
1358
1425
|
const mvnTreeString = readFileSync(tempMvnTree, {
|
|
1359
1426
|
encoding: "utf-8",
|
|
1360
1427
|
});
|
|
1361
|
-
const parsedList = parseMavenTree(mvnTreeString);
|
|
1428
|
+
const parsedList = parseMavenTree(mvnTreeString, f);
|
|
1362
1429
|
const dlist = parsedList.pkgList;
|
|
1363
|
-
|
|
1364
|
-
|
|
1430
|
+
const tmpParentComponent = dlist.splice(0, 1)[0];
|
|
1431
|
+
tmpParentComponent.type = "application";
|
|
1365
1432
|
if (dlist?.length) {
|
|
1366
1433
|
pkgList = pkgList.concat(dlist);
|
|
1367
1434
|
}
|
|
1435
|
+
// Retain the parent hierarchy
|
|
1436
|
+
if (!Object.keys(parentComponent).length) {
|
|
1437
|
+
parentComponent = tmpParentComponent;
|
|
1438
|
+
parentComponent.components = [];
|
|
1439
|
+
} else {
|
|
1440
|
+
parentComponent.components.push(tmpParentComponent);
|
|
1441
|
+
}
|
|
1368
1442
|
if (parsedList.dependenciesList && parsedList.dependenciesList) {
|
|
1369
|
-
dependencies =
|
|
1443
|
+
dependencies = mergeDependencies(
|
|
1444
|
+
dependencies,
|
|
1445
|
+
parsedList.dependenciesList,
|
|
1446
|
+
tmpParentComponent,
|
|
1447
|
+
);
|
|
1370
1448
|
}
|
|
1371
1449
|
unlinkSync(tempMvnTree);
|
|
1372
1450
|
}
|
|
1373
1451
|
}
|
|
1374
1452
|
}
|
|
1375
1453
|
} // for
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
readFileSync(abjson, {
|
|
1384
|
-
encoding: "utf-8",
|
|
1385
|
-
}),
|
|
1386
|
-
);
|
|
1387
|
-
if (bomJsonObj) {
|
|
1388
|
-
if (
|
|
1389
|
-
!tools &&
|
|
1390
|
-
bomJsonObj.metadata &&
|
|
1391
|
-
bomJsonObj.metadata.tools &&
|
|
1392
|
-
Array.isArray(bomJsonObj.metadata.tools)
|
|
1393
|
-
) {
|
|
1394
|
-
tools = bomJsonObj.metadata.tools;
|
|
1395
|
-
}
|
|
1396
|
-
if (
|
|
1397
|
-
bomJsonObj.metadata?.component &&
|
|
1398
|
-
!Object.keys(parentComponent).length
|
|
1399
|
-
) {
|
|
1400
|
-
parentComponent = bomJsonObj.metadata.component;
|
|
1401
|
-
options.parentComponent = parentComponent;
|
|
1402
|
-
pkgList = [];
|
|
1454
|
+
// Locate and parse all bom.json files from the maven plugin
|
|
1455
|
+
if (!PREFER_MAVEN_DEPS_TREE) {
|
|
1456
|
+
for (const abjson of bomJsonFiles) {
|
|
1457
|
+
let bomJsonObj = undefined;
|
|
1458
|
+
try {
|
|
1459
|
+
if (DEBUG_MODE) {
|
|
1460
|
+
console.log(`Extracting data from generated bom file ${abjson}`);
|
|
1403
1461
|
}
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1462
|
+
bomJsonObj = JSON.parse(
|
|
1463
|
+
readFileSync(abjson, {
|
|
1464
|
+
encoding: "utf-8",
|
|
1465
|
+
}),
|
|
1466
|
+
);
|
|
1467
|
+
if (bomJsonObj) {
|
|
1468
|
+
if (
|
|
1469
|
+
!tools &&
|
|
1470
|
+
bomJsonObj.metadata &&
|
|
1471
|
+
bomJsonObj.metadata.tools &&
|
|
1472
|
+
Array.isArray(bomJsonObj.metadata.tools)
|
|
1473
|
+
) {
|
|
1474
|
+
tools = bomJsonObj.metadata.tools;
|
|
1475
|
+
}
|
|
1476
|
+
if (
|
|
1477
|
+
bomJsonObj.metadata?.component &&
|
|
1478
|
+
!Object.keys(parentComponent).length
|
|
1479
|
+
) {
|
|
1480
|
+
parentComponent = bomJsonObj.metadata.component;
|
|
1481
|
+
options.parentComponent = parentComponent;
|
|
1482
|
+
pkgList = [];
|
|
1483
|
+
}
|
|
1484
|
+
if (bomJsonObj.components) {
|
|
1485
|
+
// Inject evidence into the components. #994
|
|
1486
|
+
if (options.specVersion >= 1.5) {
|
|
1487
|
+
// maven would usually generate a target directory closest to the pom.xml
|
|
1488
|
+
// I am sure there would be cases where this assumption is not true :)
|
|
1489
|
+
const srcPomFile = join(dirname(abjson), "..", "pom.xml");
|
|
1490
|
+
for (const acomp of bomJsonObj.components) {
|
|
1491
|
+
if (!acomp.evidence) {
|
|
1492
|
+
acomp.evidence = {
|
|
1493
|
+
identity: {
|
|
1494
|
+
field: "purl",
|
|
1495
|
+
confidence: 0.8,
|
|
1496
|
+
methods: [
|
|
1497
|
+
{
|
|
1498
|
+
technique: "manifest-analysis",
|
|
1499
|
+
confidence: 0.8,
|
|
1500
|
+
value: srcPomFile,
|
|
1501
|
+
},
|
|
1502
|
+
],
|
|
1503
|
+
},
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
if (!acomp.properties) {
|
|
1507
|
+
acomp.properties = [];
|
|
1508
|
+
}
|
|
1509
|
+
acomp.properties.push({
|
|
1510
|
+
name: "SrcFile",
|
|
1511
|
+
value: srcPomFile,
|
|
1512
|
+
});
|
|
1428
1513
|
}
|
|
1429
|
-
acomp.properties.push({
|
|
1430
|
-
name: "SrcFile",
|
|
1431
|
-
value: srcPomFile,
|
|
1432
|
-
});
|
|
1433
1514
|
}
|
|
1515
|
+
pkgList = pkgList.concat(bomJsonObj.components);
|
|
1516
|
+
}
|
|
1517
|
+
if (bomJsonObj.dependencies) {
|
|
1518
|
+
dependencies = mergeDependencies(
|
|
1519
|
+
dependencies,
|
|
1520
|
+
bomJsonObj.dependencies,
|
|
1521
|
+
parentComponent,
|
|
1522
|
+
);
|
|
1434
1523
|
}
|
|
1435
|
-
pkgList = pkgList.concat(bomJsonObj.components);
|
|
1436
1524
|
}
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
parentComponent,
|
|
1442
|
-
);
|
|
1525
|
+
} catch (err) {
|
|
1526
|
+
if (options.failOnError || DEBUG_MODE) {
|
|
1527
|
+
console.log(err);
|
|
1528
|
+
options.failOnError && process.exit(1);
|
|
1443
1529
|
}
|
|
1444
1530
|
}
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
if (possible_misses) {
|
|
1534
|
+
if (!DEBUG_MODE) {
|
|
1535
|
+
console.warn(
|
|
1536
|
+
"Multiple errors occurred while building this project with maven. The SBOM is therefore incomplete!",
|
|
1537
|
+
);
|
|
1538
|
+
} else if (!PREFER_MAVEN_DEPS_TREE) {
|
|
1539
|
+
console.log(
|
|
1540
|
+
"Try generating an SBOM with the maven dependency tree plugin. Set the environment variable PREFER_MAVEN_DEPS_TREE to true to enable this.",
|
|
1541
|
+
);
|
|
1450
1542
|
}
|
|
1451
1543
|
}
|
|
1452
1544
|
if (pkgList) {
|
|
@@ -4708,12 +4800,7 @@ export async function createCsharpBom(path, options) {
|
|
|
4708
4800
|
for (const f of filesToRestore) {
|
|
4709
4801
|
const buildCmd =
|
|
4710
4802
|
options.projectType === "dotnet-framework" ? "nuget" : "dotnet";
|
|
4711
|
-
|
|
4712
|
-
const basePath = dirname(f);
|
|
4713
|
-
console.log(`Executing '${buildCmd} restore' in ${basePath}`);
|
|
4714
|
-
}
|
|
4715
|
-
const result = spawnSync(
|
|
4716
|
-
buildCmd,
|
|
4803
|
+
const buildArgs =
|
|
4717
4804
|
options.projectType === "dotnet-framework"
|
|
4718
4805
|
? [
|
|
4719
4806
|
"restore",
|
|
@@ -4724,23 +4811,38 @@ export async function createCsharpBom(path, options) {
|
|
|
4724
4811
|
"-Verbosity",
|
|
4725
4812
|
"quiet",
|
|
4726
4813
|
]
|
|
4727
|
-
: ["restore", "--force", "--ignore-failed-sources", f]
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
encoding: "utf-8",
|
|
4731
|
-
},
|
|
4732
|
-
);
|
|
4733
|
-
if (DEBUG_MODE && (result.status !== 0 || result.error)) {
|
|
4734
|
-
console.error(
|
|
4735
|
-
`Restore has failed. Check if ${buildCmd} is installed and available in PATH.`,
|
|
4736
|
-
);
|
|
4737
|
-
console.log(
|
|
4738
|
-
"Authenticate with any private registries such as Azure Artifacts feed before running cdxgen.",
|
|
4739
|
-
);
|
|
4814
|
+
: ["restore", "--force", "--ignore-failed-sources", f];
|
|
4815
|
+
if (DEBUG_MODE) {
|
|
4816
|
+
const basePath = dirname(f);
|
|
4740
4817
|
console.log(
|
|
4741
|
-
|
|
4818
|
+
`Executing '${buildCmd} ${buildArgs.join(" ")}' in ${basePath}`,
|
|
4742
4819
|
);
|
|
4743
|
-
|
|
4820
|
+
}
|
|
4821
|
+
const result = spawnSync(buildCmd, buildArgs, {
|
|
4822
|
+
cwd: path,
|
|
4823
|
+
encoding: "utf-8",
|
|
4824
|
+
env: { ...process.env, DOTNET_ROLL_FORWARD: "Major" },
|
|
4825
|
+
});
|
|
4826
|
+
if (DEBUG_MODE && (result.status !== 0 || result.error)) {
|
|
4827
|
+
if (result?.stderr?.includes("To install missing framework")) {
|
|
4828
|
+
console.log(
|
|
4829
|
+
"This project requires a specific version of dotnet sdk to be installed. The cdxgen container image bundles dotnet SDK 8.0, which might be incompatible.",
|
|
4830
|
+
);
|
|
4831
|
+
console.log(
|
|
4832
|
+
"Try using the unofficial `ghcr.io/appthreat/cdxgen-dotnet6:v10` or `ghcr.io/appthreat/cdxgen-dotnet7:v10` container images.",
|
|
4833
|
+
);
|
|
4834
|
+
} else {
|
|
4835
|
+
console.error(
|
|
4836
|
+
`Restore has failed. Check if ${buildCmd} is installed and available in PATH.`,
|
|
4837
|
+
);
|
|
4838
|
+
console.log(
|
|
4839
|
+
"Authenticate with any private registries such as Azure Artifacts feed before running cdxgen.",
|
|
4840
|
+
);
|
|
4841
|
+
console.log(
|
|
4842
|
+
"Alternatively, try using the unofficial `ghcr.io/appthreat/cdxgen-dotnet6:v10` container image, which bundles nuget (mono) and a range of dotnet SDKs.",
|
|
4843
|
+
);
|
|
4844
|
+
}
|
|
4845
|
+
console.log(result.stdout, result.stderr);
|
|
4744
4846
|
options.failOnError && process.exit(1);
|
|
4745
4847
|
}
|
|
4746
4848
|
}
|
|
@@ -4932,7 +5034,7 @@ export async function createCsharpBom(path, options) {
|
|
|
4932
5034
|
parentComponent = retMap.parentComponent;
|
|
4933
5035
|
}
|
|
4934
5036
|
}
|
|
4935
|
-
if (retMap?.pkgList
|
|
5037
|
+
if (retMap?.pkgList?.length) {
|
|
4936
5038
|
pkgList = pkgList.concat(retMap.pkgList);
|
|
4937
5039
|
}
|
|
4938
5040
|
if (retMap.dependencies?.length) {
|
|
@@ -5062,10 +5164,11 @@ export function mergeDependencies(
|
|
|
5062
5164
|
}
|
|
5063
5165
|
if (adep["dependsOn"]) {
|
|
5064
5166
|
for (const eachDepends of adep["dependsOn"]) {
|
|
5065
|
-
if (
|
|
5066
|
-
parentRef
|
|
5067
|
-
|
|
5068
|
-
|
|
5167
|
+
if (parentRef) {
|
|
5168
|
+
if (eachDepends.toLowerCase() !== parentRef.toLowerCase()) {
|
|
5169
|
+
deps_map[adep.ref].add(eachDepends);
|
|
5170
|
+
}
|
|
5171
|
+
} else {
|
|
5069
5172
|
deps_map[adep.ref].add(eachDepends);
|
|
5070
5173
|
}
|
|
5071
5174
|
}
|
|
@@ -5132,6 +5235,14 @@ export function trimComponents(components) {
|
|
|
5132
5235
|
}
|
|
5133
5236
|
}
|
|
5134
5237
|
}
|
|
5238
|
+
// If the component is required in any of the child projects, then make it required
|
|
5239
|
+
if (
|
|
5240
|
+
existingComponent?.scope !== "required" &&
|
|
5241
|
+
comp?.scope === "required"
|
|
5242
|
+
) {
|
|
5243
|
+
existingComponent.scope = "required";
|
|
5244
|
+
keyCache[key] = existingComponent;
|
|
5245
|
+
}
|
|
5135
5246
|
if (compProps.length) {
|
|
5136
5247
|
existingComponent.properties = compProps;
|
|
5137
5248
|
keyCache[key] = existingComponent;
|
|
@@ -6194,6 +6305,7 @@ export async function createBom(path, options) {
|
|
|
6194
6305
|
*
|
|
6195
6306
|
* @param {Object} args CLI args
|
|
6196
6307
|
* @param {Object} bomContents BOM Json
|
|
6308
|
+
* @return {Promise<{ token: string } | { errors: string[] } | undefined>} a promise with a token (if request was successful), a body with errors (if request failed) or undefined (in case of invalid arguments)
|
|
6197
6309
|
*/
|
|
6198
6310
|
export async function submitBom(args, bomContents) {
|
|
6199
6311
|
const serverUrl = `${args.serverUrl.replace(/\/$/, "")}/api/v1/bom`;
|
|
@@ -6277,11 +6389,11 @@ export async function submitBom(args, bomContents) {
|
|
|
6277
6389
|
console.log(
|
|
6278
6390
|
"Unable to submit the SBOM to the Dependency-Track server using POST method",
|
|
6279
6391
|
);
|
|
6280
|
-
console.log(error);
|
|
6281
6392
|
}
|
|
6282
6393
|
} else {
|
|
6283
6394
|
console.log("Unable to submit the SBOM to the Dependency-Track server");
|
|
6284
|
-
console.log(error);
|
|
6285
6395
|
}
|
|
6396
|
+
console.log(error.response?.body);
|
|
6397
|
+
return error.response?.body;
|
|
6286
6398
|
}
|
|
6287
6399
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyclonedx/cdxgen",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.6.2",
|
|
4
4
|
"description": "Creates CycloneDX Software Bill of Materials (SBOM) from source or container image",
|
|
5
5
|
"homepage": "http://github.com/cyclonedx/cdxgen",
|
|
6
6
|
"author": "Prabhu Subramanian <prabhu@appthreat.com>",
|
|
@@ -47,14 +47,6 @@
|
|
|
47
47
|
"evinse": "bin/evinse.js",
|
|
48
48
|
"cdx-verify": "bin/verify.js"
|
|
49
49
|
},
|
|
50
|
-
"scripts": {
|
|
51
|
-
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --inject-globals false docker.test.js utils.test.js display.test.js postgen.test.js",
|
|
52
|
-
"watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch --inject-globals false",
|
|
53
|
-
"lint:check": "biome check *",
|
|
54
|
-
"lint": "biome check --apply *",
|
|
55
|
-
"lint:errors": "biome check * --diagnostic-level=error",
|
|
56
|
-
"gen-types": "npx -p typescript tsc"
|
|
57
|
-
},
|
|
58
50
|
"engines": {
|
|
59
51
|
"node": ">=20"
|
|
60
52
|
},
|
|
@@ -90,7 +82,8 @@
|
|
|
90
82
|
"tar": "^6.2.1",
|
|
91
83
|
"uuid": "^9.0.1",
|
|
92
84
|
"xml-js": "^1.6.11",
|
|
93
|
-
"yargs": "^17.7.2"
|
|
85
|
+
"yargs": "^17.7.2",
|
|
86
|
+
"validate-iri": "^1.0.1"
|
|
94
87
|
},
|
|
95
88
|
"optionalDependencies": {
|
|
96
89
|
"@appthreat/atom": "2.0.12",
|
|
@@ -109,10 +102,23 @@
|
|
|
109
102
|
"sequelize": "^6.37.3",
|
|
110
103
|
"sqlite3": "^5.1.7"
|
|
111
104
|
},
|
|
112
|
-
"files": [
|
|
105
|
+
"files": [
|
|
106
|
+
"*.js",
|
|
107
|
+
"bin/",
|
|
108
|
+
"data/",
|
|
109
|
+
"types/"
|
|
110
|
+
],
|
|
113
111
|
"devDependencies": {
|
|
114
|
-
"@biomejs/biome": "1.
|
|
112
|
+
"@biomejs/biome": "1.8.1",
|
|
115
113
|
"jest": "^29.7.0",
|
|
116
114
|
"typescript": "^5.4.5"
|
|
115
|
+
},
|
|
116
|
+
"scripts": {
|
|
117
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --inject-globals false docker.test.js utils.test.js display.test.js postgen.test.js",
|
|
118
|
+
"watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch --inject-globals false",
|
|
119
|
+
"lint:check": "biome check",
|
|
120
|
+
"lint": "biome check --fix",
|
|
121
|
+
"lint:errors": "biome check --diagnostic-level=error",
|
|
122
|
+
"gen-types": "npx -p typescript tsc"
|
|
117
123
|
}
|
|
118
|
-
}
|
|
124
|
+
}
|
package/server.js
CHANGED
|
@@ -131,10 +131,11 @@ const start = (options) => {
|
|
|
131
131
|
if (!filePath) {
|
|
132
132
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
133
133
|
return res.end(
|
|
134
|
-
|
|
134
|
+
JSON.stringify({
|
|
135
|
+
error: "path or url is required.",
|
|
136
|
+
}),
|
|
135
137
|
);
|
|
136
138
|
}
|
|
137
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
138
139
|
let srcDir = filePath;
|
|
139
140
|
if (filePath.startsWith("http") || filePath.startsWith("git")) {
|
|
140
141
|
srcDir = gitClone(filePath, reqOptions.gitBranch);
|
|
@@ -145,6 +146,21 @@ const start = (options) => {
|
|
|
145
146
|
if (reqOptions.requiredOnly || reqOptions["filter"] || reqOptions["only"]) {
|
|
146
147
|
bomNSData = postProcess(bomNSData, reqOptions);
|
|
147
148
|
}
|
|
149
|
+
if (reqOptions.serverUrl && reqOptions.apiKey) {
|
|
150
|
+
console.log("Publishing SBOM to Dependency Track");
|
|
151
|
+
const response = await submitBom(reqOptions, bomNSData.bomJson);
|
|
152
|
+
const errorMessages = response?.errors;
|
|
153
|
+
if (errorMessages) {
|
|
154
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
155
|
+
return res.end(
|
|
156
|
+
JSON.stringify({
|
|
157
|
+
error: "Unable to submit the SBOM to the Dependency-Track server",
|
|
158
|
+
details: errorMessages,
|
|
159
|
+
}),
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
148
164
|
if (bomNSData.bomJson) {
|
|
149
165
|
if (
|
|
150
166
|
typeof bomNSData.bomJson === "string" ||
|
|
@@ -155,10 +171,6 @@ const start = (options) => {
|
|
|
155
171
|
res.write(JSON.stringify(bomNSData.bomJson, null, null));
|
|
156
172
|
}
|
|
157
173
|
}
|
|
158
|
-
if (reqOptions.serverUrl && reqOptions.apiKey) {
|
|
159
|
-
console.log("Publishing SBOM to Dependency Track");
|
|
160
|
-
submitBom(reqOptions, bomNSData.bomJson);
|
|
161
|
-
}
|
|
162
174
|
res.end("\n");
|
|
163
175
|
if (cleanup && srcDir && srcDir.startsWith(os.tmpdir()) && fs.rmSync) {
|
|
164
176
|
console.log(`Cleaning up ${srcDir}`);
|
package/types/display.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export function printVulnerabilities(vulnerabilities: any): void;
|
|
2
|
+
export function printSponsorBanner(options: any): void;
|
|
2
3
|
export function printTable(bomJson: any, filterTypes?: any): void;
|
|
3
4
|
export function printOSTable(bomJson: any): void;
|
|
4
5
|
export function printServices(bomJson: any): void;
|
package/types/display.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../display.js"],"names":[],"mappings":"AAuVA,iEA0BC;
|
|
1
|
+
{"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../display.js"],"names":[],"mappings":"AAuVA,iEA0BC;AAED,uDAoBC;AAzXM,kEA+DN;AAQM,iDAkBN;AACM,kDAsBN;AAeM,qDA4BN;AACM,mDA8CN;AACM,uEAiCN;AA4DM,2DA+BN"}
|