@coana-tech/cli 14.12.112 → 14.12.113

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
@@ -206052,6 +206052,8 @@ async function fetchManifestFilesFromManifestsTarHash(manifestsTarHash) {
206052
206052
  }
206053
206053
  }
206054
206054
  async function fetchArtifactsFromManifestsTarHash(manifestsTarHash, includePrecomputedReachabilityResults) {
206055
+ logger.info("Fetching artifacts from Socket backend (this may take a while)");
206056
+ logger.debug("manifests tar hash", manifestsTarHash);
206055
206057
  let responseData;
206056
206058
  try {
206057
206059
  const params = new URLSearchParams({
@@ -234402,310 +234404,10 @@ var signalFixApplied = (_fixId, subprojectPath, workspacePath, vulnerabilityFixe
234402
234404
  ${vulnerabilityFixes.map((fix) => ` ${fix.dependencyName} from ${fix.currentVersion} to ${fix.fixedVersion}`).join("\n")}`);
234403
234405
  };
234404
234406
 
234405
- // dist/internal/socket-mode-helpers-socket-dependency-trees.js
234406
- import { basename as basename9, dirname as dirname26, join as join27, sep as sep6 } from "path";
234407
- var REQUIREMENTS_FILES_SEARCH_DEPTH2 = 3;
234408
- var venvExcludes = [
234409
- "venv",
234410
- ".venv",
234411
- "env",
234412
- ".env",
234413
- "virtualenv",
234414
- ".virtualenv",
234415
- "venvs",
234416
- ".venvs",
234417
- "envs",
234418
- ".envs",
234419
- "__pycache__",
234420
- ".tox",
234421
- ".nox",
234422
- ".pytest_cache",
234423
- "site-packages",
234424
- "dist-packages",
234425
- "conda-meta",
234426
- "conda-bld",
234427
- ".mypy_cache",
234428
- ".ruff_cache",
234429
- ".hypothesis"
234430
- ];
234431
- function inferWorkspaceFromManifestPath(ecosystem, manifestPath, properPythonProjects) {
234432
- switch (ecosystem) {
234433
- case "NPM": {
234434
- const base = basename9(manifestPath);
234435
- const dir = dirname26(manifestPath);
234436
- return base === "package.json" ? dir || "." : void 0;
234437
- }
234438
- case "MAVEN": {
234439
- return ".";
234440
- }
234441
- case "PIP": {
234442
- if (venvExcludes.some((exclude) => manifestPath.startsWith(`${exclude}/`) || manifestPath.includes(`/${exclude}/`))) {
234443
- return void 0;
234444
- }
234445
- const base = basename9(manifestPath);
234446
- const dir = dirname26(manifestPath);
234447
- const workspaceDir = dir === "" ? "." : dir;
234448
- if (properPythonProjects.includes(workspaceDir)) {
234449
- return workspaceDir;
234450
- }
234451
- if (base === "poetry.lock" || base === "Pipfile.lock" || base === "uv.lock") {
234452
- return workspaceDir;
234453
- }
234454
- if (base.endsWith(".txt")) {
234455
- const properProjectDirs = properPythonProjects.filter((properProjectDir) => (properProjectDir === "." || workspaceDir === "." || workspaceDir.startsWith(properProjectDir)) && workspaceDir.replace(properProjectDir, "").split(sep6).length <= REQUIREMENTS_FILES_SEARCH_DEPTH2);
234456
- const longestProperProjectDir = l(properProjectDirs, [(d4) => d4.length, "desc"]);
234457
- if (longestProperProjectDir) {
234458
- return longestProperProjectDir;
234459
- }
234460
- return workspaceDir;
234461
- }
234462
- logger.warn(`No workspace found for manifest file ${manifestPath}`);
234463
- return void 0;
234464
- }
234465
- case "NUGET": {
234466
- return ".";
234467
- }
234468
- case "RUST": {
234469
- return dirname26(manifestPath) || ".";
234470
- }
234471
- case "GO": {
234472
- const base = basename9(manifestPath);
234473
- const dir = dirname26(manifestPath);
234474
- return base === "go.mod" ? dir || "." : void 0;
234475
- }
234476
- case "RUBYGEMS": {
234477
- return dirname26(manifestPath) || ".";
234478
- }
234479
- default: {
234480
- return ".";
234481
- }
234482
- }
234483
- }
234484
- function inferProjectFromManifestPath(ecosystem, manifestPath) {
234485
- switch (ecosystem) {
234486
- case "NPM": {
234487
- const filename = basename9(manifestPath);
234488
- if (["package-lock.json", "pnpm-lock.yaml", "pnpm-lock.yml", "yarn.lock"].includes(filename)) {
234489
- return dirname26(manifestPath) || ".";
234490
- }
234491
- return void 0;
234492
- }
234493
- }
234494
- }
234495
- function getAllToplevelAncestors(artifactMap, artifactId) {
234496
- const visited = /* @__PURE__ */ new Set();
234497
- const toplevelAncestors = /* @__PURE__ */ new Set();
234498
- function findAncestors(currentId) {
234499
- if (visited.has(currentId)) {
234500
- return;
234501
- }
234502
- visited.add(currentId);
234503
- const artifact = artifactMap.get(currentId);
234504
- if (!artifact) {
234505
- return;
234506
- }
234507
- if (artifact.toplevelAncestors && artifact.toplevelAncestors.length > 0) {
234508
- for (const ancestorId of artifact.toplevelAncestors) {
234509
- toplevelAncestors.add(ancestorId);
234510
- findAncestors(ancestorId);
234511
- }
234512
- }
234513
- }
234514
- findAncestors(artifactId);
234515
- return Array.from(toplevelAncestors);
234516
- }
234517
- async function fetchArtifactsFromSocket(rootWorkingDirectory, manifestsTarHash, mode, includePrecomputedReachabilityResults) {
234518
- logger.info("Fetching artifacts from Socket backend (this may take a while)");
234519
- logger.debug("manifests tar hash", manifestsTarHash);
234520
- try {
234521
- const { artifacts } = await fetchArtifactsFromManifestsTarHash(manifestsTarHash, includePrecomputedReachabilityResults);
234522
- const properPythonProjects = [];
234523
- const pipArtifactToRepresentativeManifest = {};
234524
- for (const artifact of artifacts) {
234525
- if (artifact.type === "pypi" && artifact.manifestFiles) {
234526
- pipArtifactToRepresentativeManifest[simplePurl(artifact.type, artifact.namespace ?? "", artifact.name ?? "", artifact.version ?? "")] = artifact;
234527
- }
234528
- }
234529
- const allFiles = await getFilesRelative(rootWorkingDirectory, venvExcludes);
234530
- for (const file of allFiles) {
234531
- const base = basename9(file);
234532
- const workspaceDir = dirname26(file) || ".";
234533
- if (base === "pyproject.toml" || base === "setup.py" && await isSetupPySetuptools(join27(rootWorkingDirectory, file))) {
234534
- if (!properPythonProjects.includes(workspaceDir)) {
234535
- properPythonProjects.push(workspaceDir);
234536
- }
234537
- }
234538
- }
234539
- const dotnetManifestFiles = await glob([
234540
- "*.sln",
234541
- "*.*proj",
234542
- "*.targets",
234543
- "*.props",
234544
- "*.projitems",
234545
- "*.nuspec",
234546
- "packages.config",
234547
- "packages.*.config",
234548
- "packages.lock.json"
234549
- ], { cwd: rootWorkingDirectory, nodir: true, ignore: ["**/obj/**", "**/bin/**"], matchBase: true });
234550
- const artifactMap = new Map(artifacts.map((a4) => [a4.id, a4]));
234551
- const ecosystemToWorkspaceToAnalysisData = {};
234552
- const ecosystemWorkspaceVulnIds = /* @__PURE__ */ new Set();
234553
- const ecosystemToWorkspaceToVulnerabilities = {};
234554
- const purlsFailedToFindWorkspace = /* @__PURE__ */ new Set();
234555
- for (const artifact of artifacts) {
234556
- let processToplevelAncestors2 = function(artifact2) {
234557
- const allAncestorIds = getAllToplevelAncestors(artifactMap, artifact2.id);
234558
- allAncestorIds.forEach((ancestorId) => artifactMap.get(ancestorId)?.manifestFiles?.forEach((ref) => manifestFiles.push(ref.file)));
234559
- };
234560
- var processToplevelAncestors = processToplevelAncestors2;
234561
- const ecosystem = getAdvisoryEcosystemFromPurlType(artifact.type);
234562
- if (!ecosystem)
234563
- continue;
234564
- const manifestFiles = [];
234565
- switch (ecosystem) {
234566
- case "NUGET": {
234567
- manifestFiles.push(...dotnetManifestFiles);
234568
- break;
234569
- }
234570
- case "PIP": {
234571
- const sPurl = simplePurl(artifact.type, artifact.namespace ?? null, artifact.name ?? null, artifact.version ?? null);
234572
- if (pipArtifactToRepresentativeManifest[sPurl]) {
234573
- manifestFiles.push(...(pipArtifactToRepresentativeManifest[sPurl].manifestFiles ?? []).map((ref) => ref.file));
234574
- }
234575
- processToplevelAncestors2(artifact);
234576
- break;
234577
- }
234578
- default: {
234579
- artifact.manifestFiles?.forEach((ref) => manifestFiles.push(ref.file));
234580
- processToplevelAncestors2(artifact);
234581
- break;
234582
- }
234583
- }
234584
- const workspaceToManifestFiles = {};
234585
- manifestFiles.forEach((manifestFile) => {
234586
- const workspace = inferWorkspaceFromManifestPath(ecosystem, manifestFile, properPythonProjects);
234587
- if (!workspace)
234588
- return;
234589
- (workspaceToManifestFiles[workspace] ??= []).push(manifestFile);
234590
- });
234591
- if (Object.keys(workspaceToManifestFiles).length === 0) {
234592
- manifestFiles.forEach((manifestFile) => {
234593
- const workspace = inferProjectFromManifestPath(ecosystem, manifestFile);
234594
- if (!workspace)
234595
- return;
234596
- (workspaceToManifestFiles[workspace] ??= []).push(manifestFile);
234597
- });
234598
- }
234599
- if (Object.keys(workspaceToManifestFiles).length === 0 && artifact.vulnerabilities && artifact.vulnerabilities.length > 0) {
234600
- purlsFailedToFindWorkspace.add(simplePurl(artifact.type, artifact.namespace ?? null, artifact.name ?? null, artifact.version ?? null));
234601
- }
234602
- for (const [workspace, manifestFiles2] of Object.entries(workspaceToManifestFiles)) {
234603
- const workspaceData = (ecosystemToWorkspaceToAnalysisData[ecosystem] ??= {})[workspace] ??= {
234604
- type: "socket",
234605
- data: {
234606
- type: ecosystem,
234607
- manifestFiles: manifestFiles2,
234608
- artifacts: []
234609
- }
234610
- };
234611
- workspaceData.type;
234612
- workspaceData.data.artifacts.push(artifact);
234613
- }
234614
- if (artifact.vulnerabilities && artifact.vulnerabilities.length > 0) {
234615
- for (const workspace of Object.keys(workspaceToManifestFiles)) {
234616
- for (const vuln of artifact.vulnerabilities) {
234617
- const vulnerability = {
234618
- url: vuln.ghsaId,
234619
- severity: vuln.severity,
234620
- purlType: artifact.type,
234621
- range: vuln.range,
234622
- name: artifact.name ?? "",
234623
- dependency: artifact.name ?? "",
234624
- vulnChainDetails: computeVulnChainDetails(artifacts, artifact.id),
234625
- vulnerabilityAccessPaths: vuln.reachabilityData?.undeterminableReachability ? vuln.reachabilityData.publicComment ?? "" : vuln.reachabilityData?.pattern ?? null,
234626
- ecosystem,
234627
- artifactId: artifact.id,
234628
- precomputedReachabilityResult: vuln.reachabilityData?.precomputedReachabilityResult ?? null
234629
- };
234630
- const vulnId = `${ecosystem}-${workspace}-${artifact.namespace}-${artifact.name}-${artifact.version}-${vulnerability.url}`;
234631
- if (!ecosystemWorkspaceVulnIds.has(vulnId)) {
234632
- ecosystemWorkspaceVulnIds.add(vulnId);
234633
- ((ecosystemToWorkspaceToVulnerabilities[ecosystem] ??= {})[workspace] ??= []).push(vulnerability);
234634
- }
234635
- }
234636
- }
234637
- }
234638
- }
234639
- if (purlsFailedToFindWorkspace.size > 0) {
234640
- logger.warn(`Failed to find workspace for the following purls with vulnerabilities: ${Array.from(purlsFailedToFindWorkspace).join(", ")}.
234641
- ${mode === "reachability" ? "This means that we will not do a full reachability analysis for these vulnerabilities, but fallback to the results from the pre-computed reachability analysis." : ""}`);
234642
- }
234643
- return {
234644
- artifacts,
234645
- ecosystemToWorkspaceToAnalysisData,
234646
- ecosystemToWorkspaceToVulnerabilities
234647
- };
234648
- } catch (error) {
234649
- logger.error("Failed to fetch artifacts from Socket backend", error);
234650
- throw error;
234651
- }
234652
- }
234653
- function computeVulnChainDetails(artifacts, vulnerableArtifactId) {
234654
- const artifactMap = new Map(artifacts.map((a4) => [a4.id, a4]));
234655
- const parentsMap = /* @__PURE__ */ new Map();
234656
- for (const artifact of artifacts) {
234657
- if (artifact.dependencies) {
234658
- for (const depId of artifact.dependencies) {
234659
- if (!parentsMap.has(depId)) {
234660
- parentsMap.set(depId, []);
234661
- }
234662
- parentsMap.get(depId).push(artifact.id);
234663
- }
234664
- }
234665
- }
234666
- const res = {
234667
- packageName: "root",
234668
- version: "0.0.0",
234669
- children: [],
234670
- transitiveDependencies: {}
234671
- };
234672
- function addNode(currentId, childId, visited) {
234673
- if (visited.has(currentId))
234674
- return;
234675
- const currentArtifact = artifactMap.get(currentId);
234676
- if (!currentArtifact)
234677
- return;
234678
- const parents4 = parentsMap.get(currentId);
234679
- const newCurrentNode = {
234680
- packageName: getNameFromNamespaceAndName(currentArtifact.type, currentArtifact.namespace, currentArtifact.name),
234681
- version: currentArtifact.version ?? void 0,
234682
- children: []
234683
- };
234684
- res.transitiveDependencies[currentId] = newCurrentNode;
234685
- if (childId && !newCurrentNode.children.includes(childId)) {
234686
- newCurrentNode.children.push(childId);
234687
- }
234688
- if (currentId === vulnerableArtifactId) {
234689
- newCurrentNode.vulnerable = true;
234690
- }
234691
- if (currentArtifact.direct && !res.children.includes(currentId)) {
234692
- res.children.push(currentId);
234693
- }
234694
- visited.add(currentId);
234695
- if (parents4) {
234696
- for (const parentId of parents4) {
234697
- addNode(parentId, currentId, visited);
234698
- }
234699
- }
234700
- }
234701
- addNode(vulnerableArtifactId, void 0, /* @__PURE__ */ new Set());
234702
- return res;
234703
- }
234704
-
234705
234407
  // dist/cli-compute-fixes-and-upgrade-purls.js
234706
234408
  async function computeFixesAndUpgradePurls(path9, options, logFile) {
234707
234409
  const autofixRunId = options.manifestsTarHash && await getSocketAPI().registerAutofixOrUpgradePurlRun(options.manifestsTarHash, options, "autofix");
234708
- const { artifacts, ghsaToVulnerableArtifactIds, socketFactArtifacts } = await computeInputForComputingFixes(path9, options);
234410
+ const { artifacts, ghsaToVulnerableArtifactIds, socketFactArtifacts } = await computeInputForComputingFixes(options);
234709
234411
  if (Object.keys(ghsaToVulnerableArtifactIds).length === 0) {
234710
234412
  logger.info("Found no vulnerabilities in the project");
234711
234413
  return { type: "no-vulnerabilities-found" };
@@ -234715,7 +234417,21 @@ async function computeFixesAndUpgradePurls(path9, options, logFile) {
234715
234417
  logger.info("Consider running the tool again, requesting a fix for one of the detected vulnerabilities");
234716
234418
  return { type: "no-ghsas-fix-requested", ghsas: Object.keys(ghsaToVulnerableArtifactIds) };
234717
234419
  }
234718
- const ghsaToVulnerableArtifactIdsToApply = options.applyFixesTo.includes("all") ? ghsaToVulnerableArtifactIds : Object.fromEntries(Object.entries(ghsaToVulnerableArtifactIds).filter(([ghsa]) => options.applyFixesTo.includes(ghsa)));
234420
+ const ghsaToVulnerableArtifactIdsToApplyBeforePurlTypeFilter = options.applyFixesTo.includes("all") ? ghsaToVulnerableArtifactIds : Object.fromEntries(Object.entries(ghsaToVulnerableArtifactIds).filter(([ghsa]) => options.applyFixesTo.includes(ghsa)));
234421
+ const ghsaToVulnerableArtifactIdsToApply = {};
234422
+ for (const [ghsa, artifactIds] of Object.entries(ghsaToVulnerableArtifactIdsToApplyBeforePurlTypeFilter)) {
234423
+ const filteredIds = artifactIds.filter((id) => {
234424
+ const artifact = socketFactArtifacts[id];
234425
+ if (!options.purlTypes || options.purlTypes.includes(artifact.type)) {
234426
+ return true;
234427
+ }
234428
+ logger.warn(`Skipping upgrade for ${purlToString(artifact)} (${ghsa}) - type '${artifact.type}' not in specified types: ${options.purlTypes.join(", ")}`);
234429
+ return false;
234430
+ });
234431
+ if (filteredIds.length > 0) {
234432
+ ghsaToVulnerableArtifactIdsToApply[ghsa] = filteredIds;
234433
+ }
234434
+ }
234719
234435
  if (Object.keys(ghsaToVulnerableArtifactIdsToApply).length === 0) {
234720
234436
  logger.info("There is no overlap between the requested fixes and the detected vulnerabilities");
234721
234437
  logger.info("Consider running the tool again, requesting a fix for one of the detected vulnerabilities");
@@ -234820,10 +234536,10 @@ async function computeFixesAndUpgradePurls(path9, options, logFile) {
234820
234536
  throw error;
234821
234537
  }
234822
234538
  }
234823
- async function computeInputForComputingFixes(path9, options) {
234539
+ async function computeInputForComputingFixes(options) {
234824
234540
  if (!options.manifestsTarHash)
234825
234541
  throw new Error("Manifests tar hash is required for computing fixes");
234826
- const { artifacts } = await fetchArtifactsFromSocket(path9, options.manifestsTarHash, "autofix");
234542
+ const { artifacts } = await fetchArtifactsFromManifestsTarHash(options.manifestsTarHash);
234827
234543
  const ghsaToVulnerableArtifactIds = {};
234828
234544
  for (const [index2, artifact] of artifacts.entries()) {
234829
234545
  if (!artifact.vulnerabilities)
@@ -234866,7 +234582,6 @@ async function computeDirectDependencyUpgrades(artifacts, fixesFound) {
234866
234582
  } else {
234867
234583
  directUpdates[purl] = { transitiveFixes: [indirectFix] };
234868
234584
  }
234869
- directUpdates[purl] = { transitiveFixes: [indirectFix] };
234870
234585
  }
234871
234586
  }
234872
234587
  packageFixes[ghsa] = {
@@ -235573,7 +235288,7 @@ var DEFAULT_REPORT_FILENAME_BASE = "coana-report";
235573
235288
  // dist/internal/exclude-dirs-from-configuration-files.js
235574
235289
  import { existsSync as existsSync22 } from "fs";
235575
235290
  import { readFile as readFile32 } from "fs/promises";
235576
- import { basename as basename10, resolve as resolve42 } from "path";
235291
+ import { basename as basename9, resolve as resolve42 } from "path";
235577
235292
  var import_yaml2 = __toESM(require_dist12(), 1);
235578
235293
  async function inferExcludeDirsFromConfigurationFiles(rootWorkingDir) {
235579
235294
  const socketYmlConfigFile = resolve42(rootWorkingDir, "socket.yml");
@@ -235593,7 +235308,7 @@ async function inferExcludeDirsFromSocketConfig(socketConfigFile) {
235593
235308
  return void 0;
235594
235309
  if (ignorePaths.some((ignorePath) => ignorePath.includes("!")))
235595
235310
  return void 0;
235596
- logger.info(`Inferring paths to exclude based on Socket config file: ${basename10(socketConfigFile)}`);
235311
+ logger.info(`Inferring paths to exclude based on Socket config file: ${basename9(socketConfigFile)}`);
235597
235312
  return config3.projectIgnorePaths;
235598
235313
  } catch (e) {
235599
235314
  return void 0;
@@ -235701,7 +235416,7 @@ async function scanForVulnerabilitiesSocketMode(dependencyTree) {
235701
235416
  range: vulnerability.range,
235702
235417
  name: dependencyTreeNode.packageName,
235703
235418
  dependency: dependencyTreeNode.packageName,
235704
- vulnChainDetails: computeVulnChainDetails2(dependencyTree, dependencyIdentifier, parentsMap),
235419
+ vulnChainDetails: computeVulnChainDetails(dependencyTree, dependencyIdentifier, parentsMap),
235705
235420
  vulnerabilityAccessPaths: vulnerability.reachabilityData?.pattern ?? null,
235706
235421
  ecosystem: dependencyTree.ecosystem
235707
235422
  });
@@ -235713,7 +235428,7 @@ async function scanForVulnerabilitiesSocketMode(dependencyTree) {
235713
235428
  }
235714
235429
  return vulnerabilities;
235715
235430
  }
235716
- function computeVulnChainDetails2(dependencyTree, dependencyIdentifier, parentsMap) {
235431
+ function computeVulnChainDetails(dependencyTree, dependencyIdentifier, parentsMap) {
235717
235432
  const res = {
235718
235433
  packageName: "root",
235719
235434
  version: "0.0.0",
@@ -235750,6 +235465,304 @@ function transformToVulnChainNode(dependencyTree) {
235750
235465
  };
235751
235466
  }
235752
235467
 
235468
+ // dist/internal/socket-mode-helpers-socket-dependency-trees.js
235469
+ import { basename as basename10, dirname as dirname26, join as join27, sep as sep6 } from "path";
235470
+ var REQUIREMENTS_FILES_SEARCH_DEPTH2 = 3;
235471
+ var venvExcludes = [
235472
+ "venv",
235473
+ ".venv",
235474
+ "env",
235475
+ ".env",
235476
+ "virtualenv",
235477
+ ".virtualenv",
235478
+ "venvs",
235479
+ ".venvs",
235480
+ "envs",
235481
+ ".envs",
235482
+ "__pycache__",
235483
+ ".tox",
235484
+ ".nox",
235485
+ ".pytest_cache",
235486
+ "site-packages",
235487
+ "dist-packages",
235488
+ "conda-meta",
235489
+ "conda-bld",
235490
+ ".mypy_cache",
235491
+ ".ruff_cache",
235492
+ ".hypothesis"
235493
+ ];
235494
+ function inferWorkspaceFromManifestPath(ecosystem, manifestPath, properPythonProjects) {
235495
+ switch (ecosystem) {
235496
+ case "NPM": {
235497
+ const base = basename10(manifestPath);
235498
+ const dir = dirname26(manifestPath);
235499
+ return base === "package.json" ? dir || "." : void 0;
235500
+ }
235501
+ case "MAVEN": {
235502
+ return ".";
235503
+ }
235504
+ case "PIP": {
235505
+ if (venvExcludes.some((exclude) => manifestPath.startsWith(`${exclude}/`) || manifestPath.includes(`/${exclude}/`))) {
235506
+ return void 0;
235507
+ }
235508
+ const base = basename10(manifestPath);
235509
+ const dir = dirname26(manifestPath);
235510
+ const workspaceDir = dir === "" ? "." : dir;
235511
+ if (properPythonProjects.includes(workspaceDir)) {
235512
+ return workspaceDir;
235513
+ }
235514
+ if (base === "poetry.lock" || base === "Pipfile.lock" || base === "uv.lock") {
235515
+ return workspaceDir;
235516
+ }
235517
+ if (base.endsWith(".txt")) {
235518
+ const properProjectDirs = properPythonProjects.filter((properProjectDir) => (properProjectDir === "." || workspaceDir === "." || workspaceDir.startsWith(properProjectDir)) && workspaceDir.replace(properProjectDir, "").split(sep6).length <= REQUIREMENTS_FILES_SEARCH_DEPTH2);
235519
+ const longestProperProjectDir = l(properProjectDirs, [(d4) => d4.length, "desc"]);
235520
+ if (longestProperProjectDir) {
235521
+ return longestProperProjectDir;
235522
+ }
235523
+ return workspaceDir;
235524
+ }
235525
+ logger.warn(`No workspace found for manifest file ${manifestPath}`);
235526
+ return void 0;
235527
+ }
235528
+ case "NUGET": {
235529
+ return ".";
235530
+ }
235531
+ case "RUST": {
235532
+ return dirname26(manifestPath) || ".";
235533
+ }
235534
+ case "GO": {
235535
+ const base = basename10(manifestPath);
235536
+ const dir = dirname26(manifestPath);
235537
+ return base === "go.mod" ? dir || "." : void 0;
235538
+ }
235539
+ case "RUBYGEMS": {
235540
+ return dirname26(manifestPath) || ".";
235541
+ }
235542
+ default: {
235543
+ return ".";
235544
+ }
235545
+ }
235546
+ }
235547
+ function inferProjectFromManifestPath(ecosystem, manifestPath) {
235548
+ switch (ecosystem) {
235549
+ case "NPM": {
235550
+ const filename = basename10(manifestPath);
235551
+ if (["package-lock.json", "pnpm-lock.yaml", "pnpm-lock.yml", "yarn.lock"].includes(filename)) {
235552
+ return dirname26(manifestPath) || ".";
235553
+ }
235554
+ return void 0;
235555
+ }
235556
+ }
235557
+ }
235558
+ function getAllToplevelAncestors(artifactMap, artifactId) {
235559
+ const visited = /* @__PURE__ */ new Set();
235560
+ const toplevelAncestors = /* @__PURE__ */ new Set();
235561
+ function findAncestors(currentId) {
235562
+ if (visited.has(currentId)) {
235563
+ return;
235564
+ }
235565
+ visited.add(currentId);
235566
+ const artifact = artifactMap.get(currentId);
235567
+ if (!artifact) {
235568
+ return;
235569
+ }
235570
+ if (artifact.toplevelAncestors && artifact.toplevelAncestors.length > 0) {
235571
+ for (const ancestorId of artifact.toplevelAncestors) {
235572
+ toplevelAncestors.add(ancestorId);
235573
+ findAncestors(ancestorId);
235574
+ }
235575
+ }
235576
+ }
235577
+ findAncestors(artifactId);
235578
+ return Array.from(toplevelAncestors);
235579
+ }
235580
+ async function fetchArtifactsFromSocket(rootWorkingDirectory, manifestsTarHash, mode, includePrecomputedReachabilityResults) {
235581
+ try {
235582
+ const { artifacts } = await fetchArtifactsFromManifestsTarHash(manifestsTarHash, includePrecomputedReachabilityResults);
235583
+ const properPythonProjects = [];
235584
+ const pipArtifactToRepresentativeManifest = {};
235585
+ for (const artifact of artifacts) {
235586
+ if (artifact.type === "pypi" && artifact.manifestFiles) {
235587
+ pipArtifactToRepresentativeManifest[simplePurl(artifact.type, artifact.namespace ?? "", artifact.name ?? "", artifact.version ?? "")] = artifact;
235588
+ }
235589
+ }
235590
+ const allFiles = await getFilesRelative(rootWorkingDirectory, venvExcludes);
235591
+ for (const file of allFiles) {
235592
+ const base = basename10(file);
235593
+ const workspaceDir = dirname26(file) || ".";
235594
+ if (base === "pyproject.toml" || base === "setup.py" && await isSetupPySetuptools(join27(rootWorkingDirectory, file))) {
235595
+ if (!properPythonProjects.includes(workspaceDir)) {
235596
+ properPythonProjects.push(workspaceDir);
235597
+ }
235598
+ }
235599
+ }
235600
+ const dotnetManifestFiles = await glob([
235601
+ "*.sln",
235602
+ "*.*proj",
235603
+ "*.targets",
235604
+ "*.props",
235605
+ "*.projitems",
235606
+ "*.nuspec",
235607
+ "packages.config",
235608
+ "packages.*.config",
235609
+ "packages.lock.json"
235610
+ ], { cwd: rootWorkingDirectory, nodir: true, ignore: ["**/obj/**", "**/bin/**"], matchBase: true });
235611
+ const artifactMap = new Map(artifacts.map((a4) => [a4.id, a4]));
235612
+ const ecosystemToWorkspaceToAnalysisData = {};
235613
+ const ecosystemWorkspaceVulnIds = /* @__PURE__ */ new Set();
235614
+ const ecosystemToWorkspaceToVulnerabilities = {};
235615
+ const purlsFailedToFindWorkspace = /* @__PURE__ */ new Set();
235616
+ for (const artifact of artifacts) {
235617
+ let processToplevelAncestors2 = function(artifact2) {
235618
+ const allAncestorIds = getAllToplevelAncestors(artifactMap, artifact2.id);
235619
+ allAncestorIds.forEach((ancestorId) => artifactMap.get(ancestorId)?.manifestFiles?.forEach((ref) => manifestFiles.push(ref.file)));
235620
+ };
235621
+ var processToplevelAncestors = processToplevelAncestors2;
235622
+ const ecosystem = getAdvisoryEcosystemFromPurlType(artifact.type);
235623
+ if (!ecosystem)
235624
+ continue;
235625
+ const manifestFiles = [];
235626
+ switch (ecosystem) {
235627
+ case "NUGET": {
235628
+ manifestFiles.push(...dotnetManifestFiles);
235629
+ break;
235630
+ }
235631
+ case "PIP": {
235632
+ const sPurl = simplePurl(artifact.type, artifact.namespace ?? null, artifact.name ?? null, artifact.version ?? null);
235633
+ if (pipArtifactToRepresentativeManifest[sPurl]) {
235634
+ manifestFiles.push(...(pipArtifactToRepresentativeManifest[sPurl].manifestFiles ?? []).map((ref) => ref.file));
235635
+ }
235636
+ processToplevelAncestors2(artifact);
235637
+ break;
235638
+ }
235639
+ default: {
235640
+ artifact.manifestFiles?.forEach((ref) => manifestFiles.push(ref.file));
235641
+ processToplevelAncestors2(artifact);
235642
+ break;
235643
+ }
235644
+ }
235645
+ const workspaceToManifestFiles = {};
235646
+ manifestFiles.forEach((manifestFile) => {
235647
+ const workspace = inferWorkspaceFromManifestPath(ecosystem, manifestFile, properPythonProjects);
235648
+ if (!workspace)
235649
+ return;
235650
+ (workspaceToManifestFiles[workspace] ??= []).push(manifestFile);
235651
+ });
235652
+ if (Object.keys(workspaceToManifestFiles).length === 0) {
235653
+ manifestFiles.forEach((manifestFile) => {
235654
+ const workspace = inferProjectFromManifestPath(ecosystem, manifestFile);
235655
+ if (!workspace)
235656
+ return;
235657
+ (workspaceToManifestFiles[workspace] ??= []).push(manifestFile);
235658
+ });
235659
+ }
235660
+ if (Object.keys(workspaceToManifestFiles).length === 0 && artifact.vulnerabilities && artifact.vulnerabilities.length > 0) {
235661
+ purlsFailedToFindWorkspace.add(simplePurl(artifact.type, artifact.namespace ?? null, artifact.name ?? null, artifact.version ?? null));
235662
+ }
235663
+ for (const [workspace, manifestFiles2] of Object.entries(workspaceToManifestFiles)) {
235664
+ const workspaceData = (ecosystemToWorkspaceToAnalysisData[ecosystem] ??= {})[workspace] ??= {
235665
+ type: "socket",
235666
+ data: {
235667
+ type: ecosystem,
235668
+ manifestFiles: manifestFiles2,
235669
+ artifacts: []
235670
+ }
235671
+ };
235672
+ workspaceData.type;
235673
+ workspaceData.data.artifacts.push(artifact);
235674
+ }
235675
+ if (artifact.vulnerabilities && artifact.vulnerabilities.length > 0) {
235676
+ for (const workspace of Object.keys(workspaceToManifestFiles)) {
235677
+ for (const vuln of artifact.vulnerabilities) {
235678
+ const vulnerability = {
235679
+ url: vuln.ghsaId,
235680
+ severity: vuln.severity,
235681
+ purlType: artifact.type,
235682
+ range: vuln.range,
235683
+ name: artifact.name ?? "",
235684
+ dependency: artifact.name ?? "",
235685
+ vulnChainDetails: computeVulnChainDetails2(artifacts, artifact.id),
235686
+ vulnerabilityAccessPaths: vuln.reachabilityData?.undeterminableReachability ? vuln.reachabilityData.publicComment ?? "" : vuln.reachabilityData?.pattern ?? null,
235687
+ ecosystem,
235688
+ artifactId: artifact.id,
235689
+ precomputedReachabilityResult: vuln.reachabilityData?.precomputedReachabilityResult ?? null
235690
+ };
235691
+ const vulnId = `${ecosystem}-${workspace}-${artifact.namespace}-${artifact.name}-${artifact.version}-${vulnerability.url}`;
235692
+ if (!ecosystemWorkspaceVulnIds.has(vulnId)) {
235693
+ ecosystemWorkspaceVulnIds.add(vulnId);
235694
+ ((ecosystemToWorkspaceToVulnerabilities[ecosystem] ??= {})[workspace] ??= []).push(vulnerability);
235695
+ }
235696
+ }
235697
+ }
235698
+ }
235699
+ }
235700
+ if (purlsFailedToFindWorkspace.size > 0) {
235701
+ logger.warn(`Failed to find workspace for the following purls with vulnerabilities: ${Array.from(purlsFailedToFindWorkspace).join(", ")}.
235702
+ ${mode === "reachability" ? "This means that we will not do a full reachability analysis for these vulnerabilities, but fallback to the results from the pre-computed reachability analysis." : ""}`);
235703
+ }
235704
+ return {
235705
+ artifacts,
235706
+ ecosystemToWorkspaceToAnalysisData,
235707
+ ecosystemToWorkspaceToVulnerabilities
235708
+ };
235709
+ } catch (error) {
235710
+ logger.error("Failed to fetch artifacts from Socket backend", error);
235711
+ throw error;
235712
+ }
235713
+ }
235714
+ function computeVulnChainDetails2(artifacts, vulnerableArtifactId) {
235715
+ const artifactMap = new Map(artifacts.map((a4) => [a4.id, a4]));
235716
+ const parentsMap = /* @__PURE__ */ new Map();
235717
+ for (const artifact of artifacts) {
235718
+ if (artifact.dependencies) {
235719
+ for (const depId of artifact.dependencies) {
235720
+ if (!parentsMap.has(depId)) {
235721
+ parentsMap.set(depId, []);
235722
+ }
235723
+ parentsMap.get(depId).push(artifact.id);
235724
+ }
235725
+ }
235726
+ }
235727
+ const res = {
235728
+ packageName: "root",
235729
+ version: "0.0.0",
235730
+ children: [],
235731
+ transitiveDependencies: {}
235732
+ };
235733
+ function addNode(currentId, childId, visited) {
235734
+ if (visited.has(currentId))
235735
+ return;
235736
+ const currentArtifact = artifactMap.get(currentId);
235737
+ if (!currentArtifact)
235738
+ return;
235739
+ const parents4 = parentsMap.get(currentId);
235740
+ const newCurrentNode = {
235741
+ packageName: getNameFromNamespaceAndName(currentArtifact.type, currentArtifact.namespace, currentArtifact.name),
235742
+ version: currentArtifact.version ?? void 0,
235743
+ children: []
235744
+ };
235745
+ res.transitiveDependencies[currentId] = newCurrentNode;
235746
+ if (childId && !newCurrentNode.children.includes(childId)) {
235747
+ newCurrentNode.children.push(childId);
235748
+ }
235749
+ if (currentId === vulnerableArtifactId) {
235750
+ newCurrentNode.vulnerable = true;
235751
+ }
235752
+ if (currentArtifact.direct && !res.children.includes(currentId)) {
235753
+ res.children.push(currentId);
235754
+ }
235755
+ visited.add(currentId);
235756
+ if (parents4) {
235757
+ for (const parentId of parents4) {
235758
+ addNode(parentId, currentId, visited);
235759
+ }
235760
+ }
235761
+ }
235762
+ addNode(vulnerableArtifactId, void 0, /* @__PURE__ */ new Set());
235763
+ return res;
235764
+ }
235765
+
235753
235766
  // dist/internal/socket-report-coana-dependency-tree.js
235754
235767
  var MAX_STACKS_TO_SEND = 10;
235755
235768
  function toSocketFacts(report, dependencyTrees, subPjToWsPathToDirectDependencies) {
@@ -250816,7 +250829,7 @@ async function onlineScan(dependencyTree, apiKey, timeout) {
250816
250829
  }
250817
250830
 
250818
250831
  // dist/version.js
250819
- var version3 = "14.12.112";
250832
+ var version3 = "14.12.113";
250820
250833
 
250821
250834
  // dist/cli-core.js
250822
250835
  var { mapValues, omit, partition, pick } = import_lodash15.default;
@@ -251744,7 +251757,7 @@ applyFixes.name("apply-fixes").argument("<path>", "File system path to the folde
251744
251757
  await applyFix(path9, fixIds, options);
251745
251758
  }).configureHelp({ sortOptions: true });
251746
251759
  var computeFixesAndUpgradePurlsCmd = new Command();
251747
- computeFixesAndUpgradePurlsCmd.name("compute-fixes-and-upgrade-purls").argument("<path>", "File system path to the folder containing the project").option("-a, --apply-fixes-to <ghsas...>", 'GHSA IDs to compute fixes for. Use "all" to compute fixes for all vulnerabilities.', []).option("--dry-run", "Show what changes would be made without actually making them", false).option("-i, --include <patterns...>", "Glob patterns to include workspaces").option("-e, --exclude <patterns...>", "Glob patterns to exclude workspaces").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("--range-style <style>", 'Range style to use for the output. Currently only "pin" is supported and it only works for npm.').option("--disable-major-updates", "Do not suggest major updates. If only major update are available, the fix will not be applied.", false).option("-o, --output-file <file>", "Writes output to a JSON file").option("--minimum-release-age <minimumReleaseAge>", "Do not allow upgrades to package versions that are newer than minimumReleaseAge. Format is 2m, 5h, 3d or 1w").option("--show-affected-direct-dependencies", "Show the affected direct dependencies for each vulnerability and what upgrades could fix them - does not apply the upgrades.", false).addOption(new Option("--run-without-docker", "Run package managers without using docker").default(process.env.RUN_WITHOUT_DOCKER === "true").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()).version(version3).action(async (path9, options) => {
251760
+ computeFixesAndUpgradePurlsCmd.name("compute-fixes-and-upgrade-purls").argument("<path>", "File system path to the folder containing the project").option("-a, --apply-fixes-to <ghsas...>", 'GHSA IDs to compute fixes for. Use "all" to compute fixes for all vulnerabilities.', []).option("--dry-run", "Show what changes would be made without actually making them", false).option("-i, --include <patterns...>", "Glob patterns to include workspaces").option("-e, --exclude <patterns...>", "Glob patterns to exclude workspaces").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("--range-style <style>", 'Range style to use for the output. Currently only "pin" is supported and it only works for npm.').option("--disable-major-updates", "Do not suggest major updates. If only major update are available, the fix will not be applied.", false).option("-o, --output-file <file>", "Writes output to a JSON file").option("--minimum-release-age <minimumReleaseAge>", "Do not allow upgrades to package versions that are newer than minimumReleaseAge. Format is 2m, 5h, 3d or 1w").option("--show-affected-direct-dependencies", "Show the affected direct dependencies for each vulnerability and what upgrades could fix them - does not apply the upgrades.", false).option("--purl-types <purlTypes...>", "List of PURL types to filter artifacts by (space-separated). Only vulnerabilities from artifacts matching these types will be included.").addOption(new Option("--run-without-docker", "Run package managers without using docker").default(process.env.RUN_WITHOUT_DOCKER === "true").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()).version(version3).action(async (path9, options) => {
251748
251761
  process.env.DOCKER_IMAGE_TAG ??= version3;
251749
251762
  if (options.outputFile && !options.outputFile.endsWith(".json")) {
251750
251763
  throw new Error("Output file must have a .json extension");
@@ -251755,6 +251768,7 @@ computeFixesAndUpgradePurlsCmd.name("compute-fixes-and-upgrade-purls").argument(
251755
251768
  if (options.rangeStyle && options.rangeStyle !== "pin") {
251756
251769
  throw new Error('Range style must be "pin"');
251757
251770
  }
251771
+ options.purlTypes = options.purlTypes?.map((t4) => t4.toLowerCase());
251758
251772
  const tmpDir = await mkdtemp2(join30(tmpdir3(), "compute-fixes-and-upgrade-purls-"));
251759
251773
  const logFile = join30(tmpDir, "compute-fixes-and-upgrade-purls.log");
251760
251774
  logger.initWinstonLogger(options.debug, logFile);
@@ -251806,11 +251820,13 @@ compareReportsCommand.name("compare-reports").argument("<baselineReportPath>", "
251806
251820
  await compareReports(baselineReport, newReport, options);
251807
251821
  });
251808
251822
  var findVulnerabilities = new Command();
251809
- findVulnerabilities.name("find-vulnerabilities").requiredOption("--manifests-tar-hash <hash>", "Hash of the tarball containing all manifest files already uploaded to Socket.").action(async (options) => {
251823
+ findVulnerabilities.name("find-vulnerabilities").requiredOption("--manifests-tar-hash <hash>", "Hash of the tarball containing all manifest files already uploaded to Socket.").option("--purl-types <purlTypes...>", "List of PURL types to filter artifacts by (space-separated). Only vulnerabilities from artifacts matching these types will be included.").action(async (options) => {
251824
+ const purlTypes = options.purlTypes?.map((t4) => t4.toLowerCase());
251810
251825
  const { artifacts } = await fetchArtifactsFromManifestsTarHash(options.manifestsTarHash);
251811
- console.log(JSON.stringify(i(artifacts.flatMap((a4) => a4.vulnerabilities?.map((v) => v.ghsaId) ?? []))));
251826
+ const filteredArtifacts = purlTypes ? artifacts.filter((a4) => purlTypes.includes(a4.type)) : artifacts;
251827
+ console.log(JSON.stringify(i(filteredArtifacts.flatMap((a4) => a4.vulnerabilities?.map((v) => v.ghsaId) ?? []))));
251812
251828
  });
251813
- program2.name("coana-cli").addCommand(run2, { isDefault: true }).addCommand(findVulnerabilities).addCommand(applyFixes).addCommand(compareReportsCommand).addCommand(computeFixesAndUpgradePurlsCmd, { hidden: true }).configureHelp({ sortSubcommands: true }).version(version3);
251829
+ program2.name("coana-cli").addCommand(run2, { isDefault: true }).addCommand(findVulnerabilities, { hidden: true }).addCommand(applyFixes).addCommand(compareReportsCommand).addCommand(computeFixesAndUpgradePurlsCmd, { hidden: true }).configureHelp({ sortSubcommands: true }).version(version3);
251814
251830
  program2.parseAsync();
251815
251831
  var defaultCliOptions = {
251816
251832
  debug: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coana-tech/cli",
3
- "version": "14.12.112",
3
+ "version": "14.12.113",
4
4
  "description": "Coana CLI",
5
5
  "type": "module",
6
6
  "bin": {