@cyclonedx/cdxgen 8.4.3 → 8.4.7

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
@@ -248,7 +248,7 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
248
248
 
249
249
  | Variable | Description |
250
250
  | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
251
- | SCAN_DEBUG_MODE | Set to `debug` to enable debug messages |
251
+ | CDXGEN_DEBUG_MODE | Set to `debug` to enable debug messages |
252
252
  | GITHUB_TOKEN | Specify GitHub token to prevent traffic shaping while querying license and repo information |
253
253
  | MVN_CMD | Set to override maven command |
254
254
  | MVN_ARGS | Set to pass additional arguments such as profile or settings to maven |
package/binary.js CHANGED
@@ -7,6 +7,7 @@ const isWin = require("os").platform() === "win32";
7
7
 
8
8
  // Debug mode flag
9
9
  const DEBUG_MODE =
10
+ process.env.CDXGEN_DEBUG_MODE === "debug" ||
10
11
  process.env.SCAN_DEBUG_MODE === "debug" ||
11
12
  process.env.SHIFTLEFT_LOGGING_LEVEL === "debug" ||
12
13
  process.env.NODE_ENV === "development";
package/docker.js CHANGED
@@ -21,6 +21,7 @@ let isWinLocalTLS = false;
21
21
 
22
22
  // Debug mode flag
23
23
  const DEBUG_MODE =
24
+ process.env.CDXGEN_DEBUG_MODE === "debug" ||
24
25
  process.env.SCAN_DEBUG_MODE === "debug" ||
25
26
  process.env.SHIFTLEFT_LOGGING_LEVEL === "debug";
26
27
 
package/index.js CHANGED
@@ -55,6 +55,7 @@ let SBT_CACHE_DIR =
55
55
 
56
56
  // Debug mode flag
57
57
  const DEBUG_MODE =
58
+ process.env.CDXGEN_DEBUG_MODE === "debug" ||
58
59
  process.env.SCAN_DEBUG_MODE === "debug" ||
59
60
  process.env.SHIFTLEFT_LOGGING_LEVEL === "debug" ||
60
61
  process.env.NODE_ENV === "development";
@@ -1189,6 +1190,15 @@ const createJavaBom = async (path, options) => {
1189
1190
  const retMap = utils.parseGradleProjects(cmdOutput);
1190
1191
  const allProjects = retMap.projects || [];
1191
1192
  let rootProject = retMap.rootProject;
1193
+ if (rootProject) {
1194
+ parentComponent = {
1195
+ group: "",
1196
+ name: rootProject,
1197
+ version: "latest",
1198
+ type: "maven",
1199
+ qualifiers: { type: "jar" }
1200
+ };
1201
+ }
1192
1202
  if (!allProjects) {
1193
1203
  console.log(
1194
1204
  "No projects found. Is this a gradle multi-project application?"
@@ -1200,6 +1210,37 @@ const createJavaBom = async (path, options) => {
1200
1210
  allProjects.length,
1201
1211
  "gradle sub-projects. This might take a while ..."
1202
1212
  );
1213
+ // We need the first dependency between the root project and child projects
1214
+ // See: #249 and #315
1215
+ const rootDependsOn = [];
1216
+ for (let sp of allProjects) {
1217
+ sp = sp.replace(":", "");
1218
+ rootDependsOn.push(
1219
+ decodeURIComponent(
1220
+ new PackageURL(
1221
+ "maven",
1222
+ "",
1223
+ sp,
1224
+ parentComponent.version,
1225
+ parentComponent.qualifiers,
1226
+ null
1227
+ ).toString()
1228
+ )
1229
+ );
1230
+ }
1231
+ dependencies.push({
1232
+ ref: decodeURIComponent(
1233
+ new PackageURL(
1234
+ "maven",
1235
+ parentComponent.group,
1236
+ parentComponent.name,
1237
+ parentComponent.version,
1238
+ parentComponent.qualifiers,
1239
+ null
1240
+ ).toString()
1241
+ ),
1242
+ dependsOn: rootDependsOn
1243
+ });
1203
1244
  for (let sp of allProjects) {
1204
1245
  let gradleDepArgs = [
1205
1246
  sp + ":dependencies",
@@ -1232,15 +1273,20 @@ const createJavaBom = async (path, options) => {
1232
1273
  }
1233
1274
  const sstdout = sresult.stdout;
1234
1275
  if (sstdout) {
1276
+ sp = sp.replace(":", "");
1235
1277
  const cmdOutput = Buffer.from(sstdout).toString();
1236
- const parsedList = utils.parseGradleDep(cmdOutput, rootProject);
1278
+ const parsedList = utils.parseGradleDep(cmdOutput, sp);
1237
1279
  const dlist = parsedList.pkgList;
1238
- parentComponent = dlist.splice(0, 1)[0];
1280
+ // Do not overwrite the parentComponent in multi-project mode
1281
+ if (!parentComponent) {
1282
+ parentComponent = dlist.splice(0, 1)[0];
1283
+ }
1239
1284
  if (
1240
1285
  parsedList.dependenciesList &&
1241
1286
  parsedList.dependenciesList
1242
1287
  ) {
1243
- dependencies = dependencies.concat(
1288
+ dependencies = mergeDependencies(
1289
+ dependencies,
1244
1290
  parsedList.dependenciesList
1245
1291
  );
1246
1292
  }
@@ -1347,7 +1393,10 @@ const createJavaBom = async (path, options) => {
1347
1393
  const dlist = parsedList.pkgList;
1348
1394
  parentComponent = dlist.splice(0, 1)[0];
1349
1395
  if (parsedList.dependenciesList && parsedList.dependenciesList) {
1350
- dependencies = dependencies.concat(parsedList.dependenciesList);
1396
+ dependencies = mergeDependencies(
1397
+ dependencies,
1398
+ parsedList.dependenciesList
1399
+ );
1351
1400
  }
1352
1401
  if (dlist && dlist.length) {
1353
1402
  pkgList = pkgList.concat(dlist);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyclonedx/cdxgen",
3
- "version": "8.4.3",
3
+ "version": "8.4.7",
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>",
@@ -43,14 +43,14 @@
43
43
  },
44
44
  "repository": {
45
45
  "type": "git",
46
- "url": "git+https://github.com/cyclonedx/cdxgen.git"
46
+ "url": "git+https://github.com/CycloneDX/cdxgen"
47
47
  },
48
48
  "bugs": {
49
49
  "url": "https://github.com/cyclonedx/cdxgen/issues"
50
50
  },
51
51
  "dependencies": {
52
- "@babel/parser": "^7.21.4",
53
- "@babel/traverse": "^7.21.4",
52
+ "@babel/parser": "^7.21.8",
53
+ "@babel/traverse": "^7.21.5",
54
54
  "cheerio": "^1.0.0-rc.12",
55
55
  "edn-data": "^1.0.0",
56
56
  "glob": "^8.1.0",
@@ -66,11 +66,11 @@
66
66
  "semver": "^7.5.0",
67
67
  "ssri": "^8.0.1",
68
68
  "table": "^6.8.1",
69
- "tar": "^6.1.13",
69
+ "tar": "^6.1.14",
70
70
  "uuid": "^9.0.0",
71
71
  "xml-js": "^1.6.11",
72
72
  "xmlbuilder": "^15.1.1",
73
- "yargs": "^17.7.1"
73
+ "yargs": "^17.7.2"
74
74
  },
75
75
  "optionalDependencies": {
76
76
  "@cyclonedx/cdxgen-plugins-bin": "^1.1.0",
@@ -88,7 +88,7 @@
88
88
  "queries.json"
89
89
  ],
90
90
  "devDependencies": {
91
- "eslint": "^8.39.0",
92
- "jest": "^26.6.3"
91
+ "eslint": "^8.40.0",
92
+ "jest": "^29.5.0"
93
93
  }
94
94
  }
package/utils.js CHANGED
@@ -20,6 +20,7 @@ const { PackageURL } = require("packageurl-js");
20
20
 
21
21
  // Debug mode flag
22
22
  const DEBUG_MODE =
23
+ process.env.CDXGEN_DEBUG_MODE === "debug" ||
23
24
  process.env.SCAN_DEBUG_MODE === "debug" ||
24
25
  process.env.SHIFTLEFT_LOGGING_LEVEL === "debug";
25
26
 
@@ -256,18 +257,33 @@ const _getDepPkgList = async function (
256
257
  depKeys,
257
258
  pkg
258
259
  ) {
259
- if (pkg && pkg.dependencies) {
260
- const pkgKeys = Object.keys(pkg.dependencies);
261
- for (var k in pkgKeys) {
262
- const name = pkgKeys[k];
263
- const version = pkg.dependencies[name].version;
264
- const purl = new PackageURL("npm", "", name, version, null, null);
260
+ let pkgDependencies =
261
+ pkg.lockfileVersion && pkg.lockfileVersion >= 3
262
+ ? pkg.packages
263
+ : pkg.dependencies;
264
+ if (pkg && pkgDependencies) {
265
+ const pkgKeys = Object.keys(pkgDependencies);
266
+ for (const k of pkgKeys) {
267
+ // Skip the root package in lockFileVersion 3 and above
268
+ if (k === "") {
269
+ continue;
270
+ }
271
+ let name = k;
272
+ const version = pkgDependencies[name].version;
273
+ const purl = new PackageURL(
274
+ "npm",
275
+ "",
276
+ name.replace("node_modules/", ""),
277
+ version,
278
+ null,
279
+ null
280
+ );
265
281
  const purlString = decodeURIComponent(purl.toString());
266
- let scope = pkg.dependencies[name].dev === true ? "optional" : undefined;
282
+ let scope = pkgDependencies[name].dev === true ? "optional" : undefined;
267
283
  const apkg = {
268
- name,
284
+ name: name.replace("node_modules/", ""),
269
285
  version,
270
- _integrity: pkg.dependencies[name].integrity,
286
+ _integrity: pkgDependencies[name].integrity,
271
287
  scope,
272
288
  properties: [
273
289
  {
@@ -277,9 +293,9 @@ const _getDepPkgList = async function (
277
293
  ]
278
294
  };
279
295
  pkgList.push(apkg);
280
- if (pkg.dependencies[name].dependencies) {
296
+ if (pkgDependencies[name].dependencies) {
281
297
  // Include child dependencies
282
- const dependencies = pkg.dependencies[name].dependencies;
298
+ const dependencies = pkgDependencies[name].dependencies;
283
299
  const pkgDepKeys = Object.keys(dependencies);
284
300
  const deplist = [];
285
301
  for (const j in pkgDepKeys) {
@@ -288,7 +304,7 @@ const _getDepPkgList = async function (
288
304
  const deppurl = new PackageURL(
289
305
  "npm",
290
306
  "",
291
- depName,
307
+ depName.replace("node_modules/", ""),
292
308
  depVersion,
293
309
  null,
294
310
  null
@@ -303,13 +319,17 @@ const _getDepPkgList = async function (
303
319
  });
304
320
  depKeys[purlString] = true;
305
321
  }
306
- await _getDepPkgList(
307
- pkgLockFile,
308
- pkgList,
309
- dependenciesList,
310
- depKeys,
311
- pkg.dependencies[name]
312
- );
322
+ if (pkg.lockfileVersion && pkg.lockfileVersion >= 3) {
323
+ // Do not recurse for lock file v3 and above
324
+ } else {
325
+ await _getDepPkgList(
326
+ pkgLockFile,
327
+ pkgList,
328
+ dependenciesList,
329
+ depKeys,
330
+ pkgDependencies[name]
331
+ );
332
+ }
313
333
  } else {
314
334
  if (!depKeys[purlString]) {
315
335
  dependenciesList.push({
@@ -1184,8 +1204,28 @@ const parseGradleDep = function (
1184
1204
  const keys_cache = {};
1185
1205
  let last_level = 0;
1186
1206
  let last_purl = `pkg:maven/${rootProjectName}@${rootProjectVersion}?type=jar`;
1207
+ // Bug: 249. Get any sub-projects refered here
1208
+ const retMap = parseGradleProjects(rawOutput);
1187
1209
  const level_trees = {};
1188
1210
  level_trees[last_purl] = [];
1211
+ if (retMap && retMap.projects) {
1212
+ const subDependsOn = [];
1213
+ for (const sd of retMap.projects) {
1214
+ subDependsOn.push(
1215
+ decodeURIComponent(
1216
+ new PackageURL(
1217
+ "maven",
1218
+ "",
1219
+ sd.replace(":", ""),
1220
+ rootProject.version,
1221
+ rootProject.qualifiers,
1222
+ null
1223
+ ).toString()
1224
+ )
1225
+ );
1226
+ }
1227
+ level_trees[last_purl] = subDependsOn;
1228
+ }
1189
1229
  let stack = [last_purl];
1190
1230
  const depRegex =
1191
1231
  /^.*?--- +(?<group>[^\s:]+):(?<name>[^\s:]+)(?::(?:{strictly [[]?)?(?<versionspecified>[^,\s:}]+))?(?:})?(?:[^->]* +-> +(?<versionoverride>[^\s:]+))?/gm;
@@ -1368,6 +1408,14 @@ const parseGradleProjects = function (rawOutput) {
1368
1408
  projects.add(projName);
1369
1409
  }
1370
1410
  }
1411
+ } else if (l.includes("--- project ")) {
1412
+ const tmpB = l.split("--- project ");
1413
+ if (tmpB && tmpB.length > 1) {
1414
+ let projName = tmpB[1];
1415
+ if (projName.startsWith(":")) {
1416
+ projects.add(projName);
1417
+ }
1418
+ }
1371
1419
  }
1372
1420
  });
1373
1421
  return {
package/utils.test.js CHANGED
@@ -206,6 +206,11 @@ test("parse gradle dependencies", () => {
206
206
  );
207
207
  expect(parsedList.pkgList.length).toEqual(68);
208
208
  expect(parsedList.dependenciesList.length).toEqual(69);
209
+ parsedList = utils.parseGradleDep(
210
+ fs.readFileSync("./test/data/gradle-out-249.dep", { encoding: "utf-8" })
211
+ );
212
+ expect(parsedList.pkgList.length).toEqual(21);
213
+ expect(parsedList.dependenciesList.length).toEqual(21);
209
214
  });
210
215
 
211
216
  test("parse gradle projects", () => {
@@ -1097,6 +1102,30 @@ test("parsePkgLock", async () => {
1097
1102
  "bom-ref": "pkg:application/MyProject",
1098
1103
  name: "MyProject"
1099
1104
  });
1105
+ parsedList = await utils.parsePkgLock("./test/data/package-lock-v2.json");
1106
+ deps = parsedList.pkgList;
1107
+ expect(deps.length).toEqual(1467);
1108
+ expect(parsedList.dependenciesList.length).toEqual(1280);
1109
+ expect(deps[0]).toEqual({
1110
+ "bom-ref": "pkg:application/flink-dashboard@2.0.0",
1111
+ group: "",
1112
+ name: "flink-dashboard",
1113
+ type: "application",
1114
+ version: "2.0.0"
1115
+ });
1116
+ expect(deps[deps.length - 1].name).toEqual("zone.js");
1117
+ parsedList = await utils.parsePkgLock("./test/data/package-lock-v3.json");
1118
+ deps = parsedList.pkgList;
1119
+ expect(deps.length).toEqual(879);
1120
+ expect(parsedList.dependenciesList.length).toEqual(879);
1121
+ expect(deps[0]).toEqual({
1122
+ "bom-ref": "pkg:application/@cyclonedx/cdxgen@8.4.3",
1123
+ group: "",
1124
+ name: "@cyclonedx/cdxgen",
1125
+ type: "application",
1126
+ version: "8.4.3"
1127
+ });
1128
+ expect(deps[deps.length - 1].name).toEqual("yocto-queue");
1100
1129
  });
1101
1130
 
1102
1131
  test("parseBowerJson", async () => {