Skip to content

Commit

Permalink
Q2 2024 integration branch (#108)
Browse files Browse the repository at this point in the history
Q2 2024 release tasks
  • Loading branch information
RahulPidde23 authored Jun 10, 2024
1 parent a25d6ff commit b8709c1
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 19 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@checkmarx/cx-common-js-client",
"version": "0.1.85",
"version": "0.1.86",
"description": "Client for interaction with Checkmarx products.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
4 changes: 4 additions & 0 deletions src/dto/sastConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ export interface SastConfig {
presetName: string;
presetId?: number;
scanTimeoutInMinutes?: number;
waitTimeForRetryScan?: number;
enablePolicyViolations: boolean;
generatePDFReport: boolean;
vulnerabilityThreshold: boolean;
failBuildForNewVulnerabilitiesEnabled: boolean;
failBuildForNewVulnerabilitiesSeverity: string;
criticalThreshold?: number;
highThreshold?: number;
mediumThreshold?: number;
lowThreshold?: number;
Expand All @@ -30,4 +32,6 @@ export interface SastConfig {
postScanActionName: string;
postScanActionId?: number;
avoidDuplicateProjectScans:boolean;
enableSastBranching:boolean;
masterBranchProjectName: string;
}
1 change: 1 addition & 0 deletions src/dto/sca/scaConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ export interface ScaConfig {
pathToScaResolver: string;
scaResolverAddParameters: string;
scaScanTimeoutInMinutes?: number;
scaWaitTimeForRetryScan?: number;
}
4 changes: 4 additions & 0 deletions src/dto/scanResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class ScanResults {
scanId = 0;
thresholdEnabled: boolean = false;

criticalThreshold: number | undefined;
highThreshold: number | undefined;
mediumThreshold: number | undefined;
lowThreshold: number | undefined;
Expand All @@ -40,10 +41,12 @@ export class ScanResults {
osaViolations = [];
osaPolicies = [];
failBuildForNewVulnerabilitiesEnabled: boolean = false;
criticalResults = 0;
highResults = 0;
mediumResults = 0;
lowResults = 0;
infoResults = 0;
newCriticalCount = 0;
newHighCount = 0;
newMediumCount = 0;
newLowCount = 0;
Expand Down Expand Up @@ -86,6 +89,7 @@ export class ScanResults {
this.url = sastConfig.serverUrl;
this.enablePolicyViolations = sastConfig.enablePolicyViolations;
this.thresholdEnabled = sastConfig.vulnerabilityThreshold;
this.criticalThreshold = sastConfig.criticalThreshold;
this.highThreshold = sastConfig.highThreshold;
this.mediumThreshold = sastConfig.mediumThreshold;
this.lowThreshold = sastConfig.lowThreshold;
Expand Down
145 changes: 129 additions & 16 deletions src/services/clients/cxClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ export class CxClient {
result.syncMode = this.config.isSyncMode;

if (config.enableSastScan) {
if(!await this.isSASTSupportsCriticalSeverity() && this.sastConfig.vulnerabilityThreshold)
{
this.sastConfig.criticalThreshold = 0;
if(this.sastConfig.failBuildForNewVulnerabilitiesSeverity == "CRITICAL")
{
this.sastConfig.failBuildForNewVulnerabilitiesSeverity = '';
}
this.log.warning('SAST 9.6 and lower version does not supports critical severity because of that ignoring critical threshold.');
}
result.updateSastDefaultResults(this.sastConfig);
this.log.info('Initializing Cx client');
await this.initClients(httpClient);
Expand Down Expand Up @@ -262,7 +271,7 @@ export class CxClient {
private async isPriorVersion(version: string, proirToVersion: string): Promise<boolean> {
try {
const value = version.split(".");
var currentVersion = (value[0]) + "." + (value[1]);
let currentVersion = (value[0]) + "." + (value[1]);
if (parseFloat(currentVersion) < parseFloat(proirToVersion)) {
return true;
}
Expand All @@ -274,6 +283,25 @@ export class CxClient {
}
}

private async isSASTSupportsCriticalSeverity(): Promise<boolean> {
try {
let versionInfo = await this.getVersionInfo();
let version = versionInfo.version;

const value = version.split(".");
var currentVersion = (value[0]) + "." + (value[1]);
if(parseFloat(currentVersion) >= parseFloat("9.7"))
{
return true;
}
else
{
return false;
}
} catch (e) {
return false;
}
}
private async isScanWithSettingsSupported(): Promise<boolean> {
try {
let versionInfo = await this.getVersionInfo();
Expand Down Expand Up @@ -319,20 +347,68 @@ export class CxClient {
this.isNewProject = false;
} else {
this.log.info('Project not found, creating a new one.');
this.isNewProject = true;
if (this.sastConfig.denyProject) {
if (this.sastConfig.denyProject)
{
throw Error(
`Creation of the new project [${this.config.projectName}] is not authorized. Please use an existing project.` +
" You can enable the creation of new projects by disabling the Deny new Checkmarx projects creation checkbox in the Checkmarx plugin global settings.");
}

projectId = await this.createNewProject();
//Create newProject and checking if EnableSASTBranching is enabled then creating branch project
if (this.sastConfig.enableSastBranching)
{
if(!this.sastConfig.masterBranchProjectName)
{
throw Error("Master branch project name is mandatory to create branched project.");
}
else
{
let masterProjectId = await this.getProjectIdByProjectName(this.sastConfig.masterBranchProjectName);

if(masterProjectId)
{
projectId = await this.createChildProject(masterProjectId,this.config.projectName);
if(projectId == -1 )
{
throw Error('Branched project could not be created: ' + this.config.projectName);
}
else
{
this.isNewProject = true;
}
}
else
{
throw Error('Master branch project does not exist: ' + this.sastConfig.masterBranchProjectName);
}
}
}
else
{
projectId = await this.createNewProject();
this.isNewProject = true;
}
this.log.debug(`Project created. ID: ${projectId}`);
}

return projectId;
}

private async createChildProject(projectId :number,childProjectName :string) : Promise<number>
{
const project = {
name : childProjectName
};
const newProject = await this.httpClient.postRequest(`projects/${projectId}/branch`, project);
if (newProject != null || newProject)
{
return newProject.id;
}
else
{
throw Error(`CX Response for branch project request with name ${childProjectName} from existing project with ID ${projectId} was null`);
}
}

private async getCustomFieldsProjectName(): Promise<Array<CustomFields>> {
let result;
const encodedName = encodeURIComponent(this.config.projectName);
Expand Down Expand Up @@ -367,7 +443,7 @@ export class CxClient {
let isOverrideProjectSettings = false;
var apiVersionHeader = {};
if (await this.isScanLevelCustomFieldSupported()) {
apiVersionHeader = { 'Content-type': 'application/json;v=1.2' };
apiVersionHeader = { 'Content-type': 'application/json;v=1.2' , 'version' : '1.2'};
}
isOverrideProjectSettings = this.sastConfig.overrideProjectSettings || this.isNewProject;
const scanResponse: ScanWithSettingsResponse = await this.httpClient.postMultipartRequest('sast/scanWithSettings',
Expand Down Expand Up @@ -438,16 +514,32 @@ export class CxClient {
return result;
}

private async getProjectIdByProjectName(projectName :string): Promise<number> {
let result = 0;
const encodedName = encodeURIComponent(projectName);
const path = `projects?projectname=${encodedName}&teamid=${this.teamId}`;
try {
const projects = await this.httpClient.getRequest(path, { suppressWarnings: true });
if (projects && projects.length)
result = projects[0].id;
else
throw Error('Master branch project does not exist: ' + projectName);
} catch (err) {
const isExpectedError = err.response && err.response.notFound;
if (!isExpectedError) {
throw err;
}
}
return result;
}

private async createNewProject(): Promise<number> {
const request = {
name: this.config.projectName,
owningTeam: this.teamId,
isPublic: this.sastConfig.isPublic
};

const newProject = await this.httpClient.postRequest('projects', request);
this.log.debug(`Created new project, ID: ${newProject.id}`);

return newProject.id;
}

Expand Down Expand Up @@ -493,6 +585,7 @@ export class CxClient {

private async addStatisticsToScanResults(result: ScanResults) {
const statistics = await this.sastClient.getScanStatistics(result.scanId);
result.criticalResults = statistics.criticalSeverity;
result.highResults = statistics.highSeverity;
result.mediumResults = statistics.mediumSeverity;
result.lowResults = statistics.lowSeverity;
Expand Down Expand Up @@ -545,19 +638,37 @@ export class CxClient {
}

private printStatistics(result: ScanResults) {
const newCritical = (result.newCriticalCount > 0 && result.failBuildForNewVulnerabilitiesEnabled) ? " (" + result.newCriticalCount + " new)" : "";
const newHigh = (result.newHighCount > 0 && result.failBuildForNewVulnerabilitiesEnabled) ? " (" + result.newHighCount + " new)" : "";
const newMedium = (result.newMediumCount > 0 && result.failBuildForNewVulnerabilitiesEnabled) ? " (" + result.newMediumCount + " new)" : "";
const newLow = (result.newLowCount > 0 && result.failBuildForNewVulnerabilitiesEnabled) ? " (" + result.newLowCount + " new)" : "";
const newInfo = (result.newInfoCount > 0 && result.failBuildForNewVulnerabilitiesEnabled) ? " (" + result.newInfoCount + " new)" : "";
this.log.info(`----------------------------Checkmarx Scan Results(CxSAST):-------------------------------
if(result.criticalResults != undefined)
{
this.log.info(`----------------------------Checkmarx Scan Results(CxSAST):-------------------------------
Critical severity results: ${result.criticalResults}${newCritical}
High severity results: ${result.highResults}${newHigh}
Medium severity results: ${result.mediumResults}${newMedium}
Low severity results: ${result.lowResults}${newLow}
Info severity results: ${result.infoResults}${newInfo}
Scan results location: ${result.sastScanResultsLink}
------------------------------------------------------------------------------------------
`);
}
else
{
this.log.info(`----------------------------Checkmarx Scan Results(CxSAST):-------------------------------
Critical severity results: ${result.criticalResults}${newCritical}
High severity results: ${result.highResults}${newHigh}
Medium severity results: ${result.mediumResults}${newMedium}
Low severity results: ${result.lowResults}${newLow}
Info severity results: ${result.infoResults}${newInfo}
Medium severity results: ${result.mediumResults}${newMedium}
Low severity results: ${result.lowResults}${newLow}
Info severity results: ${result.infoResults}${newInfo}
Scan results location: ${result.sastScanResultsLink}
------------------------------------------------------------------------------------------
`);
Scan results location: ${result.sastScanResultsLink}
------------------------------------------------------------------------------------------
`);
}
}

private static toJsonQueries(scanResult: ScanResults, queries: any[]) {
Expand Down Expand Up @@ -585,6 +696,8 @@ Scan results location: ${result.sastScanResultsLink}
if(result.$.FalsePositive === "False" && result.$.Status === "New"){
severity = result.$.Severity;
switch(severity){
case "Critical":
scanResult.newCriticalCount++;
case "High":
scanResult.newHighCount++;
break;
Expand Down
4 changes: 3 additions & 1 deletion src/services/clients/sastClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,11 @@ export class SastClient {

const polling: PollingSettings = {
masterTimeoutMinutes: this.config.scanTimeoutInMinutes,
intervalSeconds: SastClient.POLLING_INTERVAL_IN_SECONDS
intervalSeconds: ( this.config.waitTimeForRetryScan != undefined && this.config.waitTimeForRetryScan > 0 ? this.config.waitTimeForRetryScan : SastClient.POLLING_INTERVAL_IN_SECONDS)
};

this.log.debug('Waiting time before retry SAST scan is: ' + polling.intervalSeconds);

let lastStatus;
const waiter = new Waiter();
try {
Expand Down
3 changes: 2 additions & 1 deletion src/services/scaWaiter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ export class SCAWaiter {

const polling: PollingSettings = {
masterTimeoutMinutes: this.config.scaScanTimeoutInMinutes,
intervalSeconds: SCAWaiter.POLLING_INTERVAL_IN_SECONDS
intervalSeconds: this.config.scaWaitTimeForRetryScan != undefined && this.config.scaWaitTimeForRetryScan > 0 ? this.config.scaWaitTimeForRetryScan : SCAWaiter.POLLING_INTERVAL_IN_SECONDS
};

this.log.debug('Waiting time before retry SCA scan is: ' + polling.intervalSeconds);
let lastStatus;
const waiter = new Waiter();
try {
Expand Down
8 changes: 8 additions & 0 deletions src/services/scanSummaryEvaluator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export abstract class ScanSummaryEvaluator {

private static getSastThresholdErrors(scanResult: any, config: any) {
const result: ThresholdError[] = [];
ScanSummaryEvaluator.addThresholdErrors(scanResult.criticalResults, config.criticalThreshold, 'critical', result);
ScanSummaryEvaluator.addThresholdErrors(scanResult.highResults, config.highThreshold, 'high', result);
ScanSummaryEvaluator.addThresholdErrors(scanResult.mediumResults, config.mediumThreshold, 'medium', result);
ScanSummaryEvaluator.addThresholdErrors(scanResult.lowResults, config.lowThreshold, 'low', result);
Expand Down Expand Up @@ -83,6 +84,13 @@ export abstract class ScanSummaryEvaluator {
result.push({
severity,
severityCount: scanResult.newHighCount
});
severity = "CRITICAL";
}
if(severity === "CRITICAL" && scanResult.newCriticalCount > 0){
result.push({
severity,
severityCount: scanResult.newCriticalCount
});
}
return result;
Expand Down
5 changes: 5 additions & 0 deletions tests/scanSummaryEvaluator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe("ScanSummaryEvaluator", function () {

it('should return threshold errors in summary', function () {
const config = getSastConfig();
config.criticalThreshold = 3;
config.highThreshold = 1;
config.mediumThreshold = 5;
config.lowThreshold = 10;
Expand All @@ -33,6 +34,7 @@ describe("ScanSummaryEvaluator", function () {

const scanResults = new ScanResults();
scanResults.updateSastDefaultResults(config);
scanResults.criticalResults = 1;
scanResults.highResults = 3;
scanResults.mediumResults = 8;
scanResults.lowResults = 4;
Expand All @@ -44,6 +46,7 @@ describe("ScanSummaryEvaluator", function () {

it('should not return threshold errors if all values are below thresholds', function () {
const config = getSastConfig();
config.criticalThreshold = 10;
config.highThreshold = 10;
config.mediumThreshold = 15;
config.lowThreshold = 20;
Expand All @@ -53,6 +56,7 @@ describe("ScanSummaryEvaluator", function () {

const scanResults = new ScanResults();
scanResults.updateSastDefaultResults(config);
scanResults.criticalResults = 2;
scanResults.highResults = 2;
scanResults.mediumResults = 11;
scanResults.lowResults = 18;
Expand All @@ -65,6 +69,7 @@ describe("ScanSummaryEvaluator", function () {

function getSastConfig(): SastConfig {
return {
criticalThreshold: 0,
highThreshold: 0,
lowThreshold: 0,
mediumThreshold: 0,
Expand Down

0 comments on commit b8709c1

Please sign in to comment.