Skip to content

Commit 2b92451

Browse files
Merge pull request #925 from Checkmarx/feature/AST-112336
2 parents 6d6be0f + 344bfd3 commit 2b92451

File tree

9 files changed

+144
-22
lines changed

9 files changed

+144
-22
lines changed

src/main/wrapper/CxConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ export class CxConfig {
77
apiKey: string;
88
tenant: string;
99
additionalParameters:string;
10+
agentName: string;
1011
}

src/main/wrapper/CxConstants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ export enum CxConstants {
116116
CMD_LEARN_MORE = "learn-more",
117117
IDE_SCANS_KEY = "scan.config.plugins.ideScans",
118118
AI_GUIDED_REMEDIATION_KEY = "scan.config.plugins.aiGuidedRemediation",
119+
STANDALONE_KEY = "scan.config.plugins.cxdevassist",
120+
ASSIST_KEY = "scan.config.plugins.cxoneassist",
119121
AI_MCP_SERVER_KEY = "scan.config.plugins.aiMcpServer",
120122
TELEMETRY = "telemetry",
121123
SUB_CMD_TELEMETRY_AI = "ai",

src/main/wrapper/CxWrapper.ts

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ export class CxWrapper {
5555
if (cxScanConfig.additionalParameters) {
5656
this.config.additionalParameters = cxScanConfig.additionalParameters;
5757
}
58+
if (cxScanConfig.agentName) {
59+
this.config.agentName = cxScanConfig.agentName;
60+
}
5861
}
5962

6063

@@ -89,6 +92,10 @@ export class CxWrapper {
8992
list.push(param)
9093
})
9194
}
95+
if (this.config.agentName) {
96+
list.push(CxConstants.AGENT);
97+
list.push(this.config.agentName);
98+
}
9299
if (formatRequired) {
93100
list.push(CxConstants.FORMAT);
94101
list.push(CxConstants.FORMAT_JSON);
@@ -130,7 +137,6 @@ export class CxWrapper {
130137
async scanAsca(
131138
sourceFile: string,
132139
updateVersion = false,
133-
agent?: string | null,
134140
ignoredFilePath?: string
135141
): Promise<CxCommandOutput> {
136142
const commands: string[] = [
@@ -144,12 +150,6 @@ export class CxWrapper {
144150
commands.push(CxConstants.ASCA_UPDATE_VERSION);
145151
}
146152

147-
if (agent) {
148-
commands.push(CxConstants.AGENT, agent);
149-
} else {
150-
commands.push(CxConstants.AGENT, '"js-wrapper"');
151-
}
152-
153153
if (ignoredFilePath) {
154154
commands.push(CxConstants.IGNORE__FILE_PATH, ignoredFilePath);
155155
}
@@ -352,8 +352,8 @@ export class CxWrapper {
352352
return exec.executeResultsCommandsFile(scanId, CxConstants.FORMAT_HTML, CxConstants.FORMAT_HTML_FILE, commands, this.config.pathToExecutable, fileName);
353353
}
354354

355-
async getResults(scanId: string, resultType: string, outputFileName: string, outputFilePath: string, agent?: string | null) {
356-
const commands = this.resultsShow(scanId, resultType, outputFileName, outputFilePath, agent)
355+
async getResults(scanId: string, resultType: string, outputFileName: string, outputFilePath: string) {
356+
const commands = this.resultsShow(scanId, resultType, outputFileName, outputFilePath)
357357
const exec = new ExecutionService();
358358
return await exec.executeCommands(this.config.pathToExecutable, commands);
359359
}
@@ -365,7 +365,7 @@ export class CxWrapper {
365365
return await exec.executeCommands(this.config.pathToExecutable, commands, CxConstants.CODE_BASHING_TYPE);
366366
}
367367

368-
resultsShow(scanId: string, reportFormat: string, outputFileName: string, outputPath: string, agent?: string | null): string[] {
368+
resultsShow(scanId: string, reportFormat: string, outputFileName: string, outputPath: string): string[] {
369369
const commands: string[] = [CxConstants.CMD_RESULT, CxConstants.SUB_CMD_SHOW, CxConstants.SCAN_ID, scanId, CxConstants.REPORT_FORMAT, reportFormat];
370370
if (outputFileName) {
371371
commands.push(CxConstants.OUTPUT_NAME);
@@ -375,10 +375,6 @@ export class CxWrapper {
375375
commands.push(CxConstants.OUTPUT_PATH);
376376
commands.push(outputPath);
377377
}
378-
if (agent) {
379-
commands.push(CxConstants.AGENT);
380-
commands.push(agent);
381-
}
382378
commands.push(...this.initializeCommands(false));
383379
return commands;
384380
}
@@ -466,6 +462,27 @@ export class CxWrapper {
466462
return value?.toLowerCase() === "true";
467463
}
468464

465+
async standaloneEnabled(): Promise<boolean> {
466+
const commands: string[] = [CxConstants.CMD_UTILS, CxConstants.SUB_CMD_TENANT];
467+
commands.push(...this.initializeCommands(false));
468+
469+
const exec = new ExecutionService();
470+
const output = await exec.executeMapTenantOutputCommands(this.config.pathToExecutable, commands);
471+
472+
const value = getTrimmedMapValue(output, CxConstants.STANDALONE_KEY);
473+
return value?.toLowerCase() === "true";
474+
}
475+
476+
async cxOneAssistEnabled(): Promise<boolean> {
477+
const commands: string[] = [CxConstants.CMD_UTILS, CxConstants.SUB_CMD_TENANT];
478+
commands.push(...this.initializeCommands(false));
479+
480+
const exec = new ExecutionService();
481+
const output = await exec.executeMapTenantOutputCommands(this.config.pathToExecutable, commands);
482+
483+
const value = getTrimmedMapValue(output, CxConstants.ASSIST_KEY);
484+
return value?.toLowerCase() === "true";
485+
}
469486

470487
async aiMcpServerEnabled(): Promise<boolean> {
471488
const commands: string[] = [CxConstants.CMD_UTILS, CxConstants.SUB_CMD_TENANT];
@@ -530,12 +547,11 @@ export class CxWrapper {
530547
return new ExecutionService().executeCommands(this.config.pathToExecutable, commands, CxConstants.MASK_TYPE);
531548
}
532549

533-
telemetryAIEvent(aiProvider: string, agent: string, eventType: string, subType: string, engine: string, problemSeverity: string, scanType: string, status: string, totalCount: number): Promise<CxCommandOutput> {
550+
telemetryAIEvent(aiProvider: string, eventType: string, subType: string, engine: string, problemSeverity: string, scanType: string, status: string, totalCount: number): Promise<CxCommandOutput> {
534551
const commands: string[] = [
535552
CxConstants.TELEMETRY,
536553
CxConstants.SUB_CMD_TELEMETRY_AI,
537554
CxConstants.AI_PROVIDER, aiProvider,
538-
CxConstants.AGENT, agent,
539555
CxConstants.TYPE, eventType,
540556
CxConstants.SUB_TYPE, subType,
541557
CxConstants.ENGINE, engine,
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { CxWrapper } from '../main/wrapper/CxWrapper';
2+
import { BaseTest } from './BaseTest';
3+
import { ExecutionService } from '../main/wrapper/ExecutionService';
4+
import { CxConstants } from '../main/wrapper/CxConstants';
5+
6+
describe('cxOneAssistEnabled tenant setting', () => {
7+
const baseConfig = new BaseTest();
8+
9+
afterEach(() => {
10+
jest.restoreAllMocks();
11+
});
12+
13+
it('returns true when assist key value is true (lowercase)', async () => {
14+
jest.spyOn(ExecutionService.prototype, 'executeMapTenantOutputCommands')
15+
.mockResolvedValue(new Map([[CxConstants.ASSIST_KEY, 'true']]));
16+
const wrapper = new CxWrapper(baseConfig);
17+
const enabled = await wrapper.cxOneAssistEnabled();
18+
expect(enabled).toBe(true);
19+
});
20+
21+
it('returns true when assist key value is TRUE (uppercase)', async () => {
22+
jest.spyOn(ExecutionService.prototype, 'executeMapTenantOutputCommands')
23+
.mockResolvedValue(new Map([[CxConstants.ASSIST_KEY, 'TRUE']]));
24+
const wrapper = new CxWrapper(baseConfig);
25+
const enabled = await wrapper.cxOneAssistEnabled();
26+
expect(enabled).toBe(true);
27+
});
28+
29+
it('returns false when assist key value is false', async () => {
30+
jest.spyOn(ExecutionService.prototype, 'executeMapTenantOutputCommands')
31+
.mockResolvedValue(new Map([[CxConstants.ASSIST_KEY, 'false']]));
32+
const wrapper = new CxWrapper(baseConfig);
33+
const enabled = await wrapper.cxOneAssistEnabled();
34+
expect(enabled).toBe(false);
35+
});
36+
37+
it('returns false when assist key is missing', async () => {
38+
jest.spyOn(ExecutionService.prototype, 'executeMapTenantOutputCommands')
39+
.mockResolvedValue(new Map([[CxConstants.IDE_SCANS_KEY, 'true']]));
40+
const wrapper = new CxWrapper(baseConfig);
41+
const enabled = await wrapper.cxOneAssistEnabled();
42+
expect(enabled).toBe(false);
43+
});
44+
45+
it('trims whitespace around key/value before evaluating', async () => {
46+
jest.spyOn(ExecutionService.prototype, 'executeMapTenantOutputCommands')
47+
.mockResolvedValue(new Map([[` ${CxConstants.ASSIST_KEY} `, ' true ']]));
48+
const wrapper = new CxWrapper(baseConfig);
49+
const enabled = await wrapper.cxOneAssistEnabled();
50+
expect(enabled).toBe(true);
51+
});
52+
});

src/tests/BaseTest.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export class BaseTest {
88
pathToExecutable: string;
99
tenant: string;
1010
additionalParameters:string;
11+
agentName:string;
1112

1213
constructor() {
1314
this.baseUri = process.env["CX_BASE_URI"];
@@ -16,6 +17,7 @@ export class BaseTest {
1617
this.clientSecret = process.env["CX_CLIENT_SECRET"];
1718
this.tenant = process.env["CX_TENANT"];
1819
this.apiKey = process.env["CX_APIKEY"];
20+
this.agentName = "VS Code"
1921
this.additionalParameters = "--debug"
2022
if (process.env["PATH_TO_EXECUTABLE"] !== null && process.env["PATH_TO_EXECUTABLE"] !== undefined) {
2123
this.pathToExecutable = process.env["PATH_TO_EXECUTABLE"];

src/tests/ResultTest.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe("Results cases",() => {
2020
const cxCommandOutput: CxCommandOutput = await auth.scanList("statuses=Completed");
2121
const sampleId = cxCommandOutput.payload.pop().id;
2222

23-
auth.getResults(sampleId,"json","jsonList", ".", "jswrapper").then(() => {
23+
auth.getResults(sampleId,"json","jsonList", "jswrapper").then(() => {
2424
fileExists("./jsonList.json").then(file => expect(file).toBe(true));
2525
});
2626
});

src/tests/ScanTest.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,6 @@ it.skip('ScanAsca with ignore file should filter one result', async () => {
292292
const cxCommandOutput: CxCommandOutput = await wrapper.scanAsca(
293293
sourcePath,
294294
false,
295-
null,
296295
ignoreFile
297296
);
298297

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { CxWrapper } from '../main/wrapper/CxWrapper';
2+
import { BaseTest } from './BaseTest';
3+
import { ExecutionService } from '../main/wrapper/ExecutionService';
4+
import { CxConstants } from '../main/wrapper/CxConstants';
5+
6+
describe('standaloneEnabled tenant setting', () => {
7+
const baseConfig = new BaseTest();
8+
9+
afterEach(() => {
10+
jest.restoreAllMocks();
11+
});
12+
13+
it('returns true when standalone tenant flag is true (lowercase)', async () => {
14+
jest.spyOn(ExecutionService.prototype, 'executeMapTenantOutputCommands')
15+
.mockResolvedValue(new Map([[CxConstants.STANDALONE_KEY, 'true']]));
16+
const wrapper = new CxWrapper(baseConfig);
17+
const enabled = await wrapper.standaloneEnabled();
18+
expect(enabled).toBe(true);
19+
});
20+
21+
it('returns true when standalone tenant flag is TRUE (uppercase)', async () => {
22+
jest.spyOn(ExecutionService.prototype, 'executeMapTenantOutputCommands')
23+
.mockResolvedValue(new Map([[CxConstants.STANDALONE_KEY, 'TRUE']]));
24+
const wrapper = new CxWrapper(baseConfig);
25+
const enabled = await wrapper.standaloneEnabled();
26+
expect(enabled).toBe(true);
27+
});
28+
29+
it('returns false when standalone tenant flag is false', async () => {
30+
jest.spyOn(ExecutionService.prototype, 'executeMapTenantOutputCommands')
31+
.mockResolvedValue(new Map([[CxConstants.STANDALONE_KEY, 'false']]));
32+
const wrapper = new CxWrapper(baseConfig);
33+
const enabled = await wrapper.standaloneEnabled();
34+
expect(enabled).toBe(false);
35+
});
36+
37+
it('returns false when standalone tenant flag key is missing', async () => {
38+
jest.spyOn(ExecutionService.prototype, 'executeMapTenantOutputCommands')
39+
.mockResolvedValue(new Map([[CxConstants.IDE_SCANS_KEY, 'true']]));
40+
const wrapper = new CxWrapper(baseConfig);
41+
const enabled = await wrapper.standaloneEnabled();
42+
expect(enabled).toBe(false);
43+
});
44+
45+
it('trims whitespace around key and value before evaluating', async () => {
46+
// Simulate raw output map entries with leading/trailing spaces
47+
jest.spyOn(ExecutionService.prototype, 'executeMapTenantOutputCommands')
48+
.mockResolvedValue(new Map([[` ${CxConstants.STANDALONE_KEY} `, ' true ']]));
49+
const wrapper = new CxWrapper(baseConfig);
50+
const enabled = await wrapper.standaloneEnabled();
51+
expect(enabled).toBe(true);
52+
});
53+
});

src/tests/TelemetryTest.test.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ describe("Telemetry cases", () => {
99
const wrapper = new CxWrapper(cxScanConfig);
1010
const cxCommandOutput: CxCommandOutput = await wrapper.telemetryAIEvent(
1111
"Cursor",
12-
"Cursos",
1312
"click",
1413
"ast-results.viewPackageDetails",
1514
"secrets",
@@ -30,7 +29,6 @@ describe("Telemetry cases", () => {
3029
"",
3130
"",
3231
"",
33-
"",
3432
"asca",
3533
"Critical",
3634
10
@@ -43,8 +41,7 @@ describe("Telemetry cases", () => {
4341
it('TelemetryAIEvent Successful case with edge case parameters', async () => {
4442
const wrapper = new CxWrapper(cxScanConfig);
4543
const cxCommandOutput: CxCommandOutput = await wrapper.telemetryAIEvent(
46-
"",
47-
"",
44+
"",
4845
"",
4946
"",
5047
"",

0 commit comments

Comments
 (0)