@coana-tech/cli 14.12.210 → 15.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.mjs +357 -58
- package/package.json +1 -1
- package/reachability-analyzers-cli.mjs +10914 -10345
- package/repos/coana-tech/goana/bin/goana-darwin-amd64.gz +0 -0
- package/repos/coana-tech/goana/bin/goana-darwin-arm64.gz +0 -0
- package/repos/coana-tech/goana/bin/goana-linux-amd64.gz +0 -0
- package/repos/coana-tech/goana/bin/goana-linux-arm64.gz +0 -0
- package/repos/coana-tech/javap-service/javap-service.jar +0 -0
package/cli.mjs
CHANGED
|
@@ -199708,7 +199708,7 @@ var {
|
|
|
199708
199708
|
} = import_index.default;
|
|
199709
199709
|
|
|
199710
199710
|
// dist/index.js
|
|
199711
|
-
import { mkdir as mkdir7, mkdtemp as mkdtemp2, readFile as readFile38, rm as
|
|
199711
|
+
import { mkdir as mkdir7, mkdtemp as mkdtemp2, readFile as readFile38, rm as rm4, writeFile as writeFile17 } from "fs/promises";
|
|
199712
199712
|
import { tmpdir as tmpdir5 } from "os";
|
|
199713
199713
|
import { dirname as dirname26, join as join35, resolve as resolve44 } from "path";
|
|
199714
199714
|
|
|
@@ -203822,6 +203822,8 @@ function getPurlType(ecosystem) {
|
|
|
203822
203822
|
return "cargo" /* CARGO */;
|
|
203823
203823
|
case "RUBYGEMS":
|
|
203824
203824
|
return "gem" /* GEM */;
|
|
203825
|
+
case "COMPOSER":
|
|
203826
|
+
return "composer" /* COMPOSER */;
|
|
203825
203827
|
default:
|
|
203826
203828
|
throw Error(`Unsupported ecosystem: ${ecosystem}`);
|
|
203827
203829
|
}
|
|
@@ -203842,6 +203844,8 @@ function getAdvisoryEcosystemFromPurlType(purlType) {
|
|
|
203842
203844
|
return "RUST";
|
|
203843
203845
|
case "gem" /* GEM */:
|
|
203844
203846
|
return "RUBYGEMS";
|
|
203847
|
+
case "composer" /* COMPOSER */:
|
|
203848
|
+
return "COMPOSER";
|
|
203845
203849
|
default:
|
|
203846
203850
|
return void 0;
|
|
203847
203851
|
}
|
|
@@ -203892,6 +203896,8 @@ function getNameFromNamespaceAndName(purlType, namespace2, name2) {
|
|
|
203892
203896
|
return name2;
|
|
203893
203897
|
case "golang" /* GOLANG */:
|
|
203894
203898
|
return namespace2 ? `${namespace2}/${name2}` : name2;
|
|
203899
|
+
case "composer" /* COMPOSER */:
|
|
203900
|
+
return namespace2 ? `${namespace2}/${name2}` : name2;
|
|
203895
203901
|
default:
|
|
203896
203902
|
return name2;
|
|
203897
203903
|
}
|
|
@@ -212117,7 +212123,7 @@ var ecosystemToSupport = {
|
|
|
212117
212123
|
}
|
|
212118
212124
|
},
|
|
212119
212125
|
COMPOSER: {
|
|
212120
|
-
supportStatus: "
|
|
212126
|
+
supportStatus: "reachability-analysis-support",
|
|
212121
212127
|
fixesComputation: false,
|
|
212122
212128
|
packageManagers: {
|
|
212123
212129
|
COMPOSER: {
|
|
@@ -231970,6 +231976,16 @@ import assert15 from "node:assert";
|
|
|
231970
231976
|
import { platform as platform8 } from "os";
|
|
231971
231977
|
import { join as join27, posix as posix2, relative as relative18, sep as sep3 } from "path";
|
|
231972
231978
|
|
|
231979
|
+
// ../web-compat-utils/dist/analysis-error-keys.js
|
|
231980
|
+
var InstallError = class extends Error {
|
|
231981
|
+
failedPackages;
|
|
231982
|
+
constructor(failedPackages) {
|
|
231983
|
+
super(`Failed to install packages: ${failedPackages.join(", ")}`);
|
|
231984
|
+
this.failedPackages = failedPackages;
|
|
231985
|
+
this.name = "InstallError";
|
|
231986
|
+
}
|
|
231987
|
+
};
|
|
231988
|
+
|
|
231973
231989
|
// ../utils/src/tmp-file.ts
|
|
231974
231990
|
import { rm, mkdtemp, cp as cp4, lstat as lstat2 } from "fs/promises";
|
|
231975
231991
|
import { tmpdir as tmpdir4 } from "os";
|
|
@@ -232170,7 +232186,7 @@ var ecosystemToSupport2 = {
|
|
|
232170
232186
|
}
|
|
232171
232187
|
},
|
|
232172
232188
|
COMPOSER: {
|
|
232173
|
-
supportStatus: "
|
|
232189
|
+
supportStatus: "reachability-analysis-support",
|
|
232174
232190
|
fixesComputation: false,
|
|
232175
232191
|
packageManagers: {
|
|
232176
232192
|
COMPOSER: {
|
|
@@ -232364,6 +232380,7 @@ var pullDockerImage = memoize(async (image) => {
|
|
|
232364
232380
|
var ONE_DAY_IN_MS = 24 * 60 * 60 * 1e3;
|
|
232365
232381
|
var TMP_DIR_IN_DOCKER = "/coana-tmp";
|
|
232366
232382
|
var SOCKET_PATH_IN_DOCKER = "/coana.sock";
|
|
232383
|
+
var PREINSTALL_DIR_IN_DOCKER = "/coana-preinstall";
|
|
232367
232384
|
var OtherModulesCommunicator = class {
|
|
232368
232385
|
constructor(rootWorkingDir, options, apiKey) {
|
|
232369
232386
|
this.rootWorkingDir = rootWorkingDir;
|
|
@@ -232400,6 +232417,8 @@ var OtherModulesCommunicator = class {
|
|
|
232400
232417
|
switch (cmd) {
|
|
232401
232418
|
case "runReachabilityAnalysis":
|
|
232402
232419
|
return "Running reachability analysis";
|
|
232420
|
+
case "installDependencies":
|
|
232421
|
+
return "Pre-installing dependencies";
|
|
232403
232422
|
case "runOnDependencyChain":
|
|
232404
232423
|
return "Running reachability analysis on dependency chain";
|
|
232405
232424
|
case "runOnPackageRegistryPackage":
|
|
@@ -232471,7 +232490,7 @@ var OtherModulesCommunicator = class {
|
|
|
232471
232490
|
);
|
|
232472
232491
|
return JSON.parse(await readFile32(outputFilePathThisProcess, "utf-8")).result;
|
|
232473
232492
|
}
|
|
232474
|
-
async runReachabilityAnalyzerCommand(commandName, ecosystem, subprojectPath, workspacePath, args2, env, rootWorkingDirOverride, displaySubprojectPath) {
|
|
232493
|
+
async runReachabilityAnalyzerCommand(commandName, ecosystem, subprojectPath, workspacePath, args2, env, rootWorkingDirOverride, displaySubprojectPath, extraDockerArgs) {
|
|
232475
232494
|
const tmpDir = await this.getTmpDirForSubproject(displaySubprojectPath ?? subprojectPath);
|
|
232476
232495
|
const effectiveRootWorkingDir = rootWorkingDirOverride ?? this.rootWorkingDir;
|
|
232477
232496
|
const effectiveSubprojectPath = rootWorkingDirOverride ?? subprojectPath;
|
|
@@ -232518,7 +232537,8 @@ var OtherModulesCommunicator = class {
|
|
|
232518
232537
|
finalArgs,
|
|
232519
232538
|
subprojectPath,
|
|
232520
232539
|
tmpDir,
|
|
232521
|
-
env
|
|
232540
|
+
env,
|
|
232541
|
+
extraDockerArgs
|
|
232522
232542
|
);
|
|
232523
232543
|
}
|
|
232524
232544
|
if (!succeeded)
|
|
@@ -232528,7 +232548,7 @@ var OtherModulesCommunicator = class {
|
|
|
232528
232548
|
}
|
|
232529
232549
|
);
|
|
232530
232550
|
}
|
|
232531
|
-
async runReachabilityAnalyzerCommandWithOutput(commandName, ecosystem, subprojectPath, workspacePath, args2, env, rootWorkingDirOverride, displaySubprojectPath) {
|
|
232551
|
+
async runReachabilityAnalyzerCommandWithOutput(commandName, ecosystem, subprojectPath, workspacePath, args2, env, rootWorkingDirOverride, displaySubprojectPath, extraDockerArgs) {
|
|
232532
232552
|
const tmpDir = await this.getTmpDirForSubproject(displaySubprojectPath ?? subprojectPath);
|
|
232533
232553
|
const outputFileName = `${v4_default()}-${commandName}-output.json`;
|
|
232534
232554
|
const outputFilePathThisProcess = join27(tmpDir, outputFileName);
|
|
@@ -232541,16 +232561,22 @@ var OtherModulesCommunicator = class {
|
|
|
232541
232561
|
[...args2, "-o", outputFilePathOtherProcess],
|
|
232542
232562
|
env,
|
|
232543
232563
|
rootWorkingDirOverride,
|
|
232544
|
-
displaySubprojectPath
|
|
232564
|
+
displaySubprojectPath,
|
|
232565
|
+
extraDockerArgs
|
|
232545
232566
|
);
|
|
232546
|
-
|
|
232567
|
+
const output = JSON.parse(await readFile32(outputFilePathThisProcess, "utf-8"));
|
|
232568
|
+
if (output.error?.type === "InstallError") {
|
|
232569
|
+
throw new InstallError(output.error.failedPackages);
|
|
232570
|
+
}
|
|
232571
|
+
return output.result;
|
|
232547
232572
|
}
|
|
232548
|
-
async runInDocker(ecosystem, image, entryPoint, commandName, args2, subprojectPath, tmpDir, env = process.env) {
|
|
232573
|
+
async runInDocker(ecosystem, image, entryPoint, commandName, args2, subprojectPath, tmpDir, env = process.env, extraDockerArgs) {
|
|
232549
232574
|
if (!await pullDockerImage(image)) return false;
|
|
232550
232575
|
const envArgs = Object.keys(env).filter((key) => DOCKER_ENV_WHITE_LIST.some((whiteListedKey) => key.includes(whiteListedKey))).flatMap((key) => ["-e", key]);
|
|
232551
232576
|
const cmd = cmdt`docker run --pull=never --rm -v ${this.rootWorkingDir}:/project -v ${tmpDir}:${TMP_DIR_IN_DOCKER}
|
|
232552
232577
|
-v=${this.options.coanaSocketPath}:${SOCKET_PATH_IN_DOCKER}
|
|
232553
232578
|
${await getEcosystemSpecificDockerArgs(ecosystem)}
|
|
232579
|
+
${extraDockerArgs ?? []}
|
|
232554
232580
|
${envArgs} ${image} ${entryPoint} ${commandName} ${args2}`;
|
|
232555
232581
|
return execPipeAndLogOnFailure2(cmd, subprojectPath, { env, timeout: ONE_DAY_IN_MS });
|
|
232556
232582
|
}
|
|
@@ -232611,7 +232637,42 @@ var OtherModulesCommunicator = class {
|
|
|
232611
232637
|
workspacePaths
|
|
232612
232638
|
);
|
|
232613
232639
|
}
|
|
232614
|
-
async
|
|
232640
|
+
async installDependencies(subprojectPath, workspacePath, workspaceData, ecosystem, vulnerabilities, reachabilityAnalysisOptions, otherAnalysisOptions, preinstallDir) {
|
|
232641
|
+
const tmpDir = await this.getTmpDirForSubproject(subprojectPath);
|
|
232642
|
+
if (isNexeMode()) {
|
|
232643
|
+
await extractAllToolsForNexeMode();
|
|
232644
|
+
}
|
|
232645
|
+
const inputFileName = `${v4_default()}-installDependencies-input.json`;
|
|
232646
|
+
const inputFileThisProcess = join27(tmpDir, inputFileName);
|
|
232647
|
+
const inputFileOtherProcess = this.options.runWithoutDocker ? inputFileThisProcess : posix2.join(TMP_DIR_IN_DOCKER, inputFileName);
|
|
232648
|
+
const preinstallDirOtherProcess = this.options.runWithoutDocker ? preinstallDir : PREINSTALL_DIR_IN_DOCKER;
|
|
232649
|
+
const extraDockerArgs = this.options.runWithoutDocker ? void 0 : ["-v", `${preinstallDir}:${PREINSTALL_DIR_IN_DOCKER}`];
|
|
232650
|
+
await writeFile12(
|
|
232651
|
+
inputFileThisProcess,
|
|
232652
|
+
JSON.stringify({
|
|
232653
|
+
workspaceData,
|
|
232654
|
+
vulnerabilities,
|
|
232655
|
+
reachabilityAnalysisOptions,
|
|
232656
|
+
otherAnalysisOptions
|
|
232657
|
+
})
|
|
232658
|
+
);
|
|
232659
|
+
return this.runReachabilityAnalyzerCommandWithOutput(
|
|
232660
|
+
"installDependencies",
|
|
232661
|
+
ecosystem,
|
|
232662
|
+
subprojectPath,
|
|
232663
|
+
workspacePath,
|
|
232664
|
+
argt`-i ${inputFileOtherProcess} --preinstall-dir ${preinstallDirOtherProcess}`,
|
|
232665
|
+
{
|
|
232666
|
+
...process.env,
|
|
232667
|
+
COANA_REPORT_ID: this.options.reportId,
|
|
232668
|
+
COANA_API_KEY: this.apiKey.type === "present" ? this.apiKey.value : ""
|
|
232669
|
+
},
|
|
232670
|
+
void 0,
|
|
232671
|
+
void 0,
|
|
232672
|
+
extraDockerArgs
|
|
232673
|
+
);
|
|
232674
|
+
}
|
|
232675
|
+
async runReachabilityAnalysis(subprojectPath, workspacePath, workspaceData, ecosystem, vulnerabilities, reachabilityAnalysisOptions, otherAnalysisOptions, rootWorkingDirOverride, displaySubprojectPath, preinstallDir) {
|
|
232615
232676
|
const tmpDir = await this.getTmpDirForSubproject(displaySubprojectPath ?? subprojectPath);
|
|
232616
232677
|
if (isNexeMode()) {
|
|
232617
232678
|
await extractAllToolsForNexeMode();
|
|
@@ -232619,6 +232680,8 @@ var OtherModulesCommunicator = class {
|
|
|
232619
232680
|
const inputFileName = `${v4_default()}-runReachabilityAnalysis-input.json`;
|
|
232620
232681
|
const inputFileThisProcess = join27(tmpDir, inputFileName);
|
|
232621
232682
|
const inputFileOtherProcess = this.options.runWithoutDocker ? inputFileThisProcess : posix2.join(TMP_DIR_IN_DOCKER, inputFileName);
|
|
232683
|
+
const preinstallDirOtherProcess = preinstallDir ? this.options.runWithoutDocker ? preinstallDir : PREINSTALL_DIR_IN_DOCKER : void 0;
|
|
232684
|
+
const extraDockerArgs = preinstallDir && !this.options.runWithoutDocker ? ["-v", `${preinstallDir}:${PREINSTALL_DIR_IN_DOCKER}`] : void 0;
|
|
232622
232685
|
await writeFile12(
|
|
232623
232686
|
inputFileThisProcess,
|
|
232624
232687
|
JSON.stringify({
|
|
@@ -232628,19 +232691,21 @@ var OtherModulesCommunicator = class {
|
|
|
232628
232691
|
otherAnalysisOptions
|
|
232629
232692
|
})
|
|
232630
232693
|
);
|
|
232694
|
+
const preinstallArgs = preinstallDirOtherProcess ? argt`--preinstall-dir ${preinstallDirOtherProcess}` : [];
|
|
232631
232695
|
return this.runReachabilityAnalyzerCommandWithOutput(
|
|
232632
232696
|
"runReachabilityAnalysis",
|
|
232633
232697
|
ecosystem,
|
|
232634
232698
|
subprojectPath,
|
|
232635
232699
|
workspacePath,
|
|
232636
|
-
argt`-i ${inputFileOtherProcess}`,
|
|
232700
|
+
[...argt`-i ${inputFileOtherProcess}`, ...preinstallArgs],
|
|
232637
232701
|
{
|
|
232638
232702
|
...process.env,
|
|
232639
232703
|
COANA_REPORT_ID: this.options.reportId,
|
|
232640
232704
|
COANA_API_KEY: this.apiKey.type === "present" ? this.apiKey.value : ""
|
|
232641
232705
|
},
|
|
232642
232706
|
rootWorkingDirOverride,
|
|
232643
|
-
displaySubprojectPath
|
|
232707
|
+
displaySubprojectPath,
|
|
232708
|
+
extraDockerArgs
|
|
232644
232709
|
);
|
|
232645
232710
|
}
|
|
232646
232711
|
};
|
|
@@ -234897,7 +234962,7 @@ function prettyApplyFixesTo(applyFixesToOption) {
|
|
|
234897
234962
|
// dist/cli-core.js
|
|
234898
234963
|
import assert16 from "node:assert";
|
|
234899
234964
|
import { existsSync as existsSync30, writeFileSync as writeFileSync3 } from "fs";
|
|
234900
|
-
import { mkdir as mkdir6, writeFile as writeFile15 } from "fs/promises";
|
|
234965
|
+
import { mkdir as mkdir6, rm as rm3, writeFile as writeFile15 } from "fs/promises";
|
|
234901
234966
|
var import_lodash15 = __toESM(require_lodash(), 1);
|
|
234902
234967
|
import os2 from "os";
|
|
234903
234968
|
import { join as join34, relative as relative22, resolve as resolve42 } from "path";
|
|
@@ -235363,6 +235428,20 @@ function isShortestPath(root3, vulnPath) {
|
|
|
235363
235428
|
var FAILED_TO_INSTALL_PACKAGE_KEY = "[UNABLE_TO_INSTALL_PACKAGE_ERROR]: ";
|
|
235364
235429
|
var CLI_ANALYSIS_ERROR_MESSAGE = "Sharing log due to analysis error";
|
|
235365
235430
|
var ANALYSIS_LOW_CONFIDENCE_MESSAGE = "Analysis had low confidence in result";
|
|
235431
|
+
var InstallError2 = class extends Error {
|
|
235432
|
+
constructor(failedPackages) {
|
|
235433
|
+
super(`Failed to install packages: ${failedPackages.join(", ")}`);
|
|
235434
|
+
this.failedPackages = failedPackages;
|
|
235435
|
+
this.name = "InstallError";
|
|
235436
|
+
}
|
|
235437
|
+
};
|
|
235438
|
+
var AnalysisHaltError = class extends Error {
|
|
235439
|
+
constructor(errorMessages) {
|
|
235440
|
+
super(`Analysis failed with errors: ${errorMessages.join("; ")}`);
|
|
235441
|
+
this.errorMessages = errorMessages;
|
|
235442
|
+
this.name = "AnalysisHaltError";
|
|
235443
|
+
}
|
|
235444
|
+
};
|
|
235366
235445
|
|
|
235367
235446
|
// ../web-compat-utils/src/pluralize.ts
|
|
235368
235447
|
function pluralize(count, word) {
|
|
@@ -236280,9 +236359,10 @@ function toSocketReachabilitySchema(vulnerability) {
|
|
|
236280
236359
|
if (codeAwareScanResult.type === "analysisError") {
|
|
236281
236360
|
return { type: "error", error: codeAwareScanResult.message };
|
|
236282
236361
|
}
|
|
236362
|
+
if (codeAwareScanResult.type === "skippedUnsupportedEcosystem") {
|
|
236363
|
+
return { type: "unknown", reason: codeAwareScanResult.message };
|
|
236364
|
+
}
|
|
236283
236365
|
if (codeAwareScanResult.type === "otherError") {
|
|
236284
|
-
if (codeAwareScanResult.message.includes("Reachability analysis for languages using"))
|
|
236285
|
-
return { type: "unknown", reason: codeAwareScanResult.message };
|
|
236286
236366
|
return { type: "error", error: codeAwareScanResult.message };
|
|
236287
236367
|
}
|
|
236288
236368
|
if (codeAwareScanResult.type === "success") {
|
|
@@ -251742,7 +251822,7 @@ async function onlineScan(dependencyTree, apiKey, timeout) {
|
|
|
251742
251822
|
}
|
|
251743
251823
|
|
|
251744
251824
|
// dist/version.js
|
|
251745
|
-
var version3 = "
|
|
251825
|
+
var version3 = "15.0.2";
|
|
251746
251826
|
|
|
251747
251827
|
// dist/cli-core.js
|
|
251748
251828
|
var { mapValues, omit, partition, pickBy: pickBy2 } = import_lodash15.default;
|
|
@@ -251956,8 +252036,11 @@ var CliCore = class {
|
|
|
251956
252036
|
await this.cleanupLogging();
|
|
251957
252037
|
} catch (e) {
|
|
251958
252038
|
await this.spinner.fail();
|
|
251959
|
-
|
|
251960
|
-
|
|
252039
|
+
const isExpectedHalt = e instanceof InstallError2 || e instanceof AnalysisHaltError;
|
|
252040
|
+
if (!isExpectedHalt) {
|
|
252041
|
+
logger.error("CLI failed with error:", e);
|
|
252042
|
+
}
|
|
252043
|
+
await this.shareErrorLogWithBackend(e, !isExpectedHalt, "cli-error");
|
|
251961
252044
|
await this.cleanupLogging();
|
|
251962
252045
|
process.exit(1);
|
|
251963
252046
|
}
|
|
@@ -252005,46 +252088,79 @@ var CliCore = class {
|
|
|
252005
252088
|
logger.info(bold(` ${ecosystem} (${workspaces.length}):`));
|
|
252006
252089
|
workspaces.forEach((workspace) => logger.info(bold(` ${workspace}`)));
|
|
252007
252090
|
});
|
|
252091
|
+
let preinstallDir;
|
|
252092
|
+
try {
|
|
252093
|
+
logger.info(bold("Pre-installing dependencies for all projects..."));
|
|
252094
|
+
preinstallDir = await createTmpDirectory("coana-preinstall");
|
|
252095
|
+
await this.preInstallAllDependencies(preinstallDir, ecosystemToWorkspaceToAnalysisData, ecosystemToWorkspaceToVulnerabilities, otherModulesCommunicator);
|
|
252096
|
+
logger.info(bold("All dependencies pre-installed successfully"));
|
|
252097
|
+
} catch (e) {
|
|
252098
|
+
if (this.options.reachContinueOnInstallErrors) {
|
|
252099
|
+
logger.info("Continuing with pre-installed dependencies despite errors");
|
|
252100
|
+
} else {
|
|
252101
|
+
if (preinstallDir) {
|
|
252102
|
+
await rm3(preinstallDir, { recursive: true, force: true }).catch((err) => logger.debug(`Failed to cleanup preinstall dir: ${err instanceof Error ? err.message : String(err)}`));
|
|
252103
|
+
}
|
|
252104
|
+
throw e;
|
|
252105
|
+
}
|
|
252106
|
+
}
|
|
252008
252107
|
const vulnsWithResults = [];
|
|
252009
252108
|
const allWorkspaceDiagnostics = [];
|
|
252010
252109
|
const allWorkspaceTimings = /* @__PURE__ */ new Map();
|
|
252011
252110
|
const allEcosystems = Object.entries(ecosystemToWorkspaceToAnalysisData);
|
|
252012
252111
|
const totalEcosystems = allEcosystems.length;
|
|
252013
252112
|
let currentOverallWorkspace = 0;
|
|
252014
|
-
|
|
252015
|
-
|
|
252016
|
-
|
|
252017
|
-
|
|
252018
|
-
|
|
252019
|
-
|
|
252020
|
-
|
|
252021
|
-
|
|
252022
|
-
|
|
252023
|
-
|
|
252024
|
-
|
|
252025
|
-
|
|
252026
|
-
|
|
252027
|
-
|
|
252028
|
-
|
|
252029
|
-
|
|
252030
|
-
|
|
252031
|
-
|
|
252032
|
-
|
|
252033
|
-
|
|
252034
|
-
|
|
252035
|
-
|
|
252036
|
-
|
|
252037
|
-
|
|
252038
|
-
|
|
252039
|
-
|
|
252040
|
-
|
|
252041
|
-
|
|
252042
|
-
|
|
252043
|
-
|
|
252044
|
-
|
|
252113
|
+
try {
|
|
252114
|
+
for (const [ecosystemIndex, [ecosystem, workspaceToAnalysisData]] of allEcosystems.entries()) {
|
|
252115
|
+
this.sendProgress("RUN_ON_SUBPROJECT", true, this.rootWorkingDirectory);
|
|
252116
|
+
const isEcosystemToAnalyze = !this.options.purlTypes || this.options.purlTypes.some((purlType) => getAdvisoryEcosystemFromPurlType(purlType) === ecosystem);
|
|
252117
|
+
if (!isEcosystemToAnalyze) {
|
|
252118
|
+
logger.info(`Skipping reachability analysis for ecosystem ${getPurlType(ecosystem)} since it is not included in the list of ecosystems to analyze.`);
|
|
252119
|
+
}
|
|
252120
|
+
const ecosystemPreinstallDir = preinstallDir ? join34(preinstallDir, ecosystem) : void 0;
|
|
252121
|
+
const { vulnerabilities, diagnostics, timings } = await this.runReachabilityAnalysisForWorkspaces(
|
|
252122
|
+
workspaceToAnalysisData,
|
|
252123
|
+
ecosystemToWorkspaceToVulnerabilities[ecosystem] ?? {},
|
|
252124
|
+
{},
|
|
252125
|
+
// We do not need the direct dependencies for socket mode
|
|
252126
|
+
otherModulesCommunicator,
|
|
252127
|
+
this.rootWorkingDirectory,
|
|
252128
|
+
ecosystem,
|
|
252129
|
+
[
|
|
252130
|
+
"NPM",
|
|
252131
|
+
"PIP",
|
|
252132
|
+
"GO",
|
|
252133
|
+
"MAVEN",
|
|
252134
|
+
"NUGET",
|
|
252135
|
+
"RUST",
|
|
252136
|
+
"RUBYGEMS",
|
|
252137
|
+
...process.env.COANA_ENABLE_PHP_ANALYSIS ? ["COMPOSER"] : []
|
|
252138
|
+
].includes(ecosystem) && isEcosystemToAnalyze,
|
|
252139
|
+
(workspaceName, workspaceNumber, totalWorkspacesForCurrentEcosystem) => {
|
|
252140
|
+
currentOverallWorkspace++;
|
|
252141
|
+
logger.info(bold(`Analyzing ecosystem ${ecosystem} for project ${workspaceName} (${workspaceNumber}/${totalWorkspacesForCurrentEcosystem}) - Overall progress: Project ${currentOverallWorkspace}/${totalWorkspaces}, ecosystem ${ecosystemIndex + 1}/${totalEcosystems}`));
|
|
252142
|
+
},
|
|
252143
|
+
ecosystemPreinstallDir
|
|
252144
|
+
);
|
|
252145
|
+
vulnsWithResults.push(...Object.values(vulnerabilities).flat());
|
|
252146
|
+
for (const [workspacePath, workspaceDiagnostics] of Object.entries(diagnostics)) {
|
|
252147
|
+
allWorkspaceDiagnostics.push({
|
|
252148
|
+
// the workspace path is the subproject path in socket mode
|
|
252149
|
+
subprojectPath: workspacePath ?? ".",
|
|
252150
|
+
workspacePath: ".",
|
|
252151
|
+
purl_type: getPurlType(ecosystem),
|
|
252152
|
+
diagnostics: workspaceDiagnostics
|
|
252153
|
+
});
|
|
252154
|
+
if (timings[workspacePath] !== void 0) {
|
|
252155
|
+
allWorkspaceTimings.set(`${ecosystem}:${workspacePath}`, timings[workspacePath]);
|
|
252156
|
+
}
|
|
252045
252157
|
}
|
|
252158
|
+
this.sendProgress("RUN_ON_SUBPROJECT", false, this.rootWorkingDirectory);
|
|
252159
|
+
}
|
|
252160
|
+
} finally {
|
|
252161
|
+
if (preinstallDir) {
|
|
252162
|
+
await rm3(preinstallDir, { recursive: true, force: true }).catch((err) => logger.debug(`Failed to cleanup preinstall dir: ${err instanceof Error ? err.message : String(err)}`));
|
|
252046
252163
|
}
|
|
252047
|
-
this.sendProgress("RUN_ON_SUBPROJECT", false, this.rootWorkingDirectory);
|
|
252048
252164
|
}
|
|
252049
252165
|
for (const vuln of vulnsWithResults) {
|
|
252050
252166
|
if (vuln.codeAwareScanResult.type === "success" && vuln.codeAwareScanResult.lowConfidence === true && vuln.codeAwareScanResult.detectedOccurrences?.stacks?.length === 0) {
|
|
@@ -252055,6 +252171,15 @@ var CliCore = class {
|
|
|
252055
252171
|
vuln.reachability = "UNKNOWN";
|
|
252056
252172
|
}
|
|
252057
252173
|
}
|
|
252174
|
+
if (!this.options.reachContinueOnAnalysisErrors) {
|
|
252175
|
+
const isInstallError = (msg) => msg.startsWith(FAILED_TO_INSTALL_PACKAGE_KEY);
|
|
252176
|
+
const errorMessages = vulnsWithResults.filter((v) => v.codeAwareScanResult.type === "analysisError" || v.codeAwareScanResult.type === "otherError").map((v) => v.codeAwareScanResult.message).filter((msg) => !this.options.reachContinueOnInstallErrors || !isInstallError(msg));
|
|
252177
|
+
if (errorMessages.length > 0) {
|
|
252178
|
+
const uniqueErrors = [...new Set(errorMessages)];
|
|
252179
|
+
this.logAnalysisErrors(errorMessages.length, uniqueErrors);
|
|
252180
|
+
throw new AnalysisHaltError(uniqueErrors);
|
|
252181
|
+
}
|
|
252182
|
+
}
|
|
252058
252183
|
displayResultsSummary(vulnsWithResults, allWorkspaceTimings);
|
|
252059
252184
|
displayWorkspaceDiagnosticsSummary(allWorkspaceDiagnostics, vulnsWithResults);
|
|
252060
252185
|
await this.shareLogIfAnalysisError(vulnsWithResults);
|
|
@@ -252308,7 +252433,7 @@ Subproject: ${subproject}`);
|
|
|
252308
252433
|
this.sendProgress("RUN_ON_SUBPROJECT", false, subProjAndWsPath.subprojectPath);
|
|
252309
252434
|
}
|
|
252310
252435
|
}
|
|
252311
|
-
async runReachabilityAnalysisForWorkspaces(workspacePathToDataForAnalysis, workspaceToVulnerabilities, workspaceToDirectDependencies, otherModulesCommunicator, subprojectPath, ecosystem, reachabilitySupported, analysisStarting) {
|
|
252436
|
+
async runReachabilityAnalysisForWorkspaces(workspacePathToDataForAnalysis, workspaceToVulnerabilities, workspaceToDirectDependencies, otherModulesCommunicator, subprojectPath, ecosystem, reachabilitySupported, analysisStarting, preinstallDir) {
|
|
252312
252437
|
const workspaces = Object.keys(workspacePathToDataForAnalysis);
|
|
252313
252438
|
const totalWorkspaces = workspaces.length;
|
|
252314
252439
|
const concurrency = Number(this.options.concurrency);
|
|
@@ -252373,6 +252498,8 @@ Subproject: ${subproject}`);
|
|
|
252373
252498
|
[effectiveSubprojectPath, releaseDir] = await npmProjectDirPool.acquire();
|
|
252374
252499
|
}
|
|
252375
252500
|
try {
|
|
252501
|
+
const perProjectEcosystems = ["PIP", "RUBYGEMS", "COMPOSER"];
|
|
252502
|
+
const effectivePreinstallDir = preinstallDir && perProjectEcosystems.includes(ecosystem) ? join34(preinstallDir, workspacePath.replace(/\//g, "_")) : preinstallDir;
|
|
252376
252503
|
const resAndDiagnostics = await this.runReachabilityAnalysis(
|
|
252377
252504
|
otherModulesCommunicator,
|
|
252378
252505
|
effectiveSubprojectPath,
|
|
@@ -252384,7 +252511,8 @@ Subproject: ${subproject}`);
|
|
|
252384
252511
|
// When using temp copy for concurrent analysis, override rootWorkingDir
|
|
252385
252512
|
npmProjectDirPool ? effectiveSubprojectPath : void 0,
|
|
252386
252513
|
// Pass original subprojectPath for display when using temp copy
|
|
252387
|
-
npmProjectDirPool ? subprojectPath : void 0
|
|
252514
|
+
npmProjectDirPool ? subprojectPath : void 0,
|
|
252515
|
+
effectivePreinstallDir
|
|
252388
252516
|
);
|
|
252389
252517
|
augmentedVulnerabilitiesToAnalyze = resAndDiagnostics.vulnerabilities;
|
|
252390
252518
|
workspaceDiagnostics = resAndDiagnostics.diagnostics;
|
|
@@ -252395,7 +252523,7 @@ Subproject: ${subproject}`);
|
|
|
252395
252523
|
augmentedVulnerabilitiesToAnalyze = vulnerabilitiesToAnalyze.map((v) => ({
|
|
252396
252524
|
...v,
|
|
252397
252525
|
results: {
|
|
252398
|
-
type: "
|
|
252526
|
+
type: "skippedUnsupportedEcosystem",
|
|
252399
252527
|
message: `Reachability analysis for languages using ${ecosystem} not supported yet`
|
|
252400
252528
|
}
|
|
252401
252529
|
}));
|
|
@@ -252407,6 +252535,10 @@ Subproject: ${subproject}`);
|
|
|
252407
252535
|
];
|
|
252408
252536
|
return [workspacePath, { vulnerabilities: augmentedVulnerabilities, diagnostics: workspaceDiagnostics }];
|
|
252409
252537
|
} catch (e) {
|
|
252538
|
+
if (e instanceof InstallError2) {
|
|
252539
|
+
this.logInstallError(e.failedPackages, ecosystem);
|
|
252540
|
+
throw e;
|
|
252541
|
+
}
|
|
252410
252542
|
logger.error(`${workspacePrefix}Reachability analysis failed for workspace ${workspacePath} in subproject ${subprojectPath}: ${e.message}`);
|
|
252411
252543
|
return [
|
|
252412
252544
|
workspacePath,
|
|
@@ -252483,6 +252615,141 @@ Subproject: ${subproject}`);
|
|
|
252483
252615
|
}
|
|
252484
252616
|
}
|
|
252485
252617
|
}
|
|
252618
|
+
/**
|
|
252619
|
+
* Pre-installs all dependencies across all ecosystems and workspaces to the given dir.
|
|
252620
|
+
* If any installations fail, reports all failures and throws an InstallError.
|
|
252621
|
+
*/
|
|
252622
|
+
async preInstallAllDependencies(preinstallDir, ecosystemToWorkspaceToAnalysisData, ecosystemToWorkspaceToVulnerabilities, otherModulesCommunicator) {
|
|
252623
|
+
const installTasks = [];
|
|
252624
|
+
for (const [ecosystem, workspaceToAnalysisData] of Object.entries(ecosystemToWorkspaceToAnalysisData)) {
|
|
252625
|
+
if (ecosystem === "GO" && this.options.reachContinueOnInstallErrors)
|
|
252626
|
+
continue;
|
|
252627
|
+
const ecosystemDir = join34(preinstallDir, ecosystem);
|
|
252628
|
+
await mkdir6(ecosystemDir, { recursive: true });
|
|
252629
|
+
for (const [workspace, analysisData] of Object.entries(workspaceToAnalysisData)) {
|
|
252630
|
+
const perProjectEcosystems = ["PIP", "RUBYGEMS", "COMPOSER"];
|
|
252631
|
+
const installDir = perProjectEcosystems.includes(ecosystem) ? join34(ecosystemDir, workspace.replace(/\//g, "_")) : ecosystemDir;
|
|
252632
|
+
if (installDir !== ecosystemDir) {
|
|
252633
|
+
await mkdir6(installDir, { recursive: true });
|
|
252634
|
+
}
|
|
252635
|
+
installTasks.push({
|
|
252636
|
+
ecosystem,
|
|
252637
|
+
workspace,
|
|
252638
|
+
analysisData,
|
|
252639
|
+
vulnerabilities: ecosystemToWorkspaceToVulnerabilities[ecosystem]?.[workspace] ?? [],
|
|
252640
|
+
installDir
|
|
252641
|
+
});
|
|
252642
|
+
}
|
|
252643
|
+
}
|
|
252644
|
+
const allFailures = [];
|
|
252645
|
+
await asyncMap(installTasks, async ({ ecosystem, workspace, analysisData, vulnerabilities, installDir }) => {
|
|
252646
|
+
try {
|
|
252647
|
+
const result = await otherModulesCommunicator.installDependencies(workspace, ".", analysisData, ecosystem, vulnerabilities, {
|
|
252648
|
+
timeoutSeconds: {
|
|
252649
|
+
allVulnRuns: this.analysisTimeoutInSeconds,
|
|
252650
|
+
bucketedRuns: bucketedAnalysisTimeoutInSeconds
|
|
252651
|
+
},
|
|
252652
|
+
memoryLimitInMB: this.analysisMemoryLimitInMb
|
|
252653
|
+
}, {
|
|
252654
|
+
haltOnInstallErrors: false
|
|
252655
|
+
}, installDir);
|
|
252656
|
+
if (result.failedPackages.length > 0) {
|
|
252657
|
+
logger.info(` ${ecosystem}/${workspace}: failed to install ${result.failedPackages.join(", ")}`);
|
|
252658
|
+
allFailures.push({ ecosystem, workspace, failedPackages: result.failedPackages });
|
|
252659
|
+
} else {
|
|
252660
|
+
logger.info(` ${ecosystem}/${workspace}: all packages installed successfully`);
|
|
252661
|
+
}
|
|
252662
|
+
} catch (e) {
|
|
252663
|
+
const message2 = e instanceof Error ? e.message : String(e);
|
|
252664
|
+
logger.info(` ${ecosystem}/${workspace}: pre-install failed (${message2})`);
|
|
252665
|
+
allFailures.push({ ecosystem, workspace, failedPackages: [`(pre-install error: ${message2})`] });
|
|
252666
|
+
}
|
|
252667
|
+
}, Number(this.options.concurrency));
|
|
252668
|
+
if (allFailures.length > 0) {
|
|
252669
|
+
this.logAggregatedInstallErrors(allFailures);
|
|
252670
|
+
const allFailed = allFailures.flatMap((f6) => f6.failedPackages);
|
|
252671
|
+
throw new InstallError2(allFailed);
|
|
252672
|
+
}
|
|
252673
|
+
}
|
|
252674
|
+
logAggregatedInstallErrors(failures) {
|
|
252675
|
+
const displayLines = [""];
|
|
252676
|
+
const goFailures = failures.filter((f6) => f6.ecosystem === "GO");
|
|
252677
|
+
const installFailures = failures.filter((f6) => f6.ecosystem !== "GO");
|
|
252678
|
+
if (installFailures.length > 0) {
|
|
252679
|
+
displayLines.push(kleur_default.red().bold("Installation Errors"));
|
|
252680
|
+
displayLines.push("The following packages failed to install during dependency pre-installation:");
|
|
252681
|
+
displayLines.push("");
|
|
252682
|
+
const byEcosystem = /* @__PURE__ */ new Map();
|
|
252683
|
+
for (const f6 of installFailures) {
|
|
252684
|
+
if (!byEcosystem.has(f6.ecosystem))
|
|
252685
|
+
byEcosystem.set(f6.ecosystem, []);
|
|
252686
|
+
byEcosystem.get(f6.ecosystem).push(f6);
|
|
252687
|
+
}
|
|
252688
|
+
for (const [ecosystem, ecosystemFailures] of byEcosystem) {
|
|
252689
|
+
displayLines.push(kleur_default.bold(` ${ecosystem}:`));
|
|
252690
|
+
for (const f6 of ecosystemFailures) {
|
|
252691
|
+
const pkgList = f6.failedPackages.sort();
|
|
252692
|
+
const pkgLines = pkgList.slice(0, 10).map((pkg) => ` - ${pkg}`);
|
|
252693
|
+
if (pkgList.length > 10) {
|
|
252694
|
+
pkgLines.push(` ... and ${pkgList.length - 10} more`);
|
|
252695
|
+
}
|
|
252696
|
+
displayLines.push(` ${f6.workspace}:`);
|
|
252697
|
+
displayLines.push(...pkgLines);
|
|
252698
|
+
}
|
|
252699
|
+
displayLines.push("");
|
|
252700
|
+
}
|
|
252701
|
+
displayLines.push("Pre-installing dependencies before running the analysis might fix this problem.", "");
|
|
252702
|
+
}
|
|
252703
|
+
if (goFailures.length > 0) {
|
|
252704
|
+
displayLines.push(kleur_default.red().bold("Build Errors"));
|
|
252705
|
+
displayLines.push("The following Go projects failed to build:");
|
|
252706
|
+
displayLines.push("");
|
|
252707
|
+
for (const f6 of goFailures) {
|
|
252708
|
+
displayLines.push(` ${f6.workspace}`);
|
|
252709
|
+
}
|
|
252710
|
+
displayLines.push("");
|
|
252711
|
+
}
|
|
252712
|
+
displayLines.push("Use --reach-continue-on-install-errors to proceed with precomputed (Tier 2) reachability results for affected vulnerabilities.", "");
|
|
252713
|
+
logger.error(displayLines.join("\n"));
|
|
252714
|
+
}
|
|
252715
|
+
logInstallError(failedPackages, ecosystem) {
|
|
252716
|
+
const pkgList = failedPackages.sort();
|
|
252717
|
+
const pkgLines = pkgList.slice(0, 20).map((pkg) => ` - ${pkg}`);
|
|
252718
|
+
if (pkgList.length > 20) {
|
|
252719
|
+
pkgLines.push(` ... and ${pkgList.length - 20} more`);
|
|
252720
|
+
}
|
|
252721
|
+
const installCmd = getInstallCommandForEcosystem(ecosystem);
|
|
252722
|
+
const displayLines = [
|
|
252723
|
+
"",
|
|
252724
|
+
kleur_default.red().bold("Installation Error"),
|
|
252725
|
+
"The following packages failed to install during reachability analysis:",
|
|
252726
|
+
...pkgLines,
|
|
252727
|
+
"",
|
|
252728
|
+
"To fix this, pre-install dependencies before running the analysis:",
|
|
252729
|
+
"",
|
|
252730
|
+
` ${installCmd}`,
|
|
252731
|
+
"",
|
|
252732
|
+
"Alternatively, use --reach-continue-on-install-errors to proceed with precomputed (Tier 2) reachability results for affected vulnerabilities.",
|
|
252733
|
+
""
|
|
252734
|
+
];
|
|
252735
|
+
logger.error(displayLines.join("\n"));
|
|
252736
|
+
}
|
|
252737
|
+
logAnalysisErrors(totalErrorCount, uniqueErrors) {
|
|
252738
|
+
const errorLines = uniqueErrors.slice(0, 20).map((msg) => ` - ${msg}`);
|
|
252739
|
+
if (uniqueErrors.length > 20) {
|
|
252740
|
+
errorLines.push(` ... and ${uniqueErrors.length - 20} more`);
|
|
252741
|
+
}
|
|
252742
|
+
const displayLines = [
|
|
252743
|
+
"",
|
|
252744
|
+
kleur_default.red().bold("Analysis Error"),
|
|
252745
|
+
`Reachability analysis failed for ${totalErrorCount} ${totalErrorCount === 1 ? "vulnerability" : "vulnerabilities"}:`,
|
|
252746
|
+
...errorLines,
|
|
252747
|
+
"",
|
|
252748
|
+
"Use --reach-continue-on-analysis-errors to continue when encountering analysis errors and fallback to precomputed (Tier 2) reachability results for affected vulnerabilities.",
|
|
252749
|
+
""
|
|
252750
|
+
];
|
|
252751
|
+
logger.error(displayLines.join("\n"));
|
|
252752
|
+
}
|
|
252486
252753
|
shouldExcludeAnalyzingWorkspace(subprojectPath, workspacePath, workspacePrefix = "") {
|
|
252487
252754
|
const shouldExcludeWorkspaceForAnalysis = shouldIgnoreDueToExcludeDirsOrChangedFiles({
|
|
252488
252755
|
mainProjectDir: this.rootWorkingDirectory,
|
|
@@ -252495,7 +252762,7 @@ Subproject: ${subproject}`);
|
|
|
252495
252762
|
}
|
|
252496
252763
|
return shouldExcludeWorkspaceForAnalysis;
|
|
252497
252764
|
}
|
|
252498
|
-
async runReachabilityAnalysis(otherModulesCommunicator, subprojectPath, workspacePath, workspaceData, ecosystem, vulnerabilities, workspacePrefix = "", rootWorkingDirOverride, displaySubprojectPath) {
|
|
252765
|
+
async runReachabilityAnalysis(otherModulesCommunicator, subprojectPath, workspacePath, workspaceData, ecosystem, vulnerabilities, workspacePrefix = "", rootWorkingDirOverride, displaySubprojectPath, preinstallDir) {
|
|
252499
252766
|
const [vulnsWithActualAPIPatterns, result] = partition(vulnerabilities, (v) => Array.isArray(v.vulnerabilityAccessPaths));
|
|
252500
252767
|
for (const v of result)
|
|
252501
252768
|
v.results = typeof v.vulnerabilityAccessPaths === "string" ? { type: "noAnalysisCheck", message: v.vulnerabilityAccessPaths } : { type: "missingVulnerabilityPattern" };
|
|
@@ -252521,8 +252788,9 @@ Subproject: ${subproject}`);
|
|
|
252521
252788
|
}, {
|
|
252522
252789
|
disableBucketing: !!this.options.disableAnalysisSplitting,
|
|
252523
252790
|
lightweightReachability: this.options.lightweightReachability,
|
|
252524
|
-
skipCacheUsage: this.options.skipCacheUsage
|
|
252525
|
-
|
|
252791
|
+
skipCacheUsage: this.options.skipCacheUsage,
|
|
252792
|
+
haltOnInstallErrors: !!this.options.socketMode && !this.options.reachContinueOnInstallErrors
|
|
252793
|
+
}, rootWorkingDirOverride, displaySubprojectPath, preinstallDir);
|
|
252526
252794
|
result.push(...analysisResult.vulnerabilities);
|
|
252527
252795
|
this.sendProgress("REACHABILITY_ANALYSIS", false, subprojectPath, workspacePath);
|
|
252528
252796
|
return { vulnerabilities: result, diagnostics: analysisResult.diagnostics };
|
|
@@ -252661,6 +252929,37 @@ async function getGitDataToMetadataIfAvailable(rootWorkingDirectory) {
|
|
|
252661
252929
|
logger.debug("Unable to get git data. Is the folder even in a git repository?", e);
|
|
252662
252930
|
}
|
|
252663
252931
|
}
|
|
252932
|
+
function getInstallCommandForEcosystem(ecosystem) {
|
|
252933
|
+
switch (ecosystem) {
|
|
252934
|
+
case "NPM":
|
|
252935
|
+
return "npm install";
|
|
252936
|
+
case "PIP":
|
|
252937
|
+
return "uv sync (or your project-specific install command)";
|
|
252938
|
+
case "GO":
|
|
252939
|
+
return "go mod download";
|
|
252940
|
+
case "MAVEN":
|
|
252941
|
+
return "mvn dependency:resolve";
|
|
252942
|
+
case "NUGET":
|
|
252943
|
+
return "dotnet restore";
|
|
252944
|
+
case "RUST":
|
|
252945
|
+
return "cargo fetch";
|
|
252946
|
+
case "RUBYGEMS":
|
|
252947
|
+
return "bundle config set --local deployment true; bundle install";
|
|
252948
|
+
case "COMPOSER":
|
|
252949
|
+
return "composer install";
|
|
252950
|
+
case "ERLANG":
|
|
252951
|
+
return "rebar3 get-deps";
|
|
252952
|
+
case "PUB":
|
|
252953
|
+
return "dart pub get";
|
|
252954
|
+
case "SWIFT":
|
|
252955
|
+
return "swift package resolve";
|
|
252956
|
+
case "ACTIONS":
|
|
252957
|
+
return "Install project dependencies using your package manager";
|
|
252958
|
+
default:
|
|
252959
|
+
ecosystem;
|
|
252960
|
+
return "Install project dependencies using your package manager";
|
|
252961
|
+
}
|
|
252962
|
+
}
|
|
252664
252963
|
|
|
252665
252964
|
// dist/internal/analysis-debug-info-transformer.js
|
|
252666
252965
|
import { writeFile as writeFile16 } from "fs/promises";
|
|
@@ -252783,7 +253082,7 @@ async function writeAnalysisDebugInfo(outputFilePath, ecosystemToWorkspaceToVuln
|
|
|
252783
253082
|
handleNexeBinaryMode();
|
|
252784
253083
|
var program2 = new Command();
|
|
252785
253084
|
var run2 = new Command();
|
|
252786
|
-
run2.name("run").argument("<path>", "File system path to folder containing the project").option("-o, --output-dir <path>", "Write json report to <path>/coana-report.json").option("-d, --debug", "Enable debug logging", false).option("-s, --silent", "Silence all debug/warning output", false).option("--silent-spinner", "Silence spinner", "CI" in process.env || !process.stdin.isTTY).option("-p, --print-report", "Print the report to the console", false).option("--offline-database <path>", "Path to a coana-offline-db.json file for running the CLI without internet connectivity", void 0).option("-t, --timeout <timeout>", "Set API <timeout> in milliseconds to Coana backend.", "300000").option("-a, --analysis-timeout <timeout>", "Set <timeout> in seconds for each reachability analysis run").option("--memory-limit <memoryInMB>", "Set memory limit for analysis to <memoryInMB> megabytes of memory.", "8192").option("-c, --concurrency <concurrency>", "Set the maximum number of concurrent reachability analysis runs. It's recommended to choose a concurrency level that ensures that each analysis run has at least the --memory-limit amount of memory available. NPM reachability analysis does not support concurrent execution, so the concurrency level is ignored for NPM.", "1").option("--api-key <key>", "Set the Coana dashboard API key. By setting you also enable the dashboard integration.").addOption(new Option("--write-report-to-file", "Write the report dashboard-compatible report to dashboard-report.json. This report may help the Coana team debug issues with the report insertion mechanism.").default(false).hideHelp()).option("--project-name <repoName>", "Set the name of the repository. Used for dashboard integration.").option("--repo-url <repoUrl>", "Set the URL of the repository. Used for dashboard integration.").option("--include-dirs <relativeDirs...>", "globs for directories to include from the detection of subprojects (space-separated)(use relative paths from the project root). Notice, projects that are not included may still be scanned if they are referenced from included projects.").option("--exclude-dirs <relativeDirs...>", "globs for directories to exclude from the detection of subprojects (space-separated)(use relative paths from the project root). Notice, excluded projects may still be scanned if they are referenced from non-excluded projects.").option("--disable-analysis-splitting", "Limits Coana to at most 1 reachability analysis run per workspace").option("--print-analysis-log-file", "Store log output from the JavaScript/TypeScript reachability analysis in the file js-analysis.log file in the root of each workspace", false).option("--entry-points <entryPoints...>", "List of files to analyze for root workspace. The reachability analysis automatically analyzes all files used by the entry points. If not provided, all JavaScript and TypeScript files are considered entry points. For non-root workspaces, all JavaScript and TypeScript files are analyzed as well.").option("--include-projects-with-no-reachability-support", "Also runs Coana on projects where we support traditional SCA, but does not yet support reachability analysis.", false).option("--ecosystems <ecosystems...>", "List of ecosystems to analyze (space-separated). Currently NPM, PIP, MAVEN, NUGET and GO are supported. Default is all supported ecosystems.").addOption(new Option("--purl-types <purlTypes...>", "List of PURL types to analyze (space-separated). Currently npm, pypi, maven, nuget, golang and cargo are supported. Default is all supported purl types.").hideHelp()).option("--changed-files <files...>", "List of files that have changed. If provided, Coana only analyzes workspaces and modules that contain changed files.").option("--disable-report-submission", "Disable the submission of the report to the Coana dashboard. Used by the pipeline blocking feature.", false).option("--disable-analytics-sharing", "Disable analytics sharing.", false).option("--provider-project <path>", "File system path to folder containing the provider project (Only supported for Maven, Gradle, and SBT)").option("--provider-workspaces <dirs...>", "List of workspaces that build the provided runtime environment (Only supported for Maven, Gradle, and SBT)", (paths) => paths.split(" ")).option("--lightweight-reachability", "Runs Coana in lightweight mode. This increases analysis speed but also raises the risk of Coana misclassifying the reachability of certain complex vulnerabilities. Recommended only for use with Coana Guardrail mode.", false).addOption(new Option("--run-without-docker", "Run package managers and reachability analyzers without using docker").default(process.env.RUN_WITHOUT_DOCKER === "true").hideHelp()).addOption(new Option("--run-env <env>", "Specifies the environment in which the CLI is run. So far only MANAGED_SCAN and UNKNOWN are supported.").default("UNKNOWN").choices(["UNKNOWN", "MANAGED_SCAN"]).hideHelp()).addOption(new Option("--guardrail-mode", "Run Coana in guardrail mode. This mode is used to prevent new reachable vulnerabilities from being introduced into the codebase. Usually run as a CI check when pushing new commits to a pull request.")).option("--ignore-failing-workspaces", "Continue processing when a workspace fails instead of exiting. Failed workspaces will be logged at termination.", false).addOption(new Option("--socket-mode <output-file>", "Run Coana in socket mode and write report to <output-file>").hideHelp()).addOption(new Option("--manifests-tar-hash <hash>", "Hash of the tarball containing all manifest files already uploaded to Socket. If provided, Socket will be used for computing dependency trees.").hideHelp()).option("--skip-cache-usage", "Do not attempt to use cached analysis configuration from previous runs", false).addOption(new Option("--lazy-mode", "Enable lazy analysis mode for JavaScript/TypeScript. This can significantly speed up analysis by only analyzing code that is actually relevant for the vulnerabilities being analyzed.").default(false).hideHelp()).addOption(new Option("--min-severity <severity>", "Set the minimum severity of vulnerabilities to analyze. Supported severities are info, low, moderate, high and critical.").choices(["info", "INFO", "low", "LOW", "moderate", "MODERATE", "high", "HIGH", "critical", "CRITICAL"])).option("--use-unreachable-from-precomputation", "Skip the reachability analysis for vulnerabilities that are already known to be unreachable from the precomputed reachability analysis (Tier 2).", false).addOption(new Option("--use-only-pregenerated-sboms", "Only include artifacts that have CDX or SPDX files in their manifest files.").default(false).hideHelp()).option("--disable-external-tool-checks", "Disable validation of external tools (npm, python, go, etc.) before running analysis.", false).version(version3).configureHelp({ sortOptions: true }).action(async (path9, options) => {
|
|
253085
|
+
run2.name("run").argument("<path>", "File system path to folder containing the project").option("-o, --output-dir <path>", "Write json report to <path>/coana-report.json").option("-d, --debug", "Enable debug logging", false).option("-s, --silent", "Silence all debug/warning output", false).option("--silent-spinner", "Silence spinner", "CI" in process.env || !process.stdin.isTTY).option("-p, --print-report", "Print the report to the console", false).option("--offline-database <path>", "Path to a coana-offline-db.json file for running the CLI without internet connectivity", void 0).option("-t, --timeout <timeout>", "Set API <timeout> in milliseconds to Coana backend.", "300000").option("-a, --analysis-timeout <timeout>", "Set <timeout> in seconds for each reachability analysis run").option("--memory-limit <memoryInMB>", "Set memory limit for analysis to <memoryInMB> megabytes of memory.", "8192").option("-c, --concurrency <concurrency>", "Set the maximum number of concurrent reachability analysis runs. It's recommended to choose a concurrency level that ensures that each analysis run has at least the --memory-limit amount of memory available. NPM reachability analysis does not support concurrent execution, so the concurrency level is ignored for NPM.", "1").option("--api-key <key>", "Set the Coana dashboard API key. By setting you also enable the dashboard integration.").addOption(new Option("--write-report-to-file", "Write the report dashboard-compatible report to dashboard-report.json. This report may help the Coana team debug issues with the report insertion mechanism.").default(false).hideHelp()).option("--project-name <repoName>", "Set the name of the repository. Used for dashboard integration.").option("--repo-url <repoUrl>", "Set the URL of the repository. Used for dashboard integration.").option("--include-dirs <relativeDirs...>", "globs for directories to include from the detection of subprojects (space-separated)(use relative paths from the project root). Notice, projects that are not included may still be scanned if they are referenced from included projects.").option("--exclude-dirs <relativeDirs...>", "globs for directories to exclude from the detection of subprojects (space-separated)(use relative paths from the project root). Notice, excluded projects may still be scanned if they are referenced from non-excluded projects.").option("--disable-analysis-splitting", "Limits Coana to at most 1 reachability analysis run per workspace").option("--print-analysis-log-file", "Store log output from the JavaScript/TypeScript reachability analysis in the file js-analysis.log file in the root of each workspace", false).option("--entry-points <entryPoints...>", "List of files to analyze for root workspace. The reachability analysis automatically analyzes all files used by the entry points. If not provided, all JavaScript and TypeScript files are considered entry points. For non-root workspaces, all JavaScript and TypeScript files are analyzed as well.").option("--include-projects-with-no-reachability-support", "Also runs Coana on projects where we support traditional SCA, but does not yet support reachability analysis.", false).option("--ecosystems <ecosystems...>", "List of ecosystems to analyze (space-separated). Currently NPM, PIP, MAVEN, NUGET and GO are supported. Default is all supported ecosystems.").addOption(new Option("--purl-types <purlTypes...>", "List of PURL types to analyze (space-separated). Currently npm, pypi, maven, nuget, golang and cargo are supported. Default is all supported purl types.").hideHelp()).option("--changed-files <files...>", "List of files that have changed. If provided, Coana only analyzes workspaces and modules that contain changed files.").option("--disable-report-submission", "Disable the submission of the report to the Coana dashboard. Used by the pipeline blocking feature.", false).option("--disable-analytics-sharing", "Disable analytics sharing.", false).option("--provider-project <path>", "File system path to folder containing the provider project (Only supported for Maven, Gradle, and SBT)").option("--provider-workspaces <dirs...>", "List of workspaces that build the provided runtime environment (Only supported for Maven, Gradle, and SBT)", (paths) => paths.split(" ")).option("--lightweight-reachability", "Runs Coana in lightweight mode. This increases analysis speed but also raises the risk of Coana misclassifying the reachability of certain complex vulnerabilities. Recommended only for use with Coana Guardrail mode.", false).addOption(new Option("--run-without-docker", "Run package managers and reachability analyzers without using docker").default(process.env.RUN_WITHOUT_DOCKER === "true").hideHelp()).addOption(new Option("--run-env <env>", "Specifies the environment in which the CLI is run. So far only MANAGED_SCAN and UNKNOWN are supported.").default("UNKNOWN").choices(["UNKNOWN", "MANAGED_SCAN"]).hideHelp()).addOption(new Option("--guardrail-mode", "Run Coana in guardrail mode. This mode is used to prevent new reachable vulnerabilities from being introduced into the codebase. Usually run as a CI check when pushing new commits to a pull request.")).option("--ignore-failing-workspaces", "Continue processing when a workspace fails instead of exiting. Failed workspaces will be logged at termination.", false).option("--reach-continue-on-install-errors", "Continue analysis when package installation fails, falling back to precomputed (Tier 2) reachability results. By default, the CLI halts on installation errors in socket mode.", process.env.COANA_CONTINUE_ON_INSTALL_ERRORS === "true").option("--reach-continue-on-analysis-errors", "Continue analysis when errors occur (timeouts, OOM, parse errors, etc.), falling back to precomputed (Tier 2) reachability results. By default, the CLI halts on analysis errors in socket mode.", false).addOption(new Option("--socket-mode <output-file>", "Run Coana in socket mode and write report to <output-file>").hideHelp()).addOption(new Option("--manifests-tar-hash <hash>", "Hash of the tarball containing all manifest files already uploaded to Socket. If provided, Socket will be used for computing dependency trees.").hideHelp()).option("--skip-cache-usage", "Do not attempt to use cached analysis configuration from previous runs", false).addOption(new Option("--lazy-mode", "Enable lazy analysis mode for JavaScript/TypeScript. This can significantly speed up analysis by only analyzing code that is actually relevant for the vulnerabilities being analyzed.").default(false).hideHelp()).addOption(new Option("--min-severity <severity>", "Set the minimum severity of vulnerabilities to analyze. Supported severities are info, low, moderate, high and critical.").choices(["info", "INFO", "low", "LOW", "moderate", "MODERATE", "high", "HIGH", "critical", "CRITICAL"])).option("--use-unreachable-from-precomputation", "Skip the reachability analysis for vulnerabilities that are already known to be unreachable from the precomputed reachability analysis (Tier 2).", false).addOption(new Option("--use-only-pregenerated-sboms", "Only include artifacts that have CDX or SPDX files in their manifest files.").default(false).hideHelp()).option("--disable-external-tool-checks", "Disable validation of external tools (npm, python, go, etc.) before running analysis.", false).version(version3).configureHelp({ sortOptions: true }).action(async (path9, options) => {
|
|
252787
253086
|
process.env.DOCKER_IMAGE_TAG ??= version3;
|
|
252788
253087
|
options.ecosystems = options.ecosystems?.map((e) => e.toUpperCase());
|
|
252789
253088
|
options.minSeverity = options.minSeverity?.toUpperCase();
|
|
@@ -252838,7 +253137,7 @@ computeFixesAndUpgradePurlsCmd.name("compute-fixes-and-upgrade-purls").argument(
|
|
|
252838
253137
|
await writeFile17(outputFile, JSON.stringify(output, null, 2));
|
|
252839
253138
|
logger.info(`Result written to: ${outputFile}`);
|
|
252840
253139
|
}
|
|
252841
|
-
await
|
|
253140
|
+
await rm4(tmpDir, { recursive: true, force: true });
|
|
252842
253141
|
} catch (error) {
|
|
252843
253142
|
handleUpgradeError(error, logFile);
|
|
252844
253143
|
}
|