diff --git a/package.json b/package.json index 7606ce64..049a4b18 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "scripts": { "build": "tsc", "postbuild": "copyfiles -u 1 src/main/wrapper/resources/cx* dist/", - "test": "tsc && jest --runInBand --coverage" + "test": "copyfiles -u 1 src/tests/data/* dist/; tsc && jest --runInBand --coverage" }, "repository": "https://github.com/CheckmarxDev/ast-cli-javascript-wrapper.git", "author": "Jay Nanduri", diff --git a/src/main/kicsRealtime/CxKicsRealTime.ts b/src/main/kicsRealtime/CxKicsRealTime.ts new file mode 100644 index 00000000..9ad2dddf --- /dev/null +++ b/src/main/kicsRealtime/CxKicsRealTime.ts @@ -0,0 +1,15 @@ +export default class CxKicsRealTime { + version: string = ""; + count: string = ""; + summary : any = {}; + results: any = []; + + static parseKicsRealTimeResponse(resultObject: any): CxKicsRealTime { + let kicsRealTime: CxKicsRealTime = new CxKicsRealTime(); + kicsRealTime.version = resultObject.kics_version; + kicsRealTime.count = resultObject.total_counter; + kicsRealTime.results = resultObject.queries; + kicsRealTime.summary = resultObject.severity_counters; + return kicsRealTime; + } +} \ No newline at end of file diff --git a/src/main/wrapper/CxConstants.ts b/src/main/wrapper/CxConstants.ts index 568c6edd..4e0521dc 100644 --- a/src/main/wrapper/CxConstants.ts +++ b/src/main/wrapper/CxConstants.ts @@ -29,6 +29,7 @@ export enum CxConstants { CMD_RESULT = "results", SUB_CMD_BFL = "bfl", CMD_CODE_BASHING = "codebashing", + CMD_KICS_REALTIME = "kics-realtime", SCAN_INFO_FORMAT = "--scan-info-format", FORMAT = "--format", FORMAT_JSON = "json", @@ -47,10 +48,14 @@ export enum CxConstants { REPORT_FORMAT = "--report-format", OUTPUT_NAME = "--output-name", OUTPUT_PATH = "--output-path", + FILE_SOURCES = "--file", + ADDITONAL_PARAMS = "--additional-params", + ENGINE = "--engine", SCAN_TYPE = "CxScan", PROJECT_TYPE = "CxProject", PREDICATE_TYPE = "CxPredicate", CODE_BASHING_TYPE = "CxCodeBashing", + KICS_REALTIME_TYPE = "CxKicsRealTime", BFL_TYPE = "CxBFL", SAST = "sast", LANGUAGE = "--language", diff --git a/src/main/wrapper/CxWrapper.ts b/src/main/wrapper/CxWrapper.ts index 28fbae04..b9ab72f7 100644 --- a/src/main/wrapper/CxWrapper.ts +++ b/src/main/wrapper/CxWrapper.ts @@ -237,6 +237,16 @@ export class CxWrapper { return response; } + async kicsRealtimeScan(fileSources: string, engine:string, additionalParams: string):Promise<[Promise,any]> { + const commands: string[] = [CxConstants.CMD_SCAN, CxConstants.CMD_KICS_REALTIME, CxConstants.FILE_SOURCES, fileSources, CxConstants.ADDITONAL_PARAMS, additionalParams]; + if(engine.length>0){ + commands.push(CxConstants.ENGINE,engine) + } + commands.push(...this.initializeCommands(false)); + const exec = new ExecutionService(); + return exec.executeKicsCommands(this.config.pathToExecutable, commands, CxConstants.KICS_REALTIME_TYPE); + } + getIndexOfBflNode(bflNodes: CxBFL[], resultNodes: any[]): number { let bflNodeNotFound = -1; diff --git a/src/main/wrapper/ExecutionService.ts b/src/main/wrapper/ExecutionService.ts index d64dafaa..2e1815dc 100644 --- a/src/main/wrapper/ExecutionService.ts +++ b/src/main/wrapper/ExecutionService.ts @@ -8,6 +8,7 @@ import CxResult from "../results/CxResult"; import CxProject from "../project/CxProject"; import CxCodeBashing from "../codebashing/CxCodeBashing"; import CxBFL from "../bfl/CxBFL"; +import CxKicsRealTime from "../kicsRealtime/CxKicsRealTime"; const spawn = require('child_process').spawn; @@ -33,33 +34,79 @@ function transform(n:string) { } export class ExecutionService { + private fsObject : any = undefined + executeCommands(pathToExecutable: string, commands: string[], output? : string ): Promise { - return new Promise(function (resolve, reject) { + return (new Promise( (resolve, reject)=> { let stderr = ""; let stdout =""; - let cp = spawn(pathToExecutable, transformation(commands)); - cp.on('error', reject); - cp.on('exit',(code: number, signal: any) => { + this.fsObject = spawn(pathToExecutable, transformation(commands)); + this.fsObject.on('error', (data: { toString: () => string; }) => { + if (data) { + logger.error(data.toString().replace('\n', '')); + stderr += data.toString(); + } + reject() + }); + this.fsObject.on('exit',(code: number, signal: any) => { logger.info("Exit code received from AST-CLI: " + code); - resolve(ExecutionService.onCloseCommand(code, stderr, stdout, output )); + if(code==1){ + stderr = stdout + } + resolve(ExecutionService.onCloseCommand(code, stderr, stdout, output, this.fsObject )); }); - cp.stdout.on('data', (data: { toString: () => string; }) => { + this.fsObject.stdout.on('data', (data: { toString: () => string; }) => { if (data) { logger.info(data.toString().replace('\n', '')); stdout += data.toString(); } }); - cp.stderr.on('data', (data: { toString: () => string; }) => { + this.fsObject.stderr.on('data', (data: { toString: () => string; }) => { if (data) { logger.error(data.toString().replace('\n', '')); stderr += data.toString(); } }); - }); + })); + } + + executeKicsCommands(pathToExecutable: string, commands: string[], output? : string ): [Promise,any] { + return [new Promise( (resolve, reject)=> { + let stderr = ""; + let stdout =""; + + this.fsObject = spawn(pathToExecutable, transformation(commands)); + this.fsObject.on('error', (data: { toString: () => string; }) => { + if (data) { + logger.error(data.toString().replace('\n', '')); + stderr += data.toString(); + } + reject() + }); + this.fsObject.on('exit',(code: number, signal: any) => { + logger.info("Exit code received from AST-CLI: " + code); + if(code==1){ + stderr = stdout + } + resolve(ExecutionService.onCloseCommand(code, stderr, stdout, output, this.fsObject )); + }); + this.fsObject.stdout.on('data', (data: { toString: () => string; }) => { + if (data) { + logger.info(data.toString().replace('\n', '')); + stdout += data.toString(); + } + }); + this.fsObject.stderr.on('data', (data: { toString: () => string; }) => { + if (data) { + logger.error(data.toString().replace('\n', '')); + stderr += data.toString(); + } + }); + }), this.fsObject]; } - private static onCloseCommand(code: number, stderr: string, stdout: string, output: string) : CxCommandOutput { + private static onCloseCommand(code: number, stderr: string, stdout: string, output: string, fsObject:any) : CxCommandOutput { const cxCommandOutput = new CxCommandOutput(); cxCommandOutput.exitCode = code; if (stderr) { @@ -68,7 +115,6 @@ export class ExecutionService { if (stdout) { const stdoutSplit = stdout.split('\n'); const data = stdoutSplit.find(isJsonString); - if (data) { let resultObject = JSON.parse(data); switch (output) { @@ -88,6 +134,10 @@ export class ExecutionService { let bflNode = CxBFL.parseBFLResponse(resultObject); cxCommandOutput.payload = bflNode; break; + case "CxKicsRealTime": + let kicsResults = CxKicsRealTime.parseKicsRealTimeResponse(resultObject); + cxCommandOutput.payload = [kicsResults]; + break; default: cxCommandOutput.payload = resultObject; } diff --git a/src/main/wrapper/resources/cx-mac b/src/main/wrapper/resources/cx-mac index 6a690025..367faa2a 100755 Binary files a/src/main/wrapper/resources/cx-mac and b/src/main/wrapper/resources/cx-mac differ diff --git a/src/tests/ResultTest.test.ts b/src/tests/ResultTest.test.ts index 3daa9587..f5f5efc7 100644 --- a/src/tests/ResultTest.test.ts +++ b/src/tests/ResultTest.test.ts @@ -11,9 +11,11 @@ describe("Results cases",() => { const auth = new CxWrapper(cxScanConfig); const cxCommandOutput: CxCommandOutput = await auth.scanList(""); let sampleId = cxCommandOutput.payload.pop().id; - await auth.getResults(sampleId,"json","jsonList", "."); - const file = await fileExists("./jsonList.json"); - expect(file).toBe(true); + + auth.getResults(sampleId,"json","jsonList", ".").then(() => { + fileExists("./jsonList.json").then(file => expect(file).toBe(true)); + + }); }); it('Result List Successful case', async () => { diff --git a/src/tests/ScanTest.test.ts b/src/tests/ScanTest.test.ts index 8270f2c7..85f24c91 100644 --- a/src/tests/ScanTest.test.ts +++ b/src/tests/ScanTest.test.ts @@ -87,4 +87,15 @@ describe("ScanCreate cases", () => { const scanShowObject = await auth.scanShow(scanObject.id); expect(scanShowObject.exitCode).toEqual(0); }) + + it('KicsRealtime Successful case ', async () => { + const auth = new CxWrapper(cxScanConfig); + let [outputProcess,pid] = await auth.kicsRealtimeScan("dist/tests/data/Dockerfile","docker","-v"); + const cxCommandOutput: CxCommandOutput = await outputProcess; + console.log(" Json object from successful no wait mode case: " + JSON.stringify( cxCommandOutput.payload)); + const scanObject = cxCommandOutput.payload.pop(); + console.log(" Json object from successful no wait mode case: " + JSON.stringify(scanObject)); + expect(scanObject.results.length).toBeGreaterThan(0); + expect(pid).toBeDefined(); + }) }); \ No newline at end of file diff --git a/src/tests/data/Dockerfile b/src/tests/data/Dockerfile new file mode 100644 index 00000000..46598e80 --- /dev/null +++ b/src/tests/data/Dockerfile @@ -0,0 +1,16 @@ +FROM openjdk:11.0.1-jre-slim-stretch + +ARG webwolf_version=v8.0.0-SNAPSHOT + +RUN \ + apt-get update && apt-get install && \ + useradd --home-dir /home/webwolf --create-home -U webwolf + +USER webwolf +COPY target/webwolf-${webwolf_version}.jar /home/webwolf/webwolf.jar +COPY start-webwolf.sh /home/webwolf + +EXPOSE 9090 + +ENTRYPOINT ["/home/webwolf/start-webwolf.sh"] +CMD ["--server.port=9090", "--server.address=0.0.0.0"] \ No newline at end of file