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