@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.
@@ -79900,6 +79900,16 @@ var ApiUrls = {
79900
79900
  }
79901
79901
  };
79902
79902
 
79903
+ // ../web-compat-utils/src/analysis-error-keys.ts
79904
+ var FAILED_TO_INSTALL_PACKAGE_KEY = "[UNABLE_TO_INSTALL_PACKAGE_ERROR]: ";
79905
+ var InstallError = class extends Error {
79906
+ constructor(failedPackages) {
79907
+ super(`Failed to install packages: ${failedPackages.join(", ")}`);
79908
+ this.failedPackages = failedPackages;
79909
+ this.name = "InstallError";
79910
+ }
79911
+ };
79912
+
79903
79913
  // ../web-compat-utils/src/maven-dependency-utils.ts
79904
79914
  function deserializeMavenDependency(s2) {
79905
79915
  const [groupId, artifactId, version3] = s2.split(":");
@@ -88108,9 +88118,6 @@ var PromiseQueue = class {
88108
88118
  }
88109
88119
  };
88110
88120
 
88111
- // ../web-compat-utils/src/analysis-error-keys.ts
88112
- var FAILED_TO_INSTALL_PACKAGE_KEY = "[UNABLE_TO_INSTALL_PACKAGE_ERROR]: ";
88113
-
88114
88121
  // ../web-compat-utils/src/ghsa.ts
88115
88122
  function extractGHSAIdFromUrl(url2) {
88116
88123
  const match2 = url2.match(/(GHSA-[a-z0-9-]+)/);
@@ -88151,6 +88158,7 @@ function getVulnReachability(c) {
88151
88158
  // dist/analyzers/pip-analyzer.js
88152
88159
  var import_lodash16 = __toESM(require_lodash(), 1);
88153
88160
  import assert7 from "assert";
88161
+ import { existsSync as existsSync15 } from "fs";
88154
88162
  import { resolve as resolve19 } from "path";
88155
88163
 
88156
88164
  // ../utils/src/pip-utils.ts
@@ -88571,8 +88579,8 @@ function addPathToTrie(root3, vulnPath) {
88571
88579
  // dist/whole-program-code-aware-vulnerability-scanner/python/python-code-aware-vulnerability-scanner.js
88572
88580
  var import_lodash14 = __toESM(require_lodash(), 1);
88573
88581
  import assert6 from "assert";
88574
- import { existsSync as existsSync13 } from "fs";
88575
- import { cp as cp7, readdir as readdir5, readFile as readFile12, rm as rm5 } from "fs/promises";
88582
+ import { existsSync as existsSync14 } from "fs";
88583
+ import { cp as cp7, readdir as readdir6, readFile as readFile12, rm as rm5 } from "fs/promises";
88576
88584
  var import_semver3 = __toESM(require_semver2(), 1);
88577
88585
  import { basename as basename11, dirname as dirname15, join as join17, resolve as resolve17, sep as sep5 } from "path";
88578
88586
  import util5 from "util";
@@ -95565,7 +95573,7 @@ var prereleaseSpecifierNormalization = {
95565
95573
  };
95566
95574
  var postreleaseSpecifiers = ["post", "rev", "r"];
95567
95575
  var devReleaseSpecifiers = ["dev"];
95568
- var epochRegex = /(\d+):/;
95576
+ var epochRegex = /(\d+)!/;
95569
95577
  var releaseSegmentRegex = /(\d+(?:\.\d+)*)/;
95570
95578
  var prereleaseRegex = buildRegexWithSpecifier(prereleaseSpecifiers);
95571
95579
  var postreleaseRegex = buildRegexWithSpecifier(postreleaseSpecifiers);
@@ -110508,7 +110516,7 @@ var JavaCodeAwareVulnerabilityScanner = class _JavaCodeAwareVulnerabilityScanner
110508
110516
  if (result.error)
110509
110517
  return void 0;
110510
110518
  const packageIds = JSON.parse(await readFile8(outputFile, "utf-8")).result;
110511
- return packageIds?.map((packageId) => this.depIdToPurl.get(packageId)).filter((purl) => purl !== void 0).map((purl) => `${purl.namespace}:${purl.name}}`);
110519
+ return packageIds?.map((packageId) => this.depIdToPurl.get(packageId)).filter((purl) => purl !== void 0).map((purl) => `${purl.namespace}:${purl.name}`);
110512
110520
  });
110513
110521
  }
110514
110522
  async runAnalysis(vulnerabilities, heuristic, timeoutInSeconds, _experiment, telemetryHandler, analyzerTelemetryHandler) {
@@ -110518,7 +110526,7 @@ var JavaCodeAwareVulnerabilityScanner = class _JavaCodeAwareVulnerabilityScanner
110518
110526
  const packagesToAnalyzeSet = new Set(packagesToAnalyze);
110519
110527
  const filteredDeps = !packagesToAnalyze ? this.deps : Object.fromEntries(Object.entries(this.deps).filter(([packageId]) => {
110520
110528
  const purl = this.depIdToPurl.get(packageId);
110521
- return purl && packagesToAnalyzeSet.has(`${purl.namespace}:${purl.name}}`);
110529
+ return purl && packagesToAnalyzeSet.has(`${purl.namespace}:${purl.name}`);
110522
110530
  }));
110523
110531
  return await this.actuallyRunAnalysis(vulnerabilities.flatMap((v) => v.vulnerabilityAccessPaths), timeoutInSeconds, filteredDeps, telemetryHandler, analyzerTelemetryHandler);
110524
110532
  } catch (e) {
@@ -110591,7 +110599,7 @@ var JavaCodeAwareVulnerabilityScanner = class _JavaCodeAwareVulnerabilityScanner
110591
110599
  };
110592
110600
  }
110593
110601
  getPackagesExcludedUnrelatedToHeuristic() {
110594
- return Object.entries(this.deps).filter(([_, { src, bin }]) => !src?.length && (!bin || bin.some((f2) => !existsSync9(f2)))).map(([packageId]) => this.depIdToPurl.get(packageId)).filter((purl) => purl !== void 0).map((purl) => `${purl.namespace}:${purl.name}}`);
110602
+ return Object.entries(this.deps).filter(([_, { src, bin }]) => !src?.length && (!bin || bin.some((f2) => !existsSync9(f2)))).map(([packageId]) => this.depIdToPurl.get(packageId)).filter((purl) => purl !== void 0).map((purl) => `${purl.namespace}:${purl.name}`);
110595
110603
  }
110596
110604
  };
110597
110605
  async function convertDependencyChain2(dependencyChain, tmpDir) {
@@ -110660,6 +110668,9 @@ async function convertSocketArtifacts2(rootDir, artifacts, tmpDir) {
110660
110668
  }
110661
110669
  }
110662
110670
  }
110671
+ const artifactFile = getPathToArtifact(tmpDir, groupId, artifactId, type, classifier, version3);
110672
+ if (existsSync9(artifactFile))
110673
+ return artifactFile;
110663
110674
  if (mavenInstalled && pomFile) {
110664
110675
  try {
110665
110676
  const dependencyGetCmd = cmdt`mvn -f=${basename8(resolve10(rootDir, pomFile))} dependency:get -DgroupId=${groupId} -DartifactId=${artifactId} -Dpackaging=${type} -Dclassifier${classifier} -Dversion=${version3} -Dtransitive=false`;
@@ -110670,7 +110681,6 @@ async function convertSocketArtifacts2(rootDir, artifacts, tmpDir) {
110670
110681
  } catch {
110671
110682
  }
110672
110683
  }
110673
- const artifactFile = getPathToArtifact(tmpDir, groupId, artifactId, type, classifier, version3);
110674
110684
  await mkdir6(dirname11(artifactFile), { recursive: true });
110675
110685
  const success = await resolveMavenArtifactFromStandardRepositories(groupId, artifactId, type, classifier, version3, artifactFile);
110676
110686
  return success ? artifactFile : void 0;
@@ -110722,21 +110732,41 @@ import { tmpdir as tmpdir4 } from "os";
110722
110732
  import { join as join15 } from "path";
110723
110733
 
110724
110734
  // dist/whole-program-code-aware-vulnerability-scanner/js/dependency-preparation.js
110725
- import { existsSync as existsSync10 } from "fs";
110735
+ import { existsSync as existsSync11 } from "fs";
110726
110736
  import { resolve as resolve12 } from "path";
110727
110737
 
110728
110738
  // dist/whole-program-code-aware-vulnerability-scanner/js/setup-npm-dependencies-for-analysis.js
110729
110739
  var import_lodash9 = __toESM(require_lodash(), 1);
110730
- import { link, mkdir as mkdir7 } from "fs/promises";
110740
+ import { existsSync as existsSync10 } from "fs";
110741
+ import { link, mkdir as mkdir7, readdir as readdir5 } from "fs/promises";
110731
110742
  import { availableParallelism } from "os";
110732
110743
  import { dirname as dirname12, join as join14, resolve as resolve11 } from "path";
110733
110744
  var { chunk } = import_lodash9.default;
110734
110745
  var ROOT_PACKAGE_METADATA_NAME = "UNIQUE_ROOT_PACKAGE_METADATA_NAME";
110735
- async function setupDependenciesForAnalysis(subprojectDir, workspaceDir, directDependencies, artifactIdToArtifact) {
110746
+ async function setupDependenciesForAnalysis(subprojectDir, workspaceDir, directDependencies, artifactIdToArtifact, preinstallDir) {
110736
110747
  return await withTmpDirectory("npm-packages", async (tmpDir) => {
110737
110748
  const dirToInstallDependencies = resolve11(subprojectDir, "node_modules", ".jelly");
110738
- const { installedPackages, failedPackages } = await downloadDependenciesToDir(Object.values(artifactIdToArtifact), tmpDir);
110739
- const augmentedInstalledPackages = await extractDownloadedDependenciesToDir(dirToInstallDependencies, tmpDir, installedPackages);
110749
+ let installedPackages;
110750
+ let failedPackages;
110751
+ if (preinstallDir && existsSync10(preinstallDir)) {
110752
+ const existingFiles = await readdir5(preinstallDir);
110753
+ installedPackages = [];
110754
+ failedPackages = [];
110755
+ for (const artifact of Object.values(artifactIdToArtifact)) {
110756
+ const tarballName = artifact.name.replace("@", "").replace("/", "-");
110757
+ const expectedFilename = artifact.version ? `${tarballName}-${artifact.version}.tgz` : void 0;
110758
+ const matchingTgz = existingFiles.find((f2) => expectedFilename ? f2 === expectedFilename : f2.endsWith(".tgz") && f2.startsWith(tarballName + "-"));
110759
+ if (matchingTgz) {
110760
+ installedPackages.push({ artifact, tarFileName: resolve11(preinstallDir, matchingTgz) });
110761
+ } else {
110762
+ failedPackages.push(artifact);
110763
+ }
110764
+ }
110765
+ logger.debug(`Reusing ${installedPackages.length} pre-installed tarballs from ${preinstallDir}`);
110766
+ } else {
110767
+ ({ installedPackages, failedPackages } = await downloadDependenciesToDir(Object.values(artifactIdToArtifact), tmpDir));
110768
+ }
110769
+ const augmentedInstalledPackages = await extractDownloadedDependenciesToDir(dirToInstallDependencies, preinstallDir ?? tmpDir, installedPackages);
110740
110770
  const packageMetadatas = convertToPackageMetadatas(workspaceDir, augmentedInstalledPackages, directDependencies, artifactIdToArtifact);
110741
110771
  const packagePlacements = computePackagePlacements(packageMetadatas, resolve11(subprojectDir, "node_modules"));
110742
110772
  await hardlinkPackages(packagePlacements);
@@ -111041,8 +111071,8 @@ function tarjanAndCondensation(packageMetadatas) {
111041
111071
  }
111042
111072
 
111043
111073
  // dist/whole-program-code-aware-vulnerability-scanner/js/dependency-preparation.js
111044
- async function prepareNpmDependencies(subprojectDir, workspaceDir, artifactIdToArtifact, directDependencies, packageNamesToInstall) {
111045
- if (existsSync10(resolve12(subprojectDir, "node_modules")))
111074
+ async function prepareNpmDependencies(subprojectDir, workspaceDir, artifactIdToArtifact, directDependencies, packageNamesToInstall, preinstallDir) {
111075
+ if (existsSync11(resolve12(subprojectDir, "node_modules")))
111046
111076
  return { failedPackages: [], installedPackages: [] };
111047
111077
  const artifactToOriginal = /* @__PURE__ */ new Map();
111048
111078
  const transitiveDependenciesToInstall = Object.fromEntries(Object.entries(artifactIdToArtifact).filter(([_, dep]) => packageNamesToInstall.includes(getPackageName(dep))).map(([depId, dep]) => {
@@ -111050,7 +111080,7 @@ async function prepareNpmDependencies(subprojectDir, workspaceDir, artifactIdToA
111050
111080
  artifactToOriginal.set(artifact, dep);
111051
111081
  return [depId, artifact];
111052
111082
  }));
111053
- const result = await setupDependenciesForAnalysis(subprojectDir, workspaceDir, directDependencies, transitiveDependenciesToInstall);
111083
+ const result = await setupDependenciesForAnalysis(subprojectDir, workspaceDir, directDependencies, transitiveDependenciesToInstall, preinstallDir);
111054
111084
  return {
111055
111085
  failedPackages: result.failedPackages.map((artifact) => artifactToOriginal.get(artifact)),
111056
111086
  installedPackages: result.installedPackages.map((artifact) => artifactToOriginal.get(artifact))
@@ -111070,6 +111100,11 @@ function convertToArtifactForInstallation(dep) {
111070
111100
  dependencies: dep.dependencies
111071
111101
  };
111072
111102
  }
111103
+ async function validateNpmDependencyDownloads(artifactIdToArtifact, packageNamesToInstall, preinstallDir) {
111104
+ const artifacts = Object.entries(artifactIdToArtifact).filter(([_, dep]) => packageNamesToInstall.includes(getPackageName(dep))).map(([_, dep]) => convertToArtifactForInstallation(dep));
111105
+ const { failedPackages } = await downloadDependenciesToDir(artifacts, preinstallDir);
111106
+ return failedPackages.map((p) => p.name);
111107
+ }
111073
111108
 
111074
111109
  // dist/whole-program-code-aware-vulnerability-scanner/js/heuristics.js
111075
111110
  var lazyIndirectionBoundOptions = {
@@ -111333,7 +111368,7 @@ var JSCodeAwareVulnerabilityScanner = class _JSCodeAwareVulnerabilityScanner {
111333
111368
  ...new Set(state.vulnerabilities.flatMap((v) => Object.values(v.vulnChainDetails?.transitiveDependencies ?? {}).filter((d) => d.vulnerable === true).map((d) => d.packageName)))
111334
111369
  ];
111335
111370
  const packagesToInstall = !includePackages ? state.workspaceData.type === "coana" ? Object.values(state.workspaceData.data.dependencyTree.transitiveDependencies).map((dep) => getPackageName(dep)) : state.workspaceData.data.artifacts.map((dep) => getPackageName(dep)) : [.../* @__PURE__ */ new Set([...includePackages, ...vulnerablePackageNames])];
111336
- const { failedPackages } = await prepareNpmDependencies(state.rootWorkingDir, this.projectDir, state.workspaceData.type === "coana" ? state.workspaceData.data.dependencyTree.transitiveDependencies : Object.fromEntries(state.workspaceData.data.artifacts.map((d) => [d.id, d])), state.workspaceData.type === "coana" ? state.workspaceData.data.dependencyTree.dependencies ?? [] : state.workspaceData.data.artifacts.filter((a2) => a2.direct).map((a2) => a2.id), packagesToInstall);
111371
+ const { failedPackages } = await prepareNpmDependencies(state.rootWorkingDir, this.projectDir, state.workspaceData.type === "coana" ? state.workspaceData.data.dependencyTree.transitiveDependencies : Object.fromEntries(state.workspaceData.data.artifacts.map((d) => [d.id, d])), state.workspaceData.type === "coana" ? state.workspaceData.data.dependencyTree.dependencies ?? [] : state.workspaceData.data.artifacts.filter((a2) => a2.direct).map((a2) => a2.id), packagesToInstall, state.preinstallDir);
111337
111372
  this.packagesExcludedUnrelatedToHeuristic = failedPackages.map((p) => getPackageName(p));
111338
111373
  }
111339
111374
  async runAnalysis(vulnerabilities, heuristic, timeoutInSeconds, experiment, telemetryHandler, analyzerTelemetryHandler) {
@@ -111487,7 +111522,7 @@ function transformSourceLocations(fileMappings, detectedOccurrences) {
111487
111522
  // dist/whole-program-code-aware-vulnerability-scanner/go/go-code-aware-vulnerability-scanner.js
111488
111523
  var import_lodash11 = __toESM(require_lodash(), 1);
111489
111524
  import assert5 from "assert";
111490
- import { existsSync as existsSync11, createReadStream as createReadStream2, createWriteStream as createWriteStream4 } from "fs";
111525
+ import { existsSync as existsSync12, createReadStream as createReadStream2, createWriteStream as createWriteStream4 } from "fs";
111491
111526
  import { readFile as readFile10, rm as rm4, cp as cp6 } from "fs/promises";
111492
111527
  import zlib2 from "zlib";
111493
111528
  import { join as join16, resolve as resolve14, sep as sep3 } from "path";
@@ -111526,7 +111561,7 @@ var GoCodeAwareVulnerabilityScanner = class {
111526
111561
  }
111527
111562
  async runAnalysis(vulns, heuristic, timeoutInSeconds, _experiment, telemetryHandler, analyzerTelemetryHandler) {
111528
111563
  logger.info("Started instantiating Go code-aware analysis");
111529
- if (!existsSync11(join16(this.projectDir, "go.mod")))
111564
+ if (!existsSync12(join16(this.projectDir, "go.mod")))
111530
111565
  throw new Error("go.mod file not found in the project directory");
111531
111566
  const { memoryLimitInMB } = this.options;
111532
111567
  const tmpDir = await createTmpDirectory("goana-output");
@@ -111607,7 +111642,7 @@ ${stderr}`);
111607
111642
  try {
111608
111643
  await cp6(Dir, projectDir, { recursive: true });
111609
111644
  const projGoMod = resolve14(projectDir, "go.mod");
111610
- if (!existsSync11(projGoMod))
111645
+ if (!existsSync12(projGoMod))
111611
111646
  await cp6(GoMod, projGoMod);
111612
111647
  await exec2(cmdt`chmod --recursive +w ${projectDir}`);
111613
111648
  await runGoModTidy(projectDir);
@@ -111635,7 +111670,7 @@ ${stderr}`);
111635
111670
  }
111636
111671
  static async runOnAlreadyDownloadedPackages(packages, vuln, options) {
111637
111672
  for (const pkg of packages)
111638
- assert5(existsSync11(join16(pkg, "go.mod")), `${pkg} does not contain a go.mod file`);
111673
+ assert5(existsSync12(join16(pkg, "go.mod")), `${pkg} does not contain a go.mod file`);
111639
111674
  const [app, ...dependencies] = packages;
111640
111675
  const projectDir = await createTmpDirectory("go-run-on-already-downloaded-packages-");
111641
111676
  try {
@@ -111666,6 +111701,8 @@ ${stderr}`);
111666
111701
  await rm4(projectDir, { recursive: true, force: true });
111667
111702
  }
111668
111703
  }
111704
+ // Go dependencies are auto-installed during the reachability analysis process
111705
+ // (e.g. by `go build`), so there are no pre-install failures to track here.
111669
111706
  getPackagesExcludedUnrelatedToHeuristic() {
111670
111707
  return [];
111671
111708
  }
@@ -111673,7 +111710,7 @@ ${stderr}`);
111673
111710
 
111674
111711
  // dist/whole-program-code-aware-vulnerability-scanner/rust/rust-code-aware-vulnerability-scanner.js
111675
111712
  var import_lodash12 = __toESM(require_lodash(), 1);
111676
- import { existsSync as existsSync12 } from "node:fs";
111713
+ import { existsSync as existsSync13 } from "node:fs";
111677
111714
  import { readFile as readFile11, writeFile as writeFile9 } from "node:fs/promises";
111678
111715
  import { basename as basename10, dirname as dirname14, resolve as resolve15 } from "node:path";
111679
111716
 
@@ -111774,7 +111811,7 @@ var RustCodeAwareVulnerabilityScanner = class _RustCodeAwareVulnerabilityScanner
111774
111811
  let appCrateName;
111775
111812
  const appSrc = [];
111776
111813
  const dependencies = {};
111777
- const appCrateInfo = existsSync12(cargoTomlPath) ? await getCrateInfo(cargoTomlPath) : void 0;
111814
+ const appCrateInfo = existsSync13(cargoTomlPath) ? await getCrateInfo(cargoTomlPath) : void 0;
111778
111815
  if (appCrateInfo?.name) {
111779
111816
  appSrc.push(...i([appCrateInfo.lib, ...appCrateInfo.examples ?? [], ...appCrateInfo.tests ?? []]));
111780
111817
  appCrateName = appCrateInfo.name.replaceAll("-", "_");
@@ -111886,7 +111923,7 @@ var RustCodeAwareVulnerabilityScanner = class _RustCodeAwareVulnerabilityScanner
111886
111923
  const appDependencies = {};
111887
111924
  if (rustDependencyChain[0].src && rustDependencyChain[0].src.length > 0) {
111888
111925
  const appCargoTomlPath = resolve15(rustDependencyChain[0].src[0], "..", "Cargo.toml");
111889
- if (existsSync12(appCargoTomlPath)) {
111926
+ if (existsSync13(appCargoTomlPath)) {
111890
111927
  const cargoTomlDeps = await extractDependenciesFromCargoToml(appCargoTomlPath);
111891
111928
  for (const [packageName, names] of cargoTomlDeps.entries()) {
111892
111929
  const depId = packageNameToId.get(packageName);
@@ -111913,7 +111950,7 @@ var RustCodeAwareVulnerabilityScanner = class _RustCodeAwareVulnerabilityScanner
111913
111950
  const dependencies = {};
111914
111951
  if (dep.src && dep.src.length > 0) {
111915
111952
  const depCargoTomlPath = resolve15(dep.src[0], "..", "Cargo.toml");
111916
- if (existsSync12(depCargoTomlPath)) {
111953
+ if (existsSync13(depCargoTomlPath)) {
111917
111954
  const cargoTomlDeps = await extractDependenciesFromCargoToml(depCargoTomlPath);
111918
111955
  for (const [packageName, names] of cargoTomlDeps.entries()) {
111919
111956
  const transDepId = packageNameToId.get(packageName);
@@ -112042,7 +112079,7 @@ var RustCodeAwareVulnerabilityScanner = class _RustCodeAwareVulnerabilityScanner
112042
112079
  };
112043
112080
  }
112044
112081
  getPackagesExcludedUnrelatedToHeuristic() {
112045
- return Object.entries(this.deps).filter(([_, { src, bin }]) => !src?.length && (!bin || bin.some((f2) => !existsSync12(f2)))).map(([packageId]) => this.depIdToPurl.get(packageId)?.name).filter((name2) => name2 !== void 0).map((name2) => name2);
112082
+ return Object.entries(this.deps).filter(([_, { src, bin }]) => !src?.length && (!bin || bin.some((f2) => !existsSync13(f2)))).map(([packageId]) => this.depIdToPurl.get(packageId)?.name).filter((name2) => name2 !== void 0).map((name2) => name2);
112046
112083
  }
112047
112084
  };
112048
112085
  async function convertDependencyChain3(dependencyChain, tmpDir) {
@@ -112074,7 +112111,7 @@ function getCargoLocalRepositoryPaths() {
112074
112111
  // Cargo git dependencies
112075
112112
  { path: resolve15(cargoHome, "git", "checkouts"), type: "git" }
112076
112113
  ];
112077
- return repositories.filter((repo) => existsSync12(repo.path));
112114
+ return repositories.filter((repo) => existsSync13(repo.path));
112078
112115
  }
112079
112116
  async function findCargoPackageInLocalRepo(repo, packageName, version3, tmpDir) {
112080
112117
  try {
@@ -112114,10 +112151,10 @@ async function findCargoPackageInLocalRepo(repo, packageName, version3, tmpDir)
112114
112151
  }
112115
112152
  async function extractCargoCrate(crateFilePath, packageName, version3, tmpDir) {
112116
112153
  const packageDir = resolve15(tmpDir, `${packageName}-${version3}`);
112117
- if (existsSync12(packageDir)) {
112154
+ if (existsSync13(packageDir)) {
112118
112155
  try {
112119
112156
  const cargoTomlPath = resolve15(packageDir, "Cargo.toml");
112120
- if (existsSync12(cargoTomlPath)) {
112157
+ if (existsSync13(cargoTomlPath)) {
112121
112158
  const depCrateInfo = await getCrateInfo(cargoTomlPath);
112122
112159
  return [depCrateInfo.lib];
112123
112160
  }
@@ -112137,7 +112174,7 @@ async function extractCargoCrate(crateFilePath, packageName, version3, tmpDir) {
112137
112174
  }
112138
112175
  async function downloadAndExtractCargoCrate(packageName, version3, tmpDir) {
112139
112176
  const packageFile = resolve15(tmpDir, `${packageName}-${version3}.crate`);
112140
- if (!existsSync12(packageFile)) {
112177
+ if (!existsSync13(packageFile)) {
112141
112178
  const packageUrl = getUrlForCrate(packageName, version3);
112142
112179
  const success = await downloadFile(packageUrl, packageFile);
112143
112180
  if (!success) {
@@ -112170,7 +112207,7 @@ async function convertSocketArtifacts3(artifacts, tmpDir, artifactNameToId) {
112170
112207
  const dependencies = {};
112171
112208
  if (src && src.length > 0) {
112172
112209
  const cargoTomlPath = resolve15(dirname14(src[0]), "Cargo.toml");
112173
- if (existsSync12(cargoTomlPath)) {
112210
+ if (existsSync13(cargoTomlPath)) {
112174
112211
  const cargoTomlDeps = await extractDependenciesFromCargoToml(cargoTomlPath);
112175
112212
  for (const [packageName, names] of cargoTomlDeps.entries()) {
112176
112213
  const depArtifactId = artifactNameToId.get(packageName);
@@ -112443,12 +112480,12 @@ var PythonCodeAwareVulnerabilityScanner = class {
112443
112480
  this.projectDir = projectDir;
112444
112481
  this.vm = new PythonVersionsManager(state.rootWorkingDir);
112445
112482
  }
112446
- async prepareDependencies(preInstalledDepInfos, vulns, heuristic) {
112483
+ async prepareDependencies(preInstalledDepInfos, vulns, heuristic, preinstallDir) {
112447
112484
  const packagesToExclude = heuristic.getPackagesToExcludeFromAnalysis?.(vulns);
112448
112485
  const packagesToInstall = uniqBy(preInstalledDepInfos.filter((n) => !packagesToExclude?.has(n.packageName)), "packageName");
112449
- if (!await this.tryUsingPreinstalledVirtualEnv(packagesToInstall)) {
112486
+ if (!await this.tryUsingPreinstalledVirtualEnv(packagesToInstall) && !(preinstallDir && await this.tryUsingVenvFromPreinstallDir(preinstallDir))) {
112450
112487
  logger.info(`Setting up virtual environment`);
112451
- await this.prepareVirtualEnv(packagesToInstall);
112488
+ await this.prepareVirtualEnv(packagesToInstall, preinstallDir);
112452
112489
  logger.info("Done setting up virtual environment");
112453
112490
  }
112454
112491
  }
@@ -112663,7 +112700,7 @@ ${msg}`;
112663
112700
  // public for testing only
112664
112701
  async tryUsingPreinstalledVirtualEnv(packages) {
112665
112702
  const preinstallVirtualEnvPath = resolve17(this.projectDir, ".venv");
112666
- if (!existsSync13(preinstallVirtualEnvPath))
112703
+ if (!existsSync14(preinstallVirtualEnvPath))
112667
112704
  return false;
112668
112705
  logger.info(`Checking preinstalled virtual environment at ${preinstallVirtualEnvPath}`);
112669
112706
  try {
@@ -112684,12 +112721,20 @@ ${msg}`;
112684
112721
  await this.updateVirtualEnvInfo(this.projectDir);
112685
112722
  return true;
112686
112723
  }
112724
+ async tryUsingVenvFromPreinstallDir(preinstallDir) {
112725
+ const venvPath = join17(preinstallDir, ".venv");
112726
+ if (!existsSync14(venvPath))
112727
+ return false;
112728
+ logger.info(`Reusing virtual environment from pre-install at ${venvPath}`);
112729
+ await this.updateVirtualEnvInfo(preinstallDir);
112730
+ return true;
112731
+ }
112687
112732
  // public for testing only
112688
- async prepareVirtualEnv(packages) {
112733
+ async prepareVirtualEnv(packages, preinstallDir) {
112689
112734
  const uvCommand = getUvCommand();
112690
112735
  if (!await hasUv())
112691
112736
  throw new Error("uv (https://docs.astral.sh/uv/) is missing, but is required for Python analysis");
112692
- const tmpDir = await createTmpDirectory("coana-python-analysis-venv");
112737
+ const tmpDir = preinstallDir ?? await createTmpDirectory("coana-python-analysis-venv");
112693
112738
  const virtualEnvFolder = join17(tmpDir, ".venv");
112694
112739
  const pythonExecutable = await this.vm.getPythonExecutableForWorkspace(this.projectDir, false);
112695
112740
  await exec2(cmdt`${uvCommand} venv --python ${pythonExecutable} .venv`, tmpDir);
@@ -112762,7 +112807,7 @@ ${msg}`;
112762
112807
  await this.updateVirtualEnvInfo(tmpDir, installStats);
112763
112808
  }
112764
112809
  async updateVirtualEnvInfo(virtualEnvFolder, packageInstallationStats) {
112765
- const entries = await readdir5(join17(virtualEnvFolder, ".venv", "lib"));
112810
+ const entries = await readdir6(join17(virtualEnvFolder, ".venv", "lib"));
112766
112811
  const pydir = entries.find((entry) => entry.startsWith("python"));
112767
112812
  assert6(pydir, `No python* directory found in virtual environment: ${util5.inspect(entries)}`);
112768
112813
  this.virtualEnvInfo = {
@@ -112859,7 +112904,7 @@ async function setupMambalade() {
112859
112904
  logger.debug(`Using Python interpreter: ${python}`);
112860
112905
  await exec2(cmdt`${uvCommand} venv --no-project --no-config --python=${python} .`, venvDir);
112861
112906
  const mambaladeWheelsPath = ToolPathResolver.mambaladeDistPath;
112862
- const mambaladeWheels = (await readdir5(mambaladeWheelsPath)).filter((f2) => f2.endsWith(".whl")).map((f2) => join17(mambaladeWheelsPath, f2));
112907
+ const mambaladeWheels = (await readdir6(mambaladeWheelsPath)).filter((f2) => f2.endsWith(".whl")).map((f2) => join17(mambaladeWheelsPath, f2));
112863
112908
  if (!mambaladeWheels.length)
112864
112909
  throw new Error(`No mambalade wheel files found in ${mambaladeWheelsPath}`);
112865
112910
  logger.debug(`Installing mambalade wheels: ${mambaladeWheels.join(", ")}`);
@@ -112995,6 +113040,13 @@ async function processProject(projectDir) {
112995
113040
  }, 4)).flat());
112996
113041
  }
112997
113042
 
113043
+ // dist/analyzers/analyzer.js
113044
+ function checkForInstallErrors(failedPackages, otherAnalysisOptions) {
113045
+ if (failedPackages.length > 0 && otherAnalysisOptions.haltOnInstallErrors) {
113046
+ throw new InstallError(failedPackages);
113047
+ }
113048
+ }
113049
+
112998
113050
  // dist/analyzers/pip-analyzer.js
112999
113051
  var { once: once4 } = import_lodash16.default;
113000
113052
  var PipAnalyzer = class {
@@ -113013,9 +113065,16 @@ var PipAnalyzer = class {
113013
113065
  this.heuristic = MambaladeHeuristics.createOnlyVulnPathPackagesHeuristic(this.preInstalledDepInfos);
113014
113066
  }
113015
113067
  prepareScanner = once4(async () => {
113016
- await this.scanner.prepareDependencies(this.preInstalledDepInfos, this.state.vulnerabilities.filter((v) => Array.isArray(v.vulnerabilityAccessPaths)), this.heuristic);
113068
+ await this.scanner.prepareDependencies(this.preInstalledDepInfos, this.state.vulnerabilities.filter((v) => Array.isArray(v.vulnerabilityAccessPaths)), this.heuristic, this.state.preinstallDir);
113017
113069
  return this.scanner;
113018
113070
  });
113071
+ async installDependencies(preinstallDir) {
113072
+ if (existsSync15(resolve19(this.projectDir, ".venv")))
113073
+ return [];
113074
+ const scanner = new PythonCodeAwareVulnerabilityScanner(this.state, this.projectDir);
113075
+ await scanner.prepareDependencies(this.preInstalledDepInfos, this.state.vulnerabilities.filter((v) => Array.isArray(v.vulnerabilityAccessPaths)), this.heuristic, preinstallDir);
113076
+ return scanner.getPackagesExcludedUnrelatedToHeuristic();
113077
+ }
113019
113078
  async runPhantomDependencyAnalysis() {
113020
113079
  const info = (await this.prepareScanner()).getVirtualEnvInfo();
113021
113080
  assert7(info !== void 0);
@@ -113038,6 +113097,7 @@ var PipAnalyzer = class {
113038
113097
  };
113039
113098
  try {
113040
113099
  const scanner = await this.prepareScanner();
113100
+ checkForInstallErrors(scanner.getPackagesExcludedUnrelatedToHeuristic(), this.state.otherAnalysisOptions);
113041
113101
  const venvInfo = scanner.getVirtualEnvInfo();
113042
113102
  this.preinstalledDependencies = venvInfo !== void 0 && !venvInfo.temporary ? "YES" : "NO";
113043
113103
  return await analyzeWithHeuristics(this.state, vulns, [this.heuristic], false, scanner, wrappedCollector, statusUpdater);
@@ -113514,6 +113574,15 @@ var GoAnalyzer = class {
113514
113574
  this.state = state;
113515
113575
  this.projectDir = projectDir;
113516
113576
  }
113577
+ async installDependencies(_preinstallDir) {
113578
+ try {
113579
+ await runCommandResolveStdOut2(cmdt`go build ./...`, this.projectDir);
113580
+ return [];
113581
+ } catch (e) {
113582
+ logger.warn(`go build failed for ${this.projectDir}: ${e instanceof Error ? e.message : String(e)}`);
113583
+ return ["(go build failure)"];
113584
+ }
113585
+ }
113517
113586
  async runPhantomDependencyAnalysis() {
113518
113587
  return void 0;
113519
113588
  }
@@ -113601,9 +113670,16 @@ var MavenAnalyzer = class {
113601
113670
  constructor(state) {
113602
113671
  this.state = state;
113603
113672
  }
113673
+ async createScanner(tmpDir, statusUpdater) {
113674
+ return this.state.workspaceData.type === "coana" ? JavaCodeAwareVulnerabilityScanner.initFromDependencyTree(this.state.workspaceData.data.dependencyTree, tmpDir, statusUpdater) : JavaCodeAwareVulnerabilityScanner.initFromSocketArtifacts(this.state.subprojectDir, this.state.workspaceData.data.artifacts, tmpDir, statusUpdater);
113675
+ }
113676
+ async installDependencies(preinstallDir) {
113677
+ const scanner = await this.createScanner(preinstallDir);
113678
+ return scanner.getPackagesExcludedUnrelatedToHeuristic();
113679
+ }
113604
113680
  async runPhantomDependencyAnalysis() {
113605
113681
  return withTmpDirectory("maven-phantom-dependency-analysis", async (tmpDir) => {
113606
- const scanner = this.state.workspaceData.type === "coana" ? await JavaCodeAwareVulnerabilityScanner.initFromDependencyTree(this.state.workspaceData.data.dependencyTree, tmpDir) : await JavaCodeAwareVulnerabilityScanner.initFromSocketArtifacts(this.state.subprojectDir, this.state.workspaceData.data.artifacts, tmpDir);
113682
+ const scanner = await this.createScanner(tmpDir);
113607
113683
  return scanner.runPhantomDependencyAnalysis(this.state.reachabilityAnalysisOptions.timeoutSeconds.allVulnRuns);
113608
113684
  });
113609
113685
  }
@@ -113615,11 +113691,17 @@ var MavenAnalyzer = class {
113615
113691
  }
113616
113692
  analysisMetadataCollector?.(metadata);
113617
113693
  };
113618
- return withTmpDirectory("maven-reachability-analysis", async (tmpDir) => {
113619
- const scanner = this.state.workspaceData.type === "coana" ? await JavaCodeAwareVulnerabilityScanner.initFromDependencyTree(this.state.workspaceData.data.dependencyTree, tmpDir, statusUpdater) : await JavaCodeAwareVulnerabilityScanner.initFromSocketArtifacts(this.state.subprojectDir, this.state.workspaceData.data.artifacts, tmpDir, statusUpdater);
113694
+ const preinstallDir = this.state.preinstallDir;
113695
+ const runWithTmpDir = async (tmpDir) => {
113696
+ const scanner = await this.createScanner(tmpDir, statusUpdater);
113697
+ checkForInstallErrors(scanner.getPackagesExcludedUnrelatedToHeuristic(), this.state.otherAnalysisOptions);
113620
113698
  const heuristicsInOrder = [AlucardHeuristics.ALL_PACKAGES];
113621
113699
  return await analyzeWithHeuristics(this.state, vulns, heuristicsInOrder, false, scanner, wrappedCollector, statusUpdater);
113622
- });
113700
+ };
113701
+ if (preinstallDir) {
113702
+ return runWithTmpDir(preinstallDir);
113703
+ }
113704
+ return withTmpDirectory("maven-reachability-analysis", runWithTmpDir);
113623
113705
  }
113624
113706
  async getWorkspaceDiagnostics() {
113625
113707
  let sourceFilesDetected;
@@ -113648,7 +113730,7 @@ var MavenAnalyzer = class {
113648
113730
  // dist/analyzers/npm-analyzer.js
113649
113731
  var import_lodash19 = __toESM(require_lodash(), 1);
113650
113732
  var import_picomatch4 = __toESM(require_picomatch2(), 1);
113651
- import { existsSync as existsSync14 } from "fs";
113733
+ import { existsSync as existsSync16 } from "fs";
113652
113734
  import { rm as rm6 } from "fs/promises";
113653
113735
  import { relative as relative8, resolve as resolve20 } from "path";
113654
113736
 
@@ -113675,6 +113757,17 @@ var NpmAnalyzer = class {
113675
113757
  this.state = state;
113676
113758
  this.projectDir = projectDir;
113677
113759
  }
113760
+ async installDependencies(preinstallDir) {
113761
+ if (existsSync16(resolve20(this.state.subprojectDir, "node_modules")))
113762
+ return [];
113763
+ const artifactIdToArtifact = this.state.workspaceData.type === "coana" ? this.state.workspaceData.data.dependencyTree.transitiveDependencies : Object.fromEntries(this.state.workspaceData.data.artifacts.map((d) => [d.id, d]));
113764
+ const vulnPathPackages = computePackagesOnVulnPath(this.state.vulnerabilities);
113765
+ const vulnerablePackageNames = [
113766
+ ...new Set(this.state.vulnerabilities.flatMap((v) => Object.values(v.vulnChainDetails?.transitiveDependencies ?? {}).filter((d) => d.vulnerable === true).map((d) => d.packageName)))
113767
+ ];
113768
+ const packagesToInstall = [.../* @__PURE__ */ new Set([...vulnPathPackages, ...vulnerablePackageNames])];
113769
+ return validateNpmDependencyDownloads(artifactIdToArtifact, packagesToInstall, preinstallDir);
113770
+ }
113678
113771
  async runPhantomDependencyAnalysis() {
113679
113772
  try {
113680
113773
  return (await runJellyPhantomDependencyAnalysis(this.projectDir, this.state.reachabilityAnalysisOptions)).map((r) => r.name);
@@ -113684,7 +113777,7 @@ var NpmAnalyzer = class {
113684
113777
  }
113685
113778
  async runReachabilityAnalysis(vulns, analysisMetadataCollector, statusUpdater) {
113686
113779
  const heuristicsInOrder = this.state.otherAnalysisOptions.lightweightReachability ? [heuristics.IGNORE_DEPENDENCIES_AND_MAX_ROUNDS_3] : [heuristics.ONLY_VULN_PATH_PACKAGES_EXCEPT_VULNERABLE_PACKAGE];
113687
- const nodeModulesAlreadyExisted = existsSync14(resolve20(this.state.subprojectDir, "node_modules"));
113780
+ const nodeModulesAlreadyExisted = existsSync16(resolve20(this.state.subprojectDir, "node_modules"));
113688
113781
  this.preinstalledDependencies = nodeModulesAlreadyExisted ? "YES" : "NO";
113689
113782
  const wrappedCollector = (metadata) => {
113690
113783
  const jellyDiagnostics = metadata.analysisDiagnostics;
@@ -113696,6 +113789,7 @@ var NpmAnalyzer = class {
113696
113789
  try {
113697
113790
  const vulnerabilityScanner = new JSCodeAwareVulnerabilityScanner(this.state.rootWorkingDir, this.projectDir, this.state.reachabilityAnalysisOptions);
113698
113791
  await vulnerabilityScanner.prepareDependencies(this.state, heuristicsInOrder[0]);
113792
+ checkForInstallErrors(vulnerabilityScanner.getPackagesExcludedUnrelatedToHeuristic(), this.state.otherAnalysisOptions);
113699
113793
  logger.info(`Running import reachability analysis for ${vulns.length} ${pluralize(vulns.length, "vulnerability")}`);
113700
113794
  let reachable;
113701
113795
  const ghsaIds = extractGhsaIdsFromVulnUrls(vulns.map((v) => v.url));
@@ -113809,9 +113903,9 @@ ${e.stack}` : String(e),
113809
113903
  return res;
113810
113904
  } finally {
113811
113905
  if (!nodeModulesAlreadyExisted) {
113812
- if (existsSync14(resolve20(this.state.subprojectDir, "node_modules")))
113906
+ if (existsSync16(resolve20(this.state.subprojectDir, "node_modules")))
113813
113907
  await rm6(resolve20(this.state.subprojectDir, "node_modules"), { recursive: true });
113814
- if (existsSync14(resolve20(this.projectDir, "node_modules")))
113908
+ if (existsSync16(resolve20(this.projectDir, "node_modules")))
113815
113909
  await rm6(resolve20(this.projectDir, "node_modules"), { recursive: true });
113816
113910
  }
113817
113911
  }
@@ -113852,9 +113946,16 @@ var NugetAnalyzer = class {
113852
113946
  constructor(state) {
113853
113947
  this.state = state;
113854
113948
  }
113949
+ async createScanner(tmpDir, statusUpdater) {
113950
+ return this.state.workspaceData.type === "coana" ? DotnetCodeAwareVulnerabilityScanner.initFromDependencyTree(this.state.workspaceData.data.dependencyTree, statusUpdater) : DotnetCodeAwareVulnerabilityScanner.initFromSocketArtifacts(this.state.subprojectDir, this.state.workspaceData.data.manifestFiles, this.state.workspaceData.data.artifacts, tmpDir, statusUpdater);
113951
+ }
113952
+ async installDependencies(preinstallDir) {
113953
+ const scanner = await this.createScanner(preinstallDir);
113954
+ return scanner.getPackagesExcludedUnrelatedToHeuristic();
113955
+ }
113855
113956
  async runPhantomDependencyAnalysis() {
113856
113957
  return withTmpDirectory("nuget-phantom-dependency-analysis", async (tmpDir) => {
113857
- const scanner = this.state.workspaceData.type === "coana" ? DotnetCodeAwareVulnerabilityScanner.initFromDependencyTree(this.state.workspaceData.data.dependencyTree) : await DotnetCodeAwareVulnerabilityScanner.initFromSocketArtifacts(this.state.subprojectDir, this.state.workspaceData.data.manifestFiles, this.state.workspaceData.data.artifacts, tmpDir);
113958
+ const scanner = await this.createScanner(tmpDir);
113858
113959
  return scanner.runPhantomDependencyAnalysis(this.state.reachabilityAnalysisOptions.timeoutSeconds.allVulnRuns);
113859
113960
  });
113860
113961
  }
@@ -113866,11 +113967,17 @@ var NugetAnalyzer = class {
113866
113967
  }
113867
113968
  analysisMetadataCollector?.(metadata);
113868
113969
  };
113869
- return withTmpDirectory("nuget-reachability-analysis", async (tmpDir) => {
113870
- const scanner = this.state.workspaceData.type === "coana" ? DotnetCodeAwareVulnerabilityScanner.initFromDependencyTree(this.state.workspaceData.data.dependencyTree, statusUpdater) : await DotnetCodeAwareVulnerabilityScanner.initFromSocketArtifacts(this.state.subprojectDir, this.state.workspaceData.data.manifestFiles, this.state.workspaceData.data.artifacts, tmpDir, statusUpdater);
113970
+ const preinstallDir = this.state.preinstallDir;
113971
+ const runWithTmpDir = async (tmpDir) => {
113972
+ const scanner = await this.createScanner(tmpDir, statusUpdater);
113973
+ checkForInstallErrors(scanner.getPackagesExcludedUnrelatedToHeuristic(), this.state.otherAnalysisOptions);
113871
113974
  const heuristicsInOrder = [CocoaHeuristics.ALL_PACKAGES];
113872
113975
  return await analyzeWithHeuristics(this.state, vulns, heuristicsInOrder, false, scanner, wrappedCollector, statusUpdater);
113873
- });
113976
+ };
113977
+ if (preinstallDir) {
113978
+ return runWithTmpDir(preinstallDir);
113979
+ }
113980
+ return withTmpDirectory("nuget-reachability-analysis", runWithTmpDir);
113874
113981
  }
113875
113982
  async getWorkspaceDiagnostics() {
113876
113983
  let sourceFilesDetected;
@@ -113898,13 +114005,13 @@ var NugetAnalyzer = class {
113898
114005
 
113899
114006
  // dist/analyzers/ruby-analyzer.js
113900
114007
  var import_lodash21 = __toESM(require_lodash(), 1);
113901
- import { existsSync as existsSync16 } from "fs";
114008
+ import { existsSync as existsSync18 } from "fs";
113902
114009
  import { resolve as resolve21 } from "path";
113903
114010
 
113904
114011
  // dist/whole-program-code-aware-vulnerability-scanner/ruby/ruby-code-aware-vulnerability-scanner.js
113905
114012
  var import_lodash20 = __toESM(require_lodash(), 1);
113906
- import { createWriteStream as createWriteStream5, existsSync as existsSync15 } from "fs";
113907
- import { mkdir as mkdir9, readdir as readdir6, readFile as readFile13, rm as rm7 } from "fs/promises";
114013
+ import { createWriteStream as createWriteStream5, existsSync as existsSync17 } from "fs";
114014
+ import { mkdir as mkdir9, readdir as readdir7, readFile as readFile13, rm as rm7 } from "fs/promises";
113908
114015
  import { join as join18, relative as relative9 } from "path";
113909
114016
  import { pipeline as pipeline3 } from "stream/promises";
113910
114017
  var PRINT_ANALYSIS_COMMAND = false;
@@ -113921,12 +114028,12 @@ var RubyCodeAwareVulnerabilityScanner = class {
113921
114028
  this.projectDir = projectDir;
113922
114029
  this.options = options;
113923
114030
  }
113924
- async prepareDependencies(preInstalledDepInfos, vulns, heuristic) {
113925
- const vendorDir = join18(this.projectDir, "vendor");
113926
- if (existsSync15(vendorDir)) {
114031
+ async prepareDependencies(preInstalledDepInfos, vulns, heuristic, preinstallDir) {
114032
+ const vendorDir = preinstallDir ?? join18(this.projectDir, "vendor");
114033
+ if (existsSync17(vendorDir)) {
113927
114034
  logger.info(`Vendor directory already exists at ${vendorDir}, skipping gem installation`);
113928
114035
  this.vendorDir = vendorDir;
113929
- this.vendorDirWasCreated = false;
114036
+ this.vendorDirWasCreated = !preinstallDir;
113930
114037
  return;
113931
114038
  }
113932
114039
  const packagesToIncludeNames = heuristic.getPackagesToIncludeInAnalysis?.(vulns)?.map((p) => p.packageName);
@@ -113957,7 +114064,7 @@ var RubyCodeAwareVulnerabilityScanner = class {
113957
114064
  if (!this.vendorDir)
113958
114065
  throw new Error("Assertion error: The vendor directory is not correctly initialized");
113959
114066
  const analyzerPath = ToolPathResolver.callgraphReachabilityAnalyzersCliPath;
113960
- if (!existsSync15(analyzerPath))
114067
+ if (!existsSync17(analyzerPath))
113961
114068
  throw new Error(`callgraph-reachability-analyzers CLI not found at ${analyzerPath}`);
113962
114069
  const vulnAccPaths = sortedUniq2(vulns.flatMap((v) => v.vulnerabilityAccessPaths).sort());
113963
114070
  const vulnsOutputFile = join18(tmpDir, "vulns.json");
@@ -113968,12 +114075,12 @@ var RubyCodeAwareVulnerabilityScanner = class {
113968
114075
  const loadPaths = Array.from(loadPathsToPackageNames.keys());
113969
114076
  if (failedToFindLoadPath.length > 0) {
113970
114077
  this.packagesExcludedUnrelatedToHeuristic.push(...failedToFindLoadPath.map((p) => p.packageName));
113971
- logger.warn(`Failed to find package installation path for ${failedToFindLoadPath.map((p) => p.packageName).join(", ")}`);
114078
+ logger.debug(`Failed to find package installation path for ${failedToFindLoadPath.map((p) => p.packageName).join(", ")}`);
113972
114079
  }
113973
114080
  if (loadPaths.length === 0) {
113974
114081
  return {
113975
114082
  type: "error",
113976
- message: "No load paths found for the packages to analyze"
114083
+ message: `${FAILED_TO_INSTALL_PACKAGE_KEY}No load paths found for the packages to analyze`
113977
114084
  };
113978
114085
  }
113979
114086
  const cmd = cmdt`
@@ -114032,7 +114139,7 @@ var RubyCodeAwareVulnerabilityScanner = class {
114032
114139
  return this.packagesExcludedUnrelatedToHeuristic;
114033
114140
  }
114034
114141
  async cleanup() {
114035
- if (this.vendorDirWasCreated && this.vendorDir && existsSync15(this.vendorDir)) {
114142
+ if (this.vendorDirWasCreated && this.vendorDir && existsSync17(this.vendorDir)) {
114036
114143
  logger.info(`Deleting auto-generated vendor directory at ${this.vendorDir}`);
114037
114144
  await rm7(this.vendorDir, { recursive: true, force: true }).catch(() => {
114038
114145
  });
@@ -114048,7 +114155,7 @@ var RubyCodeAwareVulnerabilityScanner = class {
114048
114155
  if (this.vendorDirWasCreated) {
114049
114156
  for (const pkg of packagesToAnalyze) {
114050
114157
  const libPath = join18(this.vendorDir, `${pkg.packageName}-${pkg.version}`, "lib");
114051
- if (existsSync15(libPath))
114158
+ if (existsSync17(libPath))
114052
114159
  loadPathsToPackageNames.set(libPath, `${pkg.packageName}@${pkg.version}`);
114053
114160
  else
114054
114161
  failedToFindLoadPath.push(pkg);
@@ -114056,13 +114163,13 @@ var RubyCodeAwareVulnerabilityScanner = class {
114056
114163
  return { loadPathsToPackageNames, failedToFindLoadPath };
114057
114164
  }
114058
114165
  const bundlerGemsDir = join18(this.vendorDir, "bundle", "ruby");
114059
- if (existsSync15(bundlerGemsDir)) {
114060
- const rubyVersions = await readdir6(bundlerGemsDir);
114166
+ if (existsSync17(bundlerGemsDir)) {
114167
+ const rubyVersions = await readdir7(bundlerGemsDir);
114061
114168
  for (const rubyVersion of rubyVersions) {
114062
114169
  const gemsDir = join18(bundlerGemsDir, rubyVersion, "gems");
114063
- if (existsSync15(gemsDir)) {
114170
+ if (existsSync17(gemsDir)) {
114064
114171
  const nameToEntry = /* @__PURE__ */ new Map();
114065
- for (const entry of await readdir6(gemsDir, { withFileTypes: true }))
114172
+ for (const entry of await readdir7(gemsDir, { withFileTypes: true }))
114066
114173
  if (entry.isDirectory()) {
114067
114174
  const match2 = entry.name.match(/^([\w-_]+)-(\d+\.\d+\.\d+)/);
114068
114175
  if (match2)
@@ -114073,7 +114180,7 @@ var RubyCodeAwareVulnerabilityScanner = class {
114073
114180
  if (!entry)
114074
114181
  continue;
114075
114182
  const libDir = join18(gemsDir, entry, "lib");
114076
- if (existsSync15(libDir))
114183
+ if (existsSync17(libDir))
114077
114184
  loadPathsToPackageNames.set(libDir, `${pkg.packageName}@${pkg.version}`);
114078
114185
  else
114079
114186
  failedToFindLoadPath.push(pkg);
@@ -114083,7 +114190,7 @@ var RubyCodeAwareVulnerabilityScanner = class {
114083
114190
  } else
114084
114191
  for (const pkg of packagesToAnalyze) {
114085
114192
  const libPath = join18(this.vendorDir, `${pkg.packageName}-${pkg.version}`, "lib");
114086
- if (existsSync15(libPath))
114193
+ if (existsSync17(libPath))
114087
114194
  loadPathsToPackageNames.set(libPath, `${pkg.packageName}@${pkg.version}`);
114088
114195
  else
114089
114196
  failedToFindLoadPath.push(pkg);
@@ -114093,7 +114200,7 @@ var RubyCodeAwareVulnerabilityScanner = class {
114093
114200
  };
114094
114201
  async function downloadAndExtractGem(gemName, version3, vendorDir) {
114095
114202
  const gemDir = join18(vendorDir, `${gemName}-${version3}`);
114096
- if (existsSync15(gemDir)) {
114203
+ if (existsSync17(gemDir)) {
114097
114204
  logger.debug(`Gem ${gemName}@${version3} already extracted`);
114098
114205
  return;
114099
114206
  }
@@ -114146,9 +114253,16 @@ var RubyGemsAnalyzer = class {
114146
114253
  this.scanner = new RubyCodeAwareVulnerabilityScanner(state, projectDir);
114147
114254
  }
114148
114255
  prepareScanner = once5(async () => {
114149
- await this.scanner.prepareDependencies(this.preInstalledDepInfos, this.state.vulnerabilities.filter((v) => Array.isArray(v.vulnerabilityAccessPaths)), RubyHeuristics.ONLY_VULN_PATH_PACKAGES);
114256
+ await this.scanner.prepareDependencies(this.preInstalledDepInfos, this.state.vulnerabilities.filter((v) => Array.isArray(v.vulnerabilityAccessPaths)), RubyHeuristics.ONLY_VULN_PATH_PACKAGES, this.state.preinstallDir);
114150
114257
  return this.scanner;
114151
114258
  });
114259
+ async installDependencies(preinstallDir) {
114260
+ if (existsSync18(resolve21(this.projectDir, "vendor")))
114261
+ return [];
114262
+ const scanner = new RubyCodeAwareVulnerabilityScanner(this.state, this.projectDir);
114263
+ await scanner.prepareDependencies(this.preInstalledDepInfos, this.state.vulnerabilities.filter((v) => Array.isArray(v.vulnerabilityAccessPaths)), RubyHeuristics.ONLY_VULN_PATH_PACKAGES, preinstallDir);
114264
+ return scanner.getPackagesExcludedUnrelatedToHeuristic();
114265
+ }
114152
114266
  async runPhantomDependencyAnalysis() {
114153
114267
  return void 0;
114154
114268
  }
@@ -114160,9 +114274,11 @@ var RubyGemsAnalyzer = class {
114160
114274
  }
114161
114275
  analysisMetadataCollector?.(metadata);
114162
114276
  };
114163
- this.preinstalledDependencies = existsSync16(resolve21(this.projectDir, "vendor")) ? "YES" : "NO";
114277
+ this.preinstalledDependencies = existsSync18(resolve21(this.projectDir, "vendor")) ? "YES" : "NO";
114164
114278
  try {
114165
- return await analyzeWithHeuristics(this.state, vulns, [RubyHeuristics.ONLY_VULN_PATH_PACKAGES], false, await this.prepareScanner(), wrappedCollector, statusUpdater);
114279
+ const scanner = await this.prepareScanner();
114280
+ checkForInstallErrors(scanner.getPackagesExcludedUnrelatedToHeuristic(), this.state.otherAnalysisOptions);
114281
+ return await analyzeWithHeuristics(this.state, vulns, [RubyHeuristics.ONLY_VULN_PATH_PACKAGES], false, scanner, wrappedCollector, statusUpdater);
114166
114282
  } finally {
114167
114283
  await this.scanner.cleanup();
114168
114284
  }
@@ -114220,9 +114336,16 @@ var RustAnalyzer = class {
114220
114336
  constructor(state) {
114221
114337
  this.state = state;
114222
114338
  }
114339
+ async createScanner(tmpDir, statusUpdater) {
114340
+ return this.state.workspaceData.type === "coana" ? RustCodeAwareVulnerabilityScanner.initFromDependencyTree(this.state.workspaceData.data.dependencyTree, statusUpdater) : RustCodeAwareVulnerabilityScanner.initFromSocketArtifacts(this.state.subprojectDir, this.state.workspacePath, this.state.workspaceData.data.artifacts, tmpDir, statusUpdater);
114341
+ }
114342
+ async installDependencies(preinstallDir) {
114343
+ const scanner = await this.createScanner(preinstallDir);
114344
+ return scanner.getPackagesExcludedUnrelatedToHeuristic();
114345
+ }
114223
114346
  async runPhantomDependencyAnalysis() {
114224
114347
  return withTmpDirectory("cargo-phantom-dependency-analysis", async (tmpDir) => {
114225
- const scanner = this.state.workspaceData.type === "coana" ? RustCodeAwareVulnerabilityScanner.initFromDependencyTree(this.state.workspaceData.data.dependencyTree) : await RustCodeAwareVulnerabilityScanner.initFromSocketArtifacts(this.state.subprojectDir, this.state.workspacePath, this.state.workspaceData.data.artifacts, tmpDir);
114348
+ const scanner = await this.createScanner(tmpDir);
114226
114349
  return scanner.runPhantomDependencyAnalysis(this.state.reachabilityAnalysisOptions.timeoutSeconds.allVulnRuns);
114227
114350
  });
114228
114351
  }
@@ -114234,11 +114357,17 @@ var RustAnalyzer = class {
114234
114357
  }
114235
114358
  analysisMetadataCollector?.(metadata);
114236
114359
  };
114237
- return withTmpDirectory("cargo-reachability-analysis", async (tmpDir) => {
114238
- const scanner = this.state.workspaceData.type === "coana" ? RustCodeAwareVulnerabilityScanner.initFromDependencyTree(this.state.workspaceData.data.dependencyTree, statusUpdater) : await RustCodeAwareVulnerabilityScanner.initFromSocketArtifacts(this.state.subprojectDir, this.state.workspacePath, this.state.workspaceData.data.artifacts, tmpDir, statusUpdater);
114360
+ const preinstallDir = this.state.preinstallDir;
114361
+ const runWithTmpDir = async (tmpDir) => {
114362
+ const scanner = await this.createScanner(tmpDir, statusUpdater);
114363
+ checkForInstallErrors(scanner.getPackagesExcludedUnrelatedToHeuristic(), this.state.otherAnalysisOptions);
114239
114364
  const heuristicsInOrder = [RusticaHeuristics.ALL_PACKAGES];
114240
114365
  return await analyzeWithHeuristics(this.state, vulns, heuristicsInOrder, false, scanner, wrappedCollector, statusUpdater);
114241
- });
114366
+ };
114367
+ if (preinstallDir) {
114368
+ return runWithTmpDir(preinstallDir);
114369
+ }
114370
+ return withTmpDirectory("cargo-reachability-analysis", runWithTmpDir);
114242
114371
  }
114243
114372
  async getWorkspaceDiagnostics() {
114244
114373
  let sourceFilesDetected;
@@ -114277,6 +114406,17 @@ var ecosystemAnalyzer = {
114277
114406
  };
114278
114407
  var apiKey2 = COANA_API_KEY ? { type: "present", value: COANA_API_KEY } : { type: "missing" };
114279
114408
  var dashboardAPI3 = new DashboardAPI(process.env.SOCKET_MODE === "true", process.env.DISABLE_ANALYTICS_SHARING === "true");
114409
+ async function installDependenciesForAnalysis(state, preinstallDir) {
114410
+ const projectDir = resolve22(state.subprojectDir, state.workspacePath);
114411
+ const ecosystem = state.workspaceData.data.type;
114412
+ logger.info(`Pre-installing dependencies for project at "${relative10(state.rootWorkingDir, projectDir) || "."}" (${ecosystem})`);
114413
+ const constructor = ecosystemAnalyzer[ecosystem];
114414
+ if (!constructor)
114415
+ throw Error(`No analyzer associated with ecosystem ${ecosystem}`);
114416
+ const analyzer = new constructor(state, projectDir);
114417
+ const failedPackages = await analyzer.installDependencies(preinstallDir);
114418
+ return { failedPackages };
114419
+ }
114280
114420
  async function runReachabilityAnalysis(state) {
114281
114421
  const projectDir = resolve22(state.subprojectDir, state.workspacePath);
114282
114422
  const ecosystem = state.workspaceData.data.type;
@@ -114308,9 +114448,30 @@ async function getReachabilityAnalyzersStateFromInput(rootWorkingDir, subproject
114308
114448
  }
114309
114449
 
114310
114450
  // dist/reachability-analyzers-cli.js
114311
- var runReachabilityAnalysisCmd = new Command().name("runReachabilityAnalysis").argument("<rootWorkingDir>", "Directory where Coana is run").argument("<subprojectDir>", "Project root of directory being analyzed").argument("<workspacePath>", "Path to directory to analyze relative to subprojectDir").option("-d, --debug", "Enable debug logging", false).option("-s, --silent", "Silence all debug/warning output", false).option("--coana-socket-path <socketPath>", "Coana socket path").option("--silent-spinner", "Silence spinner", "CI" in process.env || !process.stdin.isTTY).requiredOption("-i, --input-file <inputFile>", "Input file for data and vulnerabilities").requiredOption("-o, --output-file <outputFile>", "Output file for the results").configureHelp({ sortSubcommands: true, sortOptions: true }).action(async (rootWorkingDir, subprojectDir, workspacePath, options) => withLoggerAndSpinner("Coana Reachability Analyzers", options, async () => {
114451
+ var runReachabilityAnalysisCmd = new Command().name("runReachabilityAnalysis").argument("<rootWorkingDir>", "Directory where Coana is run").argument("<subprojectDir>", "Project root of directory being analyzed").argument("<workspacePath>", "Path to directory to analyze relative to subprojectDir").option("-d, --debug", "Enable debug logging", false).option("-s, --silent", "Silence all debug/warning output", false).option("--coana-socket-path <socketPath>", "Coana socket path").option("--silent-spinner", "Silence spinner", "CI" in process.env || !process.stdin.isTTY).option("--preinstall-dir <preinstallDir>", "Directory with pre-installed dependencies").requiredOption("-i, --input-file <inputFile>", "Input file for data and vulnerabilities").requiredOption("-o, --output-file <outputFile>", "Output file for the results").configureHelp({ sortSubcommands: true, sortOptions: true }).action(async (rootWorkingDir, subprojectDir, workspacePath, options) => withLoggerAndSpinner("Coana Reachability Analyzers", options, async () => {
114452
+ try {
114453
+ const state = await getReachabilityAnalyzersStateFromInput(rootWorkingDir, subprojectDir, workspacePath, options.inputFile);
114454
+ if (options.preinstallDir) {
114455
+ state.preinstallDir = options.preinstallDir;
114456
+ }
114457
+ const result = await runReachabilityAnalysis(state);
114458
+ if (options.outputFile) {
114459
+ logger.debug("Writing result to file", options.outputFile);
114460
+ await writeFile10(options.outputFile, JSON.stringify({ result }));
114461
+ } else {
114462
+ logger.info("Result:", JSON.stringify(result, null, 2));
114463
+ }
114464
+ } catch (e) {
114465
+ if (e instanceof InstallError && options.outputFile) {
114466
+ await writeFile10(options.outputFile, JSON.stringify({ error: { type: "InstallError", failedPackages: e.failedPackages } }));
114467
+ return;
114468
+ }
114469
+ throw e;
114470
+ }
114471
+ }, "reachability-analyzer"));
114472
+ var installDependenciesCmd = new Command().name("installDependencies").argument("<rootWorkingDir>", "Directory where Coana is run").argument("<subprojectDir>", "Project root of directory being analyzed").argument("<workspacePath>", "Path to directory to analyze relative to subprojectDir").option("-d, --debug", "Enable debug logging", false).option("-s, --silent", "Silence all debug/warning output", false).option("--coana-socket-path <socketPath>", "Coana socket path").option("--silent-spinner", "Silence spinner", "CI" in process.env || !process.stdin.isTTY).requiredOption("-i, --input-file <inputFile>", "Input file for data and vulnerabilities").requiredOption("-o, --output-file <outputFile>", "Output file for the results").requiredOption("--preinstall-dir <preinstallDir>", "Directory to install dependencies into").configureHelp({ sortSubcommands: true, sortOptions: true }).action(async (rootWorkingDir, subprojectDir, workspacePath, options) => withLoggerAndSpinner("Coana Reachability Analyzers - Install Dependencies", options, async () => {
114312
114473
  const state = await getReachabilityAnalyzersStateFromInput(rootWorkingDir, subprojectDir, workspacePath, options.inputFile);
114313
- const result = await runReachabilityAnalysis(state);
114474
+ const result = await installDependenciesForAnalysis(state, options.preinstallDir);
114314
114475
  if (options.outputFile) {
114315
114476
  logger.debug("Writing result to file", options.outputFile);
114316
114477
  await writeFile10(options.outputFile, JSON.stringify({ result }));
@@ -114366,7 +114527,7 @@ var runOnPackageRegistryPackageCmd = new Command().name("runOnPackageRegistryPac
114366
114527
  }
114367
114528
  }, "reachability-analyzer");
114368
114529
  });
114369
- new Command().addCommand(runReachabilityAnalysisCmd, { isDefault: true }).addCommand(runOnDependencyChainCmd).addCommand(runOnPackageRegistryPackageCmd).parseAsync();
114530
+ new Command().addCommand(runReachabilityAnalysisCmd, { isDefault: true }).addCommand(installDependenciesCmd).addCommand(runOnDependencyChainCmd).addCommand(runOnPackageRegistryPackageCmd).parseAsync();
114370
114531
  /*! Bundled license information:
114371
114532
 
114372
114533
  safe-buffer/index.js: