@cyclonedx/cdxgen 11.4.0 → 11.4.2

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 +71 -57
  7. package/lib/evinser/evinser.js +26 -20
  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 +10 -8
  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 +276 -106
  22. package/lib/helpers/utils.test.js +41 -11
  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
package/README.md CHANGED
@@ -152,7 +152,8 @@ Options:
152
152
  --validate Validate the generated SBOM using json schema. Defaults to true. Pass --no-validate to di
153
153
  sable. [boolean] [default: true]
154
154
  --evidence Generate SBOM with evidence for supported languages. [boolean] [default: false]
155
- --spec-version CycloneDX Specification version to use. Defaults to 1.6 [number] [default: 1.6]
155
+ --spec-version CycloneDX Specification version to use. Defaults to 1.6
156
+ [number] [choices: 1.4, 1.5, 1.6] [default: 1.6]
156
157
  --filter Filter components containing this word in purl or component.properties.value. Multiple va
157
158
  lues allowed. [array]
158
159
  --only Include components only containing this word in purl. Useful to generate BOM with first p
@@ -163,6 +164,8 @@ Options:
163
164
  [choices: "appsec", "research", "operational", "threat-modeling", "license-compliance", "generic", "machine-learning",
164
165
  "ml", "deep-learning", "ml-deep", "ml-tiny"] [default: "generic"]
165
166
  --exclude Additional glob pattern(s) to ignore [array]
167
+ --export-proto Serialize and export BOM as protobuf binary. [boolean] [default: false]
168
+ --proto-bin-file Path for the serialized protobuf binary. [default: "bom.cdx"]
166
169
  --include-formulation Generate formulation section with git metadata and build tools. Defaults to false.
167
170
  [boolean] [default: false]
168
171
  --include-crypto Include crypto libraries as components. [boolean] [default: false]
package/bin/cdxgen.js CHANGED
@@ -4,11 +4,13 @@ import crypto from "node:crypto";
4
4
  import fs from "node:fs";
5
5
  import { basename, dirname, join, resolve } from "node:path";
6
6
  import process from "node:process";
7
+
7
8
  import globalAgent from "global-agent";
8
9
  import jws from "jws";
9
10
  import { parse as _load } from "yaml";
10
11
  import yargs from "yargs";
11
12
  import { hideBin } from "yargs/helpers";
13
+
12
14
  import { createBom, submitBom } from "../lib/cli/index.js";
13
15
  import {
14
16
  printCallStack,
@@ -21,15 +23,17 @@ import {
21
23
  printSummary,
22
24
  printTable,
23
25
  } from "../lib/helpers/display.js";
24
- import { thoughtEnd, thoughtLog } from "../lib/helpers/logger.js";
26
+ import { TRACE_MODE, thoughtEnd, thoughtLog } from "../lib/helpers/logger.js";
25
27
  import {
26
28
  ATOM_DB,
29
+ commandsExecuted,
27
30
  DEBUG_MODE,
28
31
  dirNameStr,
29
32
  getTmpDir,
30
33
  isMac,
31
34
  isSecureMode,
32
35
  isWin,
36
+ remoteHostsAccessed,
33
37
  safeExistsSync,
34
38
  } from "../lib/helpers/utils.js";
35
39
  import { validateBom } from "../lib/helpers/validator.js";
@@ -57,7 +61,7 @@ for (const configPattern of configPaths) {
57
61
  } else {
58
62
  config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
59
63
  }
60
- } catch (e) {
64
+ } catch (_e) {
61
65
  console.log("Invalid config file", configPath);
62
66
  }
63
67
  }
@@ -264,12 +268,10 @@ const args = yargs(hideBin(process.argv))
264
268
  type: "boolean",
265
269
  default: false,
266
270
  description: "Serialize and export BOM as protobuf binary.",
267
- hidden: true,
268
271
  })
269
272
  .option("proto-bin-file", {
270
273
  description: "Path for the serialized protobuf binary.",
271
274
  default: "bom.cdx",
272
- hidden: true,
273
275
  })
274
276
  .option("include-formulation", {
275
277
  type: "boolean",
@@ -832,7 +834,7 @@ const needsBomSigning = ({ generateKeyAndSign }) =>
832
834
  const jsonFile = options.output;
833
835
  // Create bom json file
834
836
  if (bomNSData.bomJson) {
835
- let jsonPayload = undefined;
837
+ let jsonPayload;
836
838
  if (
837
839
  typeof bomNSData.bomJson === "string" ||
838
840
  bomNSData.bomJson instanceof String
@@ -859,9 +861,9 @@ const needsBomSigning = ({ generateKeyAndSign }) =>
859
861
  if (alg.includes("none")) {
860
862
  alg = "RS512";
861
863
  }
862
- let privateKeyToUse = undefined;
863
- let jwkPublicKey = undefined;
864
- let publicKeyFile = undefined;
864
+ let privateKeyToUse;
865
+ let jwkPublicKey;
866
+ let publicKeyFile;
865
867
  if (options.generateKeyAndSign) {
866
868
  const jdirName = dirname(jsonFile);
867
869
  publicKeyFile = join(jdirName, "public.key");
@@ -1058,7 +1060,7 @@ const needsBomSigning = ({ generateKeyAndSign }) =>
1058
1060
  if (!validateBom(bomNSData.bomJson)) {
1059
1061
  process.exit(1);
1060
1062
  }
1061
- thoughtLog("BOM file looks valid. Thank you for using cdxgen!");
1063
+ thoughtLog("BOM file looks valid.");
1062
1064
  }
1063
1065
  thoughtEnd();
1064
1066
  // Automatically submit the bom data
@@ -1075,6 +1077,7 @@ const needsBomSigning = ({ generateKeyAndSign }) =>
1075
1077
  if (options.exportProto) {
1076
1078
  const protobomModule = await import("../lib/helpers/protobom.js");
1077
1079
  protobomModule.writeBinary(bomNSData.bomJson, options.protoBinFile);
1080
+ thoughtLog("BOM file is also available in .proto format!");
1078
1081
  }
1079
1082
  if (options.print && bomNSData.bomJson && bomNSData.bomJson.components) {
1080
1083
  printSummary(bomNSData.bomJson);
@@ -1089,4 +1092,24 @@ const needsBomSigning = ({ generateKeyAndSign }) =>
1089
1092
  printDependencyTree(bomNSData.bomJson, "provides");
1090
1093
  }
1091
1094
  }
1095
+ if (
1096
+ (DEBUG_MODE || TRACE_MODE) &&
1097
+ (!process.env?.CDXGEN_ALLOWED_HOSTS ||
1098
+ !process.env?.CDXGEN_ALLOWED_COMMANDS)
1099
+ ) {
1100
+ let allowListSuggestion = "";
1101
+ const envPrefix = isWin ? "set $env:" : "export ";
1102
+ if (remoteHostsAccessed.size) {
1103
+ allowListSuggestion = `${envPrefix}CDXGEN_ALLOWED_HOSTS="${Array.from(remoteHostsAccessed).join(",")}"\n`;
1104
+ }
1105
+ if (commandsExecuted.size) {
1106
+ allowListSuggestion = `${allowListSuggestion}${envPrefix}CDXGEN_ALLOWED_COMMANDS="${Array.from(commandsExecuted).join(",")}"\n`;
1107
+ }
1108
+ if (allowListSuggestion) {
1109
+ console.log(
1110
+ "SECURE MODE: cdxgen supports allowlists for remote hosts and external commands. Set the following environment variables to get started.",
1111
+ );
1112
+ console.log(allowListSuggestion);
1113
+ }
1114
+ }
1092
1115
  })();
package/bin/evinse.js CHANGED
@@ -2,8 +2,10 @@
2
2
  // Evinse (Evinse Verification Is Nearly SBOM Evidence)
3
3
 
4
4
  import process from "node:process";
5
+
5
6
  import yargs from "yargs";
6
7
  import { hideBin } from "yargs/helpers";
8
+
7
9
  import {
8
10
  analyzeProject,
9
11
  createEvinseFile,
package/bin/repl.js CHANGED
@@ -5,6 +5,7 @@ import { homedir } from "node:os";
5
5
  import { join } from "node:path";
6
6
  import process from "node:process";
7
7
  import repl from "node:repl";
8
+
8
9
  import jsonata from "jsonata";
9
10
 
10
11
  import { createBom } from "../lib/cli/index.js";
@@ -12,13 +13,14 @@ import {
12
13
  printCallStack,
13
14
  printDependencyTree,
14
15
  printFormulation,
15
- printOSTable,
16
16
  printOccurrences,
17
+ printOSTable,
17
18
  printServices,
18
19
  printSummary,
19
20
  printTable,
20
21
  printVulnerabilities,
21
22
  } from "../lib/helpers/display.js";
23
+ import { readBinary } from "../lib/helpers/protobom.js";
22
24
  import { getTmpDir } from "../lib/helpers/utils.js";
23
25
  import { validateBom } from "../lib/helpers/validator.js";
24
26
 
@@ -50,15 +52,15 @@ if (process.env?.CDXGEN_NODE_OPTIONS) {
50
52
  }
51
53
 
52
54
  // The current sbom is stored here
53
- let sbom = undefined;
55
+ let sbom;
54
56
 
55
- let historyFile = undefined;
57
+ let historyFile;
56
58
  const historyConfigDir = join(homedir(), ".config", ".cdxgen");
57
59
  if (!process.env.CDXGEN_REPL_HISTORY && !fs.existsSync(historyConfigDir)) {
58
60
  try {
59
61
  fs.mkdirSync(historyConfigDir, { recursive: true });
60
62
  historyFile = join(historyConfigDir, ".repl_history");
61
- } catch (e) {
63
+ } catch (_e) {
62
64
  // ignore
63
65
  }
64
66
  } else {
@@ -78,6 +80,12 @@ export const importSbom = (sbomOrPath) => {
78
80
  } catch (e) {
79
81
  console.log(`⚠ Unable to import the BOM from ${sbomOrPath} due to ${e}`);
80
82
  }
83
+ } else if (
84
+ (sbomOrPath?.endsWith(".cdx") || sbomOrPath?.endsWith(".proto")) &&
85
+ fs.existsSync(sbomOrPath)
86
+ ) {
87
+ sbom = readBinary(sbomOrPath, true);
88
+ printSummary(sbom);
81
89
  } else {
82
90
  console.log(`⚠ ${sbomOrPath} is invalid.`);
83
91
  }
package/bin/verify.js CHANGED
@@ -3,9 +3,11 @@
3
3
  import fs from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import process from "node:process";
6
+
6
7
  import jws from "jws";
7
8
  import yargs from "yargs";
8
9
  import { hideBin } from "yargs/helpers";
10
+
9
11
  import { dirNameStr } from "../lib/helpers/utils.js";
10
12
  import { getBomWithOras } from "../lib/managers/oci.js";
11
13
 
package/lib/cli/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Buffer } from "node:buffer";
2
2
  import {
3
- constants,
4
3
  accessSync,
4
+ constants,
5
5
  existsSync,
6
6
  lstatSync,
7
7
  mkdtempSync,
@@ -14,6 +14,7 @@ import {
14
14
  import { platform as _platform, arch, homedir } from "node:os";
15
15
  import { basename, dirname, join, relative, resolve, sep } from "node:path";
16
16
  import process from "node:process";
17
+
17
18
  import got from "got";
18
19
  import { PackageURL } from "packageurl-js";
19
20
  import { gte, lte } from "semver";
@@ -21,6 +22,7 @@ import { parse } from "ssri";
21
22
  import { table } from "table";
22
23
  import { v4 as uuidv4 } from "uuid";
23
24
  import { parse as loadYaml } from "yaml";
25
+
24
26
  import { findJSImportsExports } from "../helpers/analyzer.js";
25
27
  import { collectOSCryptoLibs } from "../helpers/cbomutils.js";
26
28
  import {
@@ -32,21 +34,14 @@ import {
32
34
  } from "../helpers/envcontext.js";
33
35
  import { thoughtLog } from "../helpers/logger.js";
34
36
  import {
35
- CARGO_CMD,
36
- CLJ_CMD,
37
- DEBUG_MODE,
38
- LEIN_CMD,
39
- MAX_BUFFER,
40
- PREFER_MAVEN_DEPS_TREE,
41
- PROJECT_TYPE_ALIASES,
42
- SWIFT_CMD,
43
- TIMEOUT_MS,
44
37
  addEvidenceForDotnet,
45
38
  addEvidenceForImports,
46
39
  addPlugin,
47
40
  buildGradleCommandArguments,
48
41
  buildObjectForCocoaPod,
49
42
  buildObjectForGradleModule,
43
+ CARGO_CMD,
44
+ CLJ_CMD,
50
45
  checksumFile,
51
46
  cleanupPlugin,
52
47
  collectGemModuleNames,
@@ -56,6 +51,7 @@ import {
56
51
  convertJarNSToPackages,
57
52
  convertOSQueryResults,
58
53
  createUVLock,
54
+ DEBUG_MODE,
59
55
  determineSbtVersion,
60
56
  dirNameStr,
61
57
  encodeForPurl,
@@ -87,6 +83,10 @@ import {
87
83
  isPartialTree,
88
84
  isSecureMode,
89
85
  isValidIriReference,
86
+ LEIN_CMD,
87
+ MAX_BUFFER,
88
+ PREFER_MAVEN_DEPS_TREE,
89
+ PROJECT_TYPE_ALIASES,
90
90
  parseBazelActionGraph,
91
91
  parseBazelSkyframe,
92
92
  parseBdistMetadata,
@@ -117,8 +117,8 @@ import {
117
117
  parseGoListDep,
118
118
  parseGoModData,
119
119
  parseGoModGraph,
120
- parseGoModWhy,
121
120
  parseGoModulesTxt,
121
+ parseGoModWhy,
122
122
  parseGopkgData,
123
123
  parseGosumData,
124
124
  parseGradleDep,
@@ -160,11 +160,13 @@ import {
160
160
  parseYarnLock,
161
161
  readZipEntry,
162
162
  recomputeScope,
163
+ SWIFT_CMD,
163
164
  safeExistsSync,
164
165
  safeMkdirSync,
165
166
  safeSpawnSync,
166
167
  shouldFetchLicense,
167
168
  splitOutputByGradleProjects,
169
+ TIMEOUT_MS,
168
170
  } from "../helpers/utils.js";
169
171
  import {
170
172
  executeOsQuery,
@@ -283,7 +285,7 @@ const createDefaultParentComponent = (
283
285
  };
284
286
 
285
287
  const determineParentComponent = (options) => {
286
- let parentComponent = undefined;
288
+ let parentComponent;
287
289
  if (options.parentComponent && Object.keys(options.parentComponent).length) {
288
290
  return options.parentComponent;
289
291
  }
@@ -551,7 +553,7 @@ const addFormulationSection = (options, context) => {
551
553
  if (!environmentVars.length) {
552
554
  environmentVars = undefined;
553
555
  }
554
- let sourceInput = undefined;
556
+ let sourceInput;
555
557
  if (environmentVars) {
556
558
  sourceInput = { environmentVars };
557
559
  }
@@ -889,7 +891,7 @@ function addMetadata(parentComponent = {}, options = {}, context = {}) {
889
891
  name: `oci:image:bundles:${sdkName}Sdk`,
890
892
  value: "true",
891
893
  });
892
- } catch (e) {
894
+ } catch (_e) {
893
895
  // ignore
894
896
  }
895
897
  }
@@ -1227,7 +1229,7 @@ function determinePackageType(pkg) {
1227
1229
  return "framework";
1228
1230
  }
1229
1231
  }
1230
- } catch (e) {
1232
+ } catch (_e) {
1231
1233
  // continue regardless of error
1232
1234
  }
1233
1235
  } else if (pkg.group) {
@@ -1235,19 +1237,19 @@ function determinePackageType(pkg) {
1235
1237
  return "application";
1236
1238
  }
1237
1239
  }
1238
- if (Object.prototype.hasOwnProperty.call(pkg, "description")) {
1240
+ if (Object.hasOwn(pkg, "description")) {
1239
1241
  if (pkg.description?.toLowerCase().includes("framework")) {
1240
1242
  return "framework";
1241
1243
  }
1242
1244
  }
1243
- if (Object.prototype.hasOwnProperty.call(pkg, "keywords")) {
1245
+ if (Object.hasOwn(pkg, "keywords")) {
1244
1246
  for (const keyword of pkg.keywords) {
1245
1247
  if (keyword && keyword.toLowerCase() === "framework") {
1246
1248
  return "framework";
1247
1249
  }
1248
1250
  }
1249
1251
  }
1250
- if (Object.prototype.hasOwnProperty.call(pkg, "tags")) {
1252
+ if (Object.hasOwn(pkg, "tags")) {
1251
1253
  for (const tag of pkg.tags) {
1252
1254
  if (tag && tag.toLowerCase() === "framework") {
1253
1255
  return "framework";
@@ -1275,16 +1277,16 @@ function processHashes(pkg, component) {
1275
1277
  const integrity = parse(pkg._integrity) || {};
1276
1278
  // Components may have multiple hashes with various lengths. Check each one
1277
1279
  // that is supported by the CycloneDX specification.
1278
- if (Object.prototype.hasOwnProperty.call(integrity, "sha512")) {
1280
+ if (Object.hasOwn(integrity, "sha512")) {
1279
1281
  addComponentHash("SHA-512", integrity.sha512[0].digest, component);
1280
1282
  }
1281
- if (Object.prototype.hasOwnProperty.call(integrity, "sha384")) {
1283
+ if (Object.hasOwn(integrity, "sha384")) {
1282
1284
  addComponentHash("SHA-384", integrity.sha384[0].digest, component);
1283
1285
  }
1284
- if (Object.prototype.hasOwnProperty.call(integrity, "sha256")) {
1286
+ if (Object.hasOwn(integrity, "sha256")) {
1285
1287
  addComponentHash("SHA-256", integrity.sha256[0].digest, component);
1286
1288
  }
1287
- if (Object.prototype.hasOwnProperty.call(integrity, "sha1")) {
1289
+ if (Object.hasOwn(integrity, "sha1")) {
1288
1290
  addComponentHash("SHA-1", integrity.sha1[0].digest, component);
1289
1291
  }
1290
1292
  }
@@ -1494,7 +1496,7 @@ export async function createJavaBom(path, options) {
1494
1496
  let parentComponent = {};
1495
1497
  // Support for tracking all the tools that created the BOM
1496
1498
  // For java, this would correctly include the cyclonedx maven plugin.
1497
- let tools = undefined;
1499
+ let tools;
1498
1500
  let possible_misses = false;
1499
1501
  // war/ear mode
1500
1502
  if (path.endsWith(".war") || path.endsWith(".jar")) {
@@ -1577,7 +1579,7 @@ export async function createJavaBom(path, options) {
1577
1579
  }
1578
1580
  }
1579
1581
  }
1580
- let result = undefined;
1582
+ let result;
1581
1583
  let mvnArgs;
1582
1584
  if (isQuarkus) {
1583
1585
  thoughtLog(
@@ -1660,10 +1662,7 @@ export async function createJavaBom(path, options) {
1660
1662
  // Use the cyclonedx maven plugin if there is no preference for maven deps tree
1661
1663
  if (!useMavenDepsTree) {
1662
1664
  thoughtLog("The user wants me to use the cyclonedx-maven plugin.");
1663
- console.log(
1664
- `Executing '${mavenCmd} ${mvnArgs.join(" ")}' in`,
1665
- basePath,
1666
- );
1665
+ console.log(`Executing '${mavenCmd}' in`, basePath);
1667
1666
  result = safeSpawnSync(mavenCmd, mvnArgs, {
1668
1667
  cwd: basePath,
1669
1668
  shell: true,
@@ -1698,8 +1697,9 @@ export async function createJavaBom(path, options) {
1698
1697
  const tempMvnTree = join(tempDir, "mvn-tree.txt");
1699
1698
  const tempMvnParentTree = join(tempDir, "mvn-parent-tree.txt");
1700
1699
  let mvnTreeArgs = ["dependency:tree", `-DoutputFile=${tempMvnTree}`];
1700
+ let addArgs = "";
1701
1701
  if (process.env.MVN_ARGS) {
1702
- const addArgs = process.env.MVN_ARGS.split(" ");
1702
+ addArgs = process.env.MVN_ARGS.split(" ");
1703
1703
  mvnTreeArgs = mvnTreeArgs.concat(addArgs);
1704
1704
  }
1705
1705
  // Automatically use settings.xml to improve the success for fallback
@@ -1713,17 +1713,21 @@ export async function createJavaBom(path, options) {
1713
1713
  thoughtLog(
1714
1714
  "What is the parent component here? Let's use maven command to find out.",
1715
1715
  );
1716
- result = safeSpawnSync(
1717
- "mvn",
1718
- ["dependency:tree", "-N", `-DoutputFile=${tempMvnParentTree}`],
1719
- {
1720
- cwd: basePath,
1721
- shell: true,
1722
- encoding: "utf-8",
1723
- timeout: TIMEOUT_MS,
1724
- maxBuffer: MAX_BUFFER,
1725
- },
1726
- );
1716
+ let findParentComponentArgs = [
1717
+ "dependency:tree",
1718
+ "-N",
1719
+ `-DoutputFile=${tempMvnParentTree}`,
1720
+ ];
1721
+ if (addArgs) {
1722
+ findParentComponentArgs = findParentComponentArgs.concat(addArgs);
1723
+ }
1724
+ result = safeSpawnSync("mvn", findParentComponentArgs, {
1725
+ cwd: basePath,
1726
+ shell: true,
1727
+ encoding: "utf-8",
1728
+ timeout: TIMEOUT_MS,
1729
+ maxBuffer: MAX_BUFFER,
1730
+ });
1727
1731
  if (result.status === 0) {
1728
1732
  if (safeExistsSync(tempMvnParentTree)) {
1729
1733
  const mvnTreeString = readFileSync(tempMvnParentTree, {
@@ -1768,8 +1772,13 @@ export async function createJavaBom(path, options) {
1768
1772
  // Our approach to recursively invoking the maven plugin for each sub-module is bound to result in failures
1769
1773
  // These could be due to a range of reasons that are covered below.
1770
1774
  if (pomFiles.length === 1 || DEBUG_MODE || PREFER_MAVEN_DEPS_TREE) {
1771
- console.error(result.stdout, result.stderr);
1772
- console.log("The above build errors could be due to:\n");
1775
+ if (result.stdout) {
1776
+ console.log(result.stdout);
1777
+ }
1778
+ if (result.stderr) {
1779
+ console.log(result.stderr);
1780
+ console.log("The above build errors could be due to:\n");
1781
+ }
1773
1782
  if (
1774
1783
  result.stdout &&
1775
1784
  (result.stdout.includes("Non-resolvable parent POM") ||
@@ -1868,7 +1877,7 @@ export async function createJavaBom(path, options) {
1868
1877
  // Locate and parse all bom.json files from the maven plugin
1869
1878
  if (!useMavenDepsTree) {
1870
1879
  for (const abjson of bomJsonFiles) {
1871
- let bomJsonObj = undefined;
1880
+ let bomJsonObj;
1872
1881
  try {
1873
1882
  if (DEBUG_MODE) {
1874
1883
  console.log(`Extracting data from generated bom file ${abjson}`);
@@ -2003,7 +2012,7 @@ export async function createJavaBom(path, options) {
2003
2012
  );
2004
2013
  if (process.env.GRADLE_INCLUDED_BUILDS === undefined) {
2005
2014
  const outputLines = parallelPropTaskOut.split("\n");
2006
- for (const [i, line] of outputLines.entries()) {
2015
+ for (const [_i, line] of outputLines.entries()) {
2007
2016
  if (line.startsWith("Root project '") || line.startsWith("Project '")) {
2008
2017
  break;
2009
2018
  }
@@ -3144,6 +3153,10 @@ export async function createNodejsBom(path, options) {
3144
3153
  const basePath = dirname(f);
3145
3154
  // Determine the parent component
3146
3155
  const packageJsonF = join(basePath, "package.json");
3156
+ const pnpmHooks = join(basePath, ".pnpmfile.cjs");
3157
+ if (safeExistsSync(pnpmHooks)) {
3158
+ thoughtLog("Wait, this pnpm project uses install hooks.");
3159
+ }
3147
3160
  if (!Object.keys(parentComponent).length) {
3148
3161
  if (safeExistsSync(packageJsonF)) {
3149
3162
  const pcs = await parsePkgJson(packageJsonF, true);
@@ -3832,7 +3845,7 @@ export async function createPythonBom(path, options) {
3832
3845
  }
3833
3846
  for (const f of reqFiles) {
3834
3847
  const basePath = dirname(f);
3835
- let reqData = undefined;
3848
+ let reqData;
3836
3849
  let frozen = false;
3837
3850
  // Attempt to pip freeze in a virtualenv to improve precision
3838
3851
  if (options.installDeps) {
@@ -3896,7 +3909,7 @@ export async function createPythonBom(path, options) {
3896
3909
  * The order of preference is pyproject.toml (newer) and then setup.py
3897
3910
  */
3898
3911
  if (options.installDeps) {
3899
- let pkgMap = undefined;
3912
+ let pkgMap;
3900
3913
  if (pyProjectMode && !poetryMode) {
3901
3914
  pkgMap = getPipFrozenTree(
3902
3915
  path,
@@ -4093,7 +4106,7 @@ export async function createGoBom(path, options) {
4093
4106
  let maybeBinary;
4094
4107
  try {
4095
4108
  maybeBinary = statSync(path).isFile();
4096
- } catch (err) {
4109
+ } catch (_err) {
4097
4110
  maybeBinary = false;
4098
4111
  }
4099
4112
  if (maybeBinary || options?.lifecycle?.includes("post-build")) {
@@ -4501,7 +4514,7 @@ export async function createRustBom(path, options) {
4501
4514
  let maybeBinary;
4502
4515
  try {
4503
4516
  maybeBinary = statSync(path).isFile();
4504
- } catch (err) {
4517
+ } catch (_err) {
4505
4518
  maybeBinary = false;
4506
4519
  }
4507
4520
  if (maybeBinary || options?.lifecycle?.includes("post-build")) {
@@ -4706,7 +4719,7 @@ export async function createDartBom(path, options) {
4706
4719
  * @param {Object} options Parse options from the cli
4707
4720
  */
4708
4721
  export function createCppBom(path, options) {
4709
- let parentComponent = undefined;
4722
+ let parentComponent;
4710
4723
  let dependencies = [];
4711
4724
  const addedParentComponentsMap = {};
4712
4725
  const conanLockFiles = getAllFiles(
@@ -5313,7 +5326,7 @@ export async function createSwiftBom(path, options) {
5313
5326
  if (completedPath.includes(basePath)) {
5314
5327
  continue;
5315
5328
  }
5316
- let treeData = undefined;
5329
+ let treeData;
5317
5330
  let packageArgs = ["package"];
5318
5331
  // Additional arguments to pass to the swift package command.
5319
5332
  // Example: --swift-sdks-path <swift-sdks-path> --jobs <jobs>
@@ -5939,11 +5952,11 @@ export function createPHPBom(path, options) {
5939
5952
  }
5940
5953
  options.failOnError && process.exit(1);
5941
5954
  }
5942
- let composerVersion = undefined;
5955
+ let composerVersion;
5943
5956
  if (DEBUG_MODE) {
5944
5957
  console.log("Parsing version", versionResult.stdout);
5945
5958
  }
5946
- let tmpV = undefined;
5959
+ let tmpV;
5947
5960
  if (versionResult?.stdout) {
5948
5961
  tmpV = versionResult.stdout.split(" ");
5949
5962
  }
@@ -6274,7 +6287,7 @@ export async function createRubyBom(path, options) {
6274
6287
  */
6275
6288
  export async function createCsharpBom(path, options) {
6276
6289
  let manifestFiles = [];
6277
- let pkgData = undefined;
6290
+ let pkgData;
6278
6291
  let dependencies = [];
6279
6292
  if (options?.lifecycle?.includes("post-build")) {
6280
6293
  return createBinaryBom(path, options);
@@ -6957,7 +6970,7 @@ export function dedupeBom(options, components, parentComponent, dependencies) {
6957
6970
  export async function createMultiXBom(pathList, options) {
6958
6971
  let components = [];
6959
6972
  let dependencies = [];
6960
- let bomData = undefined;
6973
+ let bomData;
6961
6974
  let parentComponent = determineParentComponent(options) || {};
6962
6975
  let parentSubComponents = [];
6963
6976
  options.createMultiXBom = true;
@@ -7727,7 +7740,7 @@ export async function createMultiXBom(pathList, options) {
7727
7740
  export async function createXBom(path, options) {
7728
7741
  try {
7729
7742
  accessSync(path, constants.R_OK);
7730
- } catch (err) {
7743
+ } catch (_err) {
7731
7744
  return undefined;
7732
7745
  }
7733
7746
  if (
@@ -8059,7 +8072,7 @@ export async function createBom(path, options) {
8059
8072
  if (!projectType) {
8060
8073
  projectType = [];
8061
8074
  }
8062
- let exportData = undefined;
8075
+ let exportData;
8063
8076
  let isContainerMode = false;
8064
8077
  // Docker and image archive support
8065
8078
  // TODO: Support any source archive
@@ -8385,13 +8398,14 @@ export async function submitBom(args, bomContents) {
8385
8398
  "with --skip-dt-tls-check argument: Skip DT TLS check.",
8386
8399
  );
8387
8400
  }
8401
+ // See issue #1963 regarding CRLF hardening
8388
8402
  return await got(serverUrl, {
8389
8403
  method: "PUT",
8390
8404
  https: {
8391
8405
  rejectUnauthorized: !args.skipDtTlsCheck,
8392
8406
  },
8393
8407
  headers: {
8394
- "X-Api-Key": args.apiKey,
8408
+ "X-Api-Key": (args.apiKey || "").replace(/[\r\n]/g, ""),
8395
8409
  "Content-Type": "application/json",
8396
8410
  "user-agent": `@CycloneDX/cdxgen ${_version}`,
8397
8411
  },