@cyclonedx/cdxgen 11.4.1 → 11.4.3

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 (57) hide show
  1. package/README.md +4 -1
  2. package/bin/cdxgen.js +32 -9
  3. package/bin/evinse.js +2 -0
  4. package/bin/repl.js +12 -4
  5. package/bin/verify.js +2 -0
  6. package/lib/cli/index.js +67 -57
  7. package/lib/evinser/evinser.js +21 -19
  8. package/lib/evinser/evinser.test.js +2 -2
  9. package/lib/evinser/swiftsem.js +1 -0
  10. package/lib/evinser/swiftsem.test.js +2 -2
  11. package/lib/helpers/analyzer.js +5 -4
  12. package/lib/helpers/cbomutils.js +2 -0
  13. package/lib/helpers/db.js +1 -0
  14. package/lib/helpers/display.js +1 -0
  15. package/lib/helpers/display.test.js +2 -0
  16. package/lib/helpers/envcontext.js +9 -7
  17. package/lib/helpers/envcontext.test.js +3 -1
  18. package/lib/helpers/logger.js +70 -10
  19. package/lib/helpers/protobom.js +29 -16
  20. package/lib/helpers/protobom.test.js +4 -1
  21. package/lib/helpers/utils.js +216 -102
  22. package/lib/helpers/utils.test.js +40 -10
  23. package/lib/helpers/validator.js +5 -5
  24. package/lib/managers/binary.js +17 -15
  25. package/lib/managers/docker.js +33 -31
  26. package/lib/managers/docker.test.js +2 -0
  27. package/lib/managers/oci.js +2 -1
  28. package/lib/managers/piptree.js +1 -0
  29. package/lib/server/server.js +90 -27
  30. package/lib/server/server.test.js +126 -0
  31. package/lib/stages/postgen/annotator.js +1 -0
  32. package/lib/stages/postgen/annotator.test.js +2 -2
  33. package/lib/stages/postgen/postgen.js +14 -6
  34. package/lib/stages/postgen/postgen.test.js +3 -2
  35. package/lib/stages/pregen/pregen.js +4 -3
  36. package/package.json +12 -11
  37. package/types/lib/cli/index.d.ts.map +1 -1
  38. package/types/lib/evinser/swiftsem.d.ts.map +1 -1
  39. package/types/lib/helpers/analyzer.d.ts.map +1 -1
  40. package/types/lib/helpers/cbomutils.d.ts.map +1 -1
  41. package/types/lib/helpers/db.d.ts.map +1 -1
  42. package/types/lib/helpers/display.d.ts.map +1 -1
  43. package/types/lib/helpers/envcontext.d.ts.map +1 -1
  44. package/types/lib/helpers/logger.d.ts +9 -0
  45. package/types/lib/helpers/logger.d.ts.map +1 -1
  46. package/types/lib/helpers/protobom.d.ts.map +1 -1
  47. package/types/lib/helpers/utils.d.ts +6 -3
  48. package/types/lib/helpers/utils.d.ts.map +1 -1
  49. package/types/lib/managers/binary.d.ts.map +1 -1
  50. package/types/lib/managers/docker.d.ts.map +1 -1
  51. package/types/lib/managers/oci.d.ts.map +1 -1
  52. package/types/lib/managers/piptree.d.ts.map +1 -1
  53. package/types/lib/server/server.d.ts +11 -0
  54. package/types/lib/server/server.d.ts.map +1 -1
  55. package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
  56. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  57. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
@@ -2,8 +2,8 @@ import { Buffer } from "node:buffer";
2
2
  import { spawnSync } from "node:child_process";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import {
5
- constants,
6
5
  chmodSync,
6
+ constants,
7
7
  copyFileSync,
8
8
  createReadStream,
9
9
  existsSync,
@@ -17,17 +17,18 @@ import {
17
17
  } from "node:fs";
18
18
  import { homedir, platform, tmpdir } from "node:os";
19
19
  import path, {
20
- basename,
21
20
  delimiter as _delimiter,
21
+ sep as _sep,
22
+ basename,
22
23
  dirname,
23
24
  extname,
24
25
  join,
25
- resolve,
26
26
  relative,
27
- sep as _sep,
27
+ resolve,
28
28
  } from "node:path";
29
29
  import process from "node:process";
30
- import { URL, fileURLToPath } from "node:url";
30
+ import { fileURLToPath, URL } from "node:url";
31
+
31
32
  import toml from "@iarna/toml";
32
33
  import Arborist from "@npmcli/arborist";
33
34
  import { load } from "cheerio";
@@ -50,8 +51,9 @@ import {
50
51
  import { IriValidationStrategy, validateIri } from "validate-iri";
51
52
  import { xml2js } from "xml-js";
52
53
  import { parse as _load } from "yaml";
54
+
53
55
  import { getTreeWithPlugin } from "../managers/piptree.js";
54
- import { thoughtLog } from "./logger.js";
56
+ import { thoughtLog, traceLog } from "./logger.js";
55
57
 
56
58
  let url = import.meta?.url;
57
59
  if (url && !url.startsWith("file://")) {
@@ -113,8 +115,20 @@ export function safeMkdirSync(filePath, options) {
113
115
  return mkdirSync(filePath, options);
114
116
  }
115
117
 
118
+ export const commandsExecuted = new Set();
119
+ function isAllowedCommand(command) {
120
+ if (!process.env.CDXGEN_ALLOWED_COMMANDS) {
121
+ return true;
122
+ }
123
+ const allow_commands = (process.env.CDXGEN_ALLOWED_COMMANDS || "").split(",");
124
+ return allow_commands.includes(command.trim());
125
+ }
126
+
116
127
  export function safeSpawnSync(command, args, options) {
117
- if (isSecureMode && process.permission && !process.permission.has("child")) {
128
+ if (
129
+ (isSecureMode && process.permission && !process.permission.has("child")) ||
130
+ !isAllowedCommand(command)
131
+ ) {
118
132
  if (DEBUG_MODE) {
119
133
  console.log(`cdxgen lacks execute permission for ${command}`);
120
134
  }
@@ -125,6 +139,8 @@ export function safeSpawnSync(command, args, options) {
125
139
  error: new Error("No execute permission"),
126
140
  };
127
141
  }
142
+ traceLog("spawn", { command, args, ...options });
143
+ commandsExecuted.add(command);
128
144
  // Fix for DEP0190 warning
129
145
  if (options?.shell === true) {
130
146
  if (args?.length) {
@@ -646,6 +662,26 @@ function isCacheDisabled() {
646
662
  }
647
663
 
648
664
  const cache = isCacheDisabled() ? undefined : gotHttpCache;
665
+ export const remoteHostsAccessed = new Set();
666
+
667
+ function isAllowedHost(hostname) {
668
+ if (!process.env.CDXGEN_ALLOWED_HOSTS) {
669
+ return true;
670
+ }
671
+ const allow_hosts = (process.env.CDXGEN_ALLOWED_HOSTS || "").split(",");
672
+ for (const ahost of allow_hosts) {
673
+ if (!ahost.length) {
674
+ continue;
675
+ }
676
+ if (hostname === ahost) {
677
+ return true;
678
+ }
679
+ // wildcard support
680
+ if (ahost.startsWith("*.") && hostname.endsWith(ahost.replace("*", ""))) {
681
+ return true;
682
+ }
683
+ }
684
+ }
649
685
 
650
686
  // Custom user-agent for cdxgen
651
687
  export const cdxgenAgent = got.extend({
@@ -656,6 +692,31 @@ export const cdxgenAgent = got.extend({
656
692
  retry: {
657
693
  limit: 0,
658
694
  },
695
+ hooks: {
696
+ beforeRequest: [
697
+ (options) => {
698
+ if (!isAllowedHost(options.url.hostname)) {
699
+ console.log(
700
+ `Access to the remote host '${options.url.hostname}' is not permitted.`,
701
+ );
702
+ return new AbortController().abort();
703
+ }
704
+ // Only allow https protocol in secure mode
705
+ if (isSecureMode && options.url.protocol !== "https:") {
706
+ console.log(
707
+ `Access to the remote host '${options.url.hostname}' is not permitted via the '${options.url.protocol}' protocol.`,
708
+ );
709
+ return new AbortController().abort();
710
+ }
711
+ remoteHostsAccessed.add(options.url.hostname);
712
+ traceLog("http", {
713
+ protocol: options.url.protocol,
714
+ pathname: options.url.pathname,
715
+ host: options.url.host,
716
+ });
717
+ },
718
+ ],
719
+ },
659
720
  });
660
721
 
661
722
  /**
@@ -1005,7 +1066,7 @@ export async function getSwiftPackageMetadata(pkgList) {
1005
1066
  if (p.repository.url.includes("://github.com/")) {
1006
1067
  try {
1007
1068
  p.license = await getRepoLicense(p.repository.url, undefined);
1008
- } catch (e) {
1069
+ } catch (_e) {
1009
1070
  console.error("error fetching repo license from", p.repository.url);
1010
1071
  }
1011
1072
  } else {
@@ -1067,7 +1128,7 @@ export async function getNpmMetadata(pkgList) {
1067
1128
  p.homepage = { url: body.homepage };
1068
1129
  }
1069
1130
  cdepList.push(p);
1070
- } catch (err) {
1131
+ } catch (_err) {
1071
1132
  cdepList.push(p);
1072
1133
  if (DEBUG_MODE) {
1073
1134
  console.error(p, "was not found on npm");
@@ -1147,7 +1208,7 @@ export async function parsePkgJson(pkgJsonFile, simple = false) {
1147
1208
  };
1148
1209
  }
1149
1210
  pkgList.push(apkg);
1150
- } catch (err) {
1211
+ } catch (_err) {
1151
1212
  // continue regardless of error
1152
1213
  }
1153
1214
  }
@@ -1332,7 +1393,7 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
1332
1393
  value: "false",
1333
1394
  });
1334
1395
  }
1335
- } catch (err) {
1396
+ } catch (_err) {
1336
1397
  // ignore
1337
1398
  }
1338
1399
  if (node?.isWorkspace) {
@@ -1615,7 +1676,7 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
1615
1676
  // legacyPeerDeps=false enables npm >v3 package dependency resolution
1616
1677
  legacyPeerDeps: false,
1617
1678
  });
1618
- let tree = undefined;
1679
+ let tree;
1619
1680
  try {
1620
1681
  const rootNodeModulesDir = join(path.dirname(pkgLockFile), "node_modules");
1621
1682
  if (safeExistsSync(rootNodeModulesDir)) {
@@ -2290,7 +2351,7 @@ export async function parsePnpmLock(
2290
2351
  lockfileVersion = yamlObj.lockfileVersion;
2291
2352
  try {
2292
2353
  lockfileVersion = Number.parseFloat(lockfileVersion, 10);
2293
- } catch (e) {
2354
+ } catch (_e) {
2294
2355
  // ignore parse errors
2295
2356
  }
2296
2357
  // This logic matches the pnpm list command to include only direct dependencies
@@ -2402,8 +2463,8 @@ export async function parsePnpmLock(
2402
2463
  {};
2403
2464
  const componentPeerDeps =
2404
2465
  yamlObj?.importers[importedComponentName]["peerDependencies"] || {};
2405
- let compPurl = undefined;
2406
- let pkgSrcFile = undefined;
2466
+ let compPurl;
2467
+ let pkgSrcFile;
2407
2468
  let fallbackMode = true;
2408
2469
  if (safeExistsSync(join(importedComponentName, "package.json"))) {
2409
2470
  pkgSrcFile = join(importedComponentName, "package.json");
@@ -2598,7 +2659,7 @@ export async function parsePnpmLock(
2598
2659
  packages[fullName]?.optionalDependencies ||
2599
2660
  snapshots[fullName]?.optionalDependencies ||
2600
2661
  {};
2601
- const peerDeps =
2662
+ const _peerDeps =
2602
2663
  packages[pkgKeys[k]]?.peerDependencies ||
2603
2664
  snapshots[pkgKeys[k]]?.peerDependencies ||
2604
2665
  packages[fullName]?.peerDependencies ||
@@ -2646,7 +2707,7 @@ export async function parsePnpmLock(
2646
2707
  let name = "";
2647
2708
  let version = "";
2648
2709
  let group = "";
2649
- let srcUrl = undefined;
2710
+ let srcUrl;
2650
2711
  const hasBin = packageNode?.hasBin;
2651
2712
  const deprecatedMessage = packageNode?.deprecated;
2652
2713
  if (lockfileVersion >= 9 && fullName.includes("@")) {
@@ -3071,7 +3132,7 @@ export async function parseBowerJson(bowerJsonFile) {
3071
3132
  },
3072
3133
  },
3073
3134
  });
3074
- } catch (err) {
3135
+ } catch (_err) {
3075
3136
  // continue regardless of error
3076
3137
  }
3077
3138
  }
@@ -3156,7 +3217,7 @@ export async function parseMinJs(minJsFile) {
3156
3217
  }
3157
3218
  }
3158
3219
  });
3159
- } catch (err) {
3220
+ } catch (_err) {
3160
3221
  // continue regardless of error
3161
3222
  }
3162
3223
  }
@@ -3270,7 +3331,7 @@ export function parsePom(pomFile) {
3270
3331
  }
3271
3332
  for (const adep of dependencies) {
3272
3333
  const version = adep.version;
3273
- let versionStr = undefined;
3334
+ let versionStr;
3274
3335
  if (version?._) {
3275
3336
  versionStr = version._;
3276
3337
  }
@@ -3327,7 +3388,7 @@ export function parseMavenTree(rawOutput, pomFile) {
3327
3388
  const tmpA = rawOutput.split("\n");
3328
3389
  let last_level = 0;
3329
3390
  let last_purl = "";
3330
- let first_ref = undefined;
3391
+ let first_ref;
3331
3392
  const stack = [];
3332
3393
  tmpA.forEach((l) => {
3333
3394
  l = l.replace("\r", "");
@@ -3345,7 +3406,7 @@ export function parseMavenTree(rawOutput, pomFile) {
3345
3406
  // Support for classifiers
3346
3407
  // com.github.jnr:jffi:jar:1.3.11:compile
3347
3408
  // com.github.jnr:jffi:jar:native:1.3.11:runtime
3348
- let classifier = undefined;
3409
+ let classifier;
3349
3410
  if (pkgArr && pkgArr.length > 2) {
3350
3411
  let versionStr = pkgArr[pkgArr.length - 2];
3351
3412
  const componentScope = pkgArr[pkgArr.length - 1];
@@ -3360,7 +3421,7 @@ export function parseMavenTree(rawOutput, pomFile) {
3360
3421
  if (!includeMavenTestScope && componentScope === "test") {
3361
3422
  return;
3362
3423
  }
3363
- let scope = undefined;
3424
+ let scope;
3364
3425
  if (["compile", "runtime"].includes(componentScope)) {
3365
3426
  scope = "required";
3366
3427
  } else if (componentScope === "test") {
@@ -3646,8 +3707,8 @@ export async function parseGradleDep(
3646
3707
  let last_project_bomref = first_bomref;
3647
3708
  const level_trees = {};
3648
3709
  level_trees[last_bomref] = [];
3649
- let scope = undefined;
3650
- let profileName = undefined;
3710
+ let scope;
3711
+ let profileName;
3651
3712
  if (retMap?.projects) {
3652
3713
  const modulesToSkip = process.env.GRADLE_SKIP_MODULES
3653
3714
  ? process.env.GRADLE_SKIP_MODULES.split(",")
@@ -4530,7 +4591,7 @@ export async function fetchPomXml({ urlPrefix, group, name, version }) {
4530
4591
  try {
4531
4592
  const res = await cdxgenAgent.get(fullUrl);
4532
4593
  return res.body;
4533
- } catch (err) {
4594
+ } catch (_err) {
4534
4595
  return undefined;
4535
4596
  }
4536
4597
  }
@@ -4663,12 +4724,12 @@ export async function getPyMetadata(pkgList, fetchDepsInfo) {
4663
4724
  if (p.name.includes("[")) {
4664
4725
  p.name = p.name.split("[")[0];
4665
4726
  }
4666
- let res = undefined;
4727
+ let res;
4667
4728
  try {
4668
4729
  res = await cdxgenAgent.get(`${PYPI_URL + p.name}/json`, {
4669
4730
  responseType: "json",
4670
4731
  });
4671
- } catch (err) {
4732
+ } catch (_err) {
4672
4733
  // retry by prefixing django- to the package name
4673
4734
  res = await cdxgenAgent.get(`${PYPI_URL}django-${p.name}/json`, {
4674
4735
  responseType: "json",
@@ -4722,7 +4783,7 @@ export async function getPyMetadata(pkgList, fetchDepsInfo) {
4722
4783
  }
4723
4784
  // Use the latest version if none specified
4724
4785
  if (!p.version || !p.version.trim().length) {
4725
- let versionSpecifiers = undefined;
4786
+ let versionSpecifiers;
4726
4787
  if (p.properties?.length) {
4727
4788
  for (const pprop of p.properties) {
4728
4789
  if (pprop.name === "cdx:pypi:versionSpecifiers") {
@@ -4810,7 +4871,7 @@ export async function getPyMetadata(pkgList, fetchDepsInfo) {
4810
4871
  p.purl = purlString;
4811
4872
  p["bom-ref"] = decodeURIComponent(purlString);
4812
4873
  cdepList.push(p);
4813
- } catch (err) {
4874
+ } catch (_err) {
4814
4875
  if (DEBUG_MODE) {
4815
4876
  console.error(p.name, "is not found on PyPI.");
4816
4877
  console.log(
@@ -4897,7 +4958,7 @@ export async function parsePiplockData(lockData) {
4897
4958
  const depBlock = lockData[k];
4898
4959
  Object.keys(depBlock).forEach((p) => {
4899
4960
  const pkg = depBlock[p];
4900
- if (Object.prototype.hasOwnProperty.call(pkg, "version")) {
4961
+ if (Object.hasOwn(pkg, "version")) {
4901
4962
  const versionStr = pkg.version.replace("==", "");
4902
4963
  pkgList.push({ name: p, version: versionStr });
4903
4964
  }
@@ -5557,7 +5618,7 @@ export async function parsePyLockData(lockData, lockFile, pyProjectFile) {
5557
5618
  */
5558
5619
  export async function parseReqFile(reqData, fetchDepsInfo) {
5559
5620
  const pkgList = [];
5560
- let compScope = undefined;
5621
+ let compScope;
5561
5622
  reqData
5562
5623
  .replace(/\r/g, "")
5563
5624
  .replace(/ [\\]\n/g, "")
@@ -5565,7 +5626,7 @@ export async function parseReqFile(reqData, fetchDepsInfo) {
5565
5626
  .split("\n")
5566
5627
  .forEach((l) => {
5567
5628
  l = l.trim();
5568
- let markers = undefined;
5629
+ let markers;
5569
5630
  if (l.includes(" ; ")) {
5570
5631
  const tmpA = l.split(" ; ");
5571
5632
  if (tmpA && tmpA.length === 2) {
@@ -6235,7 +6296,7 @@ export async function getGoPkgLicense(repoMetadata) {
6235
6296
  metadata_cache[pkgUrl] = licList;
6236
6297
  return licList;
6237
6298
  }
6238
- } catch (err) {
6299
+ } catch (_err) {
6239
6300
  return undefined;
6240
6301
  }
6241
6302
  if (group.indexOf("github.com") > -1) {
@@ -6267,14 +6328,14 @@ async function getGoPkgVCSUrl(group, name) {
6267
6328
  metadata_cache[pkgUrl] = vcs;
6268
6329
  return vcs;
6269
6330
  }
6270
- } catch (err) {
6331
+ } catch (_err) {
6271
6332
  return undefined;
6272
6333
  }
6273
6334
  return undefined;
6274
6335
  }
6275
6336
 
6276
6337
  export async function getGoPkgComponent(group, name, version, hash) {
6277
- let license = undefined;
6338
+ let license;
6278
6339
  if (shouldFetchLicense()) {
6279
6340
  if (DEBUG_MODE) {
6280
6341
  console.log(
@@ -6290,7 +6351,7 @@ export async function getGoPkgComponent(group, name, version, hash) {
6290
6351
  const purlString = new PackageURL("golang", group, name, version)
6291
6352
  .toString()
6292
6353
  .replace(/%2F/g, "/");
6293
- let vcs = undefined;
6354
+ let vcs;
6294
6355
  if (shouldFetchVCS()) {
6295
6356
  vcs = await getGoPkgVCSUrl(group, name);
6296
6357
  }
@@ -6772,13 +6833,14 @@ export async function parseGoModGraph(
6772
6833
  }
6773
6834
 
6774
6835
  /**
6775
- * Parse go mod why output
6836
+ * Parse go mod why output.
6837
+ *
6776
6838
  * @param {string} rawOutput Output from go mod why
6777
- * @returns package name or none
6839
+ * @returns {string|undefined} package name or none
6778
6840
  */
6779
6841
  export function parseGoModWhy(rawOutput) {
6780
6842
  if (typeof rawOutput === "string") {
6781
- let pkg_name = undefined;
6843
+ let pkg_name;
6782
6844
  const lines = rawOutput.split("\n");
6783
6845
  lines.forEach((l) => {
6784
6846
  if (l && !l.startsWith("#") && !l.startsWith("(")) {
@@ -6836,7 +6898,7 @@ export async function parseGopkgData(gopkgData) {
6836
6898
  const tmpA = l.split("=");
6837
6899
  key = tmpA[0].trim();
6838
6900
  value = tmpA[1].trim().replace(/"/g, "");
6839
- let digestStr = undefined;
6901
+ let digestStr;
6840
6902
  switch (key) {
6841
6903
  case "digest":
6842
6904
  digestStr = value.replace("1:", "");
@@ -7298,7 +7360,7 @@ export async function parseGemspecData(gemspecData, gemspecFile) {
7298
7360
  pkg[aprop] = apropList.split(",");
7299
7361
  }
7300
7362
  }
7301
- } catch (err) {
7363
+ } catch (_err) {
7302
7364
  const alist = l
7303
7365
  .replace(/[[\]'"]/g, "")
7304
7366
  .replaceAll("%w", "")
@@ -7325,7 +7387,7 @@ export async function parseGemspecData(gemspecData, gemspecFile) {
7325
7387
  value: exeList.join(", "),
7326
7388
  });
7327
7389
  }
7328
- } catch (err) {
7390
+ } catch (_err) {
7329
7391
  // pass
7330
7392
  }
7331
7393
  }
@@ -7447,12 +7509,12 @@ export async function parseGemfileLockData(gemLockData, lockFile) {
7447
7509
  }
7448
7510
  });
7449
7511
  specsFound = false;
7450
- let lastParent = undefined;
7451
- let lastRemote = undefined;
7452
- let lastRevision = undefined;
7453
- let lastBranch = undefined;
7454
- let lastTag = undefined;
7455
- let lastParentPlatform = undefined;
7512
+ let lastParent;
7513
+ let lastRemote;
7514
+ let lastRevision;
7515
+ let lastBranch;
7516
+ let lastTag;
7517
+ let lastParentPlatform;
7456
7518
  // Dependencies block would begin with DEPENDENCIES
7457
7519
  let dependenciesBlock = false;
7458
7520
  const rootList = [];
@@ -7630,6 +7692,59 @@ export async function parseGemfileLockData(gemLockData, lockFile) {
7630
7692
  const rootDepName = l.trim().split(" ")[0].replace("!", "");
7631
7693
  if (pkgNameRef[rootDepName]) {
7632
7694
  rootList.push(pkgNameRef[rootDepName]);
7695
+ } else {
7696
+ // We are dealing with an optional platform-dependent import
7697
+ // create a placeholder component to track this
7698
+ let specifier;
7699
+ if (l.includes("(")) {
7700
+ specifier = l.trim().split(" (").pop().replace(")", "").trim();
7701
+ }
7702
+ const untrackedPurl = new PackageURL(
7703
+ "gem",
7704
+ "",
7705
+ rootDepName,
7706
+ null,
7707
+ null,
7708
+ null,
7709
+ ).toString();
7710
+ const untrackedBomRef = decodeURIComponent(untrackedPurl);
7711
+ const untrackedProps = [
7712
+ {
7713
+ name: "SrcFile",
7714
+ value: lockFile,
7715
+ },
7716
+ ];
7717
+ if (specifier) {
7718
+ untrackedProps.push({
7719
+ name: "cdx:gem:versionSpecifiers",
7720
+ value: specifier,
7721
+ });
7722
+ }
7723
+ const untrackedRootDep = {
7724
+ name: rootDepName,
7725
+ version: undefined,
7726
+ purl: untrackedPurl,
7727
+ "bom-ref": untrackedBomRef,
7728
+ properties: untrackedProps,
7729
+ evidence: {
7730
+ identity: {
7731
+ field: "purl",
7732
+ confidence: 0.3,
7733
+ methods: [
7734
+ {
7735
+ technique: "manifest-analysis",
7736
+ confidence: 0.3,
7737
+ value: lockFile,
7738
+ },
7739
+ ],
7740
+ },
7741
+ },
7742
+ };
7743
+ pkgnames[untrackedPurl] = true;
7744
+ pkgNameRef[rootDepName] = untrackedBomRef;
7745
+ pkgList.push(untrackedRootDep);
7746
+ rootList.push(untrackedBomRef);
7747
+ dependenciesMap[untrackedBomRef] = new Set();
7633
7748
  }
7634
7749
  }
7635
7750
  });
@@ -7715,7 +7830,7 @@ export async function getCratesMetadata(pkgList) {
7715
7830
  });
7716
7831
  }
7717
7832
  cdepList.push(p);
7718
- } catch (err) {
7833
+ } catch (_err) {
7719
7834
  cdepList.push(p);
7720
7835
  }
7721
7836
  }
@@ -7769,7 +7884,7 @@ export async function getDartMetadata(pkgList) {
7769
7884
  }
7770
7885
  cdepList.push(p);
7771
7886
  }
7772
- } catch (err) {
7887
+ } catch (_err) {
7773
7888
  cdepList.push(p);
7774
7889
  }
7775
7890
  }
@@ -8290,10 +8405,10 @@ export async function parsePubLockData(pubLockData, lockFile) {
8290
8405
 
8291
8406
  export function parsePubYamlData(pubYamlData) {
8292
8407
  const pkgList = [];
8293
- let yamlObj = undefined;
8408
+ let yamlObj;
8294
8409
  try {
8295
8410
  yamlObj = _load(pubYamlData);
8296
- } catch (err) {
8411
+ } catch (_err) {
8297
8412
  // continue regardless of error
8298
8413
  }
8299
8414
  if (!yamlObj) {
@@ -8316,10 +8431,10 @@ export function parsePubYamlData(pubYamlData) {
8316
8431
 
8317
8432
  export function parseHelmYamlData(helmData) {
8318
8433
  const pkgList = [];
8319
- let yamlObj = undefined;
8434
+ let yamlObj;
8320
8435
  try {
8321
8436
  yamlObj = _load(helmData);
8322
- } catch (err) {
8437
+ } catch (_err) {
8323
8438
  // continue regardless of error
8324
8439
  }
8325
8440
  if (!yamlObj) {
@@ -8603,10 +8718,10 @@ export function parseContainerSpecData(dcData) {
8603
8718
  dcDataList = dcData.split("---");
8604
8719
  }
8605
8720
  for (const dcData of dcDataList) {
8606
- let yamlObj = undefined;
8721
+ let yamlObj;
8607
8722
  try {
8608
8723
  yamlObj = _load(dcData);
8609
- } catch (err) {
8724
+ } catch (_err) {
8610
8725
  // ignore errors
8611
8726
  }
8612
8727
  if (!yamlObj) {
@@ -8777,7 +8892,7 @@ export function parseOpenapiSpecData(oaData) {
8777
8892
  } else {
8778
8893
  oaData = JSON.parse(oaData);
8779
8894
  }
8780
- } catch (e) {
8895
+ } catch (_e) {
8781
8896
  return servlist;
8782
8897
  }
8783
8898
 
@@ -9292,7 +9407,7 @@ export async function parseNupkg(nupkgFile) {
9292
9407
  export function parseNuspecData(nupkgFile, nuspecData) {
9293
9408
  const pkgList = [];
9294
9409
  const pkg = { group: "" };
9295
- let npkg = undefined;
9410
+ let npkg;
9296
9411
  const dependenciesMap = {};
9297
9412
  const addedMap = {};
9298
9413
  try {
@@ -9304,7 +9419,7 @@ export function parseNuspecData(nupkgFile, nuspecData) {
9304
9419
  attributesKey: "$",
9305
9420
  commentKey: "value",
9306
9421
  }).package;
9307
- } catch (e) {
9422
+ } catch (_e) {
9308
9423
  // If we are parsing with invalid encoding, unicode replacement character is used
9309
9424
  if (nuspecData.charCodeAt(0) === 65533) {
9310
9425
  console.log(`Unable to parse ${nupkgFile} in utf-8 mode`);
@@ -9371,7 +9486,7 @@ export function parseNuspecData(nupkgFile, nuspecData) {
9371
9486
  }
9372
9487
  const dependsOn = [];
9373
9488
  for (const agroup of dependencyGroups) {
9374
- let targetFramework = undefined;
9489
+ let targetFramework;
9375
9490
  if (agroup?.$?.targetFramework) {
9376
9491
  targetFramework = agroup.$.targetFramework;
9377
9492
  }
@@ -9518,7 +9633,7 @@ export function parseCsProjData(csProjData, projFile, pkgNameVersions = {}) {
9518
9633
  csProjData = csProjData.slice(1);
9519
9634
  }
9520
9635
  const projectTargetFrameworks = [];
9521
- let projects = undefined;
9636
+ let projects;
9522
9637
  try {
9523
9638
  projects = xml2js(csProjData, {
9524
9639
  compact: true,
@@ -9528,7 +9643,7 @@ export function parseCsProjData(csProjData, projFile, pkgNameVersions = {}) {
9528
9643
  attributesKey: "$",
9529
9644
  commentKey: "value",
9530
9645
  }).Project;
9531
- } catch (e) {
9646
+ } catch (_e) {
9532
9647
  console.log(`Unable to parse ${projFile} with utf-8 encoding!`);
9533
9648
  }
9534
9649
  if (!projects || projects.length === 0) {
@@ -10391,7 +10506,7 @@ export function parseComposerLock(pkgLockFile, rootRequires) {
10391
10506
  let lockData = {};
10392
10507
  try {
10393
10508
  lockData = JSON.parse(readFileSync(pkgLockFile, { encoding: "utf-8" }));
10394
- } catch (e) {
10509
+ } catch (_e) {
10395
10510
  console.error("Invalid composer.lock file:", pkgLockFile);
10396
10511
  return [];
10397
10512
  }
@@ -10675,7 +10790,7 @@ export function parseSbtLock(pkgLockFile) {
10675
10790
  if (artifacts?.length) {
10676
10791
  integrity = artifacts[0].hash.replace("sha1:", "sha1-");
10677
10792
  }
10678
- let compScope = undefined;
10793
+ let compScope;
10679
10794
  if (pkg.configurations) {
10680
10795
  if (pkg.configurations.includes("runtime")) {
10681
10796
  compScope = "required";
@@ -10852,7 +10967,7 @@ export function convertOSQueryResults(
10852
10967
  if (publisher === "null") {
10853
10968
  publisher = "";
10854
10969
  }
10855
- let scope = undefined;
10970
+ let scope;
10856
10971
  const compScope = res.priority;
10857
10972
  if (["required", "optional", "excluded"].includes(compScope)) {
10858
10973
  scope = compScope;
@@ -10872,7 +10987,7 @@ export function convertOSQueryResults(
10872
10987
  if (!name && results.length === 1 && queryObj.name) {
10873
10988
  name = queryObj.name;
10874
10989
  }
10875
- let qualifiers = undefined;
10990
+ let qualifiers;
10876
10991
  if (res.identifying_number?.length) {
10877
10992
  qualifiers = {
10878
10993
  tag_id: res.identifying_number.replace("{", "").replace("}", ""),
@@ -10898,7 +11013,7 @@ export function convertOSQueryResults(
10898
11013
  subpath,
10899
11014
  ).toString();
10900
11015
  const props = [{ name: "cdx:osquery:category", value: queryCategory }];
10901
- let providesList = undefined;
11016
+ let providesList;
10902
11017
  if (enhance) {
10903
11018
  switch (queryObj.purlType) {
10904
11019
  case "deb":
@@ -11166,7 +11281,7 @@ export function parseSwiftResolved(resolvedFile) {
11166
11281
  }
11167
11282
  pkgList.push(rootPkg);
11168
11283
  }
11169
- } catch (err) {
11284
+ } catch (_err) {
11170
11285
  // continue regardless of error
11171
11286
  }
11172
11287
  }
@@ -11304,8 +11419,8 @@ export async function collectJarNS(jarPath, pomPathMap = {}) {
11304
11419
  let pomname =
11305
11420
  pomPathMap[basename(jf).replace(".jar", ".pom")] ||
11306
11421
  jf.replace(".jar", ".pom");
11307
- let pomData = undefined;
11308
- let purl = undefined;
11422
+ let pomData;
11423
+ let purl;
11309
11424
  // In some cases, the pom name might be slightly different to the jar name
11310
11425
  if (!safeExistsSync(pomname)) {
11311
11426
  let searchDir = dirname(jf);
@@ -11429,7 +11544,7 @@ export async function collectJarNS(jarPath, pomPathMap = {}) {
11429
11544
  { alg: "SHA-256", content: hashValues["sha256"] },
11430
11545
  { alg: "SHA-512", content: hashValues["sha512"] },
11431
11546
  ];
11432
- } catch (e) {
11547
+ } catch (_e) {
11433
11548
  // ignore
11434
11549
  }
11435
11550
  jarNSMapping[purl || jf] = {
@@ -11462,10 +11577,10 @@ export async function convertJarNSToPackages(jarNSMapping) {
11462
11577
  if (!pom) {
11463
11578
  pom = {};
11464
11579
  }
11465
- let purlObj = undefined;
11580
+ let purlObj;
11466
11581
  try {
11467
11582
  purlObj = PackageURL.fromString(purl);
11468
- } catch (e) {
11583
+ } catch (_e) {
11469
11584
  // ignore
11470
11585
  purlObj = {};
11471
11586
  }
@@ -11674,7 +11789,7 @@ export async function extractJarArchive(jarFile, tempDir, jarNSMapping = {}) {
11674
11789
  const pkgList = [];
11675
11790
  let jarFiles = [];
11676
11791
  const fname = basename(jarFile);
11677
- let pomname = undefined;
11792
+ let pomname;
11678
11793
  // If there is a pom file in the same directory, try to use it
11679
11794
  const manifestname = join(dirname(jarFile), "META-INF", "MANIFEST.MF");
11680
11795
  // Issue 439: Current implementation checks for existance of a .pom file, but .pom file is not used.
@@ -11775,7 +11890,7 @@ export async function extractJarArchive(jarFile, tempDir, jarNSMapping = {}) {
11775
11890
  await zip.extract(null, tempDir);
11776
11891
  await zip.close();
11777
11892
  jarResult = { status: 0 };
11778
- } catch (e) {
11893
+ } catch (_e) {
11779
11894
  if (DEBUG_MODE) {
11780
11895
  console.log(`Unable to extract ${jf}. Skipping.`);
11781
11896
  }
@@ -11973,7 +12088,7 @@ export async function extractJarArchive(jarFile, tempDir, jarNSMapping = {}) {
11973
12088
  force: true,
11974
12089
  });
11975
12090
  }
11976
- } catch (err) {
12091
+ } catch (_err) {
11977
12092
  // ignore cleanup errors
11978
12093
  }
11979
12094
  } // for
@@ -12092,7 +12207,7 @@ export async function readZipEntry(
12092
12207
  filePattern,
12093
12208
  contentEncoding = "utf-8",
12094
12209
  ) {
12095
- let retData = undefined;
12210
+ let retData;
12096
12211
  try {
12097
12212
  const zip = new StreamZip.async({ file: zipFile });
12098
12213
  const entriesCount = await zip.entriesCount;
@@ -12216,7 +12331,7 @@ export function getGradleCommand(srcPath, rootPath) {
12216
12331
  // Enable execute permission
12217
12332
  try {
12218
12333
  chmodSync(join(srcPath, findGradleFile), 0o775);
12219
- } catch (e) {
12334
+ } catch (_e) {
12220
12335
  // continue regardless of error
12221
12336
  }
12222
12337
  gradleCmd = resolve(join(srcPath, findGradleFile));
@@ -12224,7 +12339,7 @@ export function getGradleCommand(srcPath, rootPath) {
12224
12339
  // Check if the root directory has a wrapper script
12225
12340
  try {
12226
12341
  chmodSync(join(rootPath, findGradleFile), 0o775);
12227
- } catch (e) {
12342
+ } catch (_e) {
12228
12343
  // continue regardless of error
12229
12344
  }
12230
12345
  gradleCmd = resolve(join(rootPath, findGradleFile));
@@ -12248,7 +12363,7 @@ export function getMillCommand(srcPath) {
12248
12363
  // Enable execute permission
12249
12364
  try {
12250
12365
  chmodSync(join(srcPath, millCmd), 0o775);
12251
- } catch (e) {
12366
+ } catch (_e) {
12252
12367
  // continue regardless of error
12253
12368
  }
12254
12369
  millCmd = resolve(join(srcPath, millCmd));
@@ -12751,13 +12866,13 @@ async function fullScanCocoaPod(dependency, component, options) {
12751
12866
  podspecLocation.replace("<DEFAULT>", branchName),
12752
12867
  );
12753
12868
  podspecLocation = podspecLocation.replace("<DEFAULT>", branchName);
12754
- } catch (err) {
12869
+ } catch (_err) {
12755
12870
  try {
12756
12871
  httpResult = await cdxgenAgent.get(
12757
12872
  `${podspecLocation.replace("<DEFAULT>", branchName)}.json`,
12758
12873
  );
12759
12874
  podspecLocation = `${podspecLocation.replace("<DEFAULT>", branchName)}.json`;
12760
- } catch (err) {
12875
+ } catch (_err) {
12761
12876
  continue;
12762
12877
  }
12763
12878
  }
@@ -12837,7 +12952,7 @@ async function fullScanCocoaPod(dependency, component, options) {
12837
12952
  podspecText.lastIndexOf("}") + 1,
12838
12953
  ),
12839
12954
  );
12840
- } catch (e) {
12955
+ } catch (_e) {
12841
12956
  return;
12842
12957
  }
12843
12958
  const externalRefs = [];
@@ -13104,7 +13219,7 @@ export function getMavenCommand(srcPath, rootPath) {
13104
13219
  // Enable execute permission
13105
13220
  try {
13106
13221
  chmodSync(join(srcPath, findMavenFile), 0o775);
13107
- } catch (e) {
13222
+ } catch (_e) {
13108
13223
  // continue regardless of error
13109
13224
  }
13110
13225
  mavenWrapperCmd = resolve(join(srcPath, findMavenFile));
@@ -13113,7 +13228,7 @@ export function getMavenCommand(srcPath, rootPath) {
13113
13228
  // Check if the root directory has a wrapper script
13114
13229
  try {
13115
13230
  chmodSync(join(rootPath, findMavenFile), 0o775);
13116
- } catch (e) {
13231
+ } catch (_e) {
13117
13232
  // continue regardless of error
13118
13233
  }
13119
13234
  mavenWrapperCmd = resolve(join(rootPath, findMavenFile));
@@ -13503,7 +13618,7 @@ export function getPipFrozenTree(
13503
13618
  const formulationList = [];
13504
13619
  const rootList = [];
13505
13620
  const dependenciesList = [];
13506
- let result = undefined;
13621
+ let result;
13507
13622
  let frozen = true;
13508
13623
  const env = {
13509
13624
  ...process.env,
@@ -13967,7 +14082,7 @@ export function getPipTreeForPackages(
13967
14082
  const failedPkgList = [];
13968
14083
  const rootList = [];
13969
14084
  const dependenciesList = [];
13970
- let result = undefined;
14085
+ let result;
13971
14086
  const env = {
13972
14087
  ...process.env,
13973
14088
  };
@@ -14139,9 +14254,8 @@ export function parsePackageJsonName(name) {
14139
14254
  projectName: "",
14140
14255
  moduleName: "",
14141
14256
  };
14142
- const match = (typeof name === "object" ? name.name || "" : name || "").match(
14143
- nameRegExp,
14144
- );
14257
+ const safeName = name?.name ?? name ?? "";
14258
+ const match = safeName.match(nameRegExp);
14145
14259
  if (match) {
14146
14260
  returnObject.scope =
14147
14261
  (match[1] && name.includes("@") ? `@${match[1]}` : match[1]) || null;
@@ -14268,7 +14382,7 @@ export async function addEvidenceForImports(
14268
14382
  }
14269
14383
  // Capture metadata such as description from local node_modules in deep mode
14270
14384
  if (deep && !pkg.description && pkg.properties) {
14271
- let localNodeModulesPath = undefined;
14385
+ let localNodeModulesPath;
14272
14386
  for (const aprop of pkg.properties) {
14273
14387
  if (aprop.name === "LocalNodeModulesPath") {
14274
14388
  localNodeModulesPath = resolve(join(aprop.value, "package.json"));
@@ -14323,7 +14437,7 @@ export function parseCmakeDotFile(dotFile, pkgType, options = {}) {
14323
14437
  let name = "";
14324
14438
  const group = "";
14325
14439
  const version = "";
14326
- let path = undefined;
14440
+ let path;
14327
14441
  if (l.startsWith("digraph")) {
14328
14442
  const tmpA = l.split(" ");
14329
14443
  if (tmpA && tmpA.length > 1) {
@@ -14465,7 +14579,7 @@ export function parseCmakeLikeFile(cmakeListFile, pkgType, options = {}) {
14465
14579
  .filter((v) => v.length > 1);
14466
14580
  const parentName =
14467
14581
  tmpB.length > 0 ? tmpB[0].replace(":", "").trim() : "";
14468
- let parentVersion = undefined;
14582
+ let parentVersion;
14469
14583
  // In case of meson.build we can find the version number after the word version
14470
14584
  // thanks to our replaces and splits
14471
14585
  const versionIndex = tmpB.findIndex(
@@ -14722,7 +14836,7 @@ export function getCppModules(src, options, osPkgsList, epkgList) {
14722
14836
  const pkgAddedMap = {};
14723
14837
  let sliceData;
14724
14838
  const epkgMap = {};
14725
- let parentComponent = undefined;
14839
+ let parentComponent;
14726
14840
  const dependsOn = new Set();
14727
14841
 
14728
14842
  (epkgList || []).forEach((p) => {
@@ -14758,8 +14872,8 @@ export function getCppModules(src, options, osPkgsList, epkgList) {
14758
14872
  // Are there any dependencies declared in vcpkg.json
14759
14873
  if (vcPkgData.dependencies && Array.isArray(vcPkgData.dependencies)) {
14760
14874
  for (const avcdep of vcPkgData.dependencies) {
14761
- let avcpkgName = undefined;
14762
- let scope = undefined;
14875
+ let avcpkgName;
14876
+ let scope;
14763
14877
  if (typeof avcdep === "string" || avcdep instanceof String) {
14764
14878
  avcpkgName = avcdep;
14765
14879
  } else if (Object.keys(avcdep).length && avcdep.name) {
@@ -15026,7 +15140,7 @@ export function parseCUsageSlice(sliceData) {
15026
15140
  usageData[slFileName] = allLines;
15027
15141
  }
15028
15142
  }
15029
- } catch (err) {
15143
+ } catch (_err) {
15030
15144
  // ignore
15031
15145
  }
15032
15146
  return usageData;
@@ -15169,7 +15283,7 @@ export async function getNugetMetadata(pkgList, dependencies = undefined) {
15169
15283
  const cdepList = [];
15170
15284
  const depRepList = {};
15171
15285
  for (const p of pkgList) {
15172
- let cacheKey = undefined;
15286
+ let cacheKey;
15173
15287
  try {
15174
15288
  // If there is a version, we can safely use the cache to retrieve the license
15175
15289
  // See: https://github.com/CycloneDX/cdxgen/issues/352
@@ -15471,7 +15585,7 @@ export function isValidIriReference(iri) {
15471
15585
  } else if (iri.toLocaleLowerCase().startsWith("http")) {
15472
15586
  try {
15473
15587
  new URL(iri);
15474
- } catch (error) {
15588
+ } catch (_error) {
15475
15589
  iriIsValid = false;
15476
15590
  }
15477
15591
  }
@@ -15625,7 +15739,7 @@ export function collectExecutables(basePath, binPaths) {
15625
15739
  ignore: ignoreList,
15626
15740
  });
15627
15741
  executables = executables.concat(files);
15628
- } catch (err) {
15742
+ } catch (_err) {
15629
15743
  // ignore
15630
15744
  }
15631
15745
  }
@@ -15684,7 +15798,7 @@ export function collectSharedLibs(
15684
15798
  ignore: ignoreList,
15685
15799
  });
15686
15800
  sharedLibs = sharedLibs.concat(files);
15687
- } catch (err) {
15801
+ } catch (_err) {
15688
15802
  // ignore
15689
15803
  }
15690
15804
  }