@soos-io/soos-sast
Version:
SOOS Static Application Security Testing (SAST) scanning support. Register for a free SOOS trial at https://app.soos.io/register
162 lines (161 loc) • 8.06 kB
JavaScript
#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const api_client_1 = require("@soos-io/api-client");
const utilities_1 = require("@soos-io/api-client/dist/utilities");
const process_1 = require("process");
const package_json_1 = require("../package.json");
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 constants_1 = require("./constants");
const parseArgs = () => {
const analysisArgumentParser = AnalysisArgumentParser_1.default.create(api_client_1.IntegrationName.SoosSast, api_client_1.IntegrationType.Script, api_client_1.ScanType.SAST, 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 value.split(",").map((pattern) => pattern.trim());
},
defaultValue: [],
});
analysisArgumentParser.addArgument("filesToExclude", "Listing of files or patterns patterns to exclude from the search for manifest files. eg: **/sa**.sarif.json/, **/sast.sarif.json", {
argParser: (value) => {
return value.split(",").map((pattern) => pattern.trim());
},
defaultValue: [],
});
analysisArgumentParser.addArgument("sourceCodePath", "The path to start searching for SAST files.", {
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(),
});
analysisArgumentParser.addArgument("sarifGenerator", "The type of generator that was used to create the SARIF 2.1 files (eg when called from the soosio/sast Docker image).", {
defaultValue: "File",
internal: true,
});
return analysisArgumentParser.parseArguments();
};
const runAnalysis = async (args) => {
const scanType = api_client_1.ScanType.SAST;
const soosAnalysisService = AnalysisService_1.default.create(args.apiKey, args.apiURL);
let projectHash;
let branchHash;
let analysisId;
let scanStatusUrl;
let scanStatus;
try {
const result = await soosAnalysisService.setupScan({
clientId: args.clientId,
projectName: args.projectName,
commitHash: args.commitHash,
contributingDeveloperAudit: [
{
contributingDeveloperId: args.contributingDeveloperId,
source: args.contributingDeveloperSource,
sourceName: args.contributingDeveloperSourceName,
},
],
branchName: args.branchName,
buildVersion: args.buildVersion,
buildUri: args.buildURI,
branchUri: args.branchURI,
integrationType: args.integrationType,
operatingEnvironment: args.operatingEnvironment,
integrationName: args.integrationName,
appVersion: args.appVersion,
scanType,
scriptVersion: args.scriptVersion,
commandLine: process.argv.length > 2
? (0, utilities_1.obfuscateCommandLine)((0, utilities_1.reassembleCommandLine)(process.argv.slice(2)), constants_1.SOOS_SAST_CONSTANTS.ObfuscatedArguments.map((a) => `--${a}`))
: null,
});
projectHash = result.projectHash;
branchHash = result.branchHash;
analysisId = result.analysisId;
scanStatusUrl = result.scanStatusUrl;
const { filePaths, hasMoreThanMaximumFiles } = await soosAnalysisService.findAnalysisFiles(scanType, args.sourceCodePath, constants_1.SOOS_SAST_CONSTANTS.FilePattern, args.filesToExclude, args.directoriesToExclude, constants_1.SOOS_SAST_CONSTANTS.MaxFiles);
if (filePaths.length === 0) {
const noFilesMessage = `No SAST input files found. Please ensure you have generated Sarif JSON files before running soos-sast. They need to match the pattern ${constants_1.SOOS_SAST_CONSTANTS.FilePattern}. See https://kb.soos.io/getting-started-with-sast-secrets for more information.`;
await soosAnalysisService.updateScanStatus({
analysisId,
clientId: args.clientId,
projectHash,
branchHash,
scanType,
status: api_client_1.ScanStatus.NoFiles,
message: noFilesMessage,
scanStatusUrl,
});
api_client_1.soosLogger.error(noFilesMessage);
api_client_1.soosLogger.always(`${noFilesMessage} - exit 1`);
(0, process_1.exit)(1);
}
api_client_1.soosLogger.info("Uploading SAST File(s)...");
const formData = await soosAnalysisService.getAnalysisFilesAsFormData(filePaths, args.sourceCodePath);
await soosAnalysisService.analysisApiClient.uploadScanToolResult({
clientId: args.clientId,
projectHash,
branchHash,
scanType,
scanId: analysisId,
resultFile: formData,
hasMoreThanMaximumFiles,
});
api_client_1.soosLogger.info("Scan results uploaded successfully.");
scanStatus = await soosAnalysisService.waitForScanToFinish({
scanStatusUrl,
scanUrl: result.scanUrl,
scanType,
});
if ((0, utilities_1.isScanDone)(scanStatus) &&
args.exportFormat !== api_client_1.AttributionFormatEnum.Unknown &&
args.exportFileType !== api_client_1.AttributionFileTypeEnum.Unknown) {
await soosAnalysisService.generateFormattedOutput({
clientId: args.clientId,
projectHash: result.projectHash,
projectName: args.projectName,
branchHash: result.branchHash,
analysisId: result.analysisId,
format: args.exportFormat,
fileType: args.exportFileType,
includeDependentProjects: false,
includeOriginalSbom: false,
includeVulnerabilities: false,
workingDirectory: args.outputDirectory,
});
}
const exitCodeWithMessage = (0, utilities_1.getAnalysisExitCodeWithMessage)(scanStatus, args.integrationName, args.onFailure);
api_client_1.soosLogger.always(`${exitCodeWithMessage.message} - exit ${exitCodeWithMessage.exitCode}`);
(0, process_1.exit)(exitCodeWithMessage.exitCode);
}
catch (error) {
if (projectHash && branchHash && analysisId && (!scanStatus || !(0, utilities_1.isScanDone)(scanStatus)))
await soosAnalysisService.updateScanStatus({
analysisId,
clientId: args.clientId,
projectHash,
branchHash,
scanType,
status: api_client_1.ScanStatus.Error,
message: `Error while performing scan.`,
scanStatusUrl,
});
api_client_1.soosLogger.error(error);
api_client_1.soosLogger.always(`${error} - exit 1`);
(0, process_1.exit)(1);
}
};
(async () => {
try {
const args = parseArgs();
api_client_1.soosLogger.setMinLogLevel(args.logLevel);
api_client_1.soosLogger.always("Starting SOOS SAST Analysis");
api_client_1.soosLogger.debug(JSON.stringify((0, utilities_1.obfuscateProperties)(args, ["apiKey"]), null, 2));
await runAnalysis(args);
}
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);
}
})();