@cdxgen/cdxgen 13.2.0 → 13.3.0

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 (158) hide show
  1. package/README.md +28 -12
  2. package/bin/cdxgen.js +227 -119
  3. package/bin/evinse.js +5 -0
  4. package/bin/sign.js +88 -14
  5. package/bin/tracebom.js +64 -4
  6. package/bin/validate.js +29 -7
  7. package/bin/verify.js +79 -39
  8. package/data/remediations.json +24 -0
  9. package/lib/cli/bomAssembly.js +105 -15
  10. package/lib/cli/cliOptions.js +93 -1
  11. package/lib/cli/index.js +43 -4
  12. package/lib/cli/jsBom.js +49 -24
  13. package/lib/cli/jvmBom.js +46 -12
  14. package/lib/cli/managedBom.js +112 -41
  15. package/lib/cli/nativeBom.js +125 -14
  16. package/lib/core/env.js +5 -6
  17. package/lib/core/fs.js +174 -6
  18. package/lib/core/metadataProperties.js +97 -0
  19. package/lib/core/projectConfig.js +31 -4
  20. package/lib/ecosystems/bunutils.js +269 -101
  21. package/lib/ecosystems/caxa.js +434 -2
  22. package/lib/ecosystems/cmakeResolver.js +66 -0
  23. package/lib/ecosystems/cppEvidence.js +64 -31
  24. package/lib/ecosystems/ecosystems.js +19 -8
  25. package/lib/ecosystems/gradleutils.js +42 -7
  26. package/lib/ecosystems/jsEvidence.js +19 -20
  27. package/lib/ecosystems/kosi.js +10 -3
  28. package/lib/ecosystems/npmutils.js +110 -9
  29. package/lib/ecosystems/parsers-dotnet.js +51 -10
  30. package/lib/ecosystems/parsers-go.js +47 -9
  31. package/lib/ecosystems/parsers-js.js +171 -50
  32. package/lib/ecosystems/parsers-misc.js +747 -161
  33. package/lib/ecosystems/parsers-python.js +26 -14
  34. package/lib/ecosystems/parsers-rust.js +24 -18
  35. package/lib/ecosystems/rubyutils.js +1426 -166
  36. package/lib/ecosystems/rusi.js +32 -1
  37. package/lib/evinser/evinser.js +436 -128
  38. package/lib/evinser/swiftsem.js +1914 -302
  39. package/lib/helpers/bomSigner.js +652 -221
  40. package/lib/inventory/atomUtils.js +568 -31
  41. package/lib/inventory/cdxrs.js +103 -12
  42. package/lib/inventory/depsUtils.js +183 -11
  43. package/lib/inventory/display.js +4 -5
  44. package/lib/inventory/dosai.js +550 -13
  45. package/lib/inventory/dynamic.js +39 -1
  46. package/lib/inventory/evidenceUtils.js +14 -6
  47. package/lib/inventory/fetchBatch.js +116 -17
  48. package/lib/inventory/protobom.js +8 -1
  49. package/lib/inventory/purl.js +152 -3
  50. package/lib/inventory/sbomDocument.js +2 -70
  51. package/lib/inventory/source.js +37 -19
  52. package/lib/inventory/traceRunner.js +210 -21
  53. package/lib/managers/binary.js +115 -24
  54. package/lib/managers/docker.js +440 -20
  55. package/lib/managers/oci.js +39 -1
  56. package/lib/parsers/cmakeLists.js +452 -0
  57. package/lib/parsers/largeJson.js +454 -0
  58. package/lib/parsers/npmrc.js +19 -1
  59. package/lib/stages/postgen/postgen.js +68 -15
  60. package/lib/validator/bomValidator.js +6 -16
  61. package/lib/validator/index.js +48 -10
  62. package/lib/validator/reporters/console.js +3 -0
  63. package/lib/validator/reporters/json.js +1 -0
  64. package/lib/validator/reporters/sarif.js +7 -0
  65. package/package.json +20 -20
  66. package/types/lib/cli/bomAssembly.d.ts +2 -1
  67. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  68. package/types/lib/cli/cliOptions.d.ts +33 -1
  69. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  70. package/types/lib/cli/index.d.ts.map +1 -1
  71. package/types/lib/cli/jsBom.d.ts.map +1 -1
  72. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  73. package/types/lib/cli/managedBom.d.ts.map +1 -1
  74. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  75. package/types/lib/core/env.d.ts.map +1 -1
  76. package/types/lib/core/fs.d.ts +55 -0
  77. package/types/lib/core/fs.d.ts.map +1 -1
  78. package/types/lib/core/metadataProperties.d.ts +39 -0
  79. package/types/lib/core/metadataProperties.d.ts.map +1 -0
  80. package/types/lib/core/projectConfig.d.ts +6 -2
  81. package/types/lib/core/projectConfig.d.ts.map +1 -1
  82. package/types/lib/ecosystems/bunutils.d.ts +12 -5
  83. package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
  84. package/types/lib/ecosystems/caxa.d.ts +14 -0
  85. package/types/lib/ecosystems/caxa.d.ts.map +1 -1
  86. package/types/lib/ecosystems/cmakeResolver.d.ts +23 -0
  87. package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
  88. package/types/lib/ecosystems/cppEvidence.d.ts +1 -1
  89. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  90. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  91. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  92. package/types/lib/ecosystems/gradleutils.d.ts +20 -4
  93. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  94. package/types/lib/ecosystems/jsEvidence.d.ts +5 -2
  95. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
  96. package/types/lib/ecosystems/kosi.d.ts +13 -0
  97. package/types/lib/ecosystems/kosi.d.ts.map +1 -1
  98. package/types/lib/ecosystems/npmutils.d.ts +42 -0
  99. package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
  100. package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
  101. package/types/lib/ecosystems/parsers-go.d.ts +10 -0
  102. package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
  103. package/types/lib/ecosystems/parsers-js.d.ts +10 -4
  104. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  105. package/types/lib/ecosystems/parsers-misc.d.ts +67 -3
  106. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  107. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  108. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
  109. package/types/lib/ecosystems/pythonutils.d.ts +1 -1
  110. package/types/lib/ecosystems/rubyutils.d.ts +143 -2
  111. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  112. package/types/lib/ecosystems/rusi.d.ts +13 -0
  113. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  114. package/types/lib/evinser/evinser.d.ts +59 -9
  115. package/types/lib/evinser/evinser.d.ts.map +1 -1
  116. package/types/lib/evinser/swiftsem.d.ts +280 -15
  117. package/types/lib/evinser/swiftsem.d.ts.map +1 -1
  118. package/types/lib/helpers/bomSigner.d.ts +106 -13
  119. package/types/lib/helpers/bomSigner.d.ts.map +1 -1
  120. package/types/lib/inventory/atomUtils.d.ts +145 -3
  121. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  122. package/types/lib/inventory/cdxrs.d.ts +8 -3
  123. package/types/lib/inventory/cdxrs.d.ts.map +1 -1
  124. package/types/lib/inventory/depsUtils.d.ts +15 -0
  125. package/types/lib/inventory/depsUtils.d.ts.map +1 -1
  126. package/types/lib/inventory/display.d.ts.map +1 -1
  127. package/types/lib/inventory/dosai.d.ts +64 -1
  128. package/types/lib/inventory/dosai.d.ts.map +1 -1
  129. package/types/lib/inventory/dynamic.d.ts.map +1 -1
  130. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  131. package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
  132. package/types/lib/inventory/plugins.d.ts.map +1 -1
  133. package/types/lib/inventory/protobom.d.ts.map +1 -1
  134. package/types/lib/inventory/purl.d.ts +71 -2
  135. package/types/lib/inventory/purl.d.ts.map +1 -1
  136. package/types/lib/inventory/sbomDocument.d.ts.map +1 -1
  137. package/types/lib/inventory/source.d.ts.map +1 -1
  138. package/types/lib/inventory/traceRunner.d.ts +47 -1
  139. package/types/lib/inventory/traceRunner.d.ts.map +1 -1
  140. package/types/lib/managers/binary.d.ts +30 -1
  141. package/types/lib/managers/binary.d.ts.map +1 -1
  142. package/types/lib/managers/docker.d.ts +29 -0
  143. package/types/lib/managers/docker.d.ts.map +1 -1
  144. package/types/lib/managers/oci.d.ts +14 -0
  145. package/types/lib/managers/oci.d.ts.map +1 -1
  146. package/types/lib/parsers/cmakeLists.d.ts +76 -0
  147. package/types/lib/parsers/cmakeLists.d.ts.map +1 -0
  148. package/types/lib/parsers/largeJson.d.ts +52 -0
  149. package/types/lib/parsers/largeJson.d.ts.map +1 -0
  150. package/types/lib/parsers/npmrc.d.ts +5 -0
  151. package/types/lib/parsers/npmrc.d.ts.map +1 -1
  152. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  153. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  154. package/types/lib/validator/index.d.ts +10 -1
  155. package/types/lib/validator/index.d.ts.map +1 -1
  156. package/types/lib/validator/reporters/console.d.ts.map +1 -1
  157. package/types/lib/validator/reporters/json.d.ts.map +1 -1
  158. package/types/lib/validator/reporters/sarif.d.ts.map +1 -1
@@ -105,7 +105,9 @@ export async function parsePiplockData(lockData) {
105
105
  Object.keys(depBlock).forEach((p) => {
106
106
  const pkg = depBlock[p];
107
107
  if (Object.hasOwn(pkg, "version")) {
108
- const versionStr = pkg.version.replace("==", "");
108
+ // `===` (arbitrary equality) pins as tightly as `==`, so both are
109
+ // stripped whole rather than leaving a stray `=` behind.
110
+ const versionStr = pkg.version.replace(/^\s*={2,3}\s*/, "");
109
111
  pkgList.push({ name: p, version: versionStr });
110
112
  }
111
113
  });
@@ -1427,6 +1429,16 @@ export async function parsePyLockData(lockData, lockFile, pyProjectFile) {
1427
1429
  };
1428
1430
  }
1429
1431
 
1432
+ /**
1433
+ * First version clause of a PEP 508 requirement: an operator and the version
1434
+ * that follows it.
1435
+ *
1436
+ * `===` (arbitrary equality) is tried before `==`, whitespace may separate the
1437
+ * operator from the version, and a version may carry a PEP 440 epoch (`1!2.0`)
1438
+ * or a local version label (`2.1.0+cpu`).
1439
+ */
1440
+ const PEP440_VERSION_CLAUSE = /(===|==|!=|<=|>=|~=|<|>)\s*([0-9A-Za-z.*_+!-]*)/;
1441
+
1430
1442
  /**
1431
1443
  * Method to parse requirements.txt file. This must be replaced with atom parsedeps.
1432
1444
  *
@@ -1513,10 +1525,13 @@ async function parseReqData(reqFile, reqData = null, fetchDepsInfo = false) {
1513
1525
  continue;
1514
1526
  }
1515
1527
  let comment = null;
1516
- const commentMatch = l.match(/\s+#(.*)$/);
1517
- if (commentMatch) {
1518
- comment = commentMatch[1].trim();
1519
- l = l.substring(0, commentMatch.index).trim();
1528
+ // Equivalent to /\s+#(.*)$/ but linear: an unanchored `\s+` backtracks
1529
+ // quadratically on long whitespace runs without a '#', which a crafted
1530
+ // requirements.txt used to burn seconds of CPU per line.
1531
+ const hashIndex = l.indexOf("#");
1532
+ if (hashIndex > 0 && /\s/.test(l[hashIndex - 1])) {
1533
+ comment = l.substring(hashIndex + 1).trim();
1534
+ l = l.substring(0, hashIndex).trim();
1520
1535
  }
1521
1536
  const properties = reqFile
1522
1537
  ? [
@@ -1607,9 +1622,7 @@ async function parseReqData(reqFile, reqData = null, fetchDepsInfo = false) {
1607
1622
  if (PYTHON_STD_MODULES.includes(name)) {
1608
1623
  continue;
1609
1624
  }
1610
- const versionMatch = versionSpecifiers.match(
1611
- /(==|!=|<=|>=|<|>|~=)([0-9.a-zA-Z_*\-+]*)/,
1612
- );
1625
+ const versionMatch = versionSpecifiers.match(PEP440_VERSION_CLAUSE);
1613
1626
  let version = null;
1614
1627
  if (versionMatch) {
1615
1628
  version = versionMatch[2].replaceAll("*", "0") || null;
@@ -1636,7 +1649,7 @@ async function parseReqData(reqFile, reqData = null, fetchDepsInfo = false) {
1636
1649
  value: extras.join(","),
1637
1650
  });
1638
1651
  }
1639
- if (versionSpecifiers && !versionSpecifiers.startsWith("==")) {
1652
+ if (versionSpecifiers && !versionSpecifiers.trim().startsWith("==")) {
1640
1653
  properties.push({
1641
1654
  name: "cdx:pypi:versionSpecifiers",
1642
1655
  value: versionSpecifiers.trim(),
@@ -1673,9 +1686,7 @@ async function parseReqData(reqFile, reqData = null, fetchDepsInfo = false) {
1673
1686
  if (PYTHON_STD_MODULES.includes(name)) {
1674
1687
  continue;
1675
1688
  }
1676
- const versionMatch = versionSpecifiers.match(
1677
- /(==|!=|<=|>=|<|>|~=)([0-9.a-zA-Z_*\-+]*)/,
1678
- );
1689
+ const versionMatch = versionSpecifiers.match(PEP440_VERSION_CLAUSE);
1679
1690
  let version = null;
1680
1691
  if (versionMatch) {
1681
1692
  version = versionMatch[2].replaceAll("*", "0") || null;
@@ -1691,7 +1702,7 @@ async function parseReqData(reqFile, reqData = null, fetchDepsInfo = false) {
1691
1702
  if (licenses) {
1692
1703
  apkg.licenses = licenses;
1693
1704
  }
1694
- if (versionSpecifiers && !versionSpecifiers.startsWith("==")) {
1705
+ if (versionSpecifiers && !versionSpecifiers.trim().startsWith("==")) {
1695
1706
  properties.push({
1696
1707
  name: "cdx:pypi:versionSpecifiers",
1697
1708
  value: versionSpecifiers.trim(),
@@ -2201,6 +2212,7 @@ function normaliseMojoVersion(spec) {
2201
2212
  const trimmed = spec.trim();
2202
2213
  if (!trimmed) return undefined;
2203
2214
  // Strip common comparison operators and take the first concrete version.
2204
- const match = trimmed.match(/(\d+(?:\.\d+)*(?:[+-][A-Za-z0-9.]+)?)/);
2215
+ // A PEP 440 epoch (`1!2.0`) is part of the version, not a separator.
2216
+ const match = trimmed.match(/((?:\d+!)?\d+(?:\.\d+)*(?:[+-][A-Za-z0-9.]+)?)/);
2205
2217
  return match ? match[1] : undefined;
2206
2218
  }
@@ -1309,15 +1309,20 @@ export function parseCargoDependencyData(cargoLockData) {
1309
1309
  );
1310
1310
  }
1311
1311
  });
1312
- // Create a map of package names to package objects
1313
- const pkgMap = pkgList.reduce((acc, item) => {
1314
- acc[item.name] = item;
1315
- return acc;
1316
- }, {});
1317
- const result = [];
1318
- // parse dependency version
1319
- Object.values(pkgMap).forEach((pkg) => {
1320
- const dependsOn = new Set();
1312
+ // A lock file can hold several versions of one crate. Cargo then names the
1313
+ // version in every reference to it (`getrandom 0.3.4`), and a bare name is
1314
+ // left only for crates with a single version.
1315
+ const pkgsByName = new Map();
1316
+ for (const pkg of pkgList) {
1317
+ pkgsByName.set(pkg.name, [...(pkgsByName.get(pkg.name) || []), pkg]);
1318
+ }
1319
+ // Every package gets its own entry, so each version keeps its edges. The
1320
+ // same name and version from two sources share a purl; their edges merge.
1321
+ const edgesByRef = new Map();
1322
+ for (const pkg of pkgList) {
1323
+ const ref = purlFromPackageInfo(pkg);
1324
+ const dependsOn = edgesByRef.get(ref) || new Set();
1325
+ edgesByRef.set(ref, dependsOn);
1321
1326
  pkg.dependencies?.forEach((dep) => {
1322
1327
  if (dep.indexOf(" ") !== -1) {
1323
1328
  // fill version in dependency definition like `libc 0.2.79`
@@ -1328,20 +1333,21 @@ export function parseCargoDependencyData(cargoLockData) {
1328
1333
  version: depSplit[1].trim(),
1329
1334
  }),
1330
1335
  );
1331
- } else if (pkgMap[dep]) {
1332
- dependsOn.add(purlFromPackageInfo(pkgMap[dep]));
1336
+ } else if (pkgsByName.get(dep)?.length === 1) {
1337
+ dependsOn.add(purlFromPackageInfo(pkgsByName.get(dep)[0]));
1333
1338
  } else if (DEBUG_MODE) {
1334
1339
  console.warn(
1335
- `The package "${dep.name}" appears as a dependency to "${pkg.name}" but is not itself listed in the Cargo.lock file. The Cargo.lock file is invalid! The produced SBOM will not list ${dep.name} as a dependency.`,
1340
+ pkgsByName.has(dep)
1341
+ ? `The package "${dep}" appears as a dependency to "${pkg.name}" without a version, but the Cargo.lock file lists more than one version of it. The produced SBOM will not list ${dep} as a dependency.`
1342
+ : `The package "${dep}" appears as a dependency to "${pkg.name}" but is not itself listed in the Cargo.lock file. The Cargo.lock file is invalid! The produced SBOM will not list ${dep} as a dependency.`,
1336
1343
  );
1337
1344
  }
1338
1345
  });
1339
- result.push({
1340
- ref: purlFromPackageInfo(pkg),
1341
- dependsOn: [...dependsOn],
1342
- });
1343
- });
1344
- return result;
1346
+ }
1347
+ return [...edgesByRef].map(([ref, dependsOn]) => ({
1348
+ ref,
1349
+ dependsOn: [...dependsOn],
1350
+ }));
1345
1351
  }
1346
1352
 
1347
1353
  /**