Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support scan vorpal command (AST-42348) #329

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from 9 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
17 changes: 17 additions & 0 deletions src/main/java/com/checkmarx/ast/ScanResult/Error.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.checkmarx.ast.ScanResult;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Error {
public int code;
public String description;

@JsonCreator
public Error(
@JsonProperty("code") int code,
@JsonProperty("description") String description)
{
this.code = code;
this.description = description;
}
}
52 changes: 52 additions & 0 deletions src/main/java/com/checkmarx/ast/ScanResult/ScanDetail.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.checkmarx.ast.ScanResult;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.ToString;
import lombok.Value;

@Value
@ToString(callSuper = true)
@JsonDeserialize()
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ScanDetail {

int ruleID;
String language;
String ruleName;
String severity;
String fileName;
int line;
int problematicLine;
int length;
String remediationAdvise;
String description;

@JsonCreator
public ScanDetail(
@JsonProperty("rule_id") int ruleID,
@JsonProperty("language") String language,
@JsonProperty("rule_name") String ruleName,
@JsonProperty("severity") String severity,
@JsonProperty("file_name") String fileName,
@JsonProperty("line") int line,
@JsonProperty("problematic_line") int problematicLine,
@JsonProperty("length") int length,
@JsonProperty("remediation_advise") String remediationAdvise,
@JsonProperty("description") String description)
{
this.ruleID = ruleID;
this.language = language;
this.ruleName = ruleName;
this.severity = severity;
this.fileName = fileName;
this.line = line;
this.problematicLine = problematicLine;
this.length = length;
this.remediationAdvise = remediationAdvise;
this.description = description;
}
}
45 changes: 45 additions & 0 deletions src/main/java/com/checkmarx/ast/ScanResult/ScanResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.checkmarx.ast.ScanResult;
import com.checkmarx.ast.utils.JsonParser;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.type.TypeFactory;
import lombok.ToString;
import lombok.Value;

import java.util.List;

@Value
@ToString(callSuper = true)
@JsonDeserialize()
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ScanResult {

String requestId;
boolean status;
String message;
List<ScanDetail> scanDetails;
Error error;

@JsonCreator
public ScanResult(
@JsonProperty("request_id") String requestId,
@JsonProperty("Status") boolean status,
@JsonProperty("Message") String message,
@JsonProperty("scan_details") List<ScanDetail> scanDetails,
@JsonProperty("error") Error error)
{
this.requestId = requestId;
this.status = status;
this.message = message;
this.scanDetails = scanDetails;
this.error = error;
}

public static <T> T fromLine(String line) {
return JsonParser.parse(line, TypeFactory.defaultInstance().constructType(ScanResult.class));
}
}
5 changes: 3 additions & 2 deletions src/main/java/com/checkmarx/ast/project/Project.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.checkmarx.ast.project;

import com.checkmarx.ast.utils.JsonParser;
import com.checkmarx.ast.wrapper.CxBaseObject;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
Expand Down Expand Up @@ -36,10 +37,10 @@ public Project(@JsonProperty("ID") String id,
}

public static <T> T fromLine(String line) {
return parse(line, TypeFactory.defaultInstance().constructType(Project.class));
return JsonParser.parse(line, TypeFactory.defaultInstance().constructType(Project.class));
}

public static <T> List<T> listFromLine(String line) {
return parse(line, TypeFactory.defaultInstance().constructCollectionType(List.class, Project.class));
return JsonParser.parse(line, TypeFactory.defaultInstance().constructCollectionType(List.class, Project.class));
}
}
5 changes: 3 additions & 2 deletions src/main/java/com/checkmarx/ast/scan/Scan.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.checkmarx.ast.scan;

import com.checkmarx.ast.utils.JsonParser;
import com.checkmarx.ast.wrapper.CxBaseObject;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
Expand Down Expand Up @@ -43,10 +44,10 @@ public Scan(@JsonProperty("ID") String id, @JsonProperty("ProjectID") String pro
}

public static <T> T fromLine(String line) {
return parse(line, TypeFactory.defaultInstance().constructType(Scan.class));
return JsonParser.parse(line, TypeFactory.defaultInstance().constructType(Scan.class));
}

public static <T> List<T> listFromLine(String line) {
return parse(line, TypeFactory.defaultInstance().constructCollectionType(List.class, Scan.class));
return JsonParser.parse(line, TypeFactory.defaultInstance().constructCollectionType(List.class, Scan.class));
}
}
3 changes: 2 additions & 1 deletion src/main/java/com/checkmarx/ast/tenant/TenantSetting.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.checkmarx.ast.tenant;

import com.checkmarx.ast.utils.JsonParser;
import com.checkmarx.ast.wrapper.CxBaseObject;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
Expand Down Expand Up @@ -31,7 +32,7 @@ public TenantSetting(@JsonProperty("key") String key, @JsonProperty("value") Str
}

public static <T> List<T> listFromLine(String line) {
return CxBaseObject.parse(line,
return JsonParser.parse(line,
TypeFactory.defaultInstance()
.constructCollectionType(List.class, TenantSetting.class));
}
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/com/checkmarx/ast/utils/JsonParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.checkmarx.ast.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;

public class JsonParser {
public static <T> T parse(String line, JavaType type) {
T result = null;
if (!StringUtils.isBlank(line) && isValidJSON(line)) {
try {
result = new ObjectMapper().readValue(line, type);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
return result;
}

private static boolean isValidJSON(final String json) {
try {
final ObjectMapper mapper = new ObjectMapper();
mapper.readTree(json);
return true;
} catch (IOException e) {
return false;
}
}
}
22 changes: 0 additions & 22 deletions src/main/java/com/checkmarx/ast/wrapper/CxBaseObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,4 @@ protected CxBaseObject(@JsonProperty("ID") String id,
this.updatedAt = updatedAt;
this.tags = tags;
}

public static <T> T parse(String line, JavaType type) {
T result = null;
if (!StringUtils.isBlank(line) && isValidJSON(line)) {
try {
result = new ObjectMapper().readValue(line, type);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
return result;
}

public static boolean isValidJSON(final String json) {
try {
final ObjectMapper mapper = new ObjectMapper();
mapper.readTree(json);
return true;
} catch (IOException e) {
return false;
}
}
}
5 changes: 4 additions & 1 deletion src/main/java/com/checkmarx/ast/wrapper/CxConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public final class CxConstants {
static final String SUB_CMD_SHOW = "show";
static final String RESULTS_BFL_SUB_CMD = "bfl";
static final String SUB_CMD_LIST = "list";
static final String SUB_CMD_VORPAL = "vorpal";
static final String SUB_CMD_CREATE = "create";
static final String SUB_CMD_CANCEL = "cancel";
static final String CMD_TRIAGE = "triage";
Expand All @@ -50,7 +51,9 @@ public final class CxConstants {
static final String CWE_ID = "--cwe-id";
static final String LANGUAGE = "--language";
static final String VULNERABILITY_TYPE = "--vulnerability-type";
static final String FILE_SOURCES = "--file";
static final String FILE = "--file";
checkmarx-kobi-hagmi marked this conversation as resolved.
Show resolved Hide resolved
static final String FILE_SOURCE = "--file-source";
static final String VORPAL_LATEST_VERSION = "--vorpal-latest-version";
static final String ADDITONAL_PARAMS = "--additional-params";
static final String ENGINE = "--engine";
static final String SUB_CMD_KICS_REALTIME = "kics-realtime";
Expand Down
21 changes: 19 additions & 2 deletions src/main/java/com/checkmarx/ast/wrapper/CxWrapper.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.checkmarx.ast.wrapper;

import com.checkmarx.ast.ScanResult.ScanResult;
import com.checkmarx.ast.codebashing.CodeBashing;
import com.checkmarx.ast.kicsRealtimeResults.KicsRealtimeResults;
import com.checkmarx.ast.learnMore.LearnMore;
Expand All @@ -12,6 +13,7 @@
import com.checkmarx.ast.results.result.Node;
import com.checkmarx.ast.scan.Scan;
import com.checkmarx.ast.tenant.TenantSetting;
import com.checkmarx.ast.utils.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.databind.type.TypeFactory;
Expand Down Expand Up @@ -216,6 +218,21 @@ public List<Project> projectList(String filter) throws IOException, InterruptedE
return Execution.executeCommand(withConfigArguments(arguments), logger, Project::listFromLine);
}

public ScanResult ScanVorpal(String fileSource, boolean vorpalLatestVersion) throws IOException, InterruptedException, CxException {
this.logger.info("Fetching Vorpal scanResult");

List<String> arguments = new ArrayList<>();
arguments.add(CxConstants.CMD_SCAN);
arguments.add(CxConstants.SUB_CMD_VORPAL);
arguments.add(CxConstants.FILE_SOURCE);
OrShamirCM marked this conversation as resolved.
Show resolved Hide resolved
arguments.add(fileSource);
if (vorpalLatestVersion) {
checkmarx-kobi-hagmi marked this conversation as resolved.
Show resolved Hide resolved
arguments.add(CxConstants.VORPAL_LATEST_VERSION);
}

return Execution.executeCommand(withConfigArguments(arguments), logger, ScanResult::fromLine);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you have error, how it handles it? error in the CLI or error that not part of the scan results object error

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case of an error, the java-wrapper's CxException will be thrown. added test:
void testScanVorpal_WhenMissingFileExtension_ReturnFileExtensionIsRequiredFailure() throws Exception {
// ScanResult scanResult = wrapper.ScanVorpal("src/test/resources/python-vul-file", false);
Assertions.assertThrowsExactly(CxException.class, () -> {
wrapper.ScanVorpal("src/test/resources/python-vul-file", false);
}, "file must have an extension");
}

Copy link
Contributor

@OrShamirCM OrShamirCM Jun 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont want to throw an error and break the IDE.. We want to show the errors in the IDE and the wrapper should return the error message

}

public List<String> projectBranches(@NonNull UUID projectId, String filter)
throws CxException, IOException, InterruptedException {
this.logger.info("Fetching the branches for project id {} using the filter: {}", projectId, filter);
Expand All @@ -229,7 +246,7 @@ public List<String> projectBranches(@NonNull UUID projectId, String filter)

return Execution.executeCommand(withConfigArguments(arguments),
logger,
line -> CxBaseObject.parse(line, BRANCHES_TYPE));
line -> JsonParser.parse(line, BRANCHES_TYPE));
}

public List<CodeBashing> codeBashingList(@NonNull String cweId, @NonNull String language, @NonNull String queryName) throws IOException, InterruptedException, CxException {
Expand Down Expand Up @@ -336,7 +353,7 @@ public KicsRealtimeResults kicsRealtimeScan(@NonNull String fileSources, String
List<String> arguments = new ArrayList<>();
arguments.add(CxConstants.CMD_SCAN);
arguments.add(CxConstants.SUB_CMD_KICS_REALTIME);
arguments.add(CxConstants.FILE_SOURCES);
arguments.add(CxConstants.FILE);
OrShamirCM marked this conversation as resolved.
Show resolved Hide resolved
arguments.add(fileSources);
arguments.add(CxConstants.ADDITONAL_PARAMS);
arguments.add(additionalParams);
Expand Down
Binary file modified src/main/resources/cx.exe
Binary file not shown.
54 changes: 54 additions & 0 deletions src/test/java/com/checkmarx/ast/ScanTest.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.checkmarx.ast;

import com.checkmarx.ast.ScanResult.Error;
import com.checkmarx.ast.ScanResult.ScanDetail;
import com.checkmarx.ast.ScanResult.ScanResult;
import com.checkmarx.ast.kicsRealtimeResults.KicsRealtimeResults;
import com.checkmarx.ast.scan.Scan;
import com.checkmarx.ast.wrapper.CxException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

Expand All @@ -19,6 +23,56 @@ void testScanShow() throws Exception {
Assertions.assertEquals(scanList.get(0).getId(), scan.getId());
}

@Test
void testScanVorpal_WhenFileWithVulnerabilitiesIsSent_ReturnSuccessfulResponseWithCorrectValues() throws Exception {
ScanResult scanResult = wrapper.ScanVorpal("src/test/resources/python-vul-file.py", true);
Assertions.assertNotNull(scanResult.getRequestId());
Assertions.assertTrue(scanResult.isStatus());
Assertions.assertEquals(2, scanResult.getScanDetails().size());
Assertions.assertNull(scanResult.getError());
ScanDetail firstScanDetails = scanResult.getScanDetails().get(0);
Assertions.assertEquals(37, firstScanDetails.getLine());
Assertions.assertEquals("Stored XSS", firstScanDetails.getRuleName());
Assertions.assertEquals("High", firstScanDetails.getSeverity());
Assertions.assertNotNull(firstScanDetails.getRemediationAdvise());
Assertions.assertNotNull(firstScanDetails.getDescription());
ScanDetail secondScanDetails = scanResult.getScanDetails().get(1);
Assertions.assertEquals(76, secondScanDetails.getLine());
Assertions.assertEquals("Missing HSTS Header", secondScanDetails.getRuleName());
Assertions.assertEquals("Medium", secondScanDetails.getSeverity());
Assertions.assertNotNull(secondScanDetails.getRemediationAdvise());
Assertions.assertNotNull(secondScanDetails.getDescription());
}

@Test
void testScanVorpal_WhenFileWithoutVulnerabilitiesIsSent_ReturnSuccessfulResponseWithCorrectValues() throws Exception {
ScanResult scanResult = wrapper.ScanVorpal("src/test/resources/csharp-no-vul.cs", true);
Assertions.assertNotNull(scanResult.getRequestId());
Assertions.assertTrue(scanResult.isStatus());
Assertions.assertEquals(0, scanResult.getScanDetails().size());
Assertions.assertNull(scanResult.getError());
}

@Test
void testScanVorpal_WhenInvalidRequestIsSent_ReturnInternalErrorFailure() throws Exception {
ScanResult scanResult = wrapper.ScanVorpal("src/test/resources/python-vul-file.py", false);
Assertions.assertEquals("some-request-id", scanResult.getRequestId());
Assertions.assertFalse(scanResult.isStatus());
Assertions.assertNull(scanResult.getScanDetails());
Error error = scanResult.getError();
Assertions.assertNotNull(error);
Assertions.assertEquals("An internal error occurred.", error.description);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please have a test with error and not a scan results model

Assertions.assertEquals(2, error.code);
}

@Test
void testScanVorpal_WhenMissingFileExtension_ReturnFileExtensionIsRequiredFailure() throws Exception {
// ScanResult scanResult = wrapper.ScanVorpal("src/test/resources/python-vul-file", false);
Assertions.assertThrowsExactly(CxException.class, () -> {
wrapper.ScanVorpal("src/test/resources/python-vul-file", false);
}, "file must have an extension");
}

@Test
void testScanList() throws Exception {
List<Scan> cxOutput = wrapper.scanList("limit=10");
Expand Down
Loading
Loading