@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/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 = [`${cdxMavenPlugin}:${cdxMavenGoal}`, "-DoutputName=bom"];
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
- console.log(`Executing '${mavenCmd} ${mvnArgs.join(" ")}' in`, basePath);
1272
- let result = spawnSync(mavenCmd, mvnArgs, {
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
- `Fallback to executing ${mavenCmd} ${mvnTreeArgs.join(" ")}`,
1285
+ `Executing '${mavenCmd} ${mvnArgs.join(" ")}' in`,
1286
+ basePath,
1297
1287
  );
1298
- result = spawnSync(mavenCmd, mvnTreeArgs, {
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
- parentComponent = dlist.splice(0, 1)[0];
1364
- parentComponent.type = "application";
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 = dependencies.concat(parsedList.dependenciesList);
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
- for (const abjson of bomJsonFiles) {
1377
- let bomJsonObj = undefined;
1378
- try {
1379
- if (DEBUG_MODE) {
1380
- console.log(`Extracting data from generated bom file ${abjson}`);
1381
- }
1382
- bomJsonObj = JSON.parse(
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
- if (bomJsonObj.components) {
1405
- // Inject evidence into the components. #994
1406
- if (options.specVersion >= 1.5) {
1407
- // maven would usually generate a target directory closest to the pom.xml
1408
- // I am sure there would be cases where this assumption is not true :)
1409
- const srcPomFile = join(dirname(abjson), "..", "pom.xml");
1410
- for (const acomp of bomJsonObj.components) {
1411
- if (!acomp.evidence) {
1412
- acomp.evidence = {
1413
- identity: {
1414
- field: "purl",
1415
- confidence: 0.8,
1416
- methods: [
1417
- {
1418
- technique: "manifest-analysis",
1419
- confidence: 0.8,
1420
- value: srcPomFile,
1421
- },
1422
- ],
1423
- },
1424
- };
1425
- }
1426
- if (!acomp.properties) {
1427
- acomp.properties = [];
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
- if (bomJsonObj.dependencies) {
1438
- dependencies = mergeDependencies(
1439
- dependencies,
1440
- bomJsonObj.dependencies,
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
- } catch (err) {
1446
- if (options.failOnError || DEBUG_MODE) {
1447
- console.log(err);
1448
- options.failOnError && process.exit(1);
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
- if (DEBUG_MODE) {
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
- cwd: path,
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
- "Alternatively, try using the unofficial `ghcr.io/appthreat/cdxgen-dotnet6:v10` container image, which bundles nuget (mono) and a range of dotnet SDKs.",
4818
+ `Executing '${buildCmd} ${buildArgs.join(" ")}' in ${basePath}`,
4742
4819
  );
4743
- console.log(result.stderr);
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.length) {
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
- eachDepends.toLowerCase() !== parentRef.toLowerCase()
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.5.2",
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": ["*.js", "bin/", "data/", "types/"],
105
+ "files": [
106
+ "*.js",
107
+ "bin/",
108
+ "data/",
109
+ "types/"
110
+ ],
113
111
  "devDependencies": {
114
- "@biomejs/biome": "1.7.3",
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
- "{'error': 'true', 'message': 'path or url is required.'}\n",
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}`);
@@ -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;
@@ -1 +1 @@
1
- {"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../display.js"],"names":[],"mappings":"AAuVA,iEA0BC;AAnWM,kEA+DN;AAQM,iDAkBN;AACM,kDAsBN;AAeM,qDA4BN;AACM,mDA8CN;AACM,uEAiCN;AA4DM,2DA+BN"}
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"}