@cyclonedx/cdxgen 9.11.1 → 9.11.3

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 CHANGED
@@ -345,7 +345,7 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
345
345
  - Gradle
346
346
  - Scala SBT
347
347
  - Python (requirements.txt, setup.py, pyproject.toml, poetry.lock)
348
- - .NET (project.assets.json, paket.lock)
348
+ - .NET (packages.lock.json, project.assets.json, paket.lock)
349
349
  - Go (go.mod)
350
350
  - PHP (composer.lock)
351
351
 
package/index.js CHANGED
@@ -1236,46 +1236,50 @@ export const createJavaBom = async (path, options) => {
1236
1236
  maxBuffer: MAX_BUFFER
1237
1237
  });
1238
1238
  if (result.status !== 0 || result.error) {
1239
- console.error(result.stdout, result.stderr);
1240
- console.log(
1241
- "Resolve the above maven error. This could be due to the following:\n"
1242
- );
1243
- if (
1244
- result.stdout &&
1245
- (result.stdout.includes("Non-resolvable parent POM") ||
1246
- result.stdout.includes("points at wrong local POM"))
1247
- ) {
1248
- console.log(
1249
- "1. Check if the pom.xml contains valid settings such `parent.relativePath` to make mvn command work from within the sub-directory."
1250
- );
1251
- } else if (
1252
- result.stdout &&
1253
- (result.stdout.includes("Could not resolve dependencies") ||
1254
- result.stdout.includes("no dependency information available"))
1255
- ) {
1239
+ // Our approach to recursively invoking the maven plugin for each sub-module is bound to result in failures
1240
+ // These could be due to a range of reasons that are covered below.
1241
+ if (pomFiles.length === 1 || DEBUG_MODE) {
1242
+ console.error(result.stdout, result.stderr);
1256
1243
  console.log(
1257
- "1. Try building the project with 'mvn package -Dmaven.test.skip=true' using the correct version of Java and maven before invoking cdxgen."
1244
+ "Resolve the above maven error. This could be due to the following:\n"
1258
1245
  );
1259
- } else if (
1260
- result.stdout &&
1261
- result.stdout.includes(
1262
- "Could not resolve target platform specification"
1263
- )
1264
- ) {
1246
+ if (
1247
+ result.stdout &&
1248
+ (result.stdout.includes("Non-resolvable parent POM") ||
1249
+ result.stdout.includes("points at wrong local POM"))
1250
+ ) {
1251
+ console.log(
1252
+ "1. Check if the pom.xml contains valid settings such `parent.relativePath` to make mvn command work from within the sub-directory."
1253
+ );
1254
+ } else if (
1255
+ result.stdout &&
1256
+ (result.stdout.includes("Could not resolve dependencies") ||
1257
+ result.stdout.includes("no dependency information available"))
1258
+ ) {
1259
+ console.log(
1260
+ "1. Try building the project with 'mvn package -Dmaven.test.skip=true' using the correct version of Java and maven before invoking cdxgen."
1261
+ );
1262
+ } else if (
1263
+ result.stdout &&
1264
+ result.stdout.includes(
1265
+ "Could not resolve target platform specification"
1266
+ )
1267
+ ) {
1268
+ console.log(
1269
+ "1. Some projects can be built only from the root directory. Invoke cdxgen with --no-recurse option"
1270
+ );
1271
+ } else {
1272
+ console.log(
1273
+ "1. Java version requirement: cdxgen container image bundles Java 21 with maven 3.9 which might be incompatible."
1274
+ );
1275
+ }
1265
1276
  console.log(
1266
- "1. Some projects can be built only from the root directory. Invoke cdxgen with --no-recurse option"
1277
+ "2. Private dependencies cannot be downloaded: Check if any additional arguments must be passed to maven and set them via MVN_ARGS environment variable."
1267
1278
  );
1268
- } else {
1269
1279
  console.log(
1270
- "1. Java version requirement: cdxgen container image bundles Java 21 with maven 3.9 which might be incompatible."
1280
+ "3. Check if all required environment variables including any maven profile arguments are passed correctly to this tool."
1271
1281
  );
1272
1282
  }
1273
- console.log(
1274
- "2. Private dependencies cannot be downloaded: Check if any additional arguments must be passed to maven and set them via MVN_ARGS environment variable."
1275
- );
1276
- console.log(
1277
- "3. Check if all required environment variables including any maven profile arguments are passed correctly to this tool."
1278
- );
1279
1283
  // Do not fall back to methods that can produce incomplete results when failOnError is set
1280
1284
  options.failOnError && process.exit(1);
1281
1285
  console.log(
@@ -1718,7 +1722,18 @@ export const createJavaBom = async (path, options) => {
1718
1722
  }
1719
1723
  } else {
1720
1724
  const SBT_CMD = process.env.SBT_CMD || "sbt";
1721
- const sbtVersion = determineSbtVersion(path);
1725
+ let sbtVersion = determineSbtVersion(path);
1726
+ // If can't find sbt version at the root of repository then search in
1727
+ // sbt project array too because sometimes the project folder isn't at
1728
+ // root of repository
1729
+ if (sbtVersion == null) {
1730
+ for (const i in sbtProjects) {
1731
+ sbtVersion = determineSbtVersion(sbtProjects[i]);
1732
+ if (sbtVersion != null) {
1733
+ break;
1734
+ }
1735
+ }
1736
+ }
1722
1737
  if (DEBUG_MODE) {
1723
1738
  console.log("Detected sbt version: " + sbtVersion);
1724
1739
  }
@@ -4342,16 +4357,41 @@ export const createCsharpBom = async (
4342
4357
  }
4343
4358
  } else if (pkgLockFiles.length) {
4344
4359
  manifestFiles = manifestFiles.concat(pkgLockFiles);
4360
+ let parentDependsOn = [];
4345
4361
  // packages.lock.json from nuget
4346
4362
  for (const af of pkgLockFiles) {
4347
4363
  if (DEBUG_MODE) {
4348
4364
  console.log(`Parsing ${af}`);
4349
4365
  }
4350
4366
  pkgData = readFileSync(af, { encoding: "utf-8" });
4351
- const dlist = await parseCsPkgLockData(pkgData);
4367
+ let results = await parseCsPkgLockData(pkgData, af);
4368
+ let deps = results["dependenciesList"];
4369
+ let dlist = results["pkgList"];
4370
+ let rootList = results["rootList"];
4352
4371
  if (dlist && dlist.length) {
4353
4372
  pkgList = pkgList.concat(dlist);
4354
4373
  }
4374
+ if (deps && deps.length) {
4375
+ dependencies = dependencies.concat(deps);
4376
+ }
4377
+ if (!parentComponent) {
4378
+ parentComponent = createDefaultParentComponent(
4379
+ path,
4380
+ options.type,
4381
+ options
4382
+ );
4383
+ }
4384
+ // Keep track of the direct dependencies so that we can construct one complete
4385
+ // list after processing all lock files
4386
+ if (rootList && rootList.length) {
4387
+ parentDependsOn = parentDependsOn.concat(rootList);
4388
+ }
4389
+ }
4390
+ if (parentDependsOn.length) {
4391
+ dependencies.splice(0, 0, {
4392
+ ref: parentComponent["bom-ref"],
4393
+ dependsOn: parentDependsOn.map((p) => p["bom-ref"])
4394
+ });
4355
4395
  }
4356
4396
  } else if (pkgConfigFiles.length) {
4357
4397
  manifestFiles = manifestFiles.concat(pkgConfigFiles);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyclonedx/cdxgen",
3
- "version": "9.11.1",
3
+ "version": "9.11.3",
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>",
@@ -55,9 +55,9 @@
55
55
  "url": "https://github.com/cyclonedx/cdxgen/issues"
56
56
  },
57
57
  "dependencies": {
58
- "@babel/parser": "^7.23.6",
59
- "@babel/traverse": "^7.23.7",
60
- "@npmcli/arborist": "7.2.2",
58
+ "@babel/parser": "^7.23.9",
59
+ "@babel/traverse": "^7.23.9",
60
+ "@npmcli/arborist": "7.3.1",
61
61
  "ajv": "^8.12.0",
62
62
  "ajv-formats": "^2.1.1",
63
63
  "cheerio": "^1.0.0-rc.12",
package/utils.js CHANGED
@@ -1260,6 +1260,9 @@ export const parsePnpmLock = async function (pnpmLock, parentComponent = null) {
1260
1260
  ).toString();
1261
1261
  }
1262
1262
  if (existsSync(pnpmLock)) {
1263
+ if (DEBUG_MODE) {
1264
+ console.log(`Parsing file ${pnpmLock}`);
1265
+ }
1263
1266
  const lockData = readFileSync(pnpmLock, "utf8");
1264
1267
  const yamlObj = _load(lockData);
1265
1268
  if (!yamlObj) {
@@ -1295,7 +1298,7 @@ export const parsePnpmLock = async function (pnpmLock, parentComponent = null) {
1295
1298
  } catch (e) {
1296
1299
  // ignore parse errors
1297
1300
  }
1298
- const packages = yamlObj.packages;
1301
+ const packages = yamlObj.packages || {};
1299
1302
  const pkgKeys = Object.keys(packages);
1300
1303
  for (const k in pkgKeys) {
1301
1304
  // Eg: @babel/code-frame/7.10.1
@@ -5574,28 +5577,95 @@ export const parseCsProjAssetsData = async function (
5574
5577
  };
5575
5578
  };
5576
5579
 
5577
- export const parseCsPkgLockData = async function (csLockData) {
5580
+ export const parseCsPkgLockData = async function (csLockData, pkgLockFile) {
5578
5581
  const pkgList = [];
5582
+ const dependenciesList = [];
5583
+ const rootList = [];
5579
5584
  let pkg = null;
5580
5585
  if (!csLockData) {
5581
- return pkgList;
5586
+ return {
5587
+ pkgList,
5588
+ dependenciesList,
5589
+ rootList
5590
+ };
5582
5591
  }
5583
5592
  const assetData = JSON.parse(csLockData);
5584
5593
  if (!assetData || !assetData.dependencies) {
5585
- return pkgList;
5594
+ return {
5595
+ pkgList,
5596
+ dependenciesList,
5597
+ rootList
5598
+ };
5586
5599
  }
5587
5600
  for (const aversion of Object.keys(assetData.dependencies)) {
5588
5601
  for (const alib of Object.keys(assetData.dependencies[aversion])) {
5589
5602
  const libData = assetData.dependencies[aversion][alib];
5603
+ const purl = new PackageURL(
5604
+ "nuget",
5605
+ "",
5606
+ alib,
5607
+ libData.resolved,
5608
+ null,
5609
+ null
5610
+ ).toString();
5590
5611
  pkg = {
5591
5612
  group: "",
5592
5613
  name: alib,
5593
- version: libData.resolved
5614
+ version: libData.resolved,
5615
+ purl,
5616
+ "bom-ref": decodeURIComponent(purl),
5617
+ _integrity: libData.contentHash
5618
+ ? "sha512-" + libData.contentHash
5619
+ : undefined,
5620
+ properties: [
5621
+ {
5622
+ name: "SrcFile",
5623
+ value: pkgLockFile
5624
+ }
5625
+ ],
5626
+ evidence: {
5627
+ identity: {
5628
+ field: "purl",
5629
+ confidence: 1,
5630
+ methods: [
5631
+ {
5632
+ technique: "manifest-analysis",
5633
+ confidence: 1,
5634
+ value: pkgLockFile
5635
+ }
5636
+ ]
5637
+ }
5638
+ }
5594
5639
  };
5595
5640
  pkgList.push(pkg);
5641
+ if (libData.type === "Direct") {
5642
+ rootList.push(pkg);
5643
+ }
5644
+ const dependsOn = [];
5645
+ if (libData.dependencies) {
5646
+ for (const adep of Object.keys(libData.dependencies)) {
5647
+ const adpurl = new PackageURL(
5648
+ "nuget",
5649
+ "",
5650
+ adep,
5651
+ libData.dependencies[adep],
5652
+ null,
5653
+ null
5654
+ ).toString();
5655
+ dependsOn.push(decodeURIComponent(adpurl));
5656
+ }
5657
+ }
5658
+ dependenciesList.push({
5659
+ ref: decodeURIComponent(purl),
5660
+ dependsOn
5661
+ });
5596
5662
  }
5597
5663
  }
5598
- return pkgList;
5664
+ return {
5665
+ pkgList,
5666
+ dependenciesList,
5667
+ rootList
5668
+ };
5599
5669
  };
5600
5670
 
5601
5671
  export const parsePaketLockData = async function (paketLockData, pkgLockFile) {
@@ -7207,6 +7277,9 @@ export const extractJarArchive = async function (
7207
7277
  */
7208
7278
  export const determineSbtVersion = function (projectPath) {
7209
7279
  const buildPropFile = join(projectPath, "project", "build.properties");
7280
+ if (DEBUG_MODE) {
7281
+ console.log("Looking for", buildPropFile);
7282
+ }
7210
7283
  if (existsSync(buildPropFile)) {
7211
7284
  const properties = propertiesReader(buildPropFile);
7212
7285
  const property = properties.get("sbt.version");
@@ -7495,6 +7568,7 @@ export const executeAtom = (src, args) => {
7495
7568
  timeout: TIMEOUT_MS,
7496
7569
  detached: !isWin && !process.env.CI,
7497
7570
  shell: isWin,
7571
+ killSignal: "SIGKILL",
7498
7572
  env
7499
7573
  });
7500
7574
  if (result.stderr) {
package/utils.test.js CHANGED
@@ -1333,16 +1333,82 @@ test("parse project.assets.json", async () => {
1333
1333
  });
1334
1334
 
1335
1335
  test("parse packages.lock.json", async () => {
1336
- expect(await parseCsPkgLockData(null)).toEqual([]);
1337
- const dep_list = await parseCsPkgLockData(
1338
- readFileSync("./test/data/packages.lock.json", { encoding: "utf-8" })
1336
+ expect(await parseCsPkgLockData(null)).toEqual({
1337
+ dependenciesList: [],
1338
+ pkgList: [],
1339
+ rootList: []
1340
+ });
1341
+ let dep_list = await parseCsPkgLockData(
1342
+ readFileSync("./test/data/packages.lock.json", { encoding: "utf-8" }),
1343
+ "./test/data/packages.lock.json"
1339
1344
  );
1340
- expect(dep_list.length).toEqual(14);
1341
- expect(dep_list[0]).toEqual({
1345
+ expect(dep_list["pkgList"].length).toEqual(14);
1346
+ expect(dep_list["pkgList"][0]).toEqual({
1342
1347
  group: "",
1343
1348
  name: "Antlr",
1344
- version: "3.5.0.2"
1349
+ version: "3.5.0.2",
1350
+ purl: "pkg:nuget/Antlr@3.5.0.2",
1351
+ "bom-ref": "pkg:nuget/Antlr@3.5.0.2",
1352
+ _integrity:
1353
+ "sha512-CSfrVuDVMx3OrQhT84zed+tOdM1clljyRLWWlQM22fJsmG836RVDGQlE6tzysXh8X8p9UjkHbLr6OqEIVhtdEA==",
1354
+ properties: [{ name: "SrcFile", value: "./test/data/packages.lock.json" }],
1355
+ evidence: {
1356
+ identity: {
1357
+ field: "purl",
1358
+ confidence: 1,
1359
+ methods: [
1360
+ {
1361
+ technique: "manifest-analysis",
1362
+ confidence: 1,
1363
+ value: "./test/data/packages.lock.json"
1364
+ }
1365
+ ]
1366
+ }
1367
+ }
1368
+ });
1369
+ dep_list = await parseCsPkgLockData(
1370
+ readFileSync("./test/data/packages2.lock.json", { encoding: "utf-8" }),
1371
+ "./test/data/packages2.lock.json"
1372
+ );
1373
+ expect(dep_list["pkgList"].length).toEqual(34);
1374
+ expect(dep_list["dependenciesList"].length).toEqual(34);
1375
+ expect(dep_list["pkgList"][0]).toEqual({
1376
+ group: "",
1377
+ name: "McMaster.Extensions.Hosting.CommandLine",
1378
+ version: "4.0.1",
1379
+ purl: "pkg:nuget/McMaster.Extensions.Hosting.CommandLine@4.0.1",
1380
+ "bom-ref": "pkg:nuget/McMaster.Extensions.Hosting.CommandLine@4.0.1",
1381
+ _integrity:
1382
+ "sha512-pZJF/zeXT3OC+3GUNO9ZicpCO9I7wYLmj0E2qPR8CRA6iUs0kGu6SCkmraB1sITx4elcVjMLiZDGMsBVMqaPhg==",
1383
+ properties: [{ name: "SrcFile", value: "./test/data/packages2.lock.json" }],
1384
+ evidence: {
1385
+ identity: {
1386
+ field: "purl",
1387
+ confidence: 1,
1388
+ methods: [
1389
+ {
1390
+ technique: "manifest-analysis",
1391
+ confidence: 1,
1392
+ value: "./test/data/packages2.lock.json"
1393
+ }
1394
+ ]
1395
+ }
1396
+ }
1345
1397
  });
1398
+ expect(dep_list["dependenciesList"][0]).toEqual({
1399
+ ref: "pkg:nuget/McMaster.Extensions.Hosting.CommandLine@4.0.1",
1400
+ dependsOn: [
1401
+ "pkg:nuget/McMaster.Extensions.CommandLineUtils@4.0.1",
1402
+ "pkg:nuget/Microsoft.Extensions.Hosting.Abstractions@6.0.0",
1403
+ "pkg:nuget/Microsoft.Extensions.Logging.Abstractions@6.0.0"
1404
+ ]
1405
+ });
1406
+ dep_list = await parseCsPkgLockData(
1407
+ readFileSync("./test/data/packages3.lock.json", { encoding: "utf-8" }),
1408
+ "./test/data/packages3.lock.json"
1409
+ );
1410
+ expect(dep_list["pkgList"].length).toEqual(15);
1411
+ expect(dep_list["dependenciesList"].length).toEqual(15);
1346
1412
  });
1347
1413
 
1348
1414
  test("parse paket.lock", async () => {