@cyclonedx/cdxgen 10.2.4 → 10.2.6

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.
Files changed (4) hide show
  1. package/index.js +13 -4
  2. package/package.json +1 -1
  3. package/utils.js +88 -12
  4. package/utils.test.js +48 -25
package/index.js CHANGED
@@ -4312,6 +4312,13 @@ export async function createCsharpBom(path, options) {
4312
4312
  csProjFiles = csProjFiles.concat(
4313
4313
  getAllFiles(path, (options.multiProject ? "**/" : "") + "*.vbproj", options)
4314
4314
  );
4315
+ csProjFiles = csProjFiles.concat(
4316
+ getAllFiles(
4317
+ path,
4318
+ (options.multiProject ? "**/" : "") + "*.vcxproj",
4319
+ options
4320
+ )
4321
+ );
4315
4322
  csProjFiles = csProjFiles.concat(
4316
4323
  getAllFiles(path, (options.multiProject ? "**/" : "") + "*.fsproj", options)
4317
4324
  );
@@ -4412,7 +4419,7 @@ export async function createCsharpBom(path, options) {
4412
4419
  }
4413
4420
  } else if (pkgLockFiles.length) {
4414
4421
  manifestFiles = manifestFiles.concat(pkgLockFiles);
4415
- let parentDependsOn = [];
4422
+ const parentDependsOn = new Set();
4416
4423
  // packages.lock.json from nuget
4417
4424
  for (const af of pkgLockFiles) {
4418
4425
  if (DEBUG_MODE) {
@@ -4432,13 +4439,15 @@ export async function createCsharpBom(path, options) {
4432
4439
  // Keep track of the direct dependencies so that we can construct one complete
4433
4440
  // list after processing all lock files
4434
4441
  if (rootList && rootList.length) {
4435
- parentDependsOn = parentDependsOn.concat(rootList);
4442
+ for (const p of rootList) {
4443
+ parentDependsOn.add(p["bom-ref"]);
4444
+ }
4436
4445
  }
4437
4446
  }
4438
- if (parentDependsOn.length) {
4447
+ if (parentDependsOn.size) {
4439
4448
  dependencies.splice(0, 0, {
4440
4449
  ref: parentComponent["bom-ref"],
4441
- dependsOn: parentDependsOn.map((p) => p["bom-ref"])
4450
+ dependsOn: Array.from(parentDependsOn)
4442
4451
  });
4443
4452
  }
4444
4453
  } else if (pkgConfigFiles.length) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyclonedx/cdxgen",
3
- "version": "10.2.4",
3
+ "version": "10.2.6",
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>",
package/utils.js CHANGED
@@ -825,19 +825,25 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
825
825
  // which isn't installed
826
826
  // Bug #795. At times, npm loses the integrity node completely and such packages are getting missed out
827
827
  // To keep things safe, we include these packages.
828
- const edgeToIntegrity = edge.to ? edge.to.integrity : undefined;
829
- if (!edgeToIntegrity) {
828
+ let edgeToIntegrityOrLocation = edge.to ? edge.to.integrity : undefined;
829
+ // Fallback to location based lookups when integrity is missing
830
+ if (!edgeToIntegrityOrLocation && edge.to && edge.to.location) {
831
+ edgeToIntegrityOrLocation = edge.to.location;
832
+ }
833
+ if (!edgeToIntegrityOrLocation) {
830
834
  // This hack is required to fix the package name
831
- targetName = node.name.replace(/-cjs$/, "");
832
- targetVersion = node.version;
833
- foundMatch = true;
835
+ targetName = edge.name.replace(/-cjs$/, "");
836
+ foundMatch = false;
834
837
  } else {
835
838
  // the edges don't actually contain a version, so we need to search the root node
836
839
  // children to find the correct version. we check the node children first, then
837
840
  // we check the root node children
838
841
  for (const child of node.children) {
839
- if (edgeToIntegrity) {
840
- if (child[1].integrity == edgeToIntegrity) {
842
+ if (edgeToIntegrityOrLocation) {
843
+ if (
844
+ child[1].integrity === edgeToIntegrityOrLocation ||
845
+ child[1].location === edgeToIntegrityOrLocation
846
+ ) {
841
847
  targetName = child[0].replace(/node_modules\//g, "");
842
848
  // The package name could be different from the targetName retrieved
843
849
  // Eg: "string-width-cjs": "npm:string-width@^4.2.0",
@@ -853,7 +859,11 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
853
859
  }
854
860
  if (!foundMatch) {
855
861
  for (const child of rootNode.children) {
856
- if (child[1].integrity == edgeToIntegrity) {
862
+ if (
863
+ edgeToIntegrityOrLocation &&
864
+ (child[1].integrity == edgeToIntegrityOrLocation ||
865
+ child[1].location == edgeToIntegrityOrLocation)
866
+ ) {
857
867
  targetName = child[0].replace(/node_modules\//g, "");
858
868
  targetVersion = child[1].version;
859
869
  // The package name could be different from the targetName retrieved
@@ -897,7 +907,6 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
897
907
  pkgList = pkgList.concat(childPkgList);
898
908
  dependenciesList = dependenciesList.concat(childDependenciesList);
899
909
  }
900
-
901
910
  dependenciesList.push({
902
911
  ref: decodeURIComponent(purlString),
903
912
  dependsOn: workspaceDependsOn
@@ -6018,17 +6027,84 @@ export function parseCsPkgLockData(csLockData, pkgLockFile) {
6018
6027
  }
6019
6028
  };
6020
6029
  pkgList.push(pkg);
6021
- if (libData.type === "Direct") {
6030
+ if (["Direct", "Project"].includes(libData.type)) {
6022
6031
  rootList.push(pkg);
6023
6032
  }
6024
6033
  const dependsOn = [];
6025
6034
  if (libData.dependencies) {
6026
- for (const adep of Object.keys(libData.dependencies)) {
6035
+ for (let adep of Object.keys(libData.dependencies)) {
6036
+ let adepResolvedVersion = libData.dependencies[adep];
6037
+ const aversionNoRuntime = aversion.split("/")[0];
6038
+ let isProjectType = false;
6039
+ // Try to get the resolved version of the dependency. See #930 and #937
6040
+ if (
6041
+ assetData.dependencies[aversion] &&
6042
+ assetData.dependencies[aversion][adep] &&
6043
+ assetData.dependencies[aversion][adep].resolved
6044
+ ) {
6045
+ adepResolvedVersion =
6046
+ assetData.dependencies[aversion][adep].resolved;
6047
+ } else if (
6048
+ aversion.includes("/") &&
6049
+ assetData.dependencies[aversionNoRuntime] &&
6050
+ assetData.dependencies[aversionNoRuntime][adep] &&
6051
+ assetData.dependencies[aversionNoRuntime][adep].resolved
6052
+ ) {
6053
+ adepResolvedVersion =
6054
+ assetData.dependencies[aversionNoRuntime][adep].resolved;
6055
+ } else if (DEBUG_MODE) {
6056
+ // Only Microsoft can call a lock file that uses version ranges as a "lock file" for "reproducible" builds.
6057
+ if (adepResolvedVersion.startsWith("[")) {
6058
+ const versionToUse = adepResolvedVersion.replace(/[[, )]/g, "");
6059
+ if (
6060
+ (assetData.dependencies[aversion] &&
6061
+ assetData.dependencies[aversion][adep] &&
6062
+ assetData.dependencies[aversion][adep].type === "Project") ||
6063
+ (assetData.dependencies[aversionNoRuntime] &&
6064
+ assetData.dependencies[aversionNoRuntime][adep] &&
6065
+ assetData.dependencies[aversionNoRuntime][adep].type ===
6066
+ "Project")
6067
+ ) {
6068
+ isProjectType = true;
6069
+ }
6070
+ // To make matters worse, the name of the project could be all lowercased
6071
+ // Eg: In react-native-windows repo, folly and Folly are used for the project name
6072
+ else if (
6073
+ (assetData.dependencies[aversion] &&
6074
+ assetData.dependencies[aversion][adep.toLowerCase()] &&
6075
+ assetData.dependencies[aversion][adep.toLowerCase()].type ===
6076
+ "Project") ||
6077
+ (assetData.dependencies[aversionNoRuntime] &&
6078
+ assetData.dependencies[aversionNoRuntime][
6079
+ adep.toLowerCase()
6080
+ ] &&
6081
+ assetData.dependencies[aversionNoRuntime][adep.toLowerCase()]
6082
+ .type === "Project")
6083
+ ) {
6084
+ isProjectType = true;
6085
+ adep = adep.toLowerCase();
6086
+ }
6087
+ // If this component is a project type, the version information would be often missing.
6088
+ // So we remove the version to match based on name alone
6089
+ if (isProjectType) {
6090
+ adepResolvedVersion = undefined;
6091
+ } else {
6092
+ console.warn(
6093
+ `The version used for ${adep} is a range - ${adepResolvedVersion}. Using the min version ${versionToUse} which may be incorrect.`
6094
+ );
6095
+ adepResolvedVersion = versionToUse;
6096
+ }
6097
+ } else {
6098
+ console.warn(
6099
+ `Unable to find the resolved version for ${adep} ${aversion}. Using ${adepResolvedVersion} which may be incorrect.`
6100
+ );
6101
+ }
6102
+ }
6027
6103
  const adpurl = new PackageURL(
6028
6104
  "nuget",
6029
6105
  "",
6030
6106
  adep,
6031
- libData.dependencies[adep],
6107
+ adepResolvedVersion,
6032
6108
  null,
6033
6109
  null
6034
6110
  ).toString();
package/utils.test.js CHANGED
@@ -1230,9 +1230,9 @@ test("parse github actions workflow data", () => {
1230
1230
  expect(dep_list.length).toEqual(3);
1231
1231
  });
1232
1232
 
1233
- test("parse cs pkg data", async () => {
1234
- expect(await parseCsPkgData(null)).toEqual([]);
1235
- const dep_list = await parseCsPkgData(
1233
+ test("parse cs pkg data", () => {
1234
+ expect(parseCsPkgData(null)).toEqual([]);
1235
+ const dep_list = parseCsPkgData(
1236
1236
  readFileSync("./test/data/packages.config", { encoding: "utf-8" })
1237
1237
  );
1238
1238
  expect(dep_list.length).toEqual(21);
@@ -1243,9 +1243,9 @@ test("parse cs pkg data", async () => {
1243
1243
  });
1244
1244
  });
1245
1245
 
1246
- test("parse cs pkg data 2", async () => {
1247
- expect(await parseCsPkgData(null)).toEqual([]);
1248
- const dep_list = await parseCsPkgData(
1246
+ test("parse cs pkg data 2", () => {
1247
+ expect(parseCsPkgData(null)).toEqual([]);
1248
+ const dep_list = parseCsPkgData(
1249
1249
  readFileSync("./test/data/packages2.config", { encoding: "utf-8" })
1250
1250
  );
1251
1251
  expect(dep_list.length).toEqual(1);
@@ -1256,9 +1256,9 @@ test("parse cs pkg data 2", async () => {
1256
1256
  });
1257
1257
  });
1258
1258
 
1259
- test("parse cs proj", async () => {
1260
- expect(await parseCsProjData(null)).toEqual([]);
1261
- const dep_list = await parseCsProjData(
1259
+ test("parse cs proj", () => {
1260
+ expect(parseCsProjData(null)).toEqual([]);
1261
+ const dep_list = parseCsProjData(
1262
1262
  readFileSync("./test/sample.csproj", { encoding: "utf-8" })
1263
1263
  );
1264
1264
  expect(dep_list.length).toEqual(5);
@@ -1269,12 +1269,12 @@ test("parse cs proj", async () => {
1269
1269
  });
1270
1270
  });
1271
1271
 
1272
- test("parse project.assets.json", async () => {
1273
- expect(await parseCsProjAssetsData(null)).toEqual({
1272
+ test("parse project.assets.json", () => {
1273
+ expect(parseCsProjAssetsData(null)).toEqual({
1274
1274
  dependenciesList: [],
1275
1275
  pkgList: []
1276
1276
  });
1277
- let dep_list = await parseCsProjAssetsData(
1277
+ let dep_list = parseCsProjAssetsData(
1278
1278
  readFileSync("./test/data/project.assets.json", { encoding: "utf-8" }),
1279
1279
  "./test/data/project.assets.json"
1280
1280
  );
@@ -1312,7 +1312,7 @@ test("parse project.assets.json", async () => {
1312
1312
  ],
1313
1313
  ref: "pkg:nuget/Castle.Core.Tests@0.0.0"
1314
1314
  });
1315
- dep_list = await parseCsProjAssetsData(
1315
+ dep_list = parseCsProjAssetsData(
1316
1316
  readFileSync("./test/data/project.assets1.json", { encoding: "utf-8" }),
1317
1317
  "./test/data/project.assets1.json"
1318
1318
  );
@@ -1334,13 +1334,13 @@ test("parse project.assets.json", async () => {
1334
1334
  */
1335
1335
  });
1336
1336
 
1337
- test("parse packages.lock.json", async () => {
1338
- expect(await parseCsPkgLockData(null)).toEqual({
1337
+ test("parse packages.lock.json", () => {
1338
+ expect(parseCsPkgLockData(null)).toEqual({
1339
1339
  dependenciesList: [],
1340
1340
  pkgList: [],
1341
1341
  rootList: []
1342
1342
  });
1343
- let dep_list = await parseCsPkgLockData(
1343
+ let dep_list = parseCsPkgLockData(
1344
1344
  readFileSync("./test/data/packages.lock.json", { encoding: "utf-8" }),
1345
1345
  "./test/data/packages.lock.json"
1346
1346
  );
@@ -1368,7 +1368,7 @@ test("parse packages.lock.json", async () => {
1368
1368
  }
1369
1369
  }
1370
1370
  });
1371
- dep_list = await parseCsPkgLockData(
1371
+ dep_list = parseCsPkgLockData(
1372
1372
  readFileSync("./test/data/packages2.lock.json", { encoding: "utf-8" }),
1373
1373
  "./test/data/packages2.lock.json"
1374
1374
  );
@@ -1405,20 +1405,43 @@ test("parse packages.lock.json", async () => {
1405
1405
  "pkg:nuget/Microsoft.Extensions.Logging.Abstractions@6.0.0"
1406
1406
  ]
1407
1407
  });
1408
- dep_list = await parseCsPkgLockData(
1408
+ dep_list = parseCsPkgLockData(
1409
1409
  readFileSync("./test/data/packages3.lock.json", { encoding: "utf-8" }),
1410
1410
  "./test/data/packages3.lock.json"
1411
1411
  );
1412
1412
  expect(dep_list["pkgList"].length).toEqual(15);
1413
+ expect(dep_list["pkgList"][1]).toEqual({
1414
+ group: "",
1415
+ name: "FSharp.Core",
1416
+ version: "4.5.2",
1417
+ purl: "pkg:nuget/FSharp.Core@4.5.2",
1418
+ "bom-ref": "pkg:nuget/FSharp.Core@4.5.2",
1419
+ _integrity:
1420
+ "sha512-apbdQOjzsjQ637kTWQuW29jqwY18jsHMyNC5A+TPJZKFEIE2cIfQWf3V7+mXrxlbX69BueYkv293/g70wuXuRw==",
1421
+ properties: [{ name: "SrcFile", value: "./test/data/packages3.lock.json" }],
1422
+ evidence: {
1423
+ identity: {
1424
+ field: "purl",
1425
+ confidence: 1,
1426
+ methods: [
1427
+ {
1428
+ technique: "manifest-analysis",
1429
+ confidence: 1,
1430
+ value: "./test/data/packages3.lock.json"
1431
+ }
1432
+ ]
1433
+ }
1434
+ }
1435
+ });
1413
1436
  expect(dep_list["dependenciesList"].length).toEqual(15);
1414
1437
  });
1415
1438
 
1416
- test("parse paket.lock", async () => {
1417
- expect(await parsePaketLockData(null)).toEqual({
1439
+ test("parse paket.lock", () => {
1440
+ expect(parsePaketLockData(null)).toEqual({
1418
1441
  pkgList: [],
1419
1442
  dependenciesList: []
1420
1443
  });
1421
- const dep_list = await parsePaketLockData(
1444
+ const dep_list = parsePaketLockData(
1422
1445
  readFileSync("./test/data/paket.lock", { encoding: "utf-8" }),
1423
1446
  "./test/data/paket.lock"
1424
1447
  );
@@ -1454,9 +1477,9 @@ test("parse paket.lock", async () => {
1454
1477
  });
1455
1478
  });
1456
1479
 
1457
- test("parse .net cs proj", async () => {
1458
- expect(await parseCsProjData(null)).toEqual([]);
1459
- const dep_list = await parseCsProjData(
1480
+ test("parse .net cs proj", () => {
1481
+ expect(parseCsProjData(null)).toEqual([]);
1482
+ const dep_list = parseCsProjData(
1460
1483
  readFileSync("./test/data/sample-dotnet.csproj", { encoding: "utf-8" })
1461
1484
  );
1462
1485
  expect(dep_list.length).toEqual(19);
@@ -2835,7 +2858,7 @@ test("parse nupkg file", async () => {
2835
2858
  );
2836
2859
  expect(deps.length).toEqual(1);
2837
2860
  expect(deps[0].name).toEqual("Microsoft.Web.Infrastructure");
2838
- deps = await parseNuspecData(
2861
+ deps = parseNuspecData(
2839
2862
  "./test/data/Microsoft.Web.Infrastructure.1.0.0.0.nuspec",
2840
2863
  readFileSync(
2841
2864
  "./test/data/Microsoft.Web.Infrastructure.1.0.0.0.nuspec",