@coana-tech/cli 14.12.201 → 15.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli.mjs CHANGED
@@ -199895,7 +199895,7 @@ var {
199895
199895
  } = import_index.default;
199896
199896
 
199897
199897
  // dist/index.js
199898
- import { mkdir as mkdir7, mkdtemp as mkdtemp2, readFile as readFile38, rm as rm3, writeFile as writeFile17 } from "fs/promises";
199898
+ import { mkdir as mkdir7, mkdtemp as mkdtemp2, readFile as readFile38, rm as rm4, writeFile as writeFile17 } from "fs/promises";
199899
199899
  import { tmpdir as tmpdir5 } from "os";
199900
199900
  import { dirname as dirname26, join as join35, resolve as resolve44 } from "path";
199901
199901
 
@@ -214060,7 +214060,7 @@ var prereleaseSpecifierNormalization = {
214060
214060
  };
214061
214061
  var postreleaseSpecifiers = ["post", "rev", "r"];
214062
214062
  var devReleaseSpecifiers = ["dev"];
214063
- var epochRegex = /(\d+):/;
214063
+ var epochRegex = /(\d+)!/;
214064
214064
  var releaseSegmentRegex = /(\d+(?:\.\d+)*)/;
214065
214065
  var prereleaseRegex = buildRegexWithSpecifier(prereleaseSpecifiers);
214066
214066
  var postreleaseRegex = buildRegexWithSpecifier(postreleaseSpecifiers);
@@ -227584,7 +227584,7 @@ var prereleaseSpecifierNormalization2 = {
227584
227584
  };
227585
227585
  var postreleaseSpecifiers2 = ["post", "rev", "r"];
227586
227586
  var devReleaseSpecifiers2 = ["dev"];
227587
- var epochRegex2 = /(\d+):/;
227587
+ var epochRegex2 = /(\d+)!/;
227588
227588
  var releaseSegmentRegex2 = /(\d+(?:\.\d+)*)/;
227589
227589
  var prereleaseRegex2 = buildRegexWithSpecifier2(prereleaseSpecifiers2);
227590
227590
  var postreleaseRegex2 = buildRegexWithSpecifier2(postreleaseSpecifiers2);
@@ -231909,6 +231909,16 @@ import assert15 from "node:assert";
231909
231909
  import { platform as platform8 } from "os";
231910
231910
  import { join as join27, posix as posix2, relative as relative18, sep as sep3 } from "path";
231911
231911
 
231912
+ // ../web-compat-utils/dist/analysis-error-keys.js
231913
+ var InstallError = class extends Error {
231914
+ failedPackages;
231915
+ constructor(failedPackages) {
231916
+ super(`Failed to install packages: ${failedPackages.join(", ")}`);
231917
+ this.failedPackages = failedPackages;
231918
+ this.name = "InstallError";
231919
+ }
231920
+ };
231921
+
231912
231922
  // ../utils/src/tmp-file.ts
231913
231923
  import { rm, mkdtemp, cp as cp4, lstat as lstat2 } from "fs/promises";
231914
231924
  import { tmpdir as tmpdir4 } from "os";
@@ -232301,6 +232311,7 @@ var pullDockerImage = memoize(async (image) => {
232301
232311
  var ONE_DAY_IN_MS = 24 * 60 * 60 * 1e3;
232302
232312
  var TMP_DIR_IN_DOCKER = "/coana-tmp";
232303
232313
  var SOCKET_PATH_IN_DOCKER = "/coana.sock";
232314
+ var PREINSTALL_DIR_IN_DOCKER = "/coana-preinstall";
232304
232315
  var OtherModulesCommunicator = class {
232305
232316
  constructor(rootWorkingDir, options, apiKey) {
232306
232317
  this.rootWorkingDir = rootWorkingDir;
@@ -232337,6 +232348,8 @@ var OtherModulesCommunicator = class {
232337
232348
  switch (cmd) {
232338
232349
  case "runReachabilityAnalysis":
232339
232350
  return "Running reachability analysis";
232351
+ case "installDependencies":
232352
+ return "Pre-installing dependencies";
232340
232353
  case "runOnDependencyChain":
232341
232354
  return "Running reachability analysis on dependency chain";
232342
232355
  case "runOnPackageRegistryPackage":
@@ -232408,7 +232421,7 @@ var OtherModulesCommunicator = class {
232408
232421
  );
232409
232422
  return JSON.parse(await readFile32(outputFilePathThisProcess, "utf-8")).result;
232410
232423
  }
232411
- async runReachabilityAnalyzerCommand(commandName, ecosystem, subprojectPath, workspacePath, args2, env, rootWorkingDirOverride, displaySubprojectPath) {
232424
+ async runReachabilityAnalyzerCommand(commandName, ecosystem, subprojectPath, workspacePath, args2, env, rootWorkingDirOverride, displaySubprojectPath, extraDockerArgs) {
232412
232425
  const tmpDir = await this.getTmpDirForSubproject(displaySubprojectPath ?? subprojectPath);
232413
232426
  const effectiveRootWorkingDir = rootWorkingDirOverride ?? this.rootWorkingDir;
232414
232427
  const effectiveSubprojectPath = rootWorkingDirOverride ?? subprojectPath;
@@ -232455,7 +232468,8 @@ var OtherModulesCommunicator = class {
232455
232468
  finalArgs,
232456
232469
  subprojectPath,
232457
232470
  tmpDir,
232458
- env
232471
+ env,
232472
+ extraDockerArgs
232459
232473
  );
232460
232474
  }
232461
232475
  if (!succeeded)
@@ -232465,7 +232479,7 @@ var OtherModulesCommunicator = class {
232465
232479
  }
232466
232480
  );
232467
232481
  }
232468
- async runReachabilityAnalyzerCommandWithOutput(commandName, ecosystem, subprojectPath, workspacePath, args2, env, rootWorkingDirOverride, displaySubprojectPath) {
232482
+ async runReachabilityAnalyzerCommandWithOutput(commandName, ecosystem, subprojectPath, workspacePath, args2, env, rootWorkingDirOverride, displaySubprojectPath, extraDockerArgs) {
232469
232483
  const tmpDir = await this.getTmpDirForSubproject(displaySubprojectPath ?? subprojectPath);
232470
232484
  const outputFileName = `${v4_default()}-${commandName}-output.json`;
232471
232485
  const outputFilePathThisProcess = join27(tmpDir, outputFileName);
@@ -232478,16 +232492,22 @@ var OtherModulesCommunicator = class {
232478
232492
  [...args2, "-o", outputFilePathOtherProcess],
232479
232493
  env,
232480
232494
  rootWorkingDirOverride,
232481
- displaySubprojectPath
232495
+ displaySubprojectPath,
232496
+ extraDockerArgs
232482
232497
  );
232483
- return JSON.parse(await readFile32(outputFilePathThisProcess, "utf-8")).result;
232498
+ const output = JSON.parse(await readFile32(outputFilePathThisProcess, "utf-8"));
232499
+ if (output.error?.type === "InstallError") {
232500
+ throw new InstallError(output.error.failedPackages);
232501
+ }
232502
+ return output.result;
232484
232503
  }
232485
- async runInDocker(ecosystem, image, entryPoint, commandName, args2, subprojectPath, tmpDir, env = process.env) {
232504
+ async runInDocker(ecosystem, image, entryPoint, commandName, args2, subprojectPath, tmpDir, env = process.env, extraDockerArgs) {
232486
232505
  if (!await pullDockerImage(image)) return false;
232487
232506
  const envArgs = Object.keys(env).filter((key) => DOCKER_ENV_WHITE_LIST.some((whiteListedKey) => key.includes(whiteListedKey))).flatMap((key) => ["-e", key]);
232488
232507
  const cmd = cmdt`docker run --pull=never --rm -v ${this.rootWorkingDir}:/project -v ${tmpDir}:${TMP_DIR_IN_DOCKER}
232489
232508
  -v=${this.options.coanaSocketPath}:${SOCKET_PATH_IN_DOCKER}
232490
232509
  ${await getEcosystemSpecificDockerArgs(ecosystem)}
232510
+ ${extraDockerArgs ?? []}
232491
232511
  ${envArgs} ${image} ${entryPoint} ${commandName} ${args2}`;
232492
232512
  return execPipeAndLogOnFailure2(cmd, subprojectPath, { env, timeout: ONE_DAY_IN_MS });
232493
232513
  }
@@ -232548,7 +232568,42 @@ var OtherModulesCommunicator = class {
232548
232568
  workspacePaths
232549
232569
  );
232550
232570
  }
232551
- async runReachabilityAnalysis(subprojectPath, workspacePath, workspaceData, ecosystem, vulnerabilities, reachabilityAnalysisOptions, otherAnalysisOptions, rootWorkingDirOverride, displaySubprojectPath) {
232571
+ async installDependencies(subprojectPath, workspacePath, workspaceData, ecosystem, vulnerabilities, reachabilityAnalysisOptions, otherAnalysisOptions, preinstallDir) {
232572
+ const tmpDir = await this.getTmpDirForSubproject(subprojectPath);
232573
+ if (isNexeMode()) {
232574
+ await extractAllToolsForNexeMode();
232575
+ }
232576
+ const inputFileName = `${v4_default()}-installDependencies-input.json`;
232577
+ const inputFileThisProcess = join27(tmpDir, inputFileName);
232578
+ const inputFileOtherProcess = this.options.runWithoutDocker ? inputFileThisProcess : posix2.join(TMP_DIR_IN_DOCKER, inputFileName);
232579
+ const preinstallDirOtherProcess = this.options.runWithoutDocker ? preinstallDir : PREINSTALL_DIR_IN_DOCKER;
232580
+ const extraDockerArgs = this.options.runWithoutDocker ? void 0 : ["-v", `${preinstallDir}:${PREINSTALL_DIR_IN_DOCKER}`];
232581
+ await writeFile12(
232582
+ inputFileThisProcess,
232583
+ JSON.stringify({
232584
+ workspaceData,
232585
+ vulnerabilities,
232586
+ reachabilityAnalysisOptions,
232587
+ otherAnalysisOptions
232588
+ })
232589
+ );
232590
+ return this.runReachabilityAnalyzerCommandWithOutput(
232591
+ "installDependencies",
232592
+ ecosystem,
232593
+ subprojectPath,
232594
+ workspacePath,
232595
+ argt`-i ${inputFileOtherProcess} --preinstall-dir ${preinstallDirOtherProcess}`,
232596
+ {
232597
+ ...process.env,
232598
+ COANA_REPORT_ID: this.options.reportId,
232599
+ COANA_API_KEY: this.apiKey.type === "present" ? this.apiKey.value : ""
232600
+ },
232601
+ void 0,
232602
+ void 0,
232603
+ extraDockerArgs
232604
+ );
232605
+ }
232606
+ async runReachabilityAnalysis(subprojectPath, workspacePath, workspaceData, ecosystem, vulnerabilities, reachabilityAnalysisOptions, otherAnalysisOptions, rootWorkingDirOverride, displaySubprojectPath, preinstallDir) {
232552
232607
  const tmpDir = await this.getTmpDirForSubproject(displaySubprojectPath ?? subprojectPath);
232553
232608
  if (isNexeMode()) {
232554
232609
  await extractAllToolsForNexeMode();
@@ -232556,6 +232611,8 @@ var OtherModulesCommunicator = class {
232556
232611
  const inputFileName = `${v4_default()}-runReachabilityAnalysis-input.json`;
232557
232612
  const inputFileThisProcess = join27(tmpDir, inputFileName);
232558
232613
  const inputFileOtherProcess = this.options.runWithoutDocker ? inputFileThisProcess : posix2.join(TMP_DIR_IN_DOCKER, inputFileName);
232614
+ const preinstallDirOtherProcess = preinstallDir ? this.options.runWithoutDocker ? preinstallDir : PREINSTALL_DIR_IN_DOCKER : void 0;
232615
+ const extraDockerArgs = preinstallDir && !this.options.runWithoutDocker ? ["-v", `${preinstallDir}:${PREINSTALL_DIR_IN_DOCKER}`] : void 0;
232559
232616
  await writeFile12(
232560
232617
  inputFileThisProcess,
232561
232618
  JSON.stringify({
@@ -232565,19 +232622,21 @@ var OtherModulesCommunicator = class {
232565
232622
  otherAnalysisOptions
232566
232623
  })
232567
232624
  );
232625
+ const preinstallArgs = preinstallDirOtherProcess ? argt`--preinstall-dir ${preinstallDirOtherProcess}` : [];
232568
232626
  return this.runReachabilityAnalyzerCommandWithOutput(
232569
232627
  "runReachabilityAnalysis",
232570
232628
  ecosystem,
232571
232629
  subprojectPath,
232572
232630
  workspacePath,
232573
- argt`-i ${inputFileOtherProcess}`,
232631
+ [...argt`-i ${inputFileOtherProcess}`, ...preinstallArgs],
232574
232632
  {
232575
232633
  ...process.env,
232576
232634
  COANA_REPORT_ID: this.options.reportId,
232577
232635
  COANA_API_KEY: this.apiKey.type === "present" ? this.apiKey.value : ""
232578
232636
  },
232579
232637
  rootWorkingDirOverride,
232580
- displaySubprojectPath
232638
+ displaySubprojectPath,
232639
+ extraDockerArgs
232581
232640
  );
232582
232641
  }
232583
232642
  };
@@ -234834,7 +234893,7 @@ function prettyApplyFixesTo(applyFixesToOption) {
234834
234893
  // dist/cli-core.js
234835
234894
  import assert16 from "node:assert";
234836
234895
  import { existsSync as existsSync28, writeFileSync as writeFileSync3 } from "fs";
234837
- import { mkdir as mkdir6, writeFile as writeFile15 } from "fs/promises";
234896
+ import { mkdir as mkdir6, rm as rm3, writeFile as writeFile15 } from "fs/promises";
234838
234897
  var import_lodash15 = __toESM(require_lodash(), 1);
234839
234898
  import os2 from "os";
234840
234899
  import { join as join34, relative as relative22, resolve as resolve42 } from "path";
@@ -235300,6 +235359,20 @@ function isShortestPath(root3, vulnPath) {
235300
235359
  var FAILED_TO_INSTALL_PACKAGE_KEY = "[UNABLE_TO_INSTALL_PACKAGE_ERROR]: ";
235301
235360
  var CLI_ANALYSIS_ERROR_MESSAGE = "Sharing log due to analysis error";
235302
235361
  var ANALYSIS_LOW_CONFIDENCE_MESSAGE = "Analysis had low confidence in result";
235362
+ var InstallError2 = class extends Error {
235363
+ constructor(failedPackages) {
235364
+ super(`Failed to install packages: ${failedPackages.join(", ")}`);
235365
+ this.failedPackages = failedPackages;
235366
+ this.name = "InstallError";
235367
+ }
235368
+ };
235369
+ var AnalysisHaltError = class extends Error {
235370
+ constructor(errorMessages) {
235371
+ super(`Analysis failed with errors: ${errorMessages.join("; ")}`);
235372
+ this.errorMessages = errorMessages;
235373
+ this.name = "AnalysisHaltError";
235374
+ }
235375
+ };
235303
235376
 
235304
235377
  // ../web-compat-utils/src/pluralize.ts
235305
235378
  function pluralize(count, word) {
@@ -236215,9 +236288,10 @@ function toSocketReachabilitySchema(vulnerability) {
236215
236288
  if (codeAwareScanResult.type === "analysisError") {
236216
236289
  return { type: "error", error: codeAwareScanResult.message };
236217
236290
  }
236291
+ if (codeAwareScanResult.type === "skippedUnsupportedEcosystem") {
236292
+ return { type: "unknown", reason: codeAwareScanResult.message };
236293
+ }
236218
236294
  if (codeAwareScanResult.type === "otherError") {
236219
- if (codeAwareScanResult.message.includes("Reachability analysis for languages using"))
236220
- return { type: "unknown", reason: codeAwareScanResult.message };
236221
236295
  return { type: "error", error: codeAwareScanResult.message };
236222
236296
  }
236223
236297
  if (codeAwareScanResult.type === "success") {
@@ -251677,7 +251751,7 @@ async function onlineScan(dependencyTree, apiKey, timeout) {
251677
251751
  }
251678
251752
 
251679
251753
  // dist/version.js
251680
- var version3 = "14.12.201";
251754
+ var version3 = "15.0.1";
251681
251755
 
251682
251756
  // dist/cli-core.js
251683
251757
  var { mapValues, omit, partition, pickBy: pickBy2 } = import_lodash15.default;
@@ -251864,8 +251938,11 @@ var CliCore = class {
251864
251938
  await this.cleanupLogging();
251865
251939
  } catch (e) {
251866
251940
  await this.spinner.fail();
251867
- logger.error("CLI failed with error:", e);
251868
- await this.shareErrorLogWithBackend(e, true, "cli-error");
251941
+ const isExpectedHalt = e instanceof InstallError2 || e instanceof AnalysisHaltError;
251942
+ if (!isExpectedHalt) {
251943
+ logger.error("CLI failed with error:", e);
251944
+ }
251945
+ await this.shareErrorLogWithBackend(e, !isExpectedHalt, "cli-error");
251869
251946
  await this.cleanupLogging();
251870
251947
  process.exit(1);
251871
251948
  }
@@ -251913,46 +251990,70 @@ var CliCore = class {
251913
251990
  logger.info(bold(` ${ecosystem} (${workspaces.length}):`));
251914
251991
  workspaces.forEach((workspace) => logger.info(bold(` ${workspace}`)));
251915
251992
  });
251993
+ let preinstallDir;
251994
+ try {
251995
+ logger.info(bold("Pre-installing dependencies for all projects..."));
251996
+ preinstallDir = await createTmpDirectory("coana-preinstall");
251997
+ await this.preInstallAllDependencies(preinstallDir, ecosystemToWorkspaceToAnalysisData, ecosystemToWorkspaceToVulnerabilities, otherModulesCommunicator);
251998
+ logger.info(bold("All dependencies pre-installed successfully"));
251999
+ } catch (e) {
252000
+ if (this.options.reachContinueOnInstallErrors) {
252001
+ logger.info("Continuing with pre-installed dependencies despite errors");
252002
+ } else {
252003
+ if (preinstallDir) {
252004
+ await rm3(preinstallDir, { recursive: true, force: true }).catch((err) => logger.debug(`Failed to cleanup preinstall dir: ${err instanceof Error ? err.message : String(err)}`));
252005
+ }
252006
+ throw e;
252007
+ }
252008
+ }
251916
252009
  const vulnsWithResults = [];
251917
252010
  const allWorkspaceDiagnostics = [];
251918
252011
  const allWorkspaceTimings = /* @__PURE__ */ new Map();
251919
252012
  const allEcosystems = Object.entries(ecosystemToWorkspaceToAnalysisData);
251920
252013
  const totalEcosystems = allEcosystems.length;
251921
252014
  let currentOverallWorkspace = 0;
251922
- for (const [ecosystemIndex, [ecosystem, workspaceToAnalysisData]] of allEcosystems.entries()) {
251923
- this.sendProgress("RUN_ON_SUBPROJECT", true, this.rootWorkingDirectory);
251924
- const isEcosystemToAnalyze = !this.options.purlTypes || this.options.purlTypes.some((purlType) => getAdvisoryEcosystemFromPurlType(purlType) === ecosystem);
251925
- if (!isEcosystemToAnalyze) {
251926
- logger.info(`Skipping reachability analysis for ecosystem ${getPurlType(ecosystem)} since it is not included in the list of ecosystems to analyze.`);
251927
- }
251928
- const { vulnerabilities, diagnostics, timings } = await this.runReachabilityAnalysisForWorkspaces(
251929
- workspaceToAnalysisData,
251930
- ecosystemToWorkspaceToVulnerabilities[ecosystem] ?? {},
251931
- {},
251932
- // We do not need the direct dependencies for socket mode
251933
- otherModulesCommunicator,
251934
- this.rootWorkingDirectory,
251935
- ecosystem,
251936
- ["NPM", "PIP", "GO", "MAVEN", "NUGET", "RUST", "RUBYGEMS"].includes(ecosystem) && isEcosystemToAnalyze,
251937
- (workspaceName, workspaceNumber, totalWorkspacesForCurrentEcosystem) => {
251938
- currentOverallWorkspace++;
251939
- logger.info(bold(`Analyzing ecosystem ${ecosystem} for project ${workspaceName} (${workspaceNumber}/${totalWorkspacesForCurrentEcosystem}) - Overall progress: Project ${currentOverallWorkspace}/${totalWorkspaces}, ecosystem ${ecosystemIndex + 1}/${totalEcosystems}`));
251940
- }
251941
- );
251942
- vulnsWithResults.push(...Object.values(vulnerabilities).flat());
251943
- for (const [workspacePath, workspaceDiagnostics] of Object.entries(diagnostics)) {
251944
- allWorkspaceDiagnostics.push({
251945
- // the workspace path is the subproject path in socket mode
251946
- subprojectPath: workspacePath ?? ".",
251947
- workspacePath: ".",
251948
- purl_type: getPurlType(ecosystem),
251949
- diagnostics: workspaceDiagnostics
251950
- });
251951
- if (timings[workspacePath] !== void 0) {
251952
- allWorkspaceTimings.set(`${ecosystem}:${workspacePath}`, timings[workspacePath]);
252015
+ try {
252016
+ for (const [ecosystemIndex, [ecosystem, workspaceToAnalysisData]] of allEcosystems.entries()) {
252017
+ this.sendProgress("RUN_ON_SUBPROJECT", true, this.rootWorkingDirectory);
252018
+ const isEcosystemToAnalyze = !this.options.purlTypes || this.options.purlTypes.some((purlType) => getAdvisoryEcosystemFromPurlType(purlType) === ecosystem);
252019
+ if (!isEcosystemToAnalyze) {
252020
+ logger.info(`Skipping reachability analysis for ecosystem ${getPurlType(ecosystem)} since it is not included in the list of ecosystems to analyze.`);
252021
+ }
252022
+ const ecosystemPreinstallDir = preinstallDir ? join34(preinstallDir, ecosystem) : void 0;
252023
+ const { vulnerabilities, diagnostics, timings } = await this.runReachabilityAnalysisForWorkspaces(
252024
+ workspaceToAnalysisData,
252025
+ ecosystemToWorkspaceToVulnerabilities[ecosystem] ?? {},
252026
+ {},
252027
+ // We do not need the direct dependencies for socket mode
252028
+ otherModulesCommunicator,
252029
+ this.rootWorkingDirectory,
252030
+ ecosystem,
252031
+ ["NPM", "PIP", "GO", "MAVEN", "NUGET", "RUST", "RUBYGEMS"].includes(ecosystem) && isEcosystemToAnalyze,
252032
+ (workspaceName, workspaceNumber, totalWorkspacesForCurrentEcosystem) => {
252033
+ currentOverallWorkspace++;
252034
+ logger.info(bold(`Analyzing ecosystem ${ecosystem} for project ${workspaceName} (${workspaceNumber}/${totalWorkspacesForCurrentEcosystem}) - Overall progress: Project ${currentOverallWorkspace}/${totalWorkspaces}, ecosystem ${ecosystemIndex + 1}/${totalEcosystems}`));
252035
+ },
252036
+ ecosystemPreinstallDir
252037
+ );
252038
+ vulnsWithResults.push(...Object.values(vulnerabilities).flat());
252039
+ for (const [workspacePath, workspaceDiagnostics] of Object.entries(diagnostics)) {
252040
+ allWorkspaceDiagnostics.push({
252041
+ // the workspace path is the subproject path in socket mode
252042
+ subprojectPath: workspacePath ?? ".",
252043
+ workspacePath: ".",
252044
+ purl_type: getPurlType(ecosystem),
252045
+ diagnostics: workspaceDiagnostics
252046
+ });
252047
+ if (timings[workspacePath] !== void 0) {
252048
+ allWorkspaceTimings.set(`${ecosystem}:${workspacePath}`, timings[workspacePath]);
252049
+ }
251953
252050
  }
252051
+ this.sendProgress("RUN_ON_SUBPROJECT", false, this.rootWorkingDirectory);
252052
+ }
252053
+ } finally {
252054
+ if (preinstallDir) {
252055
+ await rm3(preinstallDir, { recursive: true, force: true }).catch((err) => logger.debug(`Failed to cleanup preinstall dir: ${err instanceof Error ? err.message : String(err)}`));
251954
252056
  }
251955
- this.sendProgress("RUN_ON_SUBPROJECT", false, this.rootWorkingDirectory);
251956
252057
  }
251957
252058
  for (const vuln of vulnsWithResults) {
251958
252059
  if (vuln.codeAwareScanResult.type === "success" && vuln.codeAwareScanResult.lowConfidence === true && vuln.codeAwareScanResult.detectedOccurrences?.stacks?.length === 0) {
@@ -251963,6 +252064,15 @@ var CliCore = class {
251963
252064
  vuln.reachability = "UNKNOWN";
251964
252065
  }
251965
252066
  }
252067
+ if (!this.options.reachContinueOnAnalysisErrors) {
252068
+ const isInstallError = (msg) => msg.startsWith(FAILED_TO_INSTALL_PACKAGE_KEY);
252069
+ const errorMessages = vulnsWithResults.filter((v) => v.codeAwareScanResult.type === "analysisError" || v.codeAwareScanResult.type === "otherError").map((v) => v.codeAwareScanResult.message).filter((msg) => !this.options.reachContinueOnInstallErrors || !isInstallError(msg));
252070
+ if (errorMessages.length > 0) {
252071
+ const uniqueErrors = [...new Set(errorMessages)];
252072
+ this.logAnalysisErrors(errorMessages.length, uniqueErrors);
252073
+ throw new AnalysisHaltError(uniqueErrors);
252074
+ }
252075
+ }
251966
252076
  displayResultsSummary(vulnsWithResults, allWorkspaceTimings);
251967
252077
  displayWorkspaceDiagnosticsSummary(allWorkspaceDiagnostics, vulnsWithResults);
251968
252078
  await this.shareLogIfAnalysisError(vulnsWithResults);
@@ -252216,7 +252326,7 @@ Subproject: ${subproject}`);
252216
252326
  this.sendProgress("RUN_ON_SUBPROJECT", false, subProjAndWsPath.subprojectPath);
252217
252327
  }
252218
252328
  }
252219
- async runReachabilityAnalysisForWorkspaces(workspacePathToDataForAnalysis, workspaceToVulnerabilities, workspaceToDirectDependencies, otherModulesCommunicator, subprojectPath, ecosystem, reachabilitySupported, analysisStarting) {
252329
+ async runReachabilityAnalysisForWorkspaces(workspacePathToDataForAnalysis, workspaceToVulnerabilities, workspaceToDirectDependencies, otherModulesCommunicator, subprojectPath, ecosystem, reachabilitySupported, analysisStarting, preinstallDir) {
252220
252330
  const workspaces = Object.keys(workspacePathToDataForAnalysis);
252221
252331
  const totalWorkspaces = workspaces.length;
252222
252332
  const concurrency = Number(this.options.concurrency);
@@ -252281,6 +252391,8 @@ Subproject: ${subproject}`);
252281
252391
  [effectiveSubprojectPath, releaseDir] = await npmProjectDirPool.acquire();
252282
252392
  }
252283
252393
  try {
252394
+ const perProjectEcosystems = ["PIP", "RUBYGEMS"];
252395
+ const effectivePreinstallDir = preinstallDir && perProjectEcosystems.includes(ecosystem) ? join34(preinstallDir, workspacePath.replace(/\//g, "_")) : preinstallDir;
252284
252396
  const resAndDiagnostics = await this.runReachabilityAnalysis(
252285
252397
  otherModulesCommunicator,
252286
252398
  effectiveSubprojectPath,
@@ -252292,7 +252404,8 @@ Subproject: ${subproject}`);
252292
252404
  // When using temp copy for concurrent analysis, override rootWorkingDir
252293
252405
  npmProjectDirPool ? effectiveSubprojectPath : void 0,
252294
252406
  // Pass original subprojectPath for display when using temp copy
252295
- npmProjectDirPool ? subprojectPath : void 0
252407
+ npmProjectDirPool ? subprojectPath : void 0,
252408
+ effectivePreinstallDir
252296
252409
  );
252297
252410
  augmentedVulnerabilitiesToAnalyze = resAndDiagnostics.vulnerabilities;
252298
252411
  workspaceDiagnostics = resAndDiagnostics.diagnostics;
@@ -252303,7 +252416,7 @@ Subproject: ${subproject}`);
252303
252416
  augmentedVulnerabilitiesToAnalyze = vulnerabilitiesToAnalyze.map((v) => ({
252304
252417
  ...v,
252305
252418
  results: {
252306
- type: "otherError",
252419
+ type: "skippedUnsupportedEcosystem",
252307
252420
  message: `Reachability analysis for languages using ${ecosystem} not supported yet`
252308
252421
  }
252309
252422
  }));
@@ -252315,6 +252428,10 @@ Subproject: ${subproject}`);
252315
252428
  ];
252316
252429
  return [workspacePath, { vulnerabilities: augmentedVulnerabilities, diagnostics: workspaceDiagnostics }];
252317
252430
  } catch (e) {
252431
+ if (e instanceof InstallError2) {
252432
+ this.logInstallError(e.failedPackages, ecosystem);
252433
+ throw e;
252434
+ }
252318
252435
  logger.error(`${workspacePrefix}Reachability analysis failed for workspace ${workspacePath} in subproject ${subprojectPath}: ${e.message}`);
252319
252436
  return [
252320
252437
  workspacePath,
@@ -252391,6 +252508,141 @@ Subproject: ${subproject}`);
252391
252508
  }
252392
252509
  }
252393
252510
  }
252511
+ /**
252512
+ * Pre-installs all dependencies across all ecosystems and workspaces to the given dir.
252513
+ * If any installations fail, reports all failures and throws an InstallError.
252514
+ */
252515
+ async preInstallAllDependencies(preinstallDir, ecosystemToWorkspaceToAnalysisData, ecosystemToWorkspaceToVulnerabilities, otherModulesCommunicator) {
252516
+ const installTasks = [];
252517
+ for (const [ecosystem, workspaceToAnalysisData] of Object.entries(ecosystemToWorkspaceToAnalysisData)) {
252518
+ if (ecosystem === "GO" && this.options.reachContinueOnInstallErrors)
252519
+ continue;
252520
+ const ecosystemDir = join34(preinstallDir, ecosystem);
252521
+ await mkdir6(ecosystemDir, { recursive: true });
252522
+ for (const [workspace, analysisData] of Object.entries(workspaceToAnalysisData)) {
252523
+ const perProjectEcosystems = ["PIP", "RUBYGEMS"];
252524
+ const installDir = perProjectEcosystems.includes(ecosystem) ? join34(ecosystemDir, workspace.replace(/\//g, "_")) : ecosystemDir;
252525
+ if (installDir !== ecosystemDir) {
252526
+ await mkdir6(installDir, { recursive: true });
252527
+ }
252528
+ installTasks.push({
252529
+ ecosystem,
252530
+ workspace,
252531
+ analysisData,
252532
+ vulnerabilities: ecosystemToWorkspaceToVulnerabilities[ecosystem]?.[workspace] ?? [],
252533
+ installDir
252534
+ });
252535
+ }
252536
+ }
252537
+ const allFailures = [];
252538
+ await asyncMap(installTasks, async ({ ecosystem, workspace, analysisData, vulnerabilities, installDir }) => {
252539
+ try {
252540
+ const result = await otherModulesCommunicator.installDependencies(workspace, ".", analysisData, ecosystem, vulnerabilities, {
252541
+ timeoutSeconds: {
252542
+ allVulnRuns: this.analysisTimeoutInSeconds,
252543
+ bucketedRuns: bucketedAnalysisTimeoutInSeconds
252544
+ },
252545
+ memoryLimitInMB: this.analysisMemoryLimitInMb
252546
+ }, {
252547
+ haltOnInstallErrors: false
252548
+ }, installDir);
252549
+ if (result.failedPackages.length > 0) {
252550
+ logger.info(` ${ecosystem}/${workspace}: failed to install ${result.failedPackages.join(", ")}`);
252551
+ allFailures.push({ ecosystem, workspace, failedPackages: result.failedPackages });
252552
+ } else {
252553
+ logger.info(` ${ecosystem}/${workspace}: all packages installed successfully`);
252554
+ }
252555
+ } catch (e) {
252556
+ const message2 = e instanceof Error ? e.message : String(e);
252557
+ logger.info(` ${ecosystem}/${workspace}: pre-install failed (${message2})`);
252558
+ allFailures.push({ ecosystem, workspace, failedPackages: [`(pre-install error: ${message2})`] });
252559
+ }
252560
+ }, Number(this.options.concurrency));
252561
+ if (allFailures.length > 0) {
252562
+ this.logAggregatedInstallErrors(allFailures);
252563
+ const allFailed = allFailures.flatMap((f6) => f6.failedPackages);
252564
+ throw new InstallError2(allFailed);
252565
+ }
252566
+ }
252567
+ logAggregatedInstallErrors(failures) {
252568
+ const displayLines = [""];
252569
+ const goFailures = failures.filter((f6) => f6.ecosystem === "GO");
252570
+ const installFailures = failures.filter((f6) => f6.ecosystem !== "GO");
252571
+ if (installFailures.length > 0) {
252572
+ displayLines.push(kleur_default.red().bold("Installation Errors"));
252573
+ displayLines.push("The following packages failed to install during dependency pre-installation:");
252574
+ displayLines.push("");
252575
+ const byEcosystem = /* @__PURE__ */ new Map();
252576
+ for (const f6 of installFailures) {
252577
+ if (!byEcosystem.has(f6.ecosystem))
252578
+ byEcosystem.set(f6.ecosystem, []);
252579
+ byEcosystem.get(f6.ecosystem).push(f6);
252580
+ }
252581
+ for (const [ecosystem, ecosystemFailures] of byEcosystem) {
252582
+ displayLines.push(kleur_default.bold(` ${ecosystem}:`));
252583
+ for (const f6 of ecosystemFailures) {
252584
+ const pkgList = f6.failedPackages.sort();
252585
+ const pkgLines = pkgList.slice(0, 10).map((pkg) => ` - ${pkg}`);
252586
+ if (pkgList.length > 10) {
252587
+ pkgLines.push(` ... and ${pkgList.length - 10} more`);
252588
+ }
252589
+ displayLines.push(` ${f6.workspace}:`);
252590
+ displayLines.push(...pkgLines);
252591
+ }
252592
+ displayLines.push("");
252593
+ }
252594
+ displayLines.push("Pre-installing dependencies before running the analysis might fix this problem.", "");
252595
+ }
252596
+ if (goFailures.length > 0) {
252597
+ displayLines.push(kleur_default.red().bold("Build Errors"));
252598
+ displayLines.push("The following Go projects failed to build:");
252599
+ displayLines.push("");
252600
+ for (const f6 of goFailures) {
252601
+ displayLines.push(` ${f6.workspace}`);
252602
+ }
252603
+ displayLines.push("");
252604
+ }
252605
+ displayLines.push("Use --reach-continue-on-install-errors to proceed with precomputed (Tier 2) reachability results for affected vulnerabilities.", "");
252606
+ logger.error(displayLines.join("\n"));
252607
+ }
252608
+ logInstallError(failedPackages, ecosystem) {
252609
+ const pkgList = failedPackages.sort();
252610
+ const pkgLines = pkgList.slice(0, 20).map((pkg) => ` - ${pkg}`);
252611
+ if (pkgList.length > 20) {
252612
+ pkgLines.push(` ... and ${pkgList.length - 20} more`);
252613
+ }
252614
+ const installCmd = getInstallCommandForEcosystem(ecosystem);
252615
+ const displayLines = [
252616
+ "",
252617
+ kleur_default.red().bold("Installation Error"),
252618
+ "The following packages failed to install during reachability analysis:",
252619
+ ...pkgLines,
252620
+ "",
252621
+ "To fix this, pre-install dependencies before running the analysis:",
252622
+ "",
252623
+ ` ${installCmd}`,
252624
+ "",
252625
+ "Alternatively, use --reach-continue-on-install-errors to proceed with precomputed (Tier 2) reachability results for affected vulnerabilities.",
252626
+ ""
252627
+ ];
252628
+ logger.error(displayLines.join("\n"));
252629
+ }
252630
+ logAnalysisErrors(totalErrorCount, uniqueErrors) {
252631
+ const errorLines = uniqueErrors.slice(0, 20).map((msg) => ` - ${msg}`);
252632
+ if (uniqueErrors.length > 20) {
252633
+ errorLines.push(` ... and ${uniqueErrors.length - 20} more`);
252634
+ }
252635
+ const displayLines = [
252636
+ "",
252637
+ kleur_default.red().bold("Analysis Error"),
252638
+ `Reachability analysis failed for ${totalErrorCount} ${totalErrorCount === 1 ? "vulnerability" : "vulnerabilities"}:`,
252639
+ ...errorLines,
252640
+ "",
252641
+ "Use --reach-continue-on-analysis-errors to continue when encountering analysis errors and fallback to precomputed (Tier 2) reachability results for affected vulnerabilities.",
252642
+ ""
252643
+ ];
252644
+ logger.error(displayLines.join("\n"));
252645
+ }
252394
252646
  shouldExcludeAnalyzingWorkspace(subprojectPath, workspacePath, workspacePrefix = "") {
252395
252647
  const shouldExcludeWorkspaceForAnalysis = shouldIgnoreDueToExcludeDirsOrChangedFiles({
252396
252648
  mainProjectDir: this.rootWorkingDirectory,
@@ -252403,7 +252655,7 @@ Subproject: ${subproject}`);
252403
252655
  }
252404
252656
  return shouldExcludeWorkspaceForAnalysis;
252405
252657
  }
252406
- async runReachabilityAnalysis(otherModulesCommunicator, subprojectPath, workspacePath, workspaceData, ecosystem, vulnerabilities, workspacePrefix = "", rootWorkingDirOverride, displaySubprojectPath) {
252658
+ async runReachabilityAnalysis(otherModulesCommunicator, subprojectPath, workspacePath, workspaceData, ecosystem, vulnerabilities, workspacePrefix = "", rootWorkingDirOverride, displaySubprojectPath, preinstallDir) {
252407
252659
  const [vulnsWithActualAPIPatterns, result] = partition(vulnerabilities, (v) => Array.isArray(v.vulnerabilityAccessPaths));
252408
252660
  for (const v of result)
252409
252661
  v.results = typeof v.vulnerabilityAccessPaths === "string" ? { type: "noAnalysisCheck", message: v.vulnerabilityAccessPaths } : { type: "missingVulnerabilityPattern" };
@@ -252429,8 +252681,9 @@ Subproject: ${subproject}`);
252429
252681
  }, {
252430
252682
  disableBucketing: !!this.options.disableAnalysisSplitting,
252431
252683
  lightweightReachability: this.options.lightweightReachability,
252432
- skipCacheUsage: this.options.skipCacheUsage
252433
- }, rootWorkingDirOverride, displaySubprojectPath);
252684
+ skipCacheUsage: this.options.skipCacheUsage,
252685
+ haltOnInstallErrors: !!this.options.socketMode && !this.options.reachContinueOnInstallErrors
252686
+ }, rootWorkingDirOverride, displaySubprojectPath, preinstallDir);
252434
252687
  result.push(...analysisResult.vulnerabilities);
252435
252688
  this.sendProgress("REACHABILITY_ANALYSIS", false, subprojectPath, workspacePath);
252436
252689
  return { vulnerabilities: result, diagnostics: analysisResult.diagnostics };
@@ -252569,6 +252822,37 @@ async function getGitDataToMetadataIfAvailable(rootWorkingDirectory) {
252569
252822
  logger.debug("Unable to get git data. Is the folder even in a git repository?", e);
252570
252823
  }
252571
252824
  }
252825
+ function getInstallCommandForEcosystem(ecosystem) {
252826
+ switch (ecosystem) {
252827
+ case "NPM":
252828
+ return "npm install";
252829
+ case "PIP":
252830
+ return "uv sync (or your project-specific install command)";
252831
+ case "GO":
252832
+ return "go mod download";
252833
+ case "MAVEN":
252834
+ return "mvn dependency:resolve";
252835
+ case "NUGET":
252836
+ return "dotnet restore";
252837
+ case "RUST":
252838
+ return "cargo fetch";
252839
+ case "RUBYGEMS":
252840
+ return "bundle config set --local deployment true; bundle install";
252841
+ case "COMPOSER":
252842
+ return "composer install";
252843
+ case "ERLANG":
252844
+ return "rebar3 get-deps";
252845
+ case "PUB":
252846
+ return "dart pub get";
252847
+ case "SWIFT":
252848
+ return "swift package resolve";
252849
+ case "ACTIONS":
252850
+ return "Install project dependencies using your package manager";
252851
+ default:
252852
+ ecosystem;
252853
+ return "Install project dependencies using your package manager";
252854
+ }
252855
+ }
252572
252856
 
252573
252857
  // dist/internal/analysis-debug-info-transformer.js
252574
252858
  import { writeFile as writeFile16 } from "fs/promises";
@@ -252691,7 +252975,7 @@ async function writeAnalysisDebugInfo(outputFilePath, ecosystemToWorkspaceToVuln
252691
252975
  handleNexeBinaryMode();
252692
252976
  var program2 = new Command();
252693
252977
  var run2 = new Command();
252694
- run2.name("run").argument("<path>", "File system path to folder containing the project").option("-o, --output-dir <path>", "Write json report to <path>/coana-report.json").option("-d, --debug", "Enable debug logging", false).option("-s, --silent", "Silence all debug/warning output", false).option("--silent-spinner", "Silence spinner", "CI" in process.env || !process.stdin.isTTY).option("-p, --print-report", "Print the report to the console", false).option("--offline-database <path>", "Path to a coana-offline-db.json file for running the CLI without internet connectivity", void 0).option("-t, --timeout <timeout>", "Set API <timeout> in milliseconds to Coana backend.", "300000").option("-a, --analysis-timeout <timeout>", "Set <timeout> in seconds for each reachability analysis run").option("--memory-limit <memoryInMB>", "Set memory limit for analysis to <memoryInMB> megabytes of memory.", "8192").option("-c, --concurrency <concurrency>", "Set the maximum number of concurrent reachability analysis runs. It's recommended to choose a concurrency level that ensures that each analysis run has at least the --memory-limit amount of memory available. NPM reachability analysis does not support concurrent execution, so the concurrency level is ignored for NPM.", "1").option("--api-key <key>", "Set the Coana dashboard API key. By setting you also enable the dashboard integration.").addOption(new Option("--write-report-to-file", "Write the report dashboard-compatible report to dashboard-report.json. This report may help the Coana team debug issues with the report insertion mechanism.").default(false).hideHelp()).option("--project-name <repoName>", "Set the name of the repository. Used for dashboard integration.").option("--repo-url <repoUrl>", "Set the URL of the repository. Used for dashboard integration.").option("--include-dirs <relativeDirs...>", "globs for directories to include from the detection of subprojects (space-separated)(use relative paths from the project root). Notice, projects that are not included may still be scanned if they are referenced from included projects.").option("--exclude-dirs <relativeDirs...>", "globs for directories to exclude from the detection of subprojects (space-separated)(use relative paths from the project root). Notice, excluded projects may still be scanned if they are referenced from non-excluded projects.").option("--disable-analysis-splitting", "Limits Coana to at most 1 reachability analysis run per workspace").option("--print-analysis-log-file", "Store log output from the JavaScript/TypeScript reachability analysis in the file js-analysis.log file in the root of each workspace", false).option("--entry-points <entryPoints...>", "List of files to analyze for root workspace. The reachability analysis automatically analyzes all files used by the entry points. If not provided, all JavaScript and TypeScript files are considered entry points. For non-root workspaces, all JavaScript and TypeScript files are analyzed as well.").option("--include-projects-with-no-reachability-support", "Also runs Coana on projects where we support traditional SCA, but does not yet support reachability analysis.", false).option("--ecosystems <ecosystems...>", "List of ecosystems to analyze (space-separated). Currently NPM, PIP, MAVEN, NUGET and GO are supported. Default is all supported ecosystems.").addOption(new Option("--purl-types <purlTypes...>", "List of PURL types to analyze (space-separated). Currently npm, pypi, maven, nuget, golang and cargo are supported. Default is all supported purl types.").hideHelp()).option("--changed-files <files...>", "List of files that have changed. If provided, Coana only analyzes workspaces and modules that contain changed files.").option("--disable-report-submission", "Disable the submission of the report to the Coana dashboard. Used by the pipeline blocking feature.", false).option("--disable-analytics-sharing", "Disable analytics sharing.", false).option("--provider-project <path>", "File system path to folder containing the provider project (Only supported for Maven, Gradle, and SBT)").option("--provider-workspaces <dirs...>", "List of workspaces that build the provided runtime environment (Only supported for Maven, Gradle, and SBT)", (paths) => paths.split(" ")).option("--lightweight-reachability", "Runs Coana in lightweight mode. This increases analysis speed but also raises the risk of Coana misclassifying the reachability of certain complex vulnerabilities. Recommended only for use with Coana Guardrail mode.", false).addOption(new Option("--run-without-docker", "Run package managers and reachability analyzers without using docker").default(process.env.RUN_WITHOUT_DOCKER === "true").hideHelp()).addOption(new Option("--run-env <env>", "Specifies the environment in which the CLI is run. So far only MANAGED_SCAN and UNKNOWN are supported.").default("UNKNOWN").choices(["UNKNOWN", "MANAGED_SCAN"]).hideHelp()).addOption(new Option("--guardrail-mode", "Run Coana in guardrail mode. This mode is used to prevent new reachable vulnerabilities from being introduced into the codebase. Usually run as a CI check when pushing new commits to a pull request.")).option("--ignore-failing-workspaces", "Continue processing when a workspace fails instead of exiting. Failed workspaces will be logged at termination.", false).addOption(new Option("--socket-mode <output-file>", "Run Coana in socket mode and write report to <output-file>").hideHelp()).addOption(new Option("--manifests-tar-hash <hash>", "Hash of the tarball containing all manifest files already uploaded to Socket. If provided, Socket will be used for computing dependency trees.").hideHelp()).option("--skip-cache-usage", "Do not attempt to use cached analysis configuration from previous runs", false).addOption(new Option("--lazy-mode", "Enable lazy analysis mode for JavaScript/TypeScript. This can significantly speed up analysis by only analyzing code that is actually relevant for the vulnerabilities being analyzed.").default(false).hideHelp()).addOption(new Option("--min-severity <severity>", "Set the minimum severity of vulnerabilities to analyze. Supported severities are info, low, moderate, high and critical.").choices(["info", "INFO", "low", "LOW", "moderate", "MODERATE", "high", "HIGH", "critical", "CRITICAL"])).option("--use-unreachable-from-precomputation", "Skip the reachability analysis for vulnerabilities that are already known to be unreachable from the precomputed reachability analysis (Tier 2).", false).addOption(new Option("--use-only-pregenerated-sboms", "Only include artifacts that have CDX or SPDX files in their manifest files.").default(false).hideHelp()).option("--disable-external-tool-checks", "Disable validation of external tools (npm, python, go, etc.) before running analysis.", false).version(version3).configureHelp({ sortOptions: true }).action(async (path9, options) => {
252978
+ run2.name("run").argument("<path>", "File system path to folder containing the project").option("-o, --output-dir <path>", "Write json report to <path>/coana-report.json").option("-d, --debug", "Enable debug logging", false).option("-s, --silent", "Silence all debug/warning output", false).option("--silent-spinner", "Silence spinner", "CI" in process.env || !process.stdin.isTTY).option("-p, --print-report", "Print the report to the console", false).option("--offline-database <path>", "Path to a coana-offline-db.json file for running the CLI without internet connectivity", void 0).option("-t, --timeout <timeout>", "Set API <timeout> in milliseconds to Coana backend.", "300000").option("-a, --analysis-timeout <timeout>", "Set <timeout> in seconds for each reachability analysis run").option("--memory-limit <memoryInMB>", "Set memory limit for analysis to <memoryInMB> megabytes of memory.", "8192").option("-c, --concurrency <concurrency>", "Set the maximum number of concurrent reachability analysis runs. It's recommended to choose a concurrency level that ensures that each analysis run has at least the --memory-limit amount of memory available. NPM reachability analysis does not support concurrent execution, so the concurrency level is ignored for NPM.", "1").option("--api-key <key>", "Set the Coana dashboard API key. By setting you also enable the dashboard integration.").addOption(new Option("--write-report-to-file", "Write the report dashboard-compatible report to dashboard-report.json. This report may help the Coana team debug issues with the report insertion mechanism.").default(false).hideHelp()).option("--project-name <repoName>", "Set the name of the repository. Used for dashboard integration.").option("--repo-url <repoUrl>", "Set the URL of the repository. Used for dashboard integration.").option("--include-dirs <relativeDirs...>", "globs for directories to include from the detection of subprojects (space-separated)(use relative paths from the project root). Notice, projects that are not included may still be scanned if they are referenced from included projects.").option("--exclude-dirs <relativeDirs...>", "globs for directories to exclude from the detection of subprojects (space-separated)(use relative paths from the project root). Notice, excluded projects may still be scanned if they are referenced from non-excluded projects.").option("--disable-analysis-splitting", "Limits Coana to at most 1 reachability analysis run per workspace").option("--print-analysis-log-file", "Store log output from the JavaScript/TypeScript reachability analysis in the file js-analysis.log file in the root of each workspace", false).option("--entry-points <entryPoints...>", "List of files to analyze for root workspace. The reachability analysis automatically analyzes all files used by the entry points. If not provided, all JavaScript and TypeScript files are considered entry points. For non-root workspaces, all JavaScript and TypeScript files are analyzed as well.").option("--include-projects-with-no-reachability-support", "Also runs Coana on projects where we support traditional SCA, but does not yet support reachability analysis.", false).option("--ecosystems <ecosystems...>", "List of ecosystems to analyze (space-separated). Currently NPM, PIP, MAVEN, NUGET and GO are supported. Default is all supported ecosystems.").addOption(new Option("--purl-types <purlTypes...>", "List of PURL types to analyze (space-separated). Currently npm, pypi, maven, nuget, golang and cargo are supported. Default is all supported purl types.").hideHelp()).option("--changed-files <files...>", "List of files that have changed. If provided, Coana only analyzes workspaces and modules that contain changed files.").option("--disable-report-submission", "Disable the submission of the report to the Coana dashboard. Used by the pipeline blocking feature.", false).option("--disable-analytics-sharing", "Disable analytics sharing.", false).option("--provider-project <path>", "File system path to folder containing the provider project (Only supported for Maven, Gradle, and SBT)").option("--provider-workspaces <dirs...>", "List of workspaces that build the provided runtime environment (Only supported for Maven, Gradle, and SBT)", (paths) => paths.split(" ")).option("--lightweight-reachability", "Runs Coana in lightweight mode. This increases analysis speed but also raises the risk of Coana misclassifying the reachability of certain complex vulnerabilities. Recommended only for use with Coana Guardrail mode.", false).addOption(new Option("--run-without-docker", "Run package managers and reachability analyzers without using docker").default(process.env.RUN_WITHOUT_DOCKER === "true").hideHelp()).addOption(new Option("--run-env <env>", "Specifies the environment in which the CLI is run. So far only MANAGED_SCAN and UNKNOWN are supported.").default("UNKNOWN").choices(["UNKNOWN", "MANAGED_SCAN"]).hideHelp()).addOption(new Option("--guardrail-mode", "Run Coana in guardrail mode. This mode is used to prevent new reachable vulnerabilities from being introduced into the codebase. Usually run as a CI check when pushing new commits to a pull request.")).option("--ignore-failing-workspaces", "Continue processing when a workspace fails instead of exiting. Failed workspaces will be logged at termination.", false).option("--reach-continue-on-install-errors", "Continue analysis when package installation fails, falling back to precomputed (Tier 2) reachability results. By default, the CLI halts on installation errors in socket mode.", process.env.COANA_CONTINUE_ON_INSTALL_ERRORS === "true").option("--reach-continue-on-analysis-errors", "Continue analysis when errors occur (timeouts, OOM, parse errors, etc.), falling back to precomputed (Tier 2) reachability results. By default, the CLI halts on analysis errors in socket mode.", false).addOption(new Option("--socket-mode <output-file>", "Run Coana in socket mode and write report to <output-file>").hideHelp()).addOption(new Option("--manifests-tar-hash <hash>", "Hash of the tarball containing all manifest files already uploaded to Socket. If provided, Socket will be used for computing dependency trees.").hideHelp()).option("--skip-cache-usage", "Do not attempt to use cached analysis configuration from previous runs", false).addOption(new Option("--lazy-mode", "Enable lazy analysis mode for JavaScript/TypeScript. This can significantly speed up analysis by only analyzing code that is actually relevant for the vulnerabilities being analyzed.").default(false).hideHelp()).addOption(new Option("--min-severity <severity>", "Set the minimum severity of vulnerabilities to analyze. Supported severities are info, low, moderate, high and critical.").choices(["info", "INFO", "low", "LOW", "moderate", "MODERATE", "high", "HIGH", "critical", "CRITICAL"])).option("--use-unreachable-from-precomputation", "Skip the reachability analysis for vulnerabilities that are already known to be unreachable from the precomputed reachability analysis (Tier 2).", false).addOption(new Option("--use-only-pregenerated-sboms", "Only include artifacts that have CDX or SPDX files in their manifest files.").default(false).hideHelp()).option("--disable-external-tool-checks", "Disable validation of external tools (npm, python, go, etc.) before running analysis.", false).version(version3).configureHelp({ sortOptions: true }).action(async (path9, options) => {
252695
252979
  process.env.DOCKER_IMAGE_TAG ??= version3;
252696
252980
  options.ecosystems = options.ecosystems?.map((e) => e.toUpperCase());
252697
252981
  options.minSeverity = options.minSeverity?.toUpperCase();
@@ -252734,7 +253018,7 @@ computeFixesAndUpgradePurlsCmd.name("compute-fixes-and-upgrade-purls").argument(
252734
253018
  await writeFile17(outputFile, JSON.stringify(output, null, 2));
252735
253019
  logger.info(`Result written to: ${outputFile}`);
252736
253020
  }
252737
- await rm3(tmpDir, { recursive: true, force: true });
253021
+ await rm4(tmpDir, { recursive: true, force: true });
252738
253022
  } catch (error) {
252739
253023
  handleUpgradeError(error, logFile);
252740
253024
  }