@cyclonedx/cdxgen 9.3.1 → 9.4.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.
package/index.js CHANGED
@@ -199,18 +199,25 @@ const createDefaultParentComponent = (path, type = "application") => {
199
199
 
200
200
  const determineParentComponent = (options) => {
201
201
  let parentComponent = undefined;
202
- if (options.projectName && options.projectVersion) {
202
+ if (options.parentComponent && Object.keys(options.parentComponent).length) {
203
+ return options.parentComponent;
204
+ } else if (options.projectName && options.projectVersion) {
203
205
  parentComponent = {
204
206
  group: options.projectGroup || "",
205
207
  name: options.projectName,
206
208
  version: "" + options.projectVersion || "",
207
209
  type: "application"
208
210
  };
209
- } else if (
210
- options.parentComponent &&
211
- Object.keys(options.parentComponent).length
212
- ) {
213
- return options.parentComponent;
211
+ const ppurl = new PackageURL(
212
+ parentComponent.type,
213
+ parentComponent.group,
214
+ parentComponent.name,
215
+ parentComponent.version,
216
+ null,
217
+ null
218
+ ).toString();
219
+ parentComponent["bom-ref"] = ppurl;
220
+ parentComponent["purl"] = decodeURIComponent(ppurl);
214
221
  }
215
222
  return parentComponent;
216
223
  };
@@ -323,11 +330,18 @@ function addMetadata(parentComponent = {}, format = "xml", options = {}) {
323
330
  if (parentComponent) {
324
331
  delete parentComponent.evidence;
325
332
  delete parentComponent._integrity;
333
+ delete parentComponent.license;
334
+ if (!parentComponent["purl"] && parentComponent["bom-ref"]) {
335
+ parentComponent["purl"] = decodeURIComponent(
336
+ parentComponent["bom-ref"]
337
+ );
338
+ }
326
339
  }
327
340
  if (parentComponent && parentComponent.components) {
328
341
  for (const comp of parentComponent.components) {
329
342
  delete comp.evidence;
330
343
  delete comp._integrity;
344
+ delete comp.license;
331
345
  if (!comp["bom-ref"] && comp.name && comp.type) {
332
346
  let fullName =
333
347
  comp.group && comp.group.length
@@ -1216,7 +1230,8 @@ export const createJavaBom = async (path, options) => {
1216
1230
  if (bomJsonObj.dependencies && !options.requiredOnly) {
1217
1231
  dependencies = mergeDependencies(
1218
1232
  dependencies,
1219
- bomJsonObj.dependencies
1233
+ bomJsonObj.dependencies,
1234
+ parentComponent
1220
1235
  );
1221
1236
  }
1222
1237
  }
@@ -1335,16 +1350,21 @@ export const createJavaBom = async (path, options) => {
1335
1350
  let gradleDepArgs = [
1336
1351
  sp.purl === parentComponent.purl
1337
1352
  ? depTaskWithArgs[0]
1338
- : `:${sp.name}:${depTaskWithArgs[0]}`
1353
+ : `:${sp.name.replace(/\//, ":")}:${depTaskWithArgs[0]}`
1339
1354
  ];
1340
1355
  gradleDepArgs = gradleDepArgs
1341
1356
  .concat(depTaskWithArgs.slice(1))
1342
1357
  .concat(defaultDepTaskArgs);
1343
- // Support custom GRADLE_ARGS such as --configuration runtimeClassPath
1358
+ // Support custom GRADLE_ARGS such as --configuration runtimeClassPath (used for all tasks)
1344
1359
  if (process.env.GRADLE_ARGS) {
1345
1360
  const addArgs = process.env.GRADLE_ARGS.split(" ");
1346
1361
  gradleDepArgs = gradleDepArgs.concat(addArgs);
1347
1362
  }
1363
+ // gradle args only for the dependencies task
1364
+ if (process.env.GRADLE_ARGS_DEPENDENCIES) {
1365
+ const addArgs = process.env.GRADLE_ARGS_DEPENDENCIES.split(" ");
1366
+ gradleDepArgs = gradleDepArgs.concat(addArgs);
1367
+ }
1348
1368
  console.log(
1349
1369
  "Executing",
1350
1370
  gradleCmd,
@@ -1376,7 +1396,8 @@ export const createJavaBom = async (path, options) => {
1376
1396
  if (parsedList.dependenciesList && parsedList.dependenciesList) {
1377
1397
  dependencies = mergeDependencies(
1378
1398
  dependencies,
1379
- parsedList.dependenciesList
1399
+ parsedList.dependenciesList,
1400
+ parentComponent
1380
1401
  );
1381
1402
  }
1382
1403
  if (dlist && dlist.length) {
@@ -1779,9 +1800,9 @@ export const createNodejsBom = async (path, options) => {
1779
1800
  parentComponent.type = "application";
1780
1801
  ppurl = new PackageURL(
1781
1802
  "npm",
1782
- parentComponent.group,
1783
- parentComponent.name,
1784
- parentComponent.version,
1803
+ options.projectGroup || parentComponent.group,
1804
+ options.projectName || parentComponent.name,
1805
+ options.projectVersion || parentComponent.version,
1785
1806
  null,
1786
1807
  null
1787
1808
  ).toString();
@@ -1799,9 +1820,9 @@ export const createNodejsBom = async (path, options) => {
1799
1820
  };
1800
1821
  ppurl = new PackageURL(
1801
1822
  "npm",
1802
- parentComponent.group,
1803
- parentComponent.name,
1804
- parentComponent.version,
1823
+ options.projectGroup || parentComponent.group,
1824
+ options.projectName || parentComponent.name,
1825
+ options.projectVersion || parentComponent.version,
1805
1826
  null,
1806
1827
  null
1807
1828
  ).toString();
@@ -1817,7 +1838,8 @@ export const createNodejsBom = async (path, options) => {
1817
1838
  if (parsedList.dependenciesList && parsedList.dependenciesList) {
1818
1839
  dependencies = mergeDependencies(
1819
1840
  dependencies,
1820
- parsedList.dependenciesList
1841
+ parsedList.dependenciesList,
1842
+ parentComponent
1821
1843
  );
1822
1844
  }
1823
1845
  }
@@ -1829,11 +1851,10 @@ export const createNodejsBom = async (path, options) => {
1829
1851
  console.log(`Parsing ${f}`);
1830
1852
  }
1831
1853
  // Parse package-lock.json if available
1832
- const parsedList = await parsePkgLock(f);
1854
+ const parsedList = await parsePkgLock(f, options);
1833
1855
  const dlist = parsedList.pkgList;
1834
1856
  const tmpParentComponent = dlist.splice(0, 1)[0] || {};
1835
1857
  tmpParentComponent.type = "application";
1836
- // Create a default parent component based on directory name
1837
1858
  if (!Object.keys(parentComponent).length) {
1838
1859
  parentComponent = tmpParentComponent;
1839
1860
  } else {
@@ -1845,7 +1866,8 @@ export const createNodejsBom = async (path, options) => {
1845
1866
  if (parsedList.dependenciesList && parsedList.dependenciesList) {
1846
1867
  dependencies = mergeDependencies(
1847
1868
  dependencies,
1848
- parsedList.dependenciesList
1869
+ parsedList.dependenciesList,
1870
+ parentComponent
1849
1871
  );
1850
1872
  }
1851
1873
  }
@@ -1920,9 +1942,9 @@ export const createNodejsBom = async (path, options) => {
1920
1942
  tmpParentComponent.type = "application";
1921
1943
  ppurl = new PackageURL(
1922
1944
  "npm",
1923
- tmpParentComponent.group,
1924
- tmpParentComponent.name,
1925
- tmpParentComponent.version,
1945
+ options.projectGroup || tmpParentComponent.group,
1946
+ options.projectName || tmpParentComponent.name,
1947
+ options.projectVersion || tmpParentComponent.version,
1926
1948
  null,
1927
1949
  null
1928
1950
  ).toString();
@@ -1939,15 +1961,15 @@ export const createNodejsBom = async (path, options) => {
1939
1961
  const tmpA = dirName.split(sep);
1940
1962
  dirName = tmpA[tmpA.length - 1];
1941
1963
  const tmpParentComponent = {
1942
- group: "",
1943
- name: dirName,
1964
+ group: options.projectGroup || "",
1965
+ name: options.projectName || dirName,
1944
1966
  type: "application"
1945
1967
  };
1946
1968
  ppurl = new PackageURL(
1947
1969
  "npm",
1948
1970
  tmpParentComponent.group,
1949
1971
  tmpParentComponent.name,
1950
- tmpParentComponent.version,
1972
+ options.projectVersion || tmpParentComponent.version,
1951
1973
  null,
1952
1974
  null
1953
1975
  ).toString();
@@ -1991,7 +2013,8 @@ export const createNodejsBom = async (path, options) => {
1991
2013
  }
1992
2014
  dependencies = mergeDependencies(
1993
2015
  dependencies,
1994
- parsedList.dependenciesList
2016
+ parsedList.dependenciesList,
2017
+ parentComponent
1995
2018
  );
1996
2019
  }
1997
2020
  }
@@ -2020,6 +2043,8 @@ export const createNodejsBom = async (path, options) => {
2020
2043
  if (parentSubComponents.length) {
2021
2044
  parentComponent.components = parentSubComponents;
2022
2045
  }
2046
+ // We need to set this to force our version to be used rather than the directory name based one.
2047
+ options.parentComponent = parentComponent;
2023
2048
  return buildBomNSData(options, pkgList, "npm", {
2024
2049
  allImports,
2025
2050
  src: path,
@@ -2250,14 +2275,20 @@ export const createPythonBom = async (path, options) => {
2250
2275
  pkgMap = getPipFrozenTree(path, undefined, tempDir);
2251
2276
  }
2252
2277
  // Get the imported modules and a dedupe list of packages
2253
- const parentDependsOn = [];
2278
+ const parentDependsOn = new Set();
2254
2279
  const retMap = await getPyModules(path, pkgList);
2255
2280
  if (retMap.pkgList && retMap.pkgList.length) {
2256
2281
  pkgList = pkgList.concat(retMap.pkgList);
2257
2282
  for (const p of retMap.pkgList) {
2258
- if (p.version) {
2259
- parentDependsOn.push(`pkg:pypi/${p.name}@${p.version}`);
2283
+ if (
2284
+ !p.version ||
2285
+ (parentComponent &&
2286
+ p.name === parentComponent.name &&
2287
+ (p.version === parentComponent.version || p.version === "latest"))
2288
+ ) {
2289
+ continue;
2260
2290
  }
2291
+ parentDependsOn.add(`pkg:pypi/${p.name}@${p.version}`);
2261
2292
  }
2262
2293
  }
2263
2294
  if (retMap.dependenciesList) {
@@ -2275,11 +2306,11 @@ export const createPythonBom = async (path, options) => {
2275
2306
  if (
2276
2307
  parentComponent &&
2277
2308
  p.name === parentComponent.name &&
2278
- p.version === parentComponent.version
2309
+ (p.version === parentComponent.version || p.version === "latest")
2279
2310
  ) {
2280
2311
  continue;
2281
2312
  }
2282
- parentDependsOn.push(`pkg:pypi/${p.name}@${p.version}`);
2313
+ parentDependsOn.add(`pkg:pypi/${p.name}@${p.version}`);
2283
2314
  }
2284
2315
  if (pkgMap.pkgList && pkgMap.pkgList.length) {
2285
2316
  pkgList = pkgList.concat(pkgMap.pkgList);
@@ -2291,13 +2322,22 @@ export const createPythonBom = async (path, options) => {
2291
2322
  parentComponent
2292
2323
  );
2293
2324
  }
2294
- const pdependencies = {
2295
- ref: parentComponent["bom-ref"],
2296
- dependsOn: parentDependsOn.filter(
2297
- (r) => parentComponent && r !== parentComponent["bom-ref"]
2298
- )
2299
- };
2300
- dependencies.splice(0, 0, pdependencies);
2325
+ let parentPresent = false;
2326
+ for (const d of dependencies) {
2327
+ if (d.ref === parentComponent["bom-ref"]) {
2328
+ parentPresent = true;
2329
+ break;
2330
+ }
2331
+ }
2332
+ if (!parentPresent) {
2333
+ const pdependencies = {
2334
+ ref: parentComponent["bom-ref"],
2335
+ dependsOn: Array.from(parentDependsOn).filter(
2336
+ (r) => parentComponent && r !== parentComponent["bom-ref"]
2337
+ )
2338
+ };
2339
+ dependencies.splice(0, 0, pdependencies);
2340
+ }
2301
2341
  }
2302
2342
  }
2303
2343
  // Final fallback is to manually parse setup.py if we still
@@ -3158,7 +3198,8 @@ export const createSwiftBom = (path, options) => {
3158
3198
  if (retData.dependenciesList) {
3159
3199
  dependencies = mergeDependencies(
3160
3200
  dependencies,
3161
- retData.dependenciesList
3201
+ retData.dependenciesList,
3202
+ parentComponent
3162
3203
  );
3163
3204
  }
3164
3205
  } else {
@@ -3434,7 +3475,8 @@ export const createContainerSpecLikeBom = async (path, options) => {
3434
3475
  if (mbomData.bomJson.dependencies) {
3435
3476
  dependencies = mergeDependencies(
3436
3477
  dependencies,
3437
- mbomData.bomJson.dependencies
3478
+ mbomData.bomJson.dependencies,
3479
+ parentComponent
3438
3480
  );
3439
3481
  }
3440
3482
  if (mbomData.bomJson.services) {
@@ -3723,6 +3765,11 @@ export const mergeDependencies = (
3723
3765
  newDependencies,
3724
3766
  parentComponent = {}
3725
3767
  ) => {
3768
+ if (!parentComponent && DEBUG_MODE) {
3769
+ console.log(
3770
+ "Unable to determine parent component. Dependencies will be flattened."
3771
+ );
3772
+ }
3726
3773
  const deps_map = {};
3727
3774
  const parentRef =
3728
3775
  parentComponent && parentComponent["bom-ref"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyclonedx/cdxgen",
3
- "version": "9.3.1",
3
+ "version": "9.4.0",
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>",
@@ -31,13 +31,14 @@
31
31
  "type": "module",
32
32
  "exports": "./index.js",
33
33
  "bin": {
34
- "cdxgen": "./bin/cdxgen.js"
34
+ "cdxgen": "./bin/cdxgen.js",
35
+ "cdxi": "./bin/repl.js"
35
36
  },
36
37
  "scripts": {
37
38
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --inject-globals false",
38
39
  "watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch --inject-globals false",
39
- "lint": "eslint *.js *.test.js bin/cdxgen.js",
40
- "pretty": "prettier --write *.js data/*.json bin/cdxgen.js --trailing-comma=none"
40
+ "lint": "eslint *.js *.test.js bin/*.js",
41
+ "pretty": "prettier --write *.js data/*.json bin/*.js --trailing-comma=none"
41
42
  },
42
43
  "engines": {
43
44
  "node": ">=16"
@@ -50,8 +51,8 @@
50
51
  "url": "https://github.com/cyclonedx/cdxgen/issues"
51
52
  },
52
53
  "dependencies": {
53
- "@babel/parser": "^7.22.5",
54
- "@babel/traverse": "^7.22.5",
54
+ "@babel/parser": "^7.22.10",
55
+ "@babel/traverse": "^7.22.10",
55
56
  "ajv": "^8.12.0",
56
57
  "ajv-formats": "^2.1.1",
57
58
  "cheerio": "^1.0.0-rc.12",
@@ -75,11 +76,12 @@
75
76
  "yargs": "^17.7.2"
76
77
  },
77
78
  "optionalDependencies": {
78
- "@appthreat/atom": "^1.0.0",
79
+ "@appthreat/atom": "^1.0.1",
79
80
  "@cyclonedx/cdxgen-plugins-bin": "^1.2.0",
80
81
  "body-parser": "^1.20.2",
81
82
  "compression": "^1.7.4",
82
- "connect": "^3.7.0"
83
+ "connect": "^3.7.0",
84
+ "jsonata": "^2.0.3"
83
85
  },
84
86
  "files": [
85
87
  "*.js",
@@ -88,7 +90,8 @@
88
90
  ],
89
91
  "devDependencies": {
90
92
  "caxa": "^3.0.1",
91
- "eslint": "^8.43.0",
92
- "jest": "^29.5.0"
93
+ "eslint": "^8.47.0",
94
+ "jest": "^29.5.0",
95
+ "prettier": "3.0.1"
93
96
  }
94
97
  }
package/piptree.js CHANGED
@@ -57,12 +57,11 @@ def find_deps(idx, visited, reqs, traverse_count):
57
57
  if not d:
58
58
  continue
59
59
  r.project_name = d.project_name if d is not None else r.project_name
60
- if len(visited) > 100 and visited.get(r.project_name):
60
+ if len(visited) > 100 or visited.get(r.project_name, 0) > 5:
61
61
  return freqs
62
62
  specs = sorted(r.specs, reverse=True)
63
63
  specs_str = ",".join(["".join(sp) for sp in specs]) if specs else ""
64
64
  dreqs = d.requires()
65
- visited[r.project_name] = True
66
65
  freqs.append(
67
66
  {
68
67
  "name": r.project_name,
@@ -71,6 +70,7 @@ def find_deps(idx, visited, reqs, traverse_count):
71
70
  "dependencies": find_deps(idx, visited, dreqs, traverse_count + 1) if dreqs and traverse_count < 200 else [],
72
71
  }
73
72
  )
73
+ visited[r.project_name] = visited.get(r.project_name, 0) + 1
74
74
  return freqs
75
75
 
76
76