@coana-tech/cli 14.12.82 → 14.12.84
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 +50 -20
- package/package.json +1 -1
- package/repos/coana-tech/alucard/alucard.jar +0 -0
- 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/cli.mjs
CHANGED
|
@@ -229587,8 +229587,6 @@ async function upgradePurl(rootDir, upgrades, artifacts, options, logFile, cliFi
|
|
|
229587
229587
|
if (options.rangeStyle && options.rangeStyle !== "pin") {
|
|
229588
229588
|
throw new Error('Range style must be "pin"');
|
|
229589
229589
|
}
|
|
229590
|
-
logger.initWinstonLogger(options.debug);
|
|
229591
|
-
logger.silent = options.silent;
|
|
229592
229590
|
const cliRunId = cliFixRunId;
|
|
229593
229591
|
const upgradePurlRunId = cliRunId && await getSocketAPI().registerUpgradePurlRun(cliRunId, Array.from(upgrades).map(([idx, upgradeVersion]) => ({
|
|
229594
229592
|
purl: artifacts[idx],
|
|
@@ -245911,7 +245909,7 @@ async function onlineScan(dependencyTree, apiKey, timeout) {
|
|
|
245911
245909
|
}
|
|
245912
245910
|
|
|
245913
245911
|
// dist/version.js
|
|
245914
|
-
var version2 = "14.12.
|
|
245912
|
+
var version2 = "14.12.84";
|
|
245915
245913
|
|
|
245916
245914
|
// dist/cli-core.js
|
|
245917
245915
|
var { mapValues, omit, partition, pick } = import_lodash15.default;
|
|
@@ -246374,10 +246372,14 @@ Subproject: ${subproject}`);
|
|
|
246374
246372
|
async runReachabilityAnalysisForWorkspaces(workspacePathToDataForAnalysis, workspaceToVulnerabilities, workspaceToDirectDependencies, otherModulesCommunicator, subprojectPath, ecosystem, reachabilitySupported, analysisStarting) {
|
|
246375
246373
|
const workspaces = Object.keys(workspacePathToDataForAnalysis);
|
|
246376
246374
|
const totalWorkspaces = workspaces.length;
|
|
246375
|
+
const concurrency = Number(this.options.concurrency);
|
|
246376
|
+
const shouldIncludeWorkspaceInLogs = concurrency > 1;
|
|
246377
|
+
let npmAnalysisMutex = Promise.resolve();
|
|
246377
246378
|
const workspaceToAugmentedVulnerabilities = Object.fromEntries(await asyncMap(workspaces, async (workspacePath, index2) => {
|
|
246378
246379
|
analysisStarting?.(workspacePath, index2 + 1, totalWorkspaces);
|
|
246379
246380
|
const vulnerabilities = workspaceToVulnerabilities[workspacePath] ?? [];
|
|
246380
|
-
|
|
246381
|
+
const workspacePrefix = shouldIncludeWorkspaceInLogs ? `[${workspacePath}] ` : "";
|
|
246382
|
+
logger.info(`${workspacePrefix}Process workspace ${workspacePath} with ${vulnerabilities.length} ${pluralize(vulnerabilities.length, "vulnerability")}`);
|
|
246381
246383
|
try {
|
|
246382
246384
|
const dataForAnalysis = workspacePathToDataForAnalysis[workspacePath];
|
|
246383
246385
|
const [vulnsSatisfyingThreshold, vulnerabilitiesBelowThreshold] = this.options.minSeverity ? partition(vulnerabilities, (v) => !v.severity || shouldAnalyzeBasedOnSeverity(v.severity, this.options.minSeverity)) : [vulnerabilities, []];
|
|
@@ -246397,21 +246399,34 @@ Subproject: ${subproject}`);
|
|
|
246397
246399
|
}
|
|
246398
246400
|
}));
|
|
246399
246401
|
if (vulnerabilitiesBelowThreshold.length > 0) {
|
|
246400
|
-
logger.info(
|
|
246402
|
+
logger.info(`${workspacePrefix}Reachability analysis skipped for ${vulnerabilitiesBelowThreshold.length} ${pluralize(vulnerabilities.length, "vulnerability")} with severity below the min severity threshold: ${this.options.minSeverity}`);
|
|
246401
246403
|
}
|
|
246402
246404
|
if (vulnsUnreachableFromPrecomputation.length > 0) {
|
|
246403
|
-
logger.info(
|
|
246405
|
+
logger.info(`${workspacePrefix}Reachability analysis skipped for ${vulnsUnreachableFromPrecomputation.length} ${pluralize(vulnerabilities.length, "vulnerability")} that ${vulnerabilities.length !== 1 ? "are" : "is"} already known to be unreachable from precomputed (Tier 2) reachability analysis`);
|
|
246404
246406
|
}
|
|
246405
246407
|
if (vulnerabilitiesToAnalyze.length > 0) {
|
|
246406
|
-
logger.info(
|
|
246408
|
+
logger.info(`${workspacePrefix}Running reachability analysis for ${vulnerabilitiesToAnalyze.length} ${pluralize(vulnerabilities.length, "vulnerability")}`);
|
|
246407
246409
|
}
|
|
246408
|
-
|
|
246409
|
-
|
|
246410
|
-
|
|
246411
|
-
|
|
246412
|
-
|
|
246410
|
+
let augmentedVulnerabilitiesToAnalyze;
|
|
246411
|
+
if (vulnerabilitiesToAnalyze.length === 0) {
|
|
246412
|
+
augmentedVulnerabilitiesToAnalyze = [];
|
|
246413
|
+
} else if (reachabilitySupported && !this.shouldExcludeAnalyzingWorkspace(subprojectPath, workspacePath, workspacePrefix)) {
|
|
246414
|
+
if (ecosystem === "NPM" && concurrency > 1) {
|
|
246415
|
+
augmentedVulnerabilitiesToAnalyze = await this.runReachabilityAnalysisWithoutConcurrency(async () => npmAnalysisMutex, (mutex) => {
|
|
246416
|
+
npmAnalysisMutex = mutex;
|
|
246417
|
+
}, otherModulesCommunicator, subprojectPath, workspacePath, dataForAnalysis, ecosystem, vulnerabilitiesToAnalyze, workspacePrefix);
|
|
246418
|
+
} else {
|
|
246419
|
+
augmentedVulnerabilitiesToAnalyze = await this.runReachabilityAnalysis(otherModulesCommunicator, subprojectPath, workspacePath, dataForAnalysis, ecosystem, vulnerabilitiesToAnalyze, workspacePrefix);
|
|
246413
246420
|
}
|
|
246414
|
-
}
|
|
246421
|
+
} else {
|
|
246422
|
+
augmentedVulnerabilitiesToAnalyze = vulnerabilitiesToAnalyze.map((v) => ({
|
|
246423
|
+
...v,
|
|
246424
|
+
results: {
|
|
246425
|
+
type: "otherError",
|
|
246426
|
+
message: `Reachability analysis for languages using ${ecosystem} not supported yet`
|
|
246427
|
+
}
|
|
246428
|
+
}));
|
|
246429
|
+
}
|
|
246415
246430
|
const augmentedVulnerabilities = [
|
|
246416
246431
|
...vulnerabilitiesDeterminedUnreachableFromPrecomputation,
|
|
246417
246432
|
...augmentedVulnerabilitiesToAnalyze,
|
|
@@ -246419,7 +246434,7 @@ Subproject: ${subproject}`);
|
|
|
246419
246434
|
];
|
|
246420
246435
|
return [workspacePath, augmentedVulnerabilities];
|
|
246421
246436
|
} catch (e) {
|
|
246422
|
-
logger.error(
|
|
246437
|
+
logger.error(`${workspacePrefix}Reachability analysis failed for workspace ${workspacePath} in subproject ${subprojectPath}: ${e.message}`);
|
|
246423
246438
|
return [
|
|
246424
246439
|
workspacePath,
|
|
246425
246440
|
vulnerabilities.map((v) => ({
|
|
@@ -246431,7 +246446,7 @@ Subproject: ${subproject}`);
|
|
|
246431
246446
|
}))
|
|
246432
246447
|
];
|
|
246433
246448
|
}
|
|
246434
|
-
}));
|
|
246449
|
+
}, concurrency));
|
|
246435
246450
|
const successfulWorkspaceToAugmentedVulnerabilities = Object.fromEntries(Object.entries(workspaceToAugmentedVulnerabilities).filter(([_, vulns]) => vulns !== void 0));
|
|
246436
246451
|
if (ecosystem === "MAVEN" || ecosystem === "NUGET") {
|
|
246437
246452
|
pruneVulnerablePathsToShortestPathsOnly(ecosystem, successfulWorkspaceToAugmentedVulnerabilities);
|
|
@@ -246484,7 +246499,22 @@ Subproject: ${subproject}`);
|
|
|
246484
246499
|
}
|
|
246485
246500
|
}
|
|
246486
246501
|
}
|
|
246487
|
-
|
|
246502
|
+
async runReachabilityAnalysisWithoutConcurrency(getAnalysisMutex, setAnalysisMutex, otherModulesCommunicator, subprojectPath, workspacePath, dataForAnalysis, ecosystem, vulnerabilitiesToAnalyze, workspacePrefix) {
|
|
246503
|
+
const previousAnalysis = getAnalysisMutex();
|
|
246504
|
+
let resolveCurrentAnalysis;
|
|
246505
|
+
setAnalysisMutex(new Promise((resolve44) => {
|
|
246506
|
+
resolveCurrentAnalysis = resolve44;
|
|
246507
|
+
}));
|
|
246508
|
+
await previousAnalysis;
|
|
246509
|
+
let augmentedVulnerabilitiesToAnalyze;
|
|
246510
|
+
try {
|
|
246511
|
+
augmentedVulnerabilitiesToAnalyze = await this.runReachabilityAnalysis(otherModulesCommunicator, subprojectPath, workspacePath, dataForAnalysis, ecosystem, vulnerabilitiesToAnalyze, workspacePrefix);
|
|
246512
|
+
} finally {
|
|
246513
|
+
resolveCurrentAnalysis();
|
|
246514
|
+
}
|
|
246515
|
+
return augmentedVulnerabilitiesToAnalyze;
|
|
246516
|
+
}
|
|
246517
|
+
shouldExcludeAnalyzingWorkspace(subprojectPath, workspacePath, workspacePrefix = "") {
|
|
246488
246518
|
const shouldExcludeWorkspaceForAnalysis = shouldIgnoreDueToExcludeDirsOrChangedFiles({
|
|
246489
246519
|
mainProjectDir: this.rootWorkingDirectory,
|
|
246490
246520
|
excludeDirs: this.options.excludeDirs ?? [],
|
|
@@ -246492,15 +246522,15 @@ Subproject: ${subproject}`);
|
|
|
246492
246522
|
includeDirs: this.options.includeDirs ?? []
|
|
246493
246523
|
}, resolve42(subprojectPath, workspacePath));
|
|
246494
246524
|
if (shouldExcludeWorkspaceForAnalysis) {
|
|
246495
|
-
logger.info(
|
|
246525
|
+
logger.info(`${workspacePrefix}Skipping reachability analysis for workspace ${workspacePath} due to it being excluded.`);
|
|
246496
246526
|
}
|
|
246497
246527
|
return shouldExcludeWorkspaceForAnalysis;
|
|
246498
246528
|
}
|
|
246499
|
-
async runReachabilityAnalysis(otherModulesCommunicator, subprojectPath, workspacePath, workspaceData, ecosystem, vulnerabilities) {
|
|
246529
|
+
async runReachabilityAnalysis(otherModulesCommunicator, subprojectPath, workspacePath, workspaceData, ecosystem, vulnerabilities, workspacePrefix = "") {
|
|
246500
246530
|
const [vulnsWithActualAPIPatterns, result] = partition(vulnerabilities, (v) => Array.isArray(v.vulnerabilityAccessPaths));
|
|
246501
246531
|
for (const v of result)
|
|
246502
246532
|
v.results = typeof v.vulnerabilityAccessPaths === "string" ? { type: "noAnalysisCheck", message: v.vulnerabilityAccessPaths } : { type: "missingVulnerabilityPattern" };
|
|
246503
|
-
logger.info(
|
|
246533
|
+
logger.info(`${workspacePrefix}Reachability analysis not possible for ${result.length} of the ${pluralize(vulnerabilities.length, "vulnerability")}`);
|
|
246504
246534
|
if (!vulnsWithActualAPIPatterns.length)
|
|
246505
246535
|
return result;
|
|
246506
246536
|
this.sendProgress("REACHABILITY_ANALYSIS", true, subprojectPath, workspacePath);
|
|
@@ -246668,7 +246698,7 @@ async function getGitDataToMetadataIfAvailable(rootWorkingDirectory) {
|
|
|
246668
246698
|
// dist/index.js
|
|
246669
246699
|
var program2 = new Command();
|
|
246670
246700
|
var run2 = new Command();
|
|
246671
|
-
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.", "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("--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).version(version2).configureHelp({ sortOptions: true }).action(async (path2, options) => {
|
|
246701
|
+
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("--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).version(version2).configureHelp({ sortOptions: true }).action(async (path2, options) => {
|
|
246672
246702
|
process.env.DOCKER_IMAGE_TAG ??= version2;
|
|
246673
246703
|
options.ecosystems = options.ecosystems?.map((e) => e.toUpperCase());
|
|
246674
246704
|
options.minSeverity = options.minSeverity?.toUpperCase();
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|