@soos-io/soos-sca
Version:
SOOS Core SCA Security Analysis - Check for vulnerabilities, licenses, policy violations and more! Register for your free trial at https://app.soos.io/register
194 lines (193 loc) • 10.6 kB
JavaScript
#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const package_json_1 = require("../package.json");
const api_client_1 = require("@soos-io/api-client");
const utilities_1 = require("@soos-io/api-client/dist/utilities");
const constants_1 = require("./constants");
const process_1 = require("process");
const AnalysisService_1 = tslib_1.__importDefault(require("@soos-io/api-client/dist/services/AnalysisService"));
const AnalysisArgumentParser_1 = tslib_1.__importDefault(require("@soos-io/api-client/dist/services/AnalysisArgumentParser"));
const utilities_2 = require("./utilities");
const enums_1 = require("@soos-io/api-client/dist/enums");
class SOOSSCAAnalysis {
args;
constructor(args) {
this.args = args;
}
static parseArgs() {
const analysisArgumentParser = AnalysisArgumentParser_1.default.create(api_client_1.IntegrationName.SoosSca, api_client_1.IntegrationType.Script, api_client_1.ScanType.SCA, package_json_1.version);
analysisArgumentParser.addArgument("directoriesToExclude", "Listing of directories or patterns to exclude from the search for manifest files. eg: **bin/start/**, **/start/**", {
argParser: (value) => {
return (0, utilities_2.removeDuplicates)(value.split(",").map((pattern) => pattern.trim()));
},
defaultValue: constants_1.SOOS_SCA_CONSTANTS.DefaultDirectoriesToExclude,
});
analysisArgumentParser.addArgument("filesToExclude", "Listing of files or patterns patterns to exclude from the search for manifest files. eg: **/req**.txt/, **/requirements.txt", {
argParser: (value) => {
return value.split(",").map((pattern) => pattern.trim());
},
defaultValue: [],
});
analysisArgumentParser.addEnumArgument("fileMatchType", enums_1.FileMatchTypeEnum, "The method to use to locate files for scanning, looking for manifest files and/or files to hash.", {
defaultValue: enums_1.FileMatchTypeEnum.Manifest,
});
analysisArgumentParser.addEnumArgument("packageManagers", {
[api_client_1.PackageManagerType.CFamily]: api_client_1.PackageManagerType.CFamily,
[api_client_1.PackageManagerType.Dart]: api_client_1.PackageManagerType.Dart,
[api_client_1.PackageManagerType.Erlang]: api_client_1.PackageManagerType.Erlang,
[api_client_1.PackageManagerType.Go]: api_client_1.PackageManagerType.Go,
[api_client_1.PackageManagerType.Homebrew]: api_client_1.PackageManagerType.Homebrew,
[api_client_1.PackageManagerType.Java]: api_client_1.PackageManagerType.Java,
[api_client_1.PackageManagerType.NPM]: api_client_1.PackageManagerType.NPM,
[api_client_1.PackageManagerType.NuGet]: api_client_1.PackageManagerType.NuGet,
[api_client_1.PackageManagerType.Php]: api_client_1.PackageManagerType.Php,
[api_client_1.PackageManagerType.Python]: api_client_1.PackageManagerType.Python,
[api_client_1.PackageManagerType.Ruby]: api_client_1.PackageManagerType.Ruby,
[api_client_1.PackageManagerType.Rust]: api_client_1.PackageManagerType.Rust,
[api_client_1.PackageManagerType.Swift]: api_client_1.PackageManagerType.Swift,
[api_client_1.PackageManagerType.Unity]: api_client_1.PackageManagerType.Unity,
}, "A list of package managers, delimited by comma, to include when searching for manifest files.", {
allowMultipleValues: true,
});
analysisArgumentParser.addArgument("sourceCodePath", "Root path to begin recursive search for manifests.", {
defaultValue: process.cwd(),
});
analysisArgumentParser.addArgument("workingDirectory", "Absolute path where SOOS may write and read persistent files for the given build. eg Correct: /tmp/workspace/ | Incorrect: ./bin/start/", {
defaultValue: process.cwd(),
});
analysisArgumentParser.addArgument("outputDirectory", "Absolute path where SOOS will write exported reports and SBOMs. eg Correct: /out/sbom/ | Incorrect: ./out/sbom/", {
defaultValue: process.cwd(),
});
return analysisArgumentParser.parseArguments();
}
async runAnalysis() {
const scanType = api_client_1.ScanType.SCA;
const analysisService = AnalysisService_1.default.create(this.args.apiKey, this.args.apiURL);
let projectHash;
let branchHash;
let analysisId;
let scanStatusUrl;
let scanStatus;
try {
const result = await analysisService.setupScan({
clientId: this.args.clientId,
projectName: this.args.projectName,
branchName: this.args.branchName,
commitHash: this.args.commitHash,
buildVersion: this.args.buildVersion,
buildUri: this.args.buildURI,
branchUri: this.args.branchURI,
operatingEnvironment: this.args.operatingEnvironment,
integrationName: this.args.integrationName,
integrationType: this.args.integrationType,
appVersion: this.args.appVersion,
scriptVersion: this.args.scriptVersion,
contributingDeveloperAudit: [
{
contributingDeveloperId: this.args.contributingDeveloperId,
source: this.args.contributingDeveloperSource,
sourceName: this.args.contributingDeveloperSourceName,
},
],
scanType,
commandLine: process.argv.length > 2
? (0, utilities_1.obfuscateCommandLine)((0, utilities_1.reassembleCommandLine)(process.argv.slice(2)), constants_1.SOOS_SCA_CONSTANTS.ObfuscatedArguments.map((a) => `--${a}`))
: null,
});
projectHash = result.projectHash;
branchHash = result.branchHash;
analysisId = result.analysisId;
scanStatusUrl = result.scanStatusUrl;
const { manifestFiles, hashManifests } = await analysisService.findManifestsAndHashableFiles({
clientId: this.args.clientId,
projectHash,
filesToExclude: this.args.filesToExclude,
directoriesToExclude: this.args.directoriesToExclude,
sourceCodePath: this.args.sourceCodePath,
packageManagers: this.args.packageManagers ?? [],
fileMatchType: this.args.fileMatchType,
});
const { exitCode } = await analysisService.addManifestsAndHashableFilesToScan({
clientId: this.args.clientId,
projectHash: result.projectHash,
branchHash: result.branchHash,
analysisId: result.analysisId,
scanType,
scanStatusUrl: result.scanStatusUrl,
fileMatchType: this.args.fileMatchType,
manifestFiles,
hashManifests,
});
if (exitCode !== 0) {
(0, process_1.exit)(exitCode);
}
await analysisService.startScan({
clientId: this.args.clientId,
projectHash,
analysisId: result.analysisId,
scanType,
scanUrl: result.scanUrl,
});
scanStatus = await analysisService.waitForScanToFinish({
scanStatusUrl: result.scanStatusUrl,
scanUrl: result.scanUrl,
scanType,
});
if ((0, utilities_1.isScanDone)(scanStatus) &&
this.args.exportFormat !== enums_1.AttributionFormatEnum.Unknown &&
this.args.exportFileType !== enums_1.AttributionFileTypeEnum.Unknown) {
await analysisService.generateFormattedOutput({
clientId: this.args.clientId,
projectHash: result.projectHash,
projectName: this.args.projectName,
branchHash: result.branchHash,
analysisId: result.analysisId,
format: this.args.exportFormat,
fileType: this.args.exportFileType,
includeDependentProjects: false,
includeOriginalSbom: false,
includeVulnerabilities: false,
workingDirectory: this.args.outputDirectory,
});
}
const { exitCode: analysisExitCode, message } = (0, utilities_1.getAnalysisExitCodeWithMessage)(scanStatus, this.args.integrationName, this.args.onFailure);
api_client_1.soosLogger.always(`${message} - exit ${analysisExitCode}`);
(0, process_1.exit)(analysisExitCode);
}
catch (e) {
const errorMessage = e instanceof Error ? e.message : e;
if (projectHash && branchHash && analysisId && (!scanStatus || !(0, utilities_1.isScanDone)(scanStatus)))
await analysisService.updateScanStatus({
clientId: this.args.clientId,
projectHash,
branchHash,
scanType,
analysisId: analysisId,
status: api_client_1.ScanStatus.Error,
message: `Error while performing scan: ${errorMessage}`,
scanStatusUrl,
});
api_client_1.soosLogger.error(errorMessage);
api_client_1.soosLogger.always(`Error: ${errorMessage} - exit 1`);
(0, process_1.exit)(1);
}
}
static async createAndRun() {
try {
const args = this.parseArgs();
api_client_1.soosLogger.setMinLogLevel(args.logLevel);
api_client_1.soosLogger.always("Starting SOOS SCA Analysis");
api_client_1.soosLogger.debug(JSON.stringify((0, utilities_1.obfuscateProperties)(args, ["apiKey"]), null, 2));
const soosSCAAnalysis = new SOOSSCAAnalysis(args);
await soosSCAAnalysis.runAnalysis();
}
catch (error) {
api_client_1.soosLogger.error(`Error on createAndRun: ${error}`);
api_client_1.soosLogger.always(`Error on createAndRun: ${error} - exit 1`);
(0, process_1.exit)(1);
}
}
}
SOOSSCAAnalysis.createAndRun();