@cyclonedx/cdxgen 12.4.2 → 12.4.4

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 (43) hide show
  1. package/README.md +6 -0
  2. package/bin/audit.js +7 -0
  3. package/bin/cdxgen.js +48 -2
  4. package/bin/evinse.js +7 -0
  5. package/lib/audit/index.js +165 -2
  6. package/lib/audit/index.poku.js +462 -0
  7. package/lib/cli/index.js +320 -172
  8. package/lib/cli/index.poku.js +81 -0
  9. package/lib/evinser/evinser.js +31 -9
  10. package/lib/helpers/analyzer.js +890 -0
  11. package/lib/helpers/analyzer.poku.js +341 -0
  12. package/lib/helpers/atomUtils.js +445 -0
  13. package/lib/helpers/atomUtils.poku.js +137 -0
  14. package/lib/helpers/bomUtils.js +71 -0
  15. package/lib/helpers/bomUtils.poku.js +45 -0
  16. package/lib/helpers/depsUtils.js +146 -0
  17. package/lib/helpers/depsUtils.poku.js +183 -0
  18. package/lib/helpers/display.js +12 -6
  19. package/lib/helpers/display.poku.js +38 -0
  20. package/lib/helpers/utils.js +653 -191
  21. package/lib/helpers/utils.poku.js +414 -4
  22. package/lib/managers/binary.js +18 -9
  23. package/lib/stages/postgen/postgen.js +215 -0
  24. package/lib/stages/postgen/postgen.poku.js +218 -3
  25. package/lib/validator/bomValidator.js +11 -2
  26. package/package.json +8 -8
  27. package/types/lib/audit/index.d.ts.map +1 -1
  28. package/types/lib/cli/index.d.ts.map +1 -1
  29. package/types/lib/helpers/analyzer.d.ts.map +1 -1
  30. package/types/lib/helpers/atomUtils.d.ts +18 -0
  31. package/types/lib/helpers/atomUtils.d.ts.map +1 -0
  32. package/types/lib/helpers/bomUtils.d.ts +10 -0
  33. package/types/lib/helpers/bomUtils.d.ts.map +1 -1
  34. package/types/lib/helpers/depsUtils.d.ts +9 -0
  35. package/types/lib/helpers/depsUtils.d.ts.map +1 -1
  36. package/types/lib/helpers/display.d.ts.map +1 -1
  37. package/types/lib/helpers/dosaiParsers.d.ts.map +1 -1
  38. package/types/lib/helpers/utils.d.ts +19 -0
  39. package/types/lib/helpers/utils.d.ts.map +1 -1
  40. package/types/lib/managers/binary.d.ts +2 -1
  41. package/types/lib/managers/binary.d.ts.map +1 -1
  42. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  43. package/types/lib/validator/bomValidator.d.ts.map +1 -1
@@ -56,6 +56,7 @@ import { getTreeWithPlugin } from "../managers/piptree.js";
56
56
  import { IriValidationStrategy, validateIri } from "../parsers/iri.js";
57
57
  import Arborist from "../third-party/arborist/lib/index.js";
58
58
  import { analyzeSuspiciousJsFile } from "./analyzer.js";
59
+ import { buildAtomCommandEnv } from "./atomUtils.js";
59
60
  import { DEFAULT_HBOM_AUDIT_CATEGORIES } from "./auditCategories.js";
60
61
  import { parseWorkflowFile } from "./ciParsers/githubActions.js";
61
62
  import {
@@ -1115,6 +1116,50 @@ function isWindowsShellHijackRisk(command, options) {
1115
1116
 
1116
1117
  const VERSION_PROBE_ARGS = new Set(["--version", "-version", "version"]);
1117
1118
 
1119
+ const POSIX_SHELL_METACHARACTERS = /[;&|<>$`\\\n\r]/;
1120
+ const WINDOWS_SHELL_METACHARACTERS = /[&|<>^%\n\r]/;
1121
+
1122
+ function hasShellMetacharacters(value) {
1123
+ if (value === undefined || value === null) {
1124
+ return false;
1125
+ }
1126
+ const stringValue = String(value);
1127
+ return isWin
1128
+ ? WINDOWS_SHELL_METACHARACTERS.test(stringValue)
1129
+ : POSIX_SHELL_METACHARACTERS.test(stringValue);
1130
+ }
1131
+
1132
+ function getUnsafeShellToken(command, args) {
1133
+ if (hasShellMetacharacters(command)) {
1134
+ return command;
1135
+ }
1136
+ const argList = Array.isArray(args)
1137
+ ? args
1138
+ : args === undefined || args === null
1139
+ ? []
1140
+ : [args];
1141
+ return argList.find((arg) => hasShellMetacharacters(arg));
1142
+ }
1143
+
1144
+ function recordSuspiciousShellPathActivities(files, metadata = {}) {
1145
+ for (const file of files) {
1146
+ if (!hasShellMetacharacters(file)) {
1147
+ continue;
1148
+ }
1149
+ recordActivity({
1150
+ classification: "suspicious-path",
1151
+ discoveryType: metadata.discoveryType,
1152
+ kind: "inspect",
1153
+ pattern: metadata.pattern,
1154
+ reason:
1155
+ "Suspicious path contains shell metacharacters. cdxgen passes direct process arguments as argv values, but review this path before invoking external build tools on untrusted projects.",
1156
+ risk: "shell-metacharacters",
1157
+ status: "completed",
1158
+ target: file,
1159
+ });
1160
+ }
1161
+ }
1162
+
1118
1163
  function detectProbeType(command, args = []) {
1119
1164
  const normalizedCommand = basename(String(command || "")).toLowerCase();
1120
1165
  const normalizedArgs = (args || []).map((arg) => String(arg).toLowerCase());
@@ -1297,6 +1342,26 @@ export function safeSpawnSync(command, args, options) {
1297
1342
  if (options.cdxgenActivity) {
1298
1343
  delete options.cdxgenActivity;
1299
1344
  }
1345
+ if (options.shell === true) {
1346
+ const unsafeShellToken = getUnsafeShellToken(command, args);
1347
+ if (unsafeShellToken !== undefined) {
1348
+ const blockedReason = `Blocked shell execution for ${command}: command or argument contains shell metacharacters.`;
1349
+ console.warn(`\x1b[1;31mSecurity Alert: ${blockedReason}\x1b[0m`);
1350
+ recordActivity({
1351
+ kind: activityDescriptor.kind,
1352
+ ...activityDescriptor.metadata,
1353
+ reason: blockedReason,
1354
+ status: "blocked",
1355
+ target: activityDescriptor.target,
1356
+ });
1357
+ return {
1358
+ status: 1,
1359
+ stdout: undefined,
1360
+ stderr: undefined,
1361
+ error: new Error(blockedReason),
1362
+ };
1363
+ }
1364
+ }
1300
1365
  // Inject maxBuffer
1301
1366
  if (!options.maxBuffer) {
1302
1367
  options.maxBuffer = MAX_BUFFER;
@@ -1496,6 +1561,55 @@ export const PREFER_MAVEN_DEPS_TREE = !["false", "0"].includes(
1496
1561
  process.env?.PREFER_MAVEN_DEPS_TREE,
1497
1562
  );
1498
1563
 
1564
+ export function parseMavenArgs(argsString) {
1565
+ if (!argsString) {
1566
+ return [];
1567
+ }
1568
+ const args = [];
1569
+ let currentArg = "";
1570
+ let quoteChar = "";
1571
+ for (let i = 0; i < argsString.length; i++) {
1572
+ const char = argsString[i];
1573
+ if (char === "\\") {
1574
+ const nextChar = argsString[i + 1];
1575
+ if (
1576
+ nextChar &&
1577
+ (/\s/.test(nextChar) || nextChar === '"' || nextChar === "'")
1578
+ ) {
1579
+ currentArg += nextChar;
1580
+ i++;
1581
+ } else {
1582
+ currentArg += char;
1583
+ }
1584
+ continue;
1585
+ }
1586
+ if (quoteChar) {
1587
+ if (char === quoteChar) {
1588
+ quoteChar = "";
1589
+ } else {
1590
+ currentArg += char;
1591
+ }
1592
+ continue;
1593
+ }
1594
+ if (char === '"' || char === "'") {
1595
+ quoteChar = char;
1596
+ continue;
1597
+ }
1598
+ if (/\s/.test(char)) {
1599
+ if (currentArg) {
1600
+ args.push(currentArg);
1601
+ currentArg = "";
1602
+ }
1603
+ continue;
1604
+ }
1605
+ currentArg += char;
1606
+ }
1607
+ if (currentArg) {
1608
+ args.push(currentArg);
1609
+ }
1610
+ return args;
1611
+ }
1612
+
1499
1613
  /**
1500
1614
  * Determines whether license information should be fetched from remote sources,
1501
1615
  * based on the FETCH_LICENSE environment variable.
@@ -2376,6 +2490,10 @@ export function getAllFilesWithIgnore(
2376
2490
  reasonBuilder: (count) =>
2377
2491
  `Scanned ${dirPath} with glob '${patternValue}' for ${discoveryMetadata.label}; matched ${files.length} path(s)${buildReadCountSuffix(count)}.`,
2378
2492
  });
2493
+ recordSuspiciousShellPathActivities(files, {
2494
+ discoveryType: discoveryMetadata.discoveryType,
2495
+ pattern: patternValue,
2496
+ });
2379
2497
  if (files.length > 1) {
2380
2498
  thoughtLog(
2381
2499
  `Found ${files.length} files for the pattern '${pattern}' at '${dirPath}'.`,
@@ -3519,6 +3637,12 @@ export async function parsePkgLock(pkgLockFile, options = {}) {
3519
3637
  if (isDevelopmentNode) {
3520
3638
  _setNpmDevelopmentProperty(pkg);
3521
3639
  }
3640
+ if (node.optional === true) {
3641
+ _setNpmOptionalProperty(pkg);
3642
+ }
3643
+ if (node.peer === true) {
3644
+ _setNpmPeerProperty(pkg);
3645
+ }
3522
3646
  if (node.resolved) {
3523
3647
  if (node.resolved.startsWith("file:")) {
3524
3648
  pkg.properties.push({
@@ -4101,6 +4225,177 @@ function _parseYarnLine(l) {
4101
4225
  return { group, name };
4102
4226
  }
4103
4227
 
4228
+ function _resolveYarnDependencyBomRef(
4229
+ packageName,
4230
+ versionRange,
4231
+ identMap,
4232
+ workspacePackages = [],
4233
+ ) {
4234
+ if (!packageName || !versionRange) {
4235
+ return undefined;
4236
+ }
4237
+ let packageNameToUse = packageName;
4238
+ let versionRangeToUse = versionRange;
4239
+ if (versionRange.startsWith("npm:")) {
4240
+ if (versionRange.includes("@")) {
4241
+ versionRangeToUse = versionRange.split("@").splice(-1)[0];
4242
+ packageNameToUse = versionRange
4243
+ .replace("npm:", "")
4244
+ .replace(`@${versionRangeToUse}`, "");
4245
+ } else {
4246
+ versionRangeToUse = versionRange.replace("npm:", "");
4247
+ }
4248
+ }
4249
+ let resolvedVersion =
4250
+ identMap[`${packageName}|${versionRangeToUse}`] ||
4251
+ identMap[`${packageNameToUse}|${versionRangeToUse}`];
4252
+ if (!resolvedVersion) {
4253
+ const packageKeys = Object.keys(identMap).filter((key) => {
4254
+ const [pkg] = key.split("|");
4255
+ return pkg === packageName || pkg === packageNameToUse;
4256
+ });
4257
+ resolvedVersion = identMap[packageKeys[0]];
4258
+ }
4259
+ if (!resolvedVersion && workspacePackages?.length) {
4260
+ const matchingWorkspace = findMatchingWorkspace(
4261
+ workspacePackages,
4262
+ packageNameToUse,
4263
+ );
4264
+ if (matchingWorkspace) {
4265
+ const versionMatch = matchingWorkspace.match(/@([^@]+)$/);
4266
+ if (versionMatch) {
4267
+ resolvedVersion = versionMatch[1];
4268
+ }
4269
+ }
4270
+ }
4271
+ let purlPart = `pkg:npm/${encodeURIComponent(packageNameToUse).replace(/%2F/g, "/")}`;
4272
+ if (resolvedVersion?.length) {
4273
+ purlPart = `${purlPart}@${resolvedVersion}`;
4274
+ }
4275
+ return decodeURIComponent(PackageURL.fromString(purlPart).toString());
4276
+ }
4277
+
4278
+ function _collectYarnRootDependencyRefs(
4279
+ yarnLockFile,
4280
+ identMap,
4281
+ workspacePackages = [],
4282
+ ) {
4283
+ const rootRefs = _createYarnRootDependencyRefs();
4284
+ const packageJsonFile = join(dirname(yarnLockFile), "package.json");
4285
+ if (!safeExistsSync(packageJsonFile)) {
4286
+ return rootRefs;
4287
+ }
4288
+ let packageJson;
4289
+ try {
4290
+ packageJson = JSON.parse(readFileSync(packageJsonFile, "utf-8"));
4291
+ } catch {
4292
+ return rootRefs;
4293
+ }
4294
+ for (const dependencyType of Object.keys(rootRefs)) {
4295
+ for (const [packageName, versionRange] of Object.entries(
4296
+ packageJson[dependencyType] || {},
4297
+ )) {
4298
+ const bomRef = _resolveYarnDependencyBomRef(
4299
+ packageName,
4300
+ String(versionRange),
4301
+ identMap,
4302
+ workspacePackages,
4303
+ );
4304
+ if (bomRef) {
4305
+ rootRefs[dependencyType].add(bomRef);
4306
+ }
4307
+ }
4308
+ }
4309
+ return rootRefs;
4310
+ }
4311
+
4312
+ function _createYarnRootDependencyRefs() {
4313
+ return {
4314
+ dependencies: new Set(),
4315
+ devDependencies: new Set(),
4316
+ optionalDependencies: new Set(),
4317
+ peerDependencies: new Set(),
4318
+ };
4319
+ }
4320
+
4321
+ function _buildDependencyClosure(rootRefs, dependenciesMap) {
4322
+ const closure = new Set();
4323
+ const stack = [...rootRefs];
4324
+ while (stack.length) {
4325
+ const ref = stack.pop();
4326
+ if (!ref || closure.has(ref)) {
4327
+ continue;
4328
+ }
4329
+ closure.add(ref);
4330
+ for (const childRef of dependenciesMap[ref] || []) {
4331
+ stack.push(childRef);
4332
+ }
4333
+ }
4334
+ return closure;
4335
+ }
4336
+
4337
+ function _markYarnDependencyScopeClosures(
4338
+ pkgList,
4339
+ dependenciesList,
4340
+ yarnRootRefs,
4341
+ yarnOptionalDependencyRefs,
4342
+ ) {
4343
+ const dependenciesMap = {};
4344
+ for (const dependency of dependenciesList || []) {
4345
+ if (!dependenciesMap[dependency.ref]) {
4346
+ dependenciesMap[dependency.ref] = [];
4347
+ }
4348
+ dependenciesMap[dependency.ref] = Array.from(
4349
+ new Set([
4350
+ ...dependenciesMap[dependency.ref],
4351
+ ...(dependency.dependsOn || []),
4352
+ ]),
4353
+ );
4354
+ }
4355
+ const runtimeClosure = _buildDependencyClosure(
4356
+ yarnRootRefs.dependencies,
4357
+ dependenciesMap,
4358
+ );
4359
+ const devClosure = _buildDependencyClosure(
4360
+ yarnRootRefs.devDependencies,
4361
+ dependenciesMap,
4362
+ );
4363
+ const optionalClosure = _buildDependencyClosure(
4364
+ new Set([
4365
+ ...yarnRootRefs.optionalDependencies,
4366
+ ...yarnOptionalDependencyRefs,
4367
+ ]),
4368
+ dependenciesMap,
4369
+ );
4370
+ const peerClosure = _buildDependencyClosure(
4371
+ yarnRootRefs.peerDependencies,
4372
+ dependenciesMap,
4373
+ );
4374
+ for (const pkg of pkgList) {
4375
+ const ref = pkg["bom-ref"];
4376
+ if (!ref) {
4377
+ continue;
4378
+ }
4379
+ if (
4380
+ optionalClosure.has(ref) &&
4381
+ (!runtimeClosure.has(ref) ||
4382
+ yarnRootRefs.optionalDependencies.has(ref) ||
4383
+ yarnOptionalDependencyRefs.has(ref))
4384
+ ) {
4385
+ pkg.scope = "optional";
4386
+ _setNpmOptionalProperty(pkg);
4387
+ }
4388
+ if (peerClosure.has(ref) && !runtimeClosure.has(ref)) {
4389
+ pkg.scope = "optional";
4390
+ _setNpmPeerProperty(pkg);
4391
+ }
4392
+ if (devClosure.has(ref) && !runtimeClosure.has(ref)) {
4393
+ pkg.scope = "optional";
4394
+ _setNpmDevelopmentProperty(pkg);
4395
+ }
4396
+ }
4397
+ }
4398
+
4104
4399
  /**
4105
4400
  * Parse nodejs yarn lock file
4106
4401
  *
@@ -4122,6 +4417,8 @@ export async function parseYarnLock(
4122
4417
  let pkgList = [];
4123
4418
  const dependenciesList = [];
4124
4419
  const depKeys = {};
4420
+ let yarnRootRefs = _createYarnRootDependencyRefs();
4421
+ const yarnOptionalDependencyRefs = new Set();
4125
4422
  if (safeExistsSync(yarnLockFile)) {
4126
4423
  const lockData = readFileSync(yarnLockFile, "utf8");
4127
4424
  let name = "";
@@ -4138,6 +4435,11 @@ export async function parseYarnLock(
4138
4435
  const workspacePurlMap = {};
4139
4436
  // This would have the keys and the resolved version required to solve the dependency tree
4140
4437
  const identMap = yarnLockToIdentMap(lockData);
4438
+ yarnRootRefs = _collectYarnRootDependencyRefs(
4439
+ yarnLockFile,
4440
+ identMap,
4441
+ workspacePackages,
4442
+ );
4141
4443
  lockData.split("\n").forEach((l) => {
4142
4444
  l = l.replace("\r", "");
4143
4445
  if (l.startsWith("#")) {
@@ -4335,66 +4637,19 @@ export async function parseYarnLock(
4335
4637
  if (dgroupname.endsWith(":")) {
4336
4638
  dgroupname = dgroupname.substring(0, dgroupname.length - 1);
4337
4639
  }
4338
- let dgroupnameToUse = dgroupname;
4339
4640
  const range = tmpA[1].replace(/["']/g, "");
4340
- let versionRange = range;
4341
- // Deal with range with npm: prefix such as npm:string-width@^4.2.0, npm:@types/ioredis@^4.28.10
4342
- if (range.startsWith("npm:")) {
4343
- if (range.includes("@")) {
4344
- // Case like npm:string-width@^4.2.0 or npm:@types/ioredis@^4.28.10
4345
- versionRange = range.split("@").splice(-1)[0];
4346
- dgroupnameToUse = range
4347
- .replace("npm:", "")
4348
- .replace(`@${versionRange}`, "");
4349
- } else {
4350
- // Case like npm:^5.1.1 - just a version range with npm: prefix
4351
- versionRange = range.replace("npm:", "");
4352
- dgroupnameToUse = dgroupname;
4353
- }
4354
- }
4355
- let resolvedVersion =
4356
- identMap[`${dgroupname}|${versionRange}`] ||
4357
- identMap[`${dgroupnameToUse}|${versionRange}`];
4358
- // If we couldn't resolve the version directly, try to find any resolved version for this package
4359
- if (!resolvedVersion) {
4360
- const packageKeys = Object.keys(identMap).filter((key) => {
4361
- const [pkg] = key.split("|");
4362
- return pkg === dgroupname || pkg === dgroupnameToUse;
4363
- });
4364
-
4365
- if (packageKeys.length > 0) {
4366
- // Use the first available resolved version for this package
4367
- resolvedVersion = identMap[packageKeys[0]];
4368
- }
4369
- }
4370
- // If we couldn't resolve the version from yarn.lock, check if it's a workspace package
4371
- if (!resolvedVersion && workspacePackages?.length) {
4372
- // Use helper function for more efficient workspace matching
4373
- const matchingWorkspace = findMatchingWorkspace(
4374
- workspacePackages,
4375
- dgroupnameToUse,
4376
- );
4377
-
4378
- if (matchingWorkspace) {
4379
- // Extract version from workspace PURL like "npm:@swc/helpers@0.4.14"
4380
- const versionMatch = matchingWorkspace.match(/@([^@]+)$/);
4381
- if (versionMatch) {
4382
- resolvedVersion = versionMatch[1];
4383
- }
4384
- }
4385
- }
4386
- // If we still can't resolve the version, use "" as fallback
4387
- if (!resolvedVersion) {
4388
- resolvedVersion = "";
4641
+ const depBomRef = _resolveYarnDependencyBomRef(
4642
+ dgroupname,
4643
+ range,
4644
+ identMap,
4645
+ workspacePackages,
4646
+ );
4647
+ if (depBomRef) {
4648
+ deplist.add(depBomRef);
4389
4649
  }
4390
- // Handle case where the dependency name is really an alias.
4391
- // Eg: legacy-swc-helpers "npm:@swc/helpers@=0.4.14". Here the dgroupname=@swc/helpers
4392
- let purlPart = `pkg:npm/${encodeURIComponent(dgroupnameToUse).replace(/%2F/g, "/")}`;
4393
- if (resolvedVersion?.length) {
4394
- purlPart = `${purlPart}@${resolvedVersion}`;
4650
+ if (optionalDepsMode && depBomRef) {
4651
+ yarnOptionalDependencyRefs.add(depBomRef);
4395
4652
  }
4396
- const depPurlString = PackageURL.fromString(purlPart).toString();
4397
- deplist.add(decodeURIComponent(depPurlString));
4398
4653
  }
4399
4654
  } else if (name !== "") {
4400
4655
  if (!l.startsWith(" ")) {
@@ -4604,6 +4859,13 @@ export async function parseYarnLock(
4604
4859
  }
4605
4860
  }
4606
4861
 
4862
+ _markYarnDependencyScopeClosures(
4863
+ pkgList,
4864
+ dependenciesList,
4865
+ yarnRootRefs,
4866
+ yarnOptionalDependencyRefs,
4867
+ );
4868
+
4607
4869
  if (shouldFetchPackageMetadata() && pkgList?.length) {
4608
4870
  if (DEBUG_MODE) {
4609
4871
  console.log(
@@ -4762,6 +5024,14 @@ function _setNpmDevelopmentProperty(pkg) {
4762
5024
  }
4763
5025
  }
4764
5026
 
5027
+ function _setNpmOptionalProperty(pkg) {
5028
+ addComponentProperty(pkg, "cdx:npm:package:optional", "true");
5029
+ }
5030
+
5031
+ function _setNpmPeerProperty(pkg) {
5032
+ addComponentProperty(pkg, "cdx:npm:package:peer", "true");
5033
+ }
5034
+
4765
5035
  function _setTreeWorkspaceRef(
4766
5036
  dependenciesMap,
4767
5037
  depref,
@@ -4863,11 +5133,25 @@ export function parsePnpmWorkspace(workspaceFile) {
4863
5133
  if (!yamlObj) {
4864
5134
  return {};
4865
5135
  }
4866
- const packages = (yamlObj.packages || [])
4867
- .filter((n) => !/^(!|\.|__)/.test(n))
4868
- .map((n) => n.replaceAll("/**", "").replaceAll("/*", ""));
5136
+ const workspacePackages = Array.isArray(yamlObj.packages)
5137
+ ? yamlObj.packages
5138
+ : typeof yamlObj.packages === "string"
5139
+ ? [yamlObj.packages]
5140
+ : [];
5141
+ const excludePackages = workspacePackages
5142
+ .filter((n) => typeof n === "string")
5143
+ .filter((n) => n.startsWith("!"))
5144
+ .map((n) => n.replace(/^!/, ""));
5145
+ const packagePatterns = workspacePackages
5146
+ .filter((n) => typeof n === "string")
5147
+ .filter((n) => !/^(!|\.|__)/.test(n));
5148
+ const packages = packagePatterns.map((n) =>
5149
+ n.replaceAll("/**", "").replaceAll("/*", ""),
5150
+ );
4869
5151
  const catalogs = yamlObj.catalog || {};
4870
5152
  return {
5153
+ excludePackages,
5154
+ packagePatterns,
4871
5155
  packages,
4872
5156
  catalogs,
4873
5157
  };
@@ -4990,12 +5274,20 @@ export function findPnpmPackagePath(baseDir, packageName, version) {
4990
5274
  if (safeExistsSync(pnpmDir)) {
4991
5275
  // pnpm stores packages as {name}@{version} in .pnpm directory
4992
5276
  const encodedName = packageName.replace("/", "%2f");
5277
+ const virtualStoreName = packageName.replace("/", "+");
4993
5278
  let pnpmPackagePath;
4994
5279
 
4995
5280
  // Try different formats that pnpm might use
4996
5281
  const possiblePaths = [
5282
+ join(
5283
+ pnpmDir,
5284
+ `${virtualStoreName}@${version}`,
5285
+ "node_modules",
5286
+ packageName,
5287
+ ),
4997
5288
  join(pnpmDir, `${encodedName}@${version}`, "node_modules", packageName),
4998
5289
  join(pnpmDir, `${packageName}@${version}`, "node_modules", packageName),
5290
+ join(pnpmDir, `${virtualStoreName}@${version}`),
4999
5291
  join(pnpmDir, `${encodedName}@${version}`),
5000
5292
  join(pnpmDir, `${packageName}@${version}`),
5001
5293
  ];
@@ -5041,7 +5333,8 @@ export async function pnpmMetadata(pkgList, lockFilePath) {
5041
5333
  }
5042
5334
  let enhancedCount = 0;
5043
5335
  for (const pkg of pkgList) {
5044
- const packagePath = findPnpmPackagePath(baseDir, pkg.name, pkg.version);
5336
+ const packageName = pkg.group ? `${pkg.group}/${pkg.name}` : pkg.name;
5337
+ const packagePath = findPnpmPackagePath(baseDir, packageName, pkg.version);
5045
5338
  if (!packagePath) {
5046
5339
  continue;
5047
5340
  }
@@ -5118,9 +5411,10 @@ export async function pnpmMetadata(pkgList, lockFilePath) {
5118
5411
  * @param {Object} parentComponent parent component
5119
5412
  * @param {Array[String]} workspacePackages Workspace packages
5120
5413
  * @param {Object} workspaceSrcFiles Workspace package.json files
5121
- * @param {Object} workspaceCatalogs Workspace catalogs
5122
- * @param {Object} workspaceDirectDeps Direct dependencies of each workspace
5414
+ * @param {Object} _workspaceCatalogs Workspace catalogs
5415
+ * @param {Object} _workspaceDirectDeps Direct dependencies of each workspace
5123
5416
  * @param {Object} depsWorkspaceRefs Workspace references for each dependency
5417
+ * @param {string} projectRoot Root path used to relativize pnpm-lock evidence paths
5124
5418
  */
5125
5419
  export async function parsePnpmLock(
5126
5420
  pnpmLock,
@@ -5130,9 +5424,15 @@ export async function parsePnpmLock(
5130
5424
  _workspaceCatalogs = {},
5131
5425
  _workspaceDirectDeps = {},
5132
5426
  depsWorkspaceRefs = {},
5427
+ projectRoot = undefined,
5133
5428
  ) {
5134
5429
  let pkgList = [];
5135
5430
  const dependenciesList = [];
5431
+ const pnpmLockDir = dirname(pnpmLock);
5432
+ const pnpmEvidenceRoot = projectRoot ? resolve(projectRoot) : pnpmLockDir;
5433
+ const pnpmLockSrcFile = path.isAbsolute(pnpmLock)
5434
+ ? relative(pnpmEvidenceRoot, pnpmLock)
5435
+ : pnpmLock;
5136
5436
  // For lockfile >= 9, we need to track dev and optional packages manually
5137
5437
  // See: #1163
5138
5438
  // Moreover, we have changed >= 9 for >= 6
@@ -5234,7 +5534,9 @@ export async function parsePnpmLock(
5234
5534
  }
5235
5535
  // Find the root optional and peer dependencies
5236
5536
  for (const rdk of Object.keys({ ...rootOptionalDeps, ...rootPeerDeps })) {
5237
- const version = await getVersionNumPnpm(rootOptionalDeps[rdk]);
5537
+ const version = await getVersionNumPnpm(
5538
+ rootOptionalDeps[rdk] || rootPeerDeps[rdk],
5539
+ );
5238
5540
  let specifier;
5239
5541
  if (
5240
5542
  typeof rootOptionalDeps[rdk] === "object" &&
@@ -5303,8 +5605,12 @@ export async function parsePnpmLock(
5303
5605
  let compPurl;
5304
5606
  let pkgSrcFile;
5305
5607
  let fallbackMode = true;
5306
- if (safeExistsSync(join(importedComponentName, "package.json"))) {
5307
- pkgSrcFile = join(importedComponentName, "package.json");
5608
+ if (
5609
+ safeExistsSync(
5610
+ join(pnpmLockDir, importedComponentName, "package.json"),
5611
+ )
5612
+ ) {
5613
+ pkgSrcFile = join(pnpmLockDir, importedComponentName, "package.json");
5308
5614
  const importedComponentObj = await parsePkgJson(pkgSrcFile, true);
5309
5615
  if (importedComponentObj.length) {
5310
5616
  const version = importedComponentObj[0].version;
@@ -5436,7 +5742,9 @@ export async function parsePnpmLock(
5436
5742
  ...componentOptionalDeps,
5437
5743
  ...componentPeerDeps,
5438
5744
  })) {
5439
- const version = await getVersionNumPnpm(componentOptionalDeps[cdk]);
5745
+ const version = await getVersionNumPnpm(
5746
+ componentOptionalDeps[cdk] || componentPeerDeps[cdk],
5747
+ );
5440
5748
  const dpurl = new PackageURL(
5441
5749
  "npm",
5442
5750
  "",
@@ -5727,7 +6035,7 @@ export async function parsePnpmLock(
5727
6035
  const properties = [
5728
6036
  {
5729
6037
  name: "SrcFile",
5730
- value: pnpmLock,
6038
+ value: pnpmLockSrcFile,
5731
6039
  },
5732
6040
  ];
5733
6041
  if (hasBin) {
@@ -5838,7 +6146,7 @@ export async function parsePnpmLock(
5838
6146
  {
5839
6147
  technique: "manifest-analysis",
5840
6148
  confidence: 1,
5841
- value: pnpmLock,
6149
+ value: pnpmLockSrcFile,
5842
6150
  },
5843
6151
  ],
5844
6152
  },
@@ -5852,6 +6160,9 @@ export async function parsePnpmLock(
5852
6160
  },
5853
6161
  ];
5854
6162
  }
6163
+ if (possibleOptionalDeps[thePkg["bom-ref"]]) {
6164
+ _setNpmOptionalProperty(thePkg);
6165
+ }
5855
6166
  // Don't add internal workspace packages to the components list
5856
6167
  if (thePkg.type !== "application") {
5857
6168
  pkgList.push(thePkg);
@@ -6190,6 +6501,15 @@ export function parsePom(pomFile) {
6190
6501
  attributesKey: "$",
6191
6502
  commentKey: "value",
6192
6503
  }).project;
6504
+ if (project?.modelVersion?._) {
6505
+ properties.modelVersion = project.modelVersion._;
6506
+ }
6507
+ if (project?.$?.root) {
6508
+ properties.mavenRoot = project.$.root;
6509
+ }
6510
+ if (project?.$?.["preserve.model.version"]) {
6511
+ properties.preserveModelVersion = project.$["preserve.model.version"];
6512
+ }
6193
6513
  for (const aprop of [
6194
6514
  "groupId",
6195
6515
  "artifactId",
@@ -6224,14 +6544,20 @@ export function parsePom(pomFile) {
6224
6544
  null,
6225
6545
  ).toString();
6226
6546
  }
6547
+ const moduleEntries = [];
6227
6548
  if (project?.modules?.module) {
6228
- if (Array.isArray(project.modules.module)) {
6229
- // If it's an array, proceed with mapping
6230
- modules = project.modules.module.map((m) => m?._);
6231
- } else {
6232
- // If not an array, handle/convert it accordingly. For instance:
6233
- modules = [project.modules.module._];
6234
- }
6549
+ moduleEntries.push(project.modules.module);
6550
+ }
6551
+ if (project?.subprojects?.subproject) {
6552
+ moduleEntries.push(project.subprojects.subproject);
6553
+ }
6554
+ if (moduleEntries.length) {
6555
+ modules = moduleEntries.flatMap((entry) => {
6556
+ if (Array.isArray(entry)) {
6557
+ return entry.map((m) => m?._).filter(Boolean);
6558
+ }
6559
+ return entry?._ ? [entry._] : [];
6560
+ });
6235
6561
  }
6236
6562
  if (project?.properties) {
6237
6563
  for (const aprop of Object.keys(project.properties)) {
@@ -6276,18 +6602,28 @@ export function parsePom(pomFile) {
6276
6602
  if (versionStr?.includes("$")) {
6277
6603
  versionStr = properties[versionStr?.replace(/[${}]/g, "")];
6278
6604
  }
6279
- if (includeMavenTestScope || !adep.scope || adep.scope !== "test") {
6605
+ const scope = adep.scope?._;
6606
+ const type = adep.type?._ || "jar";
6607
+ const classifier = adep.classifier?._;
6608
+ const optional = adep.optional?._;
6609
+ const dependencyProperties = [
6610
+ {
6611
+ name: "SrcFile",
6612
+ value: pomFile,
6613
+ },
6614
+ ];
6615
+ const qualifiers = { type };
6616
+ if (classifier) {
6617
+ qualifiers.classifier = classifier;
6618
+ }
6619
+ if (includeMavenTestScope || scope !== "test") {
6280
6620
  deps.push({
6281
6621
  group: adep.groupId ? adep.groupId._ : "",
6282
6622
  name: adep.artifactId ? adep.artifactId._ : "",
6283
6623
  version: versionStr,
6284
- qualifiers: { type: "jar" },
6285
- properties: [
6286
- {
6287
- name: "SrcFile",
6288
- value: pomFile,
6289
- },
6290
- ],
6624
+ qualifiers,
6625
+ scope: mapMavenScope(scope, optional === "true"),
6626
+ properties: dependencyProperties,
6291
6627
  evidence: {
6292
6628
  identity: {
6293
6629
  field: "purl",
@@ -6308,6 +6644,194 @@ export function parsePom(pomFile) {
6308
6644
  return { isQuarkus, pomPurl, modules, properties, dependencies: deps };
6309
6645
  }
6310
6646
 
6647
+ function mapMavenScope(componentScope, isOptional = false) {
6648
+ if (isOptional || componentScope === "test") {
6649
+ return "optional";
6650
+ }
6651
+ if (["compile", "runtime", "import"].includes(componentScope)) {
6652
+ return "required";
6653
+ }
6654
+ if (["provided", "system"].includes(componentScope)) {
6655
+ return "excluded";
6656
+ }
6657
+ return undefined;
6658
+ }
6659
+
6660
+ function createMavenComponentFromCoordinateParts(pkgArr, pomFile, isOptional) {
6661
+ let versionStr = pkgArr[pkgArr.length - 2];
6662
+ const componentScope = pkgArr[pkgArr.length - 1];
6663
+ let classifier;
6664
+ if (
6665
+ pkgArr.length >= 6 &&
6666
+ pkgArr[3] !== versionStr &&
6667
+ !pkgArr[3].includes(".jar")
6668
+ ) {
6669
+ classifier = pkgArr[3];
6670
+ }
6671
+ if (pkgArr.length === 4) {
6672
+ versionStr = pkgArr[pkgArr.length - 1];
6673
+ }
6674
+ const qualifiers = { type: pkgArr[2] };
6675
+ if (classifier) {
6676
+ qualifiers.classifier = classifier;
6677
+ }
6678
+ const purlString = new PackageURL(
6679
+ "maven",
6680
+ pkgArr[0],
6681
+ pkgArr[1],
6682
+ versionStr,
6683
+ qualifiers,
6684
+ null,
6685
+ ).toString();
6686
+ const bomRef = decodeURIComponent(purlString);
6687
+ const scope = mapMavenScope(componentScope, isOptional);
6688
+ const properties = [];
6689
+ const apkg = {
6690
+ group: pkgArr[0],
6691
+ name: pkgArr[1],
6692
+ version: versionStr,
6693
+ qualifiers,
6694
+ scope,
6695
+ properties,
6696
+ purl: purlString,
6697
+ "bom-ref": bomRef,
6698
+ };
6699
+ if (pomFile) {
6700
+ properties.push({
6701
+ name: "SrcFile",
6702
+ value: pomFile,
6703
+ });
6704
+ apkg.evidence = {
6705
+ identity: {
6706
+ field: "purl",
6707
+ confidence: 0.5,
6708
+ methods: [
6709
+ {
6710
+ technique: "manifest-analysis",
6711
+ confidence: 0.5,
6712
+ value: pomFile,
6713
+ },
6714
+ ],
6715
+ },
6716
+ };
6717
+ }
6718
+ return apkg;
6719
+ }
6720
+
6721
+ function createMavenComponentFromTreeNode(node, pomFile) {
6722
+ const type = node.type || "jar";
6723
+ const qualifiers = { type };
6724
+ if (node.classifier) {
6725
+ qualifiers.classifier = node.classifier;
6726
+ }
6727
+ const purlString = new PackageURL(
6728
+ "maven",
6729
+ node.groupId,
6730
+ node.artifactId,
6731
+ node.version,
6732
+ qualifiers,
6733
+ null,
6734
+ ).toString();
6735
+ const bomRef = decodeURIComponent(purlString);
6736
+ const isOptional = node.optional === true || node.optional === "true";
6737
+ const properties = [];
6738
+ const apkg = {
6739
+ group: node.groupId,
6740
+ name: node.artifactId,
6741
+ version: node.version,
6742
+ qualifiers,
6743
+ scope: mapMavenScope(node.scope, isOptional),
6744
+ properties,
6745
+ purl: purlString,
6746
+ "bom-ref": bomRef,
6747
+ };
6748
+ if (pomFile) {
6749
+ properties.push({
6750
+ name: "SrcFile",
6751
+ value: pomFile,
6752
+ });
6753
+ apkg.evidence = {
6754
+ identity: {
6755
+ field: "purl",
6756
+ confidence: 0.5,
6757
+ methods: [
6758
+ {
6759
+ technique: "manifest-analysis",
6760
+ confidence: 0.5,
6761
+ value: pomFile,
6762
+ },
6763
+ ],
6764
+ },
6765
+ };
6766
+ }
6767
+ return apkg;
6768
+ }
6769
+
6770
+ /**
6771
+ * Parse maven dependency:tree json output
6772
+ *
6773
+ * @param rawOutput
6774
+ * @param pomFile
6775
+ * @returns {{parentComponent: {}, pkgList: *[], dependenciesList: *[]}|{}|{}|*|{parentComponent: {[p: string]: *}|{}, pkgList: [], dependenciesList: []}}
6776
+ */
6777
+ export function parseMavenTreeJson(rawOutput, pomFile) {
6778
+ if (!rawOutput) {
6779
+ return {};
6780
+ }
6781
+ let rootNode = rawOutput;
6782
+ if (typeof rawOutput === "string") {
6783
+ try {
6784
+ rootNode = JSON.parse(rawOutput);
6785
+ } catch (_err) {
6786
+ thoughtLog("Unable to parse Maven dependency:tree JSON output");
6787
+ return {};
6788
+ }
6789
+ }
6790
+ const deps = [];
6791
+ const dependenciesList = [];
6792
+ const keysCache = new Set();
6793
+ const levelTrees = {};
6794
+ let parentComponent = {};
6795
+ const visitNode = (node, parentRef) => {
6796
+ if (!node?.groupId || !node?.artifactId || !node?.version) {
6797
+ return undefined;
6798
+ }
6799
+ const component = createMavenComponentFromTreeNode(node, pomFile);
6800
+ const bomRef = component["bom-ref"];
6801
+ if (!Object.keys(parentComponent).length) {
6802
+ parentComponent = { ...component, type: "application" };
6803
+ }
6804
+ if (!keysCache.has(bomRef)) {
6805
+ keysCache.add(bomRef);
6806
+ deps.push(component);
6807
+ }
6808
+ if (!levelTrees[bomRef]) {
6809
+ levelTrees[bomRef] = [];
6810
+ }
6811
+ if (parentRef) {
6812
+ const cnodes = levelTrees[parentRef] || [];
6813
+ cnodes.push(bomRef);
6814
+ levelTrees[parentRef] = cnodes;
6815
+ }
6816
+ for (const child of node.children || []) {
6817
+ visitNode(child, bomRef);
6818
+ }
6819
+ return bomRef;
6820
+ };
6821
+ visitNode(rootNode);
6822
+ for (const lk of Object.keys(levelTrees)) {
6823
+ dependenciesList.push({
6824
+ ref: lk,
6825
+ dependsOn: [...new Set(levelTrees[lk])].sort(),
6826
+ });
6827
+ }
6828
+ return {
6829
+ parentComponent,
6830
+ pkgList: deps,
6831
+ dependenciesList,
6832
+ };
6833
+ }
6834
+
6311
6835
  /**
6312
6836
  * Parse maven tree output
6313
6837
  * @param {string} rawOutput Raw string output
@@ -6319,6 +6843,9 @@ export function parseMavenTree(rawOutput, pomFile) {
6319
6843
  if (!rawOutput) {
6320
6844
  return {};
6321
6845
  }
6846
+ if (rawOutput.trim().startsWith("{")) {
6847
+ return parseMavenTreeJson(rawOutput, pomFile);
6848
+ }
6322
6849
  const deps = [];
6323
6850
  const dependenciesList = [];
6324
6851
  const keys_cache = {};
@@ -6330,6 +6857,8 @@ export function parseMavenTree(rawOutput, pomFile) {
6330
6857
  const stack = [];
6331
6858
  tmpA.forEach((l) => {
6332
6859
  l = l.replace("\r", "");
6860
+ const isOptional = /\s+\(optional\)\s*$/.test(l);
6861
+ l = l.replace(/\s+\(optional\)\s*$/, "");
6333
6862
  if (!includeMavenTestScope && l.trim().endsWith(":test")) {
6334
6863
  return;
6335
6864
  }
@@ -6341,118 +6870,50 @@ export function parseMavenTree(rawOutput, pomFile) {
6341
6870
  }
6342
6871
  l = tmpline[tmpline.length - 1];
6343
6872
  const pkgArr = l.split(":");
6344
- // Support for classifiers
6345
- // com.github.jnr:jffi:jar:1.3.11:compile
6346
- // com.github.jnr:jffi:jar:native:1.3.11:runtime
6347
- let classifier;
6348
6873
  if (pkgArr && pkgArr.length > 2) {
6349
- let versionStr = pkgArr[pkgArr.length - 2];
6350
6874
  const componentScope = pkgArr[pkgArr.length - 1];
6351
- if (
6352
- pkgArr.length >= 6 &&
6353
- pkgArr[3] !== versionStr &&
6354
- !pkgArr[3].includes(".jar")
6355
- ) {
6356
- classifier = pkgArr[3];
6357
- }
6358
6875
  // Ignore test scope
6359
6876
  if (!includeMavenTestScope && componentScope === "test") {
6360
6877
  return;
6361
6878
  }
6362
- let scope;
6363
- if (["compile", "runtime"].includes(componentScope)) {
6364
- scope = "required";
6365
- } else if (componentScope === "test") {
6366
- scope = "optional";
6367
- } else if (componentScope === "provided") {
6368
- scope = "excluded";
6369
- }
6370
- if (pkgArr.length === 4) {
6371
- versionStr = pkgArr[pkgArr.length - 1];
6372
- }
6373
- const qualifiers = { type: pkgArr[2] };
6374
- if (classifier) {
6375
- qualifiers.classifier = classifier;
6376
- }
6377
- const purlString = new PackageURL(
6378
- "maven",
6379
- pkgArr[0],
6380
- pkgArr[1],
6381
- versionStr,
6382
- qualifiers,
6383
- null,
6384
- ).toString();
6385
- const bomRef = decodeURIComponent(purlString);
6879
+ const apkg = createMavenComponentFromCoordinateParts(
6880
+ pkgArr,
6881
+ pomFile,
6882
+ isOptional,
6883
+ );
6884
+ const bomRef = apkg["bom-ref"];
6386
6885
  const key = bomRef;
6387
6886
  if (!first_ref) {
6388
6887
  first_ref = bomRef;
6389
6888
  }
6390
6889
  if (!keys_cache[key]) {
6391
6890
  keys_cache[key] = key;
6392
- const properties = [];
6393
- if (scope) {
6394
- properties.push({
6395
- name: "cdx:maven:component_scope",
6396
- value: componentScope,
6397
- });
6398
- }
6399
- const apkg = {
6400
- group: pkgArr[0],
6401
- name: pkgArr[1],
6402
- version: versionStr,
6403
- qualifiers,
6404
- scope,
6405
- properties,
6406
- purl: purlString,
6407
- "bom-ref": bomRef,
6408
- };
6409
- if (pomFile) {
6410
- properties.push({
6411
- name: "SrcFile",
6412
- value: pomFile,
6413
- });
6414
- apkg.evidence = {
6415
- identity: {
6416
- field: "purl",
6417
- confidence: 0.5,
6418
- methods: [
6419
- {
6420
- technique: "manifest-analysis",
6421
- confidence: 0.5,
6422
- value: pomFile,
6423
- },
6424
- ],
6425
- },
6426
- };
6427
- }
6428
6891
  deps.push(apkg);
6429
- if (!level_trees[bomRef]) {
6430
- level_trees[bomRef] = [];
6431
- }
6432
- if (level === 0 || last_purl === "") {
6433
- stack.push(bomRef);
6434
- } else if (level > last_level) {
6435
- const cnodes = level_trees[last_purl] || [];
6436
- cnodes.push(bomRef);
6437
- level_trees[last_purl] = cnodes;
6438
- if (stack[stack.length - 1] !== bomRef) {
6439
- stack.push(bomRef);
6440
- }
6441
- } else {
6442
- for (let i = level; i <= last_level; i++) {
6443
- stack.pop();
6444
- }
6445
- const last_stack = stack.length
6446
- ? stack[stack.length - 1]
6447
- : first_ref;
6448
- const cnodes = level_trees[last_stack] || [];
6449
- cnodes.push(bomRef);
6450
- level_trees[last_stack] = cnodes;
6892
+ }
6893
+ if (!level_trees[bomRef]) {
6894
+ level_trees[bomRef] = [];
6895
+ }
6896
+ if (level === 0 || last_purl === "") {
6897
+ stack.push(bomRef);
6898
+ } else if (level > last_level) {
6899
+ const cnodes = level_trees[last_purl] || [];
6900
+ cnodes.push(bomRef);
6901
+ level_trees[last_purl] = cnodes;
6902
+ if (stack[stack.length - 1] !== bomRef) {
6451
6903
  stack.push(bomRef);
6452
6904
  }
6453
- last_level = level;
6454
- last_purl = bomRef;
6905
+ } else {
6906
+ for (let i = level; i <= last_level; i++) {
6907
+ stack.pop();
6908
+ }
6909
+ const last_stack = stack.length ? stack[stack.length - 1] : first_ref;
6910
+ const cnodes = level_trees[last_stack] || [];
6911
+ cnodes.push(bomRef);
6912
+ level_trees[last_stack] = cnodes;
6913
+ stack.push(bomRef);
6455
6914
  }
6915
+ last_level = level;
6916
+ last_purl = bomRef;
6456
6917
  }
6457
6918
  }
6458
6919
  });
@@ -9641,7 +10102,7 @@ export async function getPyModules(src, epkgList, options) {
9641
10102
  modList = slicesData;
9642
10103
  }
9643
10104
  } else {
9644
- modList = findAppModules(src, "python", "parsedeps", slicesFile);
10105
+ modList = findAppModules(src, "python", "parsedeps", slicesFile, options);
9645
10106
  }
9646
10107
  const pyDefaultModules = new Set(PYTHON_STD_MODULES);
9647
10108
  modList = modList.filter(
@@ -17064,7 +17525,7 @@ export async function collectMvnDependencies(
17064
17525
  `-Dmdep.stripVersion=${process.env.MAVEN_STRIP_VERSION || "false"}`,
17065
17526
  ];
17066
17527
  if (process.env.MVN_ARGS) {
17067
- const addArgs = process.env.MVN_ARGS.split(" ");
17528
+ const addArgs = parseMavenArgs(process.env.MVN_ARGS);
17068
17529
  copyArgs = copyArgs.concat(addArgs);
17069
17530
  }
17070
17531
  if (basePath && basePath !== MAVEN_CACHE_DIR) {
@@ -17548,11 +18009,11 @@ export function parsePomProperties(pomProperties) {
17548
18009
  return properties;
17549
18010
  }
17550
18011
  pomProperties.split("\n").forEach((l) => {
17551
- l = l.replace("\r", "");
18012
+ l = l.replaceAll("\r", "");
17552
18013
  if (l.includes("=")) {
17553
- const tmpA = l.split("=");
17554
- if (tmpA && tmpA.length === 2) {
17555
- properties[tmpA[0]] = tmpA[1].replace("\r", "");
18014
+ const separatorIndex = l.indexOf("=");
18015
+ if (separatorIndex !== -1) {
18016
+ properties[l.slice(0, separatorIndex)] = l.slice(separatorIndex + 1);
17556
18017
  }
17557
18018
  }
17558
18019
  });
@@ -19224,11 +19685,9 @@ export function getMavenCommand(srcPath, rootPath) {
19224
19685
  }
19225
19686
  if (isWrapperFound) {
19226
19687
  if (DEBUG_MODE) {
19227
- console.log(
19228
- "Testing the wrapper script by invoking wrapper:wrapper task",
19229
- );
19688
+ console.log("Testing the wrapper script by invoking --version");
19230
19689
  }
19231
- const result = safeSpawnSync(mavenWrapperCmd, ["wrapper:wrapper"], {
19690
+ const result = safeSpawnSync(mavenWrapperCmd, ["--version"], {
19232
19691
  cdxgenActivity: {
19233
19692
  kind: "probe",
19234
19693
  metadata: {
@@ -19449,6 +19908,7 @@ export function executeAtom(src, args, extra_env = {}) {
19449
19908
  * @param {string} language
19450
19909
  * @param {string} methodology
19451
19910
  * @param {string} slicesFile
19911
+ * @param {Object} options CLI options
19452
19912
  * @returns List of imported modules
19453
19913
  */
19454
19914
  export function findAppModules(
@@ -19456,6 +19916,7 @@ export function findAppModules(
19456
19916
  language,
19457
19917
  methodology = "usages",
19458
19918
  slicesFile = undefined,
19919
+ options = {},
19459
19920
  ) {
19460
19921
  const tempDir = safeMkdtempSync(join(tmpdir(), "atom-deps-"));
19461
19922
  const atomFile = join(tempDir, `${language}-app.atom`);
@@ -19473,7 +19934,7 @@ export function findAppModules(
19473
19934
  resolve(slicesFile),
19474
19935
  resolve(src),
19475
19936
  ];
19476
- executeAtom(src, args);
19937
+ executeAtom(src, args, buildAtomCommandEnv(options, language));
19477
19938
  if (safeExistsSync(slicesFile)) {
19478
19939
  const slicesData = JSON.parse(readFileSync(slicesFile, "utf-8"), {
19479
19940
  encoding: "utf-8",
@@ -21313,6 +21774,7 @@ export function getCppModules(src, options, osPkgsList, epkgList) {
21313
21774
  options.deep ? "c" : "h",
21314
21775
  "usages",
21315
21776
  options.usagesSlicesFile,
21777
+ options,
21316
21778
  );
21317
21779
  }
21318
21780
  const usageData = parseCUsageSlice(sliceData);