@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
167 lines (166 loc) • 8.74 kB
JavaScript
"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");
class SOOSSASTAnalysis {
args;
constructor(args) {
this.args = args;
}
static 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());
},
});
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());
},
});
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(),
});
return analysisArgumentParser.parseArguments();
}
async runAnalysis() {
const scanType = api_client_1.ScanType.SAST;
const soosAnalysisService = AnalysisService_1.default.create(this.args.apiKey, this.args.apiURL);
let projectHash;
let branchHash;
let analysisId;
let scanStatusUrl;
let scanStatus;
try {
const result = await soosAnalysisService.setupScan({
clientId: this.args.clientId,
projectName: this.args.projectName,
commitHash: this.args.commitHash,
contributingDeveloperAudit: !this.args.contributingDeveloperId ||
!this.args.contributingDeveloperSource ||
!this.args.contributingDeveloperSourceName
? []
: [
{
contributingDeveloperId: this.args.contributingDeveloperId,
source: this.args.contributingDeveloperSource,
sourceName: this.args.contributingDeveloperSourceName,
},
],
branchName: this.args.branchName,
buildVersion: this.args.buildVersion,
buildUri: this.args.buildURI,
branchUri: this.args.branchURI,
integrationType: this.args.integrationType,
operatingEnvironment: this.args.operatingEnvironment,
integrationName: this.args.integrationName,
appVersion: this.args.appVersion,
scanType,
scriptVersion: this.args.scriptVersion,
toolName: undefined,
toolVersion: undefined,
});
projectHash = result.projectHash;
branchHash = result.branchHash;
analysisId = result.analysisId;
scanStatusUrl = result.scanStatusUrl;
const { filePaths, hasMoreThanMaximumFiles } = await soosAnalysisService.findAnalysisFiles(scanType, this.args.sourceCodePath, constants_1.SOOS_SAST_CONSTANTS.FilePattern, this.args.filesToExclude, this.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: this.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, this.args.sourceCodePath);
await soosAnalysisService.analysisApiClient.uploadScanToolResult({
clientId: this.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) &&
this.args.exportFormat !== api_client_1.AttributionFormatEnum.Unknown &&
this.args.exportFileType !== api_client_1.AttributionFileTypeEnum.Unknown) {
await soosAnalysisService.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 exitCodeWithMessage = (0, utilities_1.getAnalysisExitCodeWithMessage)(scanStatus, this.args.integrationName, this.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: this.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);
}
}
static async createAndRun() {
try {
const args = this.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));
const soosSASTAnalysis = new SOOSSASTAnalysis(args);
await soosSASTAnalysis.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);
}
}
}
SOOSSASTAnalysis.createAndRun();