Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 21 additions & 11 deletions package-lock.json

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

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"README.md"
],
"dependencies": {
"log4js": "^6.9.1"
"log4js": "^6.9.1",
"ts-mockito": "^2.6.1"
},
"scripts": {
"build": "tsc",
Expand Down
13 changes: 13 additions & 0 deletions src/main/chat/CxChat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default class CxChat {
conversationId: string;
responses: string[];

constructor(conversationId: string, responses: string[]) {
this.conversationId = conversationId;
this.responses = responses;
}

static parseChat(resultObject: any): CxChat {
return new CxChat(resultObject.conversationId, resultObject.response);
}
}
15 changes: 15 additions & 0 deletions src/main/mask/CxMask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import CxMaskedSecret from "./CxMaskedSecret";

export default class CxMask {
maskedSecrets: CxMaskedSecret[];
maskedFile: string;

constructor(maskedSecrets: CxMaskedSecret[], maskedFile: string) {
this.maskedSecrets = maskedSecrets;
this.maskedFile = maskedFile;
}

static parseMask(resultObject: any): CxMask {
return new CxMask(resultObject.maskedSecrets,resultObject.maskedFile);
}
}
11 changes: 11 additions & 0 deletions src/main/mask/CxMaskedSecret.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default class CxMaskedSecret {
masked: string;
secret: string;
line: number;

constructor(masked: string, secret: string, line: number) {
this.masked = masked;
this.secret = secret;
this.line = line;
}
}
15 changes: 14 additions & 1 deletion src/main/wrapper/CxConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ export enum CxConstants {
CMD_KICS_REALTIME = "kics-realtime",
CMD_SCA_REALTIME = "sca-realtime",
CMD_SCA_REALTIME_PROJECT_DIR = "--project-dir",
CMD_CHAT = "chat",
CMD_CHAT_APIKEY = "--chat-apikey",
CMD_CHAT_FILE = "--result-file",
CMD_CHAT_LINE = "--result-line",
CMD_CHAT_SEVERITY = "--result-severity",
CMD_CHAT_VULNERABILITY = "--result-vulnerability",
CMD_CHAT_INPUT = "--user-input",
CMD_CHAT_CONVERSATION_ID = "--conversation-id",
CMD_CHAT_MODEL = "--model",
CMD_MASK_SECRETS = "mask",
SCAN_INFO_FORMAT = "--scan-info-format",
FORMAT = "--format",
FORMAT_JSON = "json",
Expand Down Expand Up @@ -70,6 +80,8 @@ export enum CxConstants {
CODE_BASHING_TYPE = "CxCodeBashing",
KICS_REALTIME_TYPE = "CxKicsRealTime",
SCA_REALTIME_TYPE = "CxScaRealTime",
CHAT_TYPE = "CxChat",
MASK_TYPE = "CxMask",
LEARN_MORE_DESCRIPTIONS_TYPE = "CxLearnMoreDescriptions",
KICS_REMEDIATION_TYPE = "CxKicsRemediation",
BFL_TYPE = "CxBFL",
Expand All @@ -81,5 +93,6 @@ export enum CxConstants {
SEVERITY_MEDIUM = "medium",
STATE_CONFIRMED = "confirmed",
CMD_LEARN_MORE = "learn-more",
IDE_SCANS_KEY = " scan.config.plugins.ideScans"
IDE_SCANS_KEY = " scan.config.plugins.ideScans",
AI_GUIDED_REMEDIATION_KEY = " scan.config.plugins.aiGuidedRemediation"
}
39 changes: 39 additions & 0 deletions src/main/wrapper/CxWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,45 @@ export class CxWrapper {
return output.has(CxConstants.IDE_SCANS_KEY) && output.get(CxConstants.IDE_SCANS_KEY).toLowerCase() === " true";
}

async guidedRemediationEnabled() : Promise<boolean> {
const commands: string[] = [CxConstants.CMD_UTILS, CxConstants.SUB_CMD_TENANT];
commands.push(...this.initializeCommands(false));
const exec = new ExecutionService();
const output = await exec.executeMapTenantOutputCommands(this.config.pathToExecutable, commands);
return output.has(CxConstants.AI_GUIDED_REMEDIATION_KEY) && output.get(CxConstants.AI_GUIDED_REMEDIATION_KEY).toLowerCase() === " true";
}

async chat(apikey: string, file: string, line: number, severity: string, vulnerability: string, input: string, conversationId?: string, model?: string): Promise<CxCommandOutput> {
const commands: string[] = [
CxConstants.CMD_CHAT,
CxConstants.CMD_CHAT_APIKEY, apikey,
CxConstants.CMD_CHAT_FILE, file,
CxConstants.CMD_CHAT_LINE, line.toString(),
CxConstants.CMD_CHAT_SEVERITY, severity,
CxConstants.CMD_CHAT_VULNERABILITY, vulnerability,
CxConstants.CMD_CHAT_INPUT, input,
];
if (conversationId) {
commands.push(CxConstants.CMD_CHAT_CONVERSATION_ID, conversationId)
}
if (model) {
commands.push(CxConstants.CMD_CHAT_MODEL, model)
}
commands.push(...this.initializeCommands(false));
return new ExecutionService().executeCommands(this.config.pathToExecutable, commands, CxConstants.CHAT_TYPE);
}

async maskSecrets( file: string): Promise<CxCommandOutput> {
const commands: string[] = [
CxConstants.CMD_UTILS,
CxConstants.CMD_MASK_SECRETS,
CxConstants.CMD_CHAT_FILE, file,
];

commands.push(...this.initializeCommands(false));
return new ExecutionService().executeCommands(this.config.pathToExecutable, commands, CxConstants.MASK_TYPE);
}

prepareAdditionalParams(additionalParameters: string) : string[] {
const params: string[] = [];

Expand Down
16 changes: 13 additions & 3 deletions src/main/wrapper/ExecutionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import CxNode from "../results/CxNode";
import CxPackageData from "../results/CxPackageData";
import CxKicsRemediation from "../remediation/CxKicsRemediation";
import CxScaRealTime from "../scaRealtime/CxScaRealTime";
import CxChat from "../chat/CxChat";
import CxMask from "../mask/CxMask";


function isJsonString(s: string) {
Expand Down Expand Up @@ -206,10 +208,18 @@ export class ExecutionService {
cxCommandOutput.payload = learnMore;
break;
case CxConstants.KICS_REMEDIATION_TYPE:
const kicsRemediationOutput = CxKicsRemediation.parseKicsRemediation(resultObject)
cxCommandOutput.payload = [kicsRemediationOutput]
const kicsRemediationOutput = CxKicsRemediation.parseKicsRemediation(resultObject);
cxCommandOutput.payload = [kicsRemediationOutput];
break;
default:
case CxConstants.CHAT_TYPE:
const chatOutput = CxChat.parseChat(resultObject);
cxCommandOutput.payload = [chatOutput];
break;
case CxConstants.MASK_TYPE:
const maskOutput = CxMask.parseMask(resultObject);
cxCommandOutput.payload = [maskOutput];
break;
default:
cxCommandOutput.payload = resultObject;
}
}
Expand Down
55 changes: 55 additions & 0 deletions src/tests/ChatTest.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {CxWrapper} from '../main/wrapper/CxWrapper';
import {CxCommandOutput} from "../main/wrapper/CxCommandOutput";
import CxChat from "../main/chat/CxChat";
import {anything, instance, mock, when} from 'ts-mockito';
import {BaseTest} from "./BaseTest";

function createOutput(exitCode:number,payload:CxChat):CxCommandOutput {
const output = new CxCommandOutput();
output.exitCode=exitCode;
output.status="";
output.payload=[payload];
return output;
}

describe("Gpt Chat Cases", () => {
// tests preparation
const cxScanConfig = new BaseTest();
const mockedWrapper: CxWrapper = mock(CxWrapper);
const originalWrapper: CxWrapper = new CxWrapper(cxScanConfig);
const outputSuccessful = createOutput(0,new CxChat("CONVERSATION",["RESPONSE"] ));

when(mockedWrapper.chat("APIKEY","FILE",anything(),anything(),anything(),anything(),anything(), anything())).thenResolve(
outputSuccessful
);
const wrapper: CxWrapper = instance(mockedWrapper);

it('Gpt Chat Successful case', async () => {
const cxCommandOutput = await wrapper.chat(
"APIKEY",
"FILE",
0,
"SEVERITY",
"VULNERABILITY",
"INPUT",
"CONVERSATION",
"MODEL"
);
expect(cxCommandOutput.exitCode).toBe(0);
});

it('Gpt Chat Failed case', async () => {
const cxCommandOutput = await originalWrapper.chat(
"APIKEY",
"FILE",
0,
"SEVERITY",
"VULNERABILITY",
"INPUT",
"",
"MODEL"
);
expect(cxCommandOutput.exitCode).toBe(0);
expect(cxCommandOutput.payload[0].responses[0]).toBe("It seems that FILE is not available for AI Guided Remediation. Please ensure that you have opened the correct workspace or the relevant file.");
});
});
14 changes: 14 additions & 0 deletions src/tests/MaskTest.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {CxWrapper} from '../main/wrapper/CxWrapper';
import {CxCommandOutput} from "../main/wrapper/CxCommandOutput";
import {BaseTest} from "./BaseTest";

describe("Mask cases",() => {
const cxScanConfig = new BaseTest();
it('Mask Successful case', async () => {
const auth = new CxWrapper(cxScanConfig);
const data = await auth.maskSecrets("dist/tests/data/package.json")
const cxCommandOutput: CxCommandOutput = data;
expect(cxCommandOutput.payload.length).toEqual(1);
});

});
9 changes: 9 additions & 0 deletions src/tests/ScanTest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,17 @@ describe("ScanCreate cases", () => {
})

it("Should check if scan create is possible", async() => {
const cxScanConfig = new BaseTest();
const auth = new CxWrapper(cxScanConfig);
const tenantSettings: boolean = await auth.ideScansEnabled();
expect(tenantSettings).toBeDefined();
})

it("Should check if AI guided remediation is active", async() => {
const cxScanConfig = new BaseTest();
const auth = new CxWrapper(cxScanConfig);
const aiEnabled: boolean = await auth.guidedRemediationEnabled();
expect(aiEnabled).toBeDefined();
})

});