Skip to content

Commit

Permalink
PA-7197 Use status issues object for counts (#11)
Browse files Browse the repository at this point in the history
### Changes:
  - Description of the change
  - Updated package.json version

**Ticket:** https://soos.atlassian.net/browse/PA-7197 Use status issues
object for counts

---------

Co-authored-by: SOOS-GSteen <[email protected]>
  • Loading branch information
SOOS-JAlvarez and SOOS-GSteen authored Dec 6, 2023
1 parent b9ebee3 commit 1a6c803
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 37 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@soos-io/api-client",
"version": "0.2.2",
"version": "0.2.3",
"description": "This is the SOOS API Client for registered clients leveraging the various integrations to the SOOS platform.",
"main": "dist/index.js",
"scripts": {
Expand Down
23 changes: 13 additions & 10 deletions src/api/SOOSAnalysisApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,13 @@ interface IScanStatusRequest {
interface IScanStatusResponse extends Pick<IScanStatusApiResponse, "status"> {
isComplete: boolean;
isSuccess: boolean;
hasIssues: boolean;
violations: number;
vulnerabilities: number;
issues: IIssuesModel;
errors: ICodedMessageModel[];
}

interface IScanStatusApiResponse {
status: ScanStatus;
violations: { count: number } | null;
vulnerabilities: { count: number } | null;
issues: IIssuesModel;
clientHash: string;
projectHash: string;
branchHash: string;
Expand All @@ -99,6 +96,15 @@ interface IScanStatusApiResponse {
errors: ICodedMessageModel[] | null;
}

interface IIssuesModel {
Violation: { count: number; maxSeverity: string } | null;
Vulnerability: { count: number; maxSeverity: string } | null;
DependencyTypo: { count: number; maxSeverity: string } | null;
DependencySubstitution: { count: number; maxSeverity: string } | null;
Dast: { count: number; maxSeverity: string } | null;
Sast: { count: number; maxSeverity: string } | null;
}

interface IStartScanRequest {
clientId: string;
projectHash: string;
Expand Down Expand Up @@ -259,15 +265,11 @@ class SOOSAnalysisApiClient {

async getScanStatus({ scanStatusUrl }: IScanStatusRequest): Promise<IScanStatusResponse> {
const response = await this.client.get<IScanStatusApiResponse>(scanStatusUrl);
const violationCount = response.data.violations?.count ?? 0;
const vulnerabilityCount = response.data.vulnerabilities?.count ?? 0;
return {
status: response.data.status,
isComplete: CompletedScanStatuses.includes(response.data.status),
isSuccess: response.data.status === ScanStatus.Finished,
hasIssues: violationCount > 0 || vulnerabilityCount > 0,
violations: violationCount,
vulnerabilities: vulnerabilityCount,
issues: response.data.issues,
errors: response.data.errors ?? [],
};
}
Expand Down Expand Up @@ -322,6 +324,7 @@ export {
IUploadManifestFilesResponse,
IGetFormattedScanRequest as IFormattedScanRequest,
IUploadScanToolResultRequest,
IIssuesModel,
};

export default SOOSAnalysisApiClient;
66 changes: 43 additions & 23 deletions src/services/AnalysisService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
SeverityEnum,
} from "../enums";
import { soosLogger } from "../logging";
import { sleep } from "../utilities";
import { getVulnerabilitiesByScanType, sleep } from "../utilities";
import * as FileSystem from "fs";
import * as Path from "path";

Expand All @@ -42,6 +42,7 @@ interface IStartScanParams {
interface IWaitForScanToFinishParams {
scanStatusUrl: string;
scanUrl: string;
scanType: ScanType;
}

interface ISetupScanParams {
Expand Down Expand Up @@ -88,6 +89,8 @@ const integrationNameToEnvVariable: Record<IntegrationName, string> = {
[IntegrationName.TravisCI]: "TRAVIS_COMMIT",
};

const GeneratedScanTypes = [ScanType.CSA, ScanType.SBOM, ScanType.SCA];

class AnalysisService {
public analysisApiClient: SOOSAnalysisApiClient;
public projectsApiClient: SOOSProjectsApiClient;
Expand Down Expand Up @@ -227,6 +230,7 @@ class AnalysisService {
async waitForScanToFinish({
scanStatusUrl,
scanUrl,
scanType,
}: IWaitForScanToFinishParams): Promise<ScanStatus> {
const scanStatus = await this.analysisApiClient.getScanStatus({
scanStatusUrl: scanStatusUrl,
Expand All @@ -235,7 +239,7 @@ class AnalysisService {
if (!scanStatus.isComplete) {
soosLogger.info(`${StringUtilities.fromCamelToTitleCase(scanStatus.status)}...`);
await sleep(SOOS_CONSTANTS.Status.DelayTime);
return await this.waitForScanToFinish({ scanStatusUrl, scanUrl });
return await this.waitForScanToFinish({ scanStatusUrl, scanUrl, scanType });
}

if (scanStatus.errors.length > 0) {
Expand All @@ -244,29 +248,43 @@ class AnalysisService {
soosLogger.groupEnd();
}

if (scanStatus.isSuccess) {
scanStatus.vulnerabilities > 0 || scanStatus.violations > 0;
}

let statusMessage = `Scan ${scanStatus.isSuccess ? "passed" : "failed"}`;
if (scanStatus.hasIssues) {
const vulnerabilities = StringUtilities.pluralizeTemplate(
scanStatus.vulnerabilities,
"vulnerability",
"vulnerabilities",
);

const violations = StringUtilities.pluralizeTemplate(scanStatus.violations, "violation");

statusMessage = statusMessage.concat(
`${
scanStatus.isSuccess ? ", but had" : " because of"
} ${vulnerabilities} and ${violations}`,
);
}

const resultMessage = `${statusMessage}. View the results at: ${scanUrl}`;
soosLogger.info(resultMessage);
const vulnerabilities = StringUtilities.pluralizeTemplate(
getVulnerabilitiesByScanType(scanStatus.issues, scanType) ?? 0,
"vulnerability",
"vulnerabilities",
);

const violations = StringUtilities.pluralizeTemplate(
scanStatus.issues.Violation?.count ?? 0,
"violation",
);

const isGeneratedScanType = GeneratedScanTypes.includes(scanType);

const substitutions = isGeneratedScanType
? StringUtilities.pluralizeTemplate(
scanStatus.issues.DependencySubstitution?.count ?? 0,
"dependency substitution",
)
: "";

const typos = isGeneratedScanType
? StringUtilities.pluralizeTemplate(
scanStatus.issues.DependencyTypo?.count ?? 0,
"dependency typo",
)
: "";

statusMessage = statusMessage.concat(
`${scanStatus.isSuccess ? ", with" : " because of"} (${vulnerabilities}) (${violations})${
substitutions ? ` (${substitutions})` : ""
}${typos ? ` (${typos})` : ""}.`,
);

soosLogger.info(statusMessage);
soosLogger.info(`View the results at: ${scanUrl}`);
return scanStatus.status;
}

Expand Down Expand Up @@ -336,4 +354,6 @@ class AnalysisService {
}
}

export { GeneratedScanTypes };

export default AnalysisService;
15 changes: 14 additions & 1 deletion src/utilities.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import axios, { AxiosError } from "axios";
import { soosLogger } from "./logging/SOOSLogger";
import StringUtilities from "./StringUtilities";
import { ScanStatus } from "./enums";
import { ScanStatus, ScanType } from "./enums";
import { IIssuesModel } from "./api/SOOSAnalysisApiClient";

const isNil = (value: unknown): value is null | undefined => value === null || value === undefined;

Expand Down Expand Up @@ -136,6 +137,17 @@ const verifyScanStatus = (scanStatus: ScanStatus): boolean => {
return fail;
};

const getVulnerabilitiesByScanType = (issues: IIssuesModel, scanType: ScanType) => {
switch (scanType) {
case ScanType.DAST:
return issues.Dast?.count;
case ScanType.SAST:
return issues.Sast?.count;
default:
return issues.Vulnerability?.count;
}
};

export {
isNil,
ensureValue,
Expand All @@ -148,4 +160,5 @@ export {
getEnvVariable,
formatBytes,
verifyScanStatus,
getVulnerabilitiesByScanType,
};

0 comments on commit 1a6c803

Please sign in to comment.