From db3f795901e61e0c405706e6ea0ce930c80f52de Mon Sep 17 00:00:00 2001 From: cx-ben-alvo <144705560+cx-ben-alvo@users.noreply.github.com> Date: Thu, 24 Jul 2025 13:18:51 +0300 Subject: [PATCH 1/2] add containers-realtime scan functionality and related constants --- .../containersRealtime/CxContainerRealtime.ts | 65 +++++++++++++++++++ .../CxRealtimeEngineStatus.ts | 8 +++ src/main/wrapper/CxConstants.ts | 2 + src/main/wrapper/CxWrapper.ts | 7 ++ src/main/wrapper/ExecutionService.ts | 5 ++ src/tests/ScanTest.test.ts | 8 +++ 6 files changed, 95 insertions(+) create mode 100644 src/main/containersRealtime/CxContainerRealtime.ts create mode 100644 src/main/containersRealtime/CxRealtimeEngineStatus.ts diff --git a/src/main/containersRealtime/CxContainerRealtime.ts b/src/main/containersRealtime/CxContainerRealtime.ts new file mode 100644 index 00000000..b772f5cf --- /dev/null +++ b/src/main/containersRealtime/CxContainerRealtime.ts @@ -0,0 +1,65 @@ +import { CxRealtimeEngineStatus } from './CxRealtimeEngineStatus'; + +export interface Location { + line: number; + startIndex: number; + endIndex: number; +} + +export default class CxContainerRealtimeResult { + imageName: string; + imageTag: string; + filepath: string; + locations: Location[]; + status: CxRealtimeEngineStatus; + vulnerabilities: { cve: string, severity: string }[]; + + static parseResult(resultObject: any): CxContainerRealtimeResult[] { + const images = resultObject.Images; + let imageResults: CxContainerRealtimeResult[] = []; + if (images instanceof Array) { + imageResults = images.map((member: any) => { + const imageResult = new CxContainerRealtimeResult(); + imageResult.imageName = member.ImageName; + imageResult.imageTag = member.ImageTag; + imageResult.filepath = member.FilePath; + imageResult.locations = Array.isArray(member.Locations) + ? member.Locations.map((loc: any) => ({ + line: loc.Line, + startIndex: loc.StartIndex, + endIndex: loc.EndIndex + })) + : []; + imageResult.status = member.Status as CxRealtimeEngineStatus; + imageResult.vulnerabilities = Array.isArray(member.Vulnerabilities) + ? member.Vulnerabilities.map((vul: any) => ({ + cve: vul.CVE, + severity: vul.Severity + })) + : []; + return imageResult; + }); + } else { + const imageResult = new CxContainerRealtimeResult(); + imageResult.imageName = images.PackageManager; + imageResult.imageTag = images.PackageName; + imageResult.filepath = images.FilePath; + imageResult.locations = Array.isArray(images.Locations) + ? images.Locations.map((loc: any) => ({ + line: loc.Line, + startIndex: loc.StartIndex, + endIndex: loc.EndIndex + })) + : []; + imageResult.status = images.Status as CxRealtimeEngineStatus; + imageResult.vulnerabilities = Array.isArray(images.Vulnerabilities) + ? images.Vulnerabilities.map((vul: any) => ({ + cve: vul.CVE, + severity: vul.Severity + })) + : []; + imageResults.push(imageResult); + } + return imageResults; + } +} \ No newline at end of file diff --git a/src/main/containersRealtime/CxRealtimeEngineStatus.ts b/src/main/containersRealtime/CxRealtimeEngineStatus.ts new file mode 100644 index 00000000..29903417 --- /dev/null +++ b/src/main/containersRealtime/CxRealtimeEngineStatus.ts @@ -0,0 +1,8 @@ +export enum CxRealtimeEngineStatus { + ok = "OK", + unknown = "Unknown", + critical = "Critical", + high = "High", + medium = "Medium", + low = "Low" +} \ No newline at end of file diff --git a/src/main/wrapper/CxConstants.ts b/src/main/wrapper/CxConstants.ts index 887ee77e..c0610bc5 100644 --- a/src/main/wrapper/CxConstants.ts +++ b/src/main/wrapper/CxConstants.ts @@ -75,6 +75,7 @@ export enum CxConstants { ASCA_UPDATE_VERSION = "--asca-latest-version", CMD_OSS = "oss-realtime", CMD_SECRETS = "secrets-realtime", + CMD_CONTAINERS_REALTIME = "containers-realtime", PROJECT_ID = "--project-id", SIMILARITY_ID = "--similarity-id", QUERY_ID = "--query-id", @@ -92,6 +93,7 @@ export enum CxConstants { SCAN_ASCA = "CxAsca", SCAN_OSS = "CxOss", SCAN_SECRETS = "CxSecrets", + SCAN_CONTAINERS_REALTIME = "CxContainersRealtime", PROJECT_TYPE = "CxProject", PREDICATE_TYPE = "CxPredicate", CODE_BASHING_TYPE = "CxCodeBashing", diff --git a/src/main/wrapper/CxWrapper.ts b/src/main/wrapper/CxWrapper.ts index 3446c555..5ec71481 100644 --- a/src/main/wrapper/CxWrapper.ts +++ b/src/main/wrapper/CxWrapper.ts @@ -168,6 +168,13 @@ export class CxWrapper { return await exec.executeCommands(this.config.pathToExecutable, commands, CxConstants.SCAN_OSS); } + async containersRealtimeScanResults(sourceFile: string): Promise { + const commands: string[] = [CxConstants.CMD_SCAN, CxConstants.CMD_CONTAINERS_REALTIME, CxConstants.SOURCE, sourceFile]; + commands.push(...this.initializeCommands(false)); + const exec = new ExecutionService(); + return await exec.executeCommands(this.config.pathToExecutable, commands, CxConstants.SCAN_CONTAINERS_REALTIME); + } + async secretsScanResults(sourceFile: string, ignoredFilePath?: string): Promise { const commands: string[] = [ CxConstants.CMD_SCAN, diff --git a/src/main/wrapper/ExecutionService.ts b/src/main/wrapper/ExecutionService.ts index 9c4182a5..02df20e6 100644 --- a/src/main/wrapper/ExecutionService.ts +++ b/src/main/wrapper/ExecutionService.ts @@ -25,6 +25,7 @@ import CxMask from "../mask/CxMask"; import CxAsca from "../asca/CxAsca"; import CxOssResult from "../oss/CxOss"; import CxSecretsResult from "../secrets/CxSecrets"; +import CxContainerRealtimeResult from "../containersRealtime/CxContainerRealtime"; let skipValue = false; const fileSourceFlag = "--file-source" @@ -211,6 +212,10 @@ export class ExecutionService { const oss = CxOssResult.parseResult(resultObject); cxCommandOutput.payload = [oss]; break; + case CxConstants.SCAN_CONTAINERS_REALTIME: + const images = CxContainerRealtimeResult.parseResult(resultObject); + cxCommandOutput.payload = [images]; + break; case CxConstants.SCAN_SECRETS: const secrets = CxSecretsResult.parseResult(resultObject); cxCommandOutput.payload = [secrets]; diff --git a/src/tests/ScanTest.test.ts b/src/tests/ScanTest.test.ts index 7af2e61b..79f8a9fe 100644 --- a/src/tests/ScanTest.test.ts +++ b/src/tests/ScanTest.test.ts @@ -227,5 +227,13 @@ describe("ScanCreate cases", () => { expect(cxCommandOutput.exitCode).toBe(0); }); + it('ScanContainersRealtime Successful case', async () => { + const wrapper = new CxWrapper(cxScanConfig); + const cxCommandOutput: CxCommandOutput = await wrapper.containersRealtimeScanResults("src/tests/data/Dockerfile"); + console.log("Json object from scanContainersRealtime successful case: " + JSON.stringify(cxCommandOutput)); + expect(cxCommandOutput.payload).toBeDefined(); + expect(cxCommandOutput.exitCode).toBe(0); + }); + }); From d1e94de3379ebcc9a42d8eb956a3545bb5a0bc61 Mon Sep 17 00:00:00 2001 From: cx-ben-alvo <144705560+cx-ben-alvo@users.noreply.github.com> Date: Thu, 24 Jul 2025 13:27:04 +0300 Subject: [PATCH 2/2] skip ScanContainersRealtime successful case test --- src/tests/ScanTest.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/ScanTest.test.ts b/src/tests/ScanTest.test.ts index 79f8a9fe..515afeff 100644 --- a/src/tests/ScanTest.test.ts +++ b/src/tests/ScanTest.test.ts @@ -227,7 +227,7 @@ describe("ScanCreate cases", () => { expect(cxCommandOutput.exitCode).toBe(0); }); - it('ScanContainersRealtime Successful case', async () => { + it.skip('ScanContainersRealtime Successful case', async () => { const wrapper = new CxWrapper(cxScanConfig); const cxCommandOutput: CxCommandOutput = await wrapper.containersRealtimeScanResults("src/tests/data/Dockerfile"); console.log("Json object from scanContainersRealtime successful case: " + JSON.stringify(cxCommandOutput));