@cyclonedx/cdxgen 9.6.0 → 9.7.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
@@ -120,12 +120,13 @@ import {
120
120
  executeOsQuery,
121
121
  getOSPackages
122
122
  } from "./binary.js";
123
- const osQueries = JSON.parse(
124
- readFileSync(join(dirName, "data", "queries.json"))
125
- );
126
123
 
127
124
  const isWin = _platform() === "win32";
128
125
 
126
+ const osQueries = !isWin
127
+ ? JSON.parse(readFileSync(join(dirName, "data", "queries.json")))
128
+ : JSON.parse(readFileSync(join(dirName, "data", "queries-win.json")));
129
+
129
130
  import { table } from "table";
130
131
 
131
132
  // Construct gradle cache directory
@@ -372,7 +373,16 @@ function addMetadata(parentComponent = {}, format = "xml", options = {}) {
372
373
  // We cannot use purl or bom-ref here since they would not match
373
374
  // purl - could have application on one side and a different type
374
375
  // bom-ref could have qualifiers on one side
375
- if (fullName !== parentFullName) {
376
+ // Ignore components that have the same name as the parent component but with latest as the version.
377
+ // These are default components created based on directory names
378
+ if (
379
+ fullName !== parentFullName &&
380
+ !(
381
+ (comp.name === parentComponent.name ||
382
+ comp.name === parentComponent.name + ":latest") &&
383
+ comp.version === "latest"
384
+ )
385
+ ) {
376
386
  if (!comp["bom-ref"]) {
377
387
  comp["bom-ref"] = `pkg:${comp.type}/${fullName}`;
378
388
  }
@@ -380,6 +390,7 @@ function addMetadata(parentComponent = {}, format = "xml", options = {}) {
380
390
  }
381
391
  }
382
392
  } // for
393
+ parentComponent.components = subComponents;
383
394
  }
384
395
  if (format === "json") {
385
396
  metadata.component = parentComponent;
@@ -650,7 +661,6 @@ function addComponent(
650
661
  return;
651
662
  }
652
663
  const licenses = pkg.licenses || getLicenses(pkg, format);
653
-
654
664
  const purl =
655
665
  pkg.purl ||
656
666
  new PackageURL(
@@ -745,8 +755,22 @@ function addComponent(
745
755
  * word for it, otherwise, identify the module as a 'library'.
746
756
  */
747
757
  function determinePackageType(pkg) {
748
- if (pkg.type === "application") {
749
- return "application";
758
+ // Retain the exact component type in certain cases.
759
+ if (
760
+ [
761
+ "application",
762
+ "container",
763
+ "platform",
764
+ "operating-system",
765
+ "device",
766
+ "device-driver",
767
+ "firmware",
768
+ "file",
769
+ "machine-learning-model",
770
+ "data"
771
+ ].includes(pkg.type)
772
+ ) {
773
+ return pkg.type;
750
774
  }
751
775
  if (pkg.purl) {
752
776
  try {
@@ -1174,7 +1198,8 @@ export const createJavaBom = async (path, options) => {
1174
1198
  cwd: basePath,
1175
1199
  shell: true,
1176
1200
  encoding: "utf-8",
1177
- timeout: TIMEOUT_MS
1201
+ timeout: TIMEOUT_MS,
1202
+ maxBuffer: 50 * 1024 * 1024
1178
1203
  });
1179
1204
  // Check if the cyclonedx plugin created the required bom.xml file
1180
1205
  // Sometimes the plugin fails silently for complex maven projects
@@ -2199,10 +2224,13 @@ export const createPythonBom = async (path, options) => {
2199
2224
  if (pdmLockFiles && pdmLockFiles.length) {
2200
2225
  poetryFiles = poetryFiles.concat(pdmLockFiles);
2201
2226
  }
2202
- const reqFiles = getAllFiles(
2227
+ let reqFiles = getAllFiles(
2203
2228
  path,
2204
2229
  (options.multiProject ? "**/" : "") + "*requirements*.txt"
2205
2230
  );
2231
+ reqFiles = reqFiles.filter(
2232
+ (f) => !f.includes(join("mercurial", "helptext", "internals"))
2233
+ );
2206
2234
  const reqDirFiles = getAllFiles(
2207
2235
  path,
2208
2236
  (options.multiProject ? "**/" : "") + "requirements/*.txt"
@@ -3131,34 +3159,44 @@ export const createCloudBuildBom = (path, options) => {
3131
3159
  };
3132
3160
 
3133
3161
  /**
3134
- * Function to create bom string for the current OS using osquery
3162
+ * Function to create obom string for the current OS using osquery
3135
3163
  *
3136
3164
  * @param path to the project
3137
3165
  * @param options Parse options from the cli
3138
3166
  */
3139
3167
  export const createOSBom = (path, options) => {
3140
3168
  console.warn(
3141
- "About to generate SBoM for the current OS installation. This would take several minutes ..."
3169
+ "About to generate OBoM for the current OS installation. This will take several minutes ..."
3142
3170
  );
3143
3171
  let pkgList = [];
3144
3172
  let bomData = {};
3173
+ let parentComponent = {};
3145
3174
  for (const queryCategory of Object.keys(osQueries)) {
3146
3175
  const queryObj = osQueries[queryCategory];
3147
3176
  const results = executeOsQuery(queryObj.query);
3148
3177
  const dlist = convertOSQueryResults(queryCategory, queryObj, results);
3149
3178
  if (dlist && dlist.length) {
3150
- pkgList = pkgList.concat(dlist);
3179
+ if (!Object.keys(parentComponent).length) {
3180
+ parentComponent = dlist.splice(0, 1)[0];
3181
+ }
3182
+ pkgList = pkgList.concat(
3183
+ dlist.sort(function (a, b) {
3184
+ return a.name.localeCompare(b.name);
3185
+ })
3186
+ );
3151
3187
  }
3152
3188
  } // for
3153
3189
  if (pkgList.length) {
3154
3190
  bomData = buildBomNSData(options, pkgList, "", {
3155
3191
  src: "",
3156
- filename: ""
3192
+ filename: "",
3193
+ parentComponent
3157
3194
  });
3158
3195
  }
3159
3196
  options.bomData = bomData;
3160
3197
  options.multiProject = true;
3161
3198
  options.installDeps = false;
3199
+ options.parentComponent = parentComponent;
3162
3200
  // Force the project type to os
3163
3201
  options.projectType = "os";
3164
3202
  options.lastWorkingDir = undefined;
@@ -3910,7 +3948,7 @@ export const mergeDependencies = (
3910
3948
  for (const akey of Object.keys(deps_map)) {
3911
3949
  retlist.push({
3912
3950
  ref: akey,
3913
- dependsOn: Array.from(deps_map[akey])
3951
+ dependsOn: Array.from(deps_map[akey]).sort()
3914
3952
  });
3915
3953
  }
3916
3954
  return retlist;
@@ -4003,7 +4041,7 @@ export const createMultiXBom = async (pathList, options) => {
4003
4041
  ["docker", "oci", "container"].includes(options.projectType) &&
4004
4042
  options.allLayersExplodedDir
4005
4043
  ) {
4006
- const { osPackages, allTypes } = getOSPackages(
4044
+ const { osPackages, dependenciesList, allTypes } = getOSPackages(
4007
4045
  options.allLayersExplodedDir
4008
4046
  );
4009
4047
  if (DEBUG_MODE) {
@@ -4018,6 +4056,17 @@ export const createMultiXBom = async (pathList, options) => {
4018
4056
  componentsXmls = componentsXmls.concat(
4019
4057
  listComponents(options, {}, osPackages, "", "xml")
4020
4058
  );
4059
+ if (dependenciesList && dependenciesList.length) {
4060
+ dependencies = dependencies.concat(dependenciesList);
4061
+ }
4062
+ if (parentComponent && Object.keys(parentComponent).length) {
4063
+ // Make the parent oci image depend on all os components
4064
+ const parentDependsOn = new Set(osPackages.map((p) => p["bom-ref"]));
4065
+ dependencies.splice(0, 0, {
4066
+ ref: parentComponent["bom-ref"],
4067
+ dependsOn: Array.from(parentDependsOn).sort()
4068
+ });
4069
+ }
4021
4070
  }
4022
4071
  if (options.projectType === "os" && options.bomData) {
4023
4072
  bomData = options.bomData;
@@ -4409,7 +4458,12 @@ export const createMultiXBom = async (pathList, options) => {
4409
4458
  // Jar scanning is enabled by default
4410
4459
  // See #330
4411
4460
  bomData = createJarBom(path, options);
4412
- if (bomData && bomData.bomJson && bomData.bomJson.components) {
4461
+ if (
4462
+ bomData &&
4463
+ bomData.bomJson &&
4464
+ bomData.bomJson.components &&
4465
+ bomData.bomJson.components.length
4466
+ ) {
4413
4467
  if (DEBUG_MODE) {
4414
4468
  console.log(
4415
4469
  `Found ${bomData.bomJson.components.length} jar packages at ${path}`
@@ -4430,7 +4484,12 @@ export const createMultiXBom = async (pathList, options) => {
4430
4484
  } // for
4431
4485
  if (options.lastWorkingDir && options.lastWorkingDir !== "") {
4432
4486
  bomData = createJarBom(options.lastWorkingDir, options);
4433
- if (bomData && bomData.bomJson && bomData.bomJson.components) {
4487
+ if (
4488
+ bomData &&
4489
+ bomData.bomJson &&
4490
+ bomData.bomJson.components &&
4491
+ bomData.bomJson.components.length
4492
+ ) {
4434
4493
  if (DEBUG_MODE) {
4435
4494
  console.log(
4436
4495
  `Found ${bomData.bomJson.components.length} jar packages at ${options.lastWorkingDir}`
@@ -4462,7 +4521,8 @@ export const createMultiXBom = async (pathList, options) => {
4462
4521
  parentComponent.components = trimComponents(parentSubComponents, "json");
4463
4522
  if (
4464
4523
  parentComponent.components.length == 1 &&
4465
- parentComponent.components[0].name == parentComponent.name
4524
+ parentComponent.components[0].name == parentComponent.name &&
4525
+ !parentComponent.purl.startsWith("pkg:container")
4466
4526
  ) {
4467
4527
  parentComponent = parentComponent.components[0];
4468
4528
  delete parentComponent.components;
@@ -4818,8 +4878,26 @@ export const createBom = async (path, options) => {
4818
4878
  purl: "pkg:oci/" + inspectData.RepoDigests[0],
4819
4879
  _integrity: inspectData.RepoDigests[0].replace("sha256:", "sha256-")
4820
4880
  };
4881
+ options.parentComponent["bom-ref"] = options.parentComponent.purl;
4821
4882
  }
4883
+ } else if (inspectData.Id) {
4884
+ options.parentComponent = {
4885
+ name: inspectData.RepoDigests[0].split("@")[0],
4886
+ version: inspectData.RepoDigests[0]
4887
+ .split("@")[1]
4888
+ .replace("sha256:", ""),
4889
+ type: "container",
4890
+ purl: "pkg:oci/" + inspectData.RepoDigests[0],
4891
+ _integrity: inspectData.RepoDigests[0].replace("sha256:", "sha256-")
4892
+ };
4893
+ options.parentComponent["bom-ref"] = options.parentComponent.purl;
4822
4894
  }
4895
+ } else {
4896
+ options.parentComponent = createDefaultParentComponent(
4897
+ path,
4898
+ "container",
4899
+ options
4900
+ );
4823
4901
  }
4824
4902
  // Pass the entire export data about the image layers
4825
4903
  options.exportData = exportData;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyclonedx/cdxgen",
3
- "version": "9.6.0",
3
+ "version": "9.7.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>",
@@ -53,8 +53,8 @@
53
53
  "url": "https://github.com/cyclonedx/cdxgen/issues"
54
54
  },
55
55
  "dependencies": {
56
- "@babel/parser": "^7.22.10",
57
- "@babel/traverse": "^7.22.10",
56
+ "@babel/parser": "^7.22.11",
57
+ "@babel/traverse": "^7.22.11",
58
58
  "ajv": "^8.12.0",
59
59
  "ajv-formats": "^2.1.1",
60
60
  "cheerio": "^1.0.0-rc.12",
@@ -68,7 +68,7 @@
68
68
  "node-stream-zip": "^1.15.0",
69
69
  "packageurl-js": "^1.0.2",
70
70
  "prettify-xml": "^1.2.0",
71
- "properties-reader": "^2.2.0",
71
+ "properties-reader": "^2.3.0",
72
72
  "semver": "^7.5.3",
73
73
  "ssri": "^10.0.4",
74
74
  "table": "^6.8.1",
@@ -80,7 +80,9 @@
80
80
  },
81
81
  "optionalDependencies": {
82
82
  "@appthreat/atom": "^1.1.4",
83
- "@cyclonedx/cdxgen-plugins-bin": "^1.2.0",
83
+ "@cyclonedx/cdxgen-plugins-bin": "^1.4.0",
84
+ "@cyclonedx/cdxgen-plugins-bin-arm64": "^1.4.0",
85
+ "@cyclonedx/cdxgen-plugins-bin-ppc64": "^1.4.0",
84
86
  "body-parser": "^1.20.2",
85
87
  "compression": "^1.7.4",
86
88
  "connect": "^3.7.0",
@@ -95,8 +97,8 @@
95
97
  ],
96
98
  "devDependencies": {
97
99
  "caxa": "^3.0.1",
98
- "eslint": "^8.47.0",
99
- "jest": "^29.5.0",
100
- "prettier": "3.0.1"
100
+ "eslint": "^8.48.0",
101
+ "jest": "^29.6.4",
102
+ "prettier": "3.0.2"
101
103
  }
102
104
  }
package/utils.js CHANGED
@@ -329,21 +329,21 @@ export const getNpmMetadata = async function (pkgList) {
329
329
  const _getDepPkgList = async function (
330
330
  pkgLockFile,
331
331
  pkgList,
332
- dependenciesList,
333
332
  depKeys,
334
- pkg
333
+ pkg,
334
+ versionCache
335
335
  ) {
336
- const pkgDependencies =
337
- pkg.lockfileVersion && pkg.lockfileVersion >= 3
338
- ? pkg.packages
339
- : pkg.dependencies;
340
- const versionCache = {};
336
+ const pkgDependencies = {
337
+ ...(pkg.packages || {}),
338
+ ...(pkg.dependencies || {})
339
+ };
341
340
  if (pkg.packages) {
342
341
  for (const k in pkg.packages) {
343
342
  if (k === "") {
344
343
  continue;
345
344
  }
346
345
  const pl = pkg.packages[k];
346
+ versionCache[k] = pl.version;
347
347
  versionCache[k.replaceAll("node_modules/", "")] = pl.version;
348
348
  }
349
349
  }
@@ -355,7 +355,13 @@ const _getDepPkgList = async function (
355
355
  continue;
356
356
  }
357
357
  const name = k;
358
- const version = pkgDependencies[name].version;
358
+ let version = pkgDependencies[name].version;
359
+ if (!version && versionCache[k]) {
360
+ version = versionCache[k];
361
+ }
362
+ if (!version && pkgDependencies["node_modules/" + name]) {
363
+ version = pkgDependencies["node_modules/" + name].version;
364
+ }
359
365
  const purl = new PackageURL(
360
366
  "npm",
361
367
  "",
@@ -415,32 +421,20 @@ const _getDepPkgList = async function (
415
421
  const deppurlString = decodeURIComponent(deppurl.toString());
416
422
  deplist.push(deppurlString);
417
423
  }
418
- if (!depKeys[purlString]) {
419
- dependenciesList.push({
420
- ref: purlString,
421
- dependsOn: deplist
422
- });
423
- depKeys[purlString] = true;
424
- }
424
+ depKeys[purlString] = (depKeys[purlString] || []).concat(deplist);
425
425
  if (pkg.lockfileVersion && pkg.lockfileVersion >= 3) {
426
426
  // Do not recurse for lock file v3 and above
427
427
  } else {
428
428
  await _getDepPkgList(
429
429
  pkgLockFile,
430
430
  pkgList,
431
- dependenciesList,
432
431
  depKeys,
433
- pkgDependencies[name]
432
+ pkgDependencies[name],
433
+ versionCache
434
434
  );
435
435
  }
436
- } else {
437
- if (!depKeys[purlString]) {
438
- dependenciesList.push({
439
- ref: purlString,
440
- dependsOn: []
441
- });
442
- depKeys[purlString] = true;
443
- }
436
+ } else if (!depKeys[purlString]) {
437
+ depKeys[purlString] = [];
444
438
  }
445
439
  }
446
440
  }
@@ -519,6 +513,7 @@ export const parsePkgLock = async (pkgLockFile, options = {}) => {
519
513
  const dependenciesList = [];
520
514
  const depKeys = {};
521
515
  let rootPkg = {};
516
+ const versionCache = {};
522
517
  if (!options) {
523
518
  options = {};
524
519
  }
@@ -612,11 +607,17 @@ export const parsePkgLock = async (pkgLockFile, options = {}) => {
612
607
  pkgList = await _getDepPkgList(
613
608
  pkgLockFile,
614
609
  pkgList,
615
- dependenciesList,
616
610
  depKeys,
617
- lockData
611
+ lockData,
612
+ versionCache
618
613
  );
619
614
  }
615
+ for (const dk of Object.keys(depKeys)) {
616
+ dependenciesList.push({
617
+ ref: dk,
618
+ dependsOn: depKeys[dk] || []
619
+ });
620
+ }
620
621
  if (fetchLicenses && pkgList && pkgList.length) {
621
622
  if (DEBUG_MODE) {
622
623
  console.log(
@@ -2007,7 +2008,8 @@ export const guessLicenseId = function (content) {
2007
2008
  * @param {Array} pkgList Package list
2008
2009
  */
2009
2010
  export const getMvnMetadata = async function (pkgList) {
2010
- const MAVEN_CENTRAL_URL = "https://repo1.maven.org/maven2/";
2011
+ const MAVEN_CENTRAL_URL =
2012
+ process.env.MAVEN_CENTRAL_URL || "https://repo1.maven.org/maven2/";
2011
2013
  const ANDROID_MAVEN = "https://maven.google.com/";
2012
2014
  const cdepList = [];
2013
2015
  if (!pkgList || !pkgList.length) {
@@ -3285,14 +3287,15 @@ export const getCratesMetadata = async function (pkgList) {
3285
3287
  * @param {Array} pkgList Package list
3286
3288
  */
3287
3289
  export const getDartMetadata = async function (pkgList) {
3288
- const PUB_DEV_URL = "https://pub.dev/api/packages/";
3290
+ const PUB_DEV_URL = process.env.PUB_DEV_URL || "https://pub.dev";
3291
+ const PUB_PACKAGES_URL = PUB_DEV_URL + "/api/packages/";
3289
3292
  const cdepList = [];
3290
3293
  for (const p of pkgList) {
3291
3294
  try {
3292
3295
  if (DEBUG_MODE) {
3293
- console.log(`Querying pub.dev for ${p.name}`);
3296
+ console.log(`Querying ${PUB_DEV_URL} for ${p.name}`);
3294
3297
  }
3295
- const res = await cdxgenAgent.get(PUB_DEV_URL + p.name, {
3298
+ const res = await cdxgenAgent.get(PUB_PACKAGES_URL + p.name, {
3296
3299
  responseType: "json",
3297
3300
  headers: {
3298
3301
  Accept: "application/vnd.pub.v2+json"
@@ -3310,7 +3313,7 @@ export const getDartMetadata = async function (pkgList) {
3310
3313
  if (pubspec.homepage) {
3311
3314
  p.homepage = { url: pubspec.homepage };
3312
3315
  }
3313
- p.license = "https://pub.dev/packages/" + p.name + "/license";
3316
+ p.license = `${PUB_DEV_URL}/packages/${p.name}/license`;
3314
3317
  cdepList.push(p);
3315
3318
  break;
3316
3319
  }
@@ -4764,49 +4767,99 @@ export const convertOSQueryResults = function (
4764
4767
  const pkgList = [];
4765
4768
  if (results && results.length) {
4766
4769
  for (const res of results) {
4767
- if (res.version) {
4768
- const version = res.version;
4769
- let name = res.name || res.device_id;
4770
- const group = "";
4771
- const subpath = res.path || res.admindir || res.source;
4772
- const publisher = res.maintainer || res.creator;
4773
- let scope = undefined;
4774
- const compScope = res.priority;
4775
- if (["required", "optional", "excluded"].includes(compScope)) {
4776
- scope = compScope;
4777
- }
4778
- const description =
4779
- res.description ||
4780
- res.arguments ||
4781
- res.device ||
4782
- res.codename ||
4783
- res.section ||
4784
- res.status ||
4785
- res.identifier ||
4786
- res.components;
4787
- // Re-use the name from query obj
4788
- if (!name && results.length === 1 && queryObj.name) {
4789
- name = queryObj.name;
4790
- }
4791
- if (name && version) {
4792
- const purl = new PackageURL(
4793
- queryObj.purlType || "swid",
4794
- group,
4795
- name,
4796
- version,
4797
- undefined,
4798
- subpath
4799
- );
4800
- pkgList.push({
4801
- name,
4802
- group,
4803
- version,
4804
- description,
4805
- publisher,
4806
- purl,
4807
- scope
4808
- });
4770
+ const version =
4771
+ res.version ||
4772
+ res.hotfix_id ||
4773
+ res.hardware_version ||
4774
+ res.port ||
4775
+ res.pid ||
4776
+ res.subject_key_id ||
4777
+ res.interface ||
4778
+ res.instance_id;
4779
+ let name =
4780
+ res.name ||
4781
+ res.device_id ||
4782
+ res.hotfix_id ||
4783
+ res.uuid ||
4784
+ res.serial ||
4785
+ res.pid ||
4786
+ res.address ||
4787
+ res.ami_id ||
4788
+ res.interface ||
4789
+ res.client_app_id;
4790
+ let group = "";
4791
+ const subpath = res.path || res.admindir || res.source;
4792
+ let publisher =
4793
+ res.publisher ||
4794
+ res.maintainer ||
4795
+ res.creator ||
4796
+ res.manufacturer ||
4797
+ res.provider ||
4798
+ "";
4799
+ if (publisher === "null") {
4800
+ publisher = "";
4801
+ }
4802
+ let scope = undefined;
4803
+ const compScope = res.priority;
4804
+ if (["required", "optional", "excluded"].includes(compScope)) {
4805
+ scope = compScope;
4806
+ }
4807
+ const description =
4808
+ res.description ||
4809
+ res.summary ||
4810
+ res.arguments ||
4811
+ res.device ||
4812
+ res.codename ||
4813
+ res.section ||
4814
+ res.status ||
4815
+ res.identifier ||
4816
+ res.components ||
4817
+ "";
4818
+ // Re-use the name from query obj
4819
+ if (!name && results.length === 1 && queryObj.name) {
4820
+ name = queryObj.name;
4821
+ }
4822
+ let qualifiers = undefined;
4823
+ if (res.identifying_number && res.identifying_number.length) {
4824
+ qualifiers = {
4825
+ tag_id: res.identifying_number.replace("{", "").replace("}", "")
4826
+ };
4827
+ }
4828
+ if (name) {
4829
+ name = name.replace(/ /g, "+").replace(/[:%]/g, "-");
4830
+ group = group.replace(/ /g, "+").replace(/[:%]/g, "-");
4831
+ const purl = new PackageURL(
4832
+ queryObj.purlType || "swid",
4833
+ group,
4834
+ name,
4835
+ version || "",
4836
+ qualifiers,
4837
+ subpath
4838
+ ).toString();
4839
+ const apkg = {
4840
+ name,
4841
+ group,
4842
+ version: version || "",
4843
+ description,
4844
+ publisher,
4845
+ "bom-ref": decodeURIComponent(purl),
4846
+ purl,
4847
+ scope,
4848
+ type: queryObj.componentType
4849
+ };
4850
+ const props = [{ name: "cdx:osquery:category", value: queryCategory }];
4851
+ for (const k of Object.keys(res).filter(
4852
+ (p) => !["name", "version", "description", "publisher"].includes(p)
4853
+ )) {
4854
+ if (res[k] && res[k] !== "null") {
4855
+ props.push({
4856
+ name: k,
4857
+ value: res[k]
4858
+ });
4859
+ }
4809
4860
  }
4861
+ apkg.properties = props;
4862
+ pkgList.push(apkg);
4810
4863
  }
4811
4864
  }
4812
4865
  }
@@ -5783,27 +5836,37 @@ export const executeAtom = (src, args) => {
5783
5836
  }
5784
5837
  const freeMemoryGB = Math.floor(freemem() / 1024 / 1024 / 1024);
5785
5838
  if (DEBUG_MODE) {
5786
- console.log("Execuing", ATOM_BIN, args.join(" "));
5839
+ console.log("Executing", ATOM_BIN, args.join(" "));
5787
5840
  }
5788
5841
  const env = {
5789
5842
  ...process.env,
5790
5843
  JAVA_OPTS: `-Xms${freeMemoryGB}G -Xmx${freeMemoryGB}G`
5791
5844
  };
5845
+ env.PATH = `${env.PATH}${_delimiter}${join(
5846
+ dirNameStr,
5847
+ "node_modules",
5848
+ ".bin"
5849
+ )}`;
5792
5850
  const result = spawnSync(ATOM_BIN, args, {
5793
5851
  cwd,
5794
5852
  encoding: "utf-8",
5795
5853
  timeout: TIMEOUT_MS,
5796
5854
  env
5797
5855
  });
5798
- if (
5799
- result.stderr &&
5800
- result.stderr.includes(
5801
- "has been compiled by a more recent version of the Java Runtime"
5802
- )
5803
- ) {
5804
- console.log(
5805
- "Atom requires Java 17 or above. Please install a suitable version and re-run cdxgen to improve the SBoM accuracy.\nAlternatively, use the cdxgen container image."
5806
- );
5856
+ if (result.stderr) {
5857
+ if (
5858
+ result.stderr.includes(
5859
+ "has been compiled by a more recent version of the Java Runtime"
5860
+ )
5861
+ ) {
5862
+ console.log(
5863
+ "Atom requires Java 17 or above. Please install a suitable version and re-run cdxgen to improve the SBoM accuracy.\nAlternatively, use the cdxgen container image."
5864
+ );
5865
+ } else if (result.stderr.includes("astgen")) {
5866
+ console.warn(
5867
+ "WARN: Unable to locate astgen command. Install atom globally using sudo npm install -g @appthreat/atom to resolve this issue."
5868
+ );
5869
+ }
5807
5870
  }
5808
5871
  if (DEBUG_MODE) {
5809
5872
  if (result.stdout) {
@@ -5813,7 +5876,7 @@ export const executeAtom = (src, args) => {
5813
5876
  console.log(result.stderr);
5814
5877
  }
5815
5878
  }
5816
- return true;
5879
+ return !result.error;
5817
5880
  };
5818
5881
 
5819
5882
  /**
@@ -6232,3 +6295,14 @@ export const addEvidenceForImports = (pkgList, allImports) => {
6232
6295
  }
6233
6296
  return pkgList;
6234
6297
  };
6298
+
6299
+ export const componentSorter = (a, b) => {
6300
+ if (a && b) {
6301
+ for (const k of ["bom-ref", "purl", "name"]) {
6302
+ if (a[k] && b[k]) {
6303
+ return a[k].localeCompare(b[k]);
6304
+ }
6305
+ }
6306
+ }
6307
+ return a.localeCompare(b);
6308
+ };
package/utils.test.js CHANGED
@@ -1358,8 +1358,8 @@ test("parsePkgLock", async () => {
1358
1358
  });
1359
1359
  parsedList = await parsePkgLock("./test/data/package-lock-v2.json");
1360
1360
  deps = parsedList.pkgList;
1361
- expect(deps.length).toEqual(1467);
1362
- expect(parsedList.dependenciesList.length).toEqual(1280);
1361
+ expect(deps.length).toEqual(5433);
1362
+ expect(parsedList.dependenciesList.length).toEqual(1616);
1363
1363
  expect(deps[0]).toEqual({
1364
1364
  "bom-ref": "pkg:npm/flink-dashboard@2.0.0",
1365
1365
  group: "",