@cyclonedx/cdxgen 9.11.2 → 9.11.4

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
@@ -1391,7 +1391,7 @@ export const createJavaBom = async (path, options) => {
1391
1391
  parentComponent = {
1392
1392
  name: rootProject,
1393
1393
  type: "application",
1394
- ...(retMap.metadata || {})
1394
+ ...retMap.metadata
1395
1395
  };
1396
1396
  const parentPurl = new PackageURL(
1397
1397
  "maven",
@@ -1415,7 +1415,7 @@ export const createJavaBom = async (path, options) => {
1415
1415
  name: rspName,
1416
1416
  type: "application",
1417
1417
  qualifiers: { type: "jar" },
1418
- ...(retMap.metadata || {})
1418
+ ...retMap.metadata
1419
1419
  };
1420
1420
  const rootSubProjectPurl = new PackageURL(
1421
1421
  "maven",
@@ -4280,14 +4280,11 @@ export const createRubyBom = async (path, options) => {
4280
4280
  * @param path to the project
4281
4281
  * @param options Parse options from the cli
4282
4282
  */
4283
- export const createCsharpBom = async (
4284
- path,
4285
- options,
4286
- parentComponent = undefined
4287
- ) => {
4283
+ export const createCsharpBom = async (path, options) => {
4288
4284
  let manifestFiles = [];
4289
4285
  let pkgData = undefined;
4290
4286
  let dependencies = [];
4287
+ let parentComponent = createDefaultParentComponent(path, "nuget", options);
4291
4288
  let csProjFiles = getAllFiles(
4292
4289
  path,
4293
4290
  (options.multiProject ? "**/" : "") + "*.csproj",
@@ -4352,21 +4349,39 @@ export const createCsharpBom = async (
4352
4349
  pkgList = pkgList.concat(dlist);
4353
4350
  }
4354
4351
  if (deps && deps.length) {
4355
- dependencies = dependencies.concat(deps);
4352
+ dependencies = mergeDependencies(dependencies, deps, parentComponent);
4356
4353
  }
4357
4354
  }
4358
4355
  } else if (pkgLockFiles.length) {
4359
4356
  manifestFiles = manifestFiles.concat(pkgLockFiles);
4357
+ let parentDependsOn = [];
4360
4358
  // packages.lock.json from nuget
4361
4359
  for (const af of pkgLockFiles) {
4362
4360
  if (DEBUG_MODE) {
4363
4361
  console.log(`Parsing ${af}`);
4364
4362
  }
4365
4363
  pkgData = readFileSync(af, { encoding: "utf-8" });
4366
- const dlist = await parseCsPkgLockData(pkgData);
4364
+ let results = await parseCsPkgLockData(pkgData, af);
4365
+ let deps = results["dependenciesList"];
4366
+ let dlist = results["pkgList"];
4367
+ let rootList = results["rootList"];
4367
4368
  if (dlist && dlist.length) {
4368
4369
  pkgList = pkgList.concat(dlist);
4369
4370
  }
4371
+ if (deps && deps.length) {
4372
+ dependencies = mergeDependencies(dependencies, deps, parentComponent);
4373
+ }
4374
+ // Keep track of the direct dependencies so that we can construct one complete
4375
+ // list after processing all lock files
4376
+ if (rootList && rootList.length) {
4377
+ parentDependsOn = parentDependsOn.concat(rootList);
4378
+ }
4379
+ }
4380
+ if (parentDependsOn.length) {
4381
+ dependencies.splice(0, 0, {
4382
+ ref: parentComponent["bom-ref"],
4383
+ dependsOn: parentDependsOn.map((p) => p["bom-ref"])
4384
+ });
4370
4385
  }
4371
4386
  } else if (pkgConfigFiles.length) {
4372
4387
  manifestFiles = manifestFiles.concat(pkgConfigFiles);
@@ -4418,15 +4433,11 @@ export const createCsharpBom = async (
4418
4433
  pkgList = pkgList.concat(dlist);
4419
4434
  }
4420
4435
  if (deps && deps.length) {
4421
- dependencies = dependencies.concat(deps);
4436
+ dependencies = mergeDependencies(dependencies, deps, parentComponent);
4422
4437
  }
4423
4438
  }
4424
4439
  }
4425
- if (!parentComponent) {
4426
- parentComponent = createDefaultParentComponent(path, options.type, options);
4427
- }
4428
4440
  if (pkgList.length) {
4429
- dependencies = mergeDependencies(dependencies, [], parentComponent);
4430
4441
  pkgList = trimComponents(pkgList, "json");
4431
4442
  // Perform deep analysis using dosai
4432
4443
  if (options.deep) {
@@ -4450,7 +4461,6 @@ export const createCsharpBom = async (
4450
4461
  if (retMap.dependencies && retMap.dependencies.length) {
4451
4462
  dependencies = dependencies.concat(retMap.dependencies);
4452
4463
  }
4453
- dependencies = mergeDependencies(dependencies, [], parentComponent);
4454
4464
  pkgList = trimComponents(pkgList, "json");
4455
4465
  }
4456
4466
  return buildBomNSData(options, pkgList, "nuget", {
@@ -4808,7 +4818,7 @@ export const createMultiXBom = async (pathList, options) => {
4808
4818
  listComponents(options, {}, bomData.bomJson.components, "gem", "xml")
4809
4819
  );
4810
4820
  }
4811
- bomData = await createCsharpBom(path, options, parentComponent);
4821
+ bomData = await createCsharpBom(path, options);
4812
4822
  if (
4813
4823
  bomData &&
4814
4824
  bomData.bomJson &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyclonedx/cdxgen",
3
- "version": "9.11.2",
3
+ "version": "9.11.4",
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
@@ -5577,28 +5577,95 @@ export const parseCsProjAssetsData = async function (
5577
5577
  };
5578
5578
  };
5579
5579
 
5580
- export const parseCsPkgLockData = async function (csLockData) {
5580
+ export const parseCsPkgLockData = async function (csLockData, pkgLockFile) {
5581
5581
  const pkgList = [];
5582
+ const dependenciesList = [];
5583
+ const rootList = [];
5582
5584
  let pkg = null;
5583
5585
  if (!csLockData) {
5584
- return pkgList;
5586
+ return {
5587
+ pkgList,
5588
+ dependenciesList,
5589
+ rootList
5590
+ };
5585
5591
  }
5586
5592
  const assetData = JSON.parse(csLockData);
5587
5593
  if (!assetData || !assetData.dependencies) {
5588
- return pkgList;
5594
+ return {
5595
+ pkgList,
5596
+ dependenciesList,
5597
+ rootList
5598
+ };
5589
5599
  }
5590
5600
  for (const aversion of Object.keys(assetData.dependencies)) {
5591
5601
  for (const alib of Object.keys(assetData.dependencies[aversion])) {
5592
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();
5593
5611
  pkg = {
5594
5612
  group: "",
5595
5613
  name: alib,
5596
- 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
+ }
5597
5639
  };
5598
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
+ });
5599
5662
  }
5600
5663
  }
5601
- return pkgList;
5664
+ return {
5665
+ pkgList,
5666
+ dependenciesList,
5667
+ rootList
5668
+ };
5602
5669
  };
5603
5670
 
5604
5671
  export const parsePaketLockData = async function (paketLockData, pkgLockFile) {
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 () => {