use of com.checkmarx.flow.dto.BugTracker in project cx-flow by checkmarx-ltd.
the class IssueService method process.
public void process(ScanResults results, ScanRequest request) throws MachinaException {
Map<String, ScanResults.XIssue> xMap;
Map<String, Issue> iMap;
List<String> newIssues = new ArrayList<>();
List<String> updatedIssues = new ArrayList<>();
List<String> closedIssues = new ArrayList<>();
BugTracker bugTracker = request.getBugTracker();
String customBean = bugTracker.getCustomBean();
if (!bugTracker.getType().equals(BugTracker.Type.CUSTOM) && !ScanUtils.empty(customBean)) {
throw new MachinaException("A valid custom bean must be used here.");
}
try {
IssueTracker tracker = (IssueTracker) context.getBean(customBean);
tracker.init(request, results);
String fpLabel = tracker.getFalsePositiveLabel();
codeBashingService.createLessonsMap();
log.info("Processing Issues with custom bean {}", customBean);
List<Issue> issues = tracker.getIssues(request);
if (issues == null) {
issues = Collections.emptyList();
}
xMap = this.getXIssueMap(tracker, results, request);
iMap = this.getIssueMap(tracker, issues, request);
for (Map.Entry<String, ScanResults.XIssue> xIssue : xMap.entrySet()) {
try {
String fileUrl;
ScanResults.XIssue currentIssue = xIssue.getValue();
codeBashingService.addCodebashingUrlToIssue(currentIssue);
/*Issue already exists -> update and comment*/
if (iMap.containsKey(xIssue.getKey())) {
Issue i = iMap.get(xIssue.getKey());
if (xIssue.getValue().isAllFalsePositive()) {
// All issues are false positive, so issue should be closed
Issue fpIssue;
log.debug("All issues are false positives");
if (properties.isListFalsePositives()) {
// Update the ticket if flag is set
log.debug("Issue is being updated to reflect false positive references. Updating issue with key {}", xIssue.getKey());
tracker.updateIssue(i, currentIssue, request);
}
if (tracker.isIssueOpened(i, request)) {
/*Close the issue if in an open state*/
log.info("Closing issue with key {}", i.getId());
tracker.closeIssue(i, request);
closedIssues.add(i.getId());
}
} else if (!i.getLabels().contains(fpLabel)) {
/*Ignore any with label indicating false positive*/
log.info("Issue still exists. Updating issue with key {}", xIssue.getKey());
fileUrl = ScanUtils.getFileUrl(request, currentIssue.getFilename());
currentIssue.setGitUrl(fileUrl);
Issue updatedIssue = tracker.updateIssue(i, currentIssue, request);
if (updatedIssue != null) {
updatedIssues.add(updatedIssue.getId());
log.debug("Update completed for issue #{}", updatedIssue.getId());
}
} else {
log.info("Skipping issue marked as false positive with key {}", xIssue.getKey());
}
} else {
/*Create the new issue*/
if (!xIssue.getValue().isAllFalsePositive()) {
fileUrl = ScanUtils.getFileUrl(request, currentIssue.getFilename());
xIssue.getValue().setGitUrl(fileUrl);
log.info("Creating new issue with key {}", xIssue.getKey());
Issue newIssue = tracker.createIssue(xIssue.getValue(), request);
if (newIssue != null) {
newIssues.add(newIssue.getId());
log.info("New issue created. #{}", newIssue.getId());
}
}
}
} catch (HttpClientErrorException e) {
log.error("Error occurred while processing issue with key {}", xIssue.getKey(), e);
}
}
/*Check if an issue exists in GitLab but not within results and close if not*/
for (Map.Entry<String, Issue> issueMap : iMap.entrySet()) {
String key = issueMap.getKey();
Issue issue = issueMap.getValue();
try {
if (!xMap.containsKey(key) && tracker.isIssueOpened(issue, request)) {
/*Close the issue*/
tracker.closeIssue(issue, request);
closedIssues.add(issue.getId());
log.info("Closing issue #{} with key {}", issue.getId(), key);
}
} catch (HttpClientErrorException e) {
log.error("Error occurred while processing issue with key {}", key, e);
}
}
Map<String, List<String>> issuesMap = new HashMap<>();
issuesMap.put("new", newIssues);
issuesMap.put("updated", updatedIssues);
issuesMap.put("closed", closedIssues);
tracker.complete(request, results);
} catch (BeansException e) {
log.error("Specified bug tracker bean was not found or properly loaded.", e);
throw new MachinaRuntimeException();
} catch (ClassCastException e) {
log.error("Bean must implement the IssueTracker Interface", e);
throw new MachinaRuntimeException();
}
}
use of com.checkmarx.flow.dto.BugTracker in project cx-flow by checkmarx-ltd.
the class JiraService method mapCustomFields.
/**
* Map custom JIRA fields to specific values (Custom Cx fields, Issue result
* fields, static fields
*/
private void mapCustomFields(ScanRequest request, ScanResults.XIssue issue, IssueInputBuilder issueBuilder, boolean update) {
BugTracker bugTracker = request.getBugTracker();
log.debug("Handling custom field mappings");
if (bugTracker.getFields() == null) {
return;
}
String projectKey = bugTracker.getProjectKey();
String issueTypeStr = bugTracker.getIssueType();
for (com.checkmarx.flow.dto.Field f : bugTracker.getFields()) {
String customField = getCustomFieldByName(projectKey, issueTypeStr, f.getJiraFieldName());
String value = "";
String fieldName;
if (update && f.isSkipUpdate()) {
log.debug("Skip update to field {}", f.getName());
continue;
}
if (!ScanUtils.empty(customField)) {
if (customField.equalsIgnoreCase("Labels")) {
log.warn("Configuring the Labels parameter would affect issue tracking and might result in duplicate bug creation or bugs not closing or opening.");
}
/*cx | static | other - specific values that can be linked from scan request or the issue details*/
String fieldType = f.getType();
if (ScanUtils.empty(fieldType)) {
log.warn("Field type not supplied for custom field: {}. Using 'result' by default.", customField);
// use default = result
fieldType = "result";
}
switch(fieldType) {
case FlowConstants.MAIN_MDC_ENTRY:
log.debug("Checkmarx custom field {}", f.getName());
if (request.getCxFields() != null) {
log.debug("Checkmarx custom field");
value = request.getCxFields().get(f.getName());
log.debug("Cx Field value: {}", value);
if (ScanUtils.empty(value) && !ScanUtils.empty(f.getJiraDefaultValue())) {
value = f.getJiraDefaultValue();
log.debug("JIRA default Value is {}", value);
}
} else {
log.debug("No value found for {}", f.getName());
value = "";
}
break;
case "sca-results":
if (issue.getScaDetails() == null) {
log.debug("Sca details not available");
break;
}
fieldName = f.getName();
switch(fieldName) {
case "package-name":
log.debug("package-name: {}", issue.getScaDetails().get(0).getVulnerabilityPackage().getId());
value = issue.getScaDetails().get(0).getVulnerabilityPackage().getId();
break;
case "current-version":
log.debug("current-version: {}", issue.getScaDetails().get(0).getVulnerabilityPackage().getVersion());
value = issue.getScaDetails().get(0).getVulnerabilityPackage().getVersion();
break;
case "fixed-version":
log.debug("fixed-version: {}", issue.getScaDetails().get(0).getFinding().getFixResolutionText());
value = issue.getScaDetails().get(0).getFinding().getFixResolutionText();
break;
case "newest-version":
log.debug(issue.getScaDetails().get(0).getVulnerabilityPackage().getNewestVersion());
value = issue.getScaDetails().get(0).getVulnerabilityPackage().getNewestVersion();
break;
case "locations":
List<String> locations = issue.getScaDetails().get(0).getVulnerabilityPackage().getLocations();
String location = null;
for (String l : locations) {
location = l + ",";
}
log.debug("locations: {}", location);
value = location.substring(0, location.length() - 1);
break;
case "dev-dependency":
log.debug("dev-dependency: {}", issue.getScaDetails().get(0).getVulnerabilityPackage().isDevelopment());
value = String.valueOf(issue.getScaDetails().get(0).getVulnerabilityPackage().isDevelopment()).toUpperCase();
break;
case "direct-dependency":
log.debug("direct-dependency: {}", issue.getScaDetails().get(0).getVulnerabilityPackage().isDirectDependency());
value = String.valueOf(issue.getScaDetails().get(0).getVulnerabilityPackage().isDirectDependency()).toUpperCase();
break;
case "risk-score":
log.debug("risk score: {}", issue.getScaDetails().get(0).getVulnerabilityPackage().getRiskScore());
value = String.valueOf(issue.getScaDetails().get(0).getVulnerabilityPackage().getRiskScore());
break;
case "outdated":
log.debug("outdated: {}", issue.getScaDetails().get(0).getVulnerabilityPackage().isOutdated());
value = String.valueOf(issue.getScaDetails().get(0).getVulnerabilityPackage().isOutdated()).toUpperCase();
break;
case "violates-policy":
log.debug("Violates-Policy: {}", issue.getScaDetails().get(0).getFinding().isViolatingPolicy());
value = String.valueOf(issue.getScaDetails().get(0).getFinding().isViolatingPolicy()).toUpperCase();
}
break;
case "static":
log.debug("Static value {} - {}", f.getName(), f.getJiraDefaultValue());
value = f.getJiraDefaultValue();
break;
default:
// result
fieldName = f.getName();
if (fieldName == null) {
log.warn("Field name not supplied for custom field: {}. Skipping.", customField);
/* there is no default, move on to the next field */
continue;
}
/*known values we can use*/
switch(fieldName) {
case "application":
log.debug("application: {}", request.getApplication());
value = request.getApplication();
break;
case "project":
log.debug("project: {}", request.getProject());
value = request.getProject();
break;
case "namespace":
log.debug("namespace: {}", request.getNamespace());
value = request.getNamespace();
break;
case "repo-name":
log.debug("repo-name: {}", request.getRepoName());
value = request.getRepoName();
break;
case "repo-url":
log.debug("repo-url: {}", request.getRepoUrl());
value = request.getRepoUrl();
break;
case "branch":
log.debug("branch: {}", request.getBranch());
value = request.getBranch();
break;
case "severity":
if (issue.getScaDetails() != null) {
log.debug("severity: {}", issue.getScaDetails().get(0).getFinding().getSeverity());
value = ScanUtils.toProperCase(String.valueOf(issue.getScaDetails().get(0).getFinding().getSeverity()));
} else {
log.debug("severity: {}", issue.getSeverity());
value = ScanUtils.toProperCase(issue.getSeverity());
}
break;
case "category":
log.debug("category: {}", issue.getVulnerability());
value = issue.getVulnerability();
break;
case "cwe":
log.debug("cwe: {}", issue.getCwe());
value = issue.getCwe();
break;
case "cve":
if (issue.getScaDetails() != null) {
log.debug("cve: {}", issue.getScaDetails().get(0).getFinding().getId());
value = issue.getScaDetails().get(0).getFinding().getId();
} else {
log.debug("cve: {}", issue.getCve());
value = issue.getCve();
}
break;
case "system-date":
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDateTime now = LocalDateTime.now().plusDays(f.getOffset());
value = dtf.format(now);
log.debug("system date: {}", value);
break;
case "recommendation":
StringBuilder recommendation = new StringBuilder();
if (issue.getLink() != null && !issue.getLink().isEmpty()) {
recommendation.append("Checkmarx Link: ").append(issue.getLink()).append(HTMLHelper.CRLF);
}
if (!ScanUtils.anyEmpty(flowProperties.getMitreUrl(), issue.getCwe())) {
recommendation.append("Mitre Details: ").append(String.format(flowProperties.getMitreUrl(), issue.getCwe())).append(HTMLHelper.CRLF);
}
if (!ScanUtils.empty(flowProperties.getCodebashUrl())) {
recommendation.append("Training: ").append(issue.getAdditionalDetails().get(FlowConstants.CODE_BASHING_LESSON)).append(HTMLHelper.CRLF);
}
if (!ScanUtils.empty(flowProperties.getWikiUrl())) {
recommendation.append("Guidance: ").append(flowProperties.getWikiUrl()).append(HTMLHelper.CRLF);
}
value = recommendation.toString();
break;
case "loc":
value = "";
if (issue.getDetails() != null) {
List<Integer> lines = issue.getDetails().entrySet().stream().filter(x -> x.getKey() != null && x.getValue() != null && !x.getValue().isFalsePositive()).map(Map.Entry::getKey).collect(Collectors.toList());
if (!lines.isEmpty()) {
Collections.sort(lines);
value = StringUtils.join(lines, ",");
log.debug("loc: {}", value);
}
}
break;
case "not-exploitable":
value = "";
List<Integer> fpLines;
if (issue.getDetails() != null) {
fpLines = issue.getDetails().entrySet().stream().filter(x -> x.getKey() != null && x.getValue() != null && x.getValue().isFalsePositive()).map(Map.Entry::getKey).collect(Collectors.toList());
if (!fpLines.isEmpty()) {
Collections.sort(fpLines);
value = StringUtils.join(fpLines, ",");
log.debug("loc: {}", value);
}
}
break;
case "site":
log.debug("site: {}", request.getSite());
value = request.getSite();
break;
case "issue-link":
if (issue.getScaDetails() != null) {
log.debug("issue-link: {}", issue.getScaDetails().get(0).getVulnerabilityLink());
value = issue.getScaDetails().get(0).getVulnerabilityLink();
} else {
log.debug("issue-link: {}", issue.getLink());
value = issue.getLink();
}
break;
case "filename":
log.debug("filename: {}", issue.getFilename());
value = issue.getFilename();
break;
case "language":
log.debug("language: {}", issue.getLanguage());
value = issue.getLanguage();
break;
case "comment":
value = "";
StringBuilder comments = new StringBuilder();
String commentFmt = "[Line %s]: [%s]".concat(HTMLHelper.CRLF);
if (issue.getDetails() != null) {
issue.getDetails().entrySet().stream().filter(x -> x.getKey() != null && x.getValue() != null && x.getValue().getComment() != null && !x.getValue().getComment().isEmpty()).forEach(c -> comments.append(String.format(commentFmt, c.getKey(), c.getValue().getComment())));
value = comments.toString();
}
break;
default:
log.warn("field value for {} not found", f.getName());
value = "";
}
/*If the value is missing, check if a default value was specified*/
if (ScanUtils.empty(value)) {
log.debug("Value is empty, defaulting to configured default (if applicable)");
if (!ScanUtils.empty(f.getJiraDefaultValue())) {
value = f.getJiraDefaultValue();
log.debug("Default value is {}", value);
}
}
break;
}
/*Determine the expected custom field type within JIRA*/
if (!ScanUtils.empty(value)) {
String jiraFieldType = f.getJiraFieldType();
if (ScanUtils.empty(jiraFieldType)) {
log.warn("JIRA field type not supplied for custom field: {}. Using 'text' by default.", f.getName());
// use default = text
jiraFieldType = "text";
}
List<String> list;
switch(jiraFieldType) {
case SECURITY_FIELD_TYPE:
log.debug("Security field");
SecurityLevel securityLevel = getSecurityLevel(projectKey, issueTypeStr, value);
if (securityLevel != null) {
log.warn("JIRA Security level was not found: {}", value);
issueBuilder.setFieldValue(SECURITY_FIELD_TYPE, securityLevel);
}
break;
case "text":
log.debug("text field");
issueBuilder.setFieldValue(customField, value);
break;
case "component":
log.debug("component field");
issueBuilder.setComponentsNames(Collections.singletonList(value));
break;
case "label":
/*csv to array | replace space with _ */
log.debug("label field");
String[] l = StringUtils.split(value, ",");
list = new ArrayList<>();
for (String x : l) {
list.add(x.replaceAll("[^a-zA-Z0-9:\\-_]+", "_"));
}
if (!ScanUtils.empty(list)) {
issueBuilder.setFieldValue(customField, list);
}
break;
case "single-select":
log.debug("single select field");
issueBuilder.setFieldValue(customField, ComplexIssueInputFieldValue.with(VALUE_FIELD_TYPE, value));
break;
case "radio":
log.debug("radio field");
issueBuilder.setFieldValue(customField, ComplexIssueInputFieldValue.with(VALUE_FIELD_TYPE, value));
break;
case "multi-select":
log.debug("multi select field");
String[] selected = StringUtils.split(value, ",");
List<ComplexIssueInputFieldValue> fields = new ArrayList<>();
for (String s : selected) {
ComplexIssueInputFieldValue fieldValue = ComplexIssueInputFieldValue.with(VALUE_FIELD_TYPE, s.trim());
fields.add(fieldValue);
}
issueBuilder.setFieldValue(customField, fields);
break;
case "cascading-select":
log.debug("cascading select list field");
log.debug("cascading values {}", value);
addCascadingSelect(issueBuilder, f, customField, value);
break;
case "single-version-picker":
log.debug("single version picker");
issueBuilder.setFieldValue(customField, ComplexIssueInputFieldValue.with(NAME_FIELD_TYPE, value));
break;
case "multi-version-picker":
log.debug("multi version picker");
String[] selectedVersions = StringUtils.split(value, ",");
List<ComplexIssueInputFieldValue> versionList = new ArrayList<>();
for (String version : selectedVersions) {
ComplexIssueInputFieldValue fieldValue = ComplexIssueInputFieldValue.with(NAME_FIELD_TYPE, version.trim());
versionList.add(fieldValue);
}
issueBuilder.setFieldValue(customField, versionList);
break;
default:
log.warn("{} not a valid option for jira field type", f.getJiraFieldType());
}
}
}
}
}
use of com.checkmarx.flow.dto.BugTracker in project cx-flow by checkmarx-ltd.
the class ConfigurationOverrider method overrideScanRequestProperties.
/**
* Override scan request details as per file/blob (MachinaOverride)
*/
public ScanRequest overrideScanRequestProperties(FlowOverride override, ScanRequest request) {
scaConfigOverrider.initScaConfig(request);
if (override == null) {
return request;
}
BugTracker bt = request.getBugTracker();
/*Override only applicable to Simple JIRA bug*/
if (request.getBugTracker().getType().equals(BugTracker.Type.JIRA) && override.getJira() != null) {
overrideJiraBugProperties(override, bt);
}
request.setBugTracker(bt);
if (!ScanUtils.empty(override.getApplication())) {
request.setApplication(override.getApplication());
}
if (!ScanUtils.empty(override.getBranches())) {
request.setActiveBranches(override.getBranches());
}
List<String> emails = override.getEmails();
if (emails != null) {
if (emails.isEmpty()) {
request.setEmail(null);
} else {
request.setEmail(emails);
}
}
FlowOverride.Filters filtersObj = override.getFilters();
if (filtersObj != null) {
FilterFactory filterFactory = new FilterFactory();
ControllerRequest controllerRequest = new ControllerRequest(filtersObj.getSeverity(), filtersObj.getCwe(), filtersObj.getCategory(), filtersObj.getStatus(), filtersObj.getState());
FilterConfiguration filter = filterFactory.getFilter(controllerRequest, null);
request.setFilter(filter);
}
return request;
}
use of com.checkmarx.flow.dto.BugTracker in project cx-flow by checkmarx-ltd.
the class BitbucketServerPushHandler method execute.
@Override
public ResponseEntity<EventResponse> execute(String uid) {
try {
// set the default bug tracker as per yml
webhookUtils.setBugTracker(configProvider.getFlowProperties(), controllerRequest);
BugTracker.Type bugType = ScanUtils.getBugTypeEnum(controllerRequest.getBug(), configProvider.getFlowProperties().getBugTrackerImpl());
Optional.ofNullable(controllerRequest.getAppOnly()).ifPresent(configProvider.getFlowProperties()::setTrackApplicationOnly);
ScanRequest.Product p = ScanRequest.Product.valueOf(product.toUpperCase(Locale.ROOT));
String currentBranch = ScanUtils.getBranchFromRef(branchFromRef);
List<String> branches = webhookUtils.getBranches(controllerRequest, configProvider.getFlowProperties());
String latestCommit = toHash;
BugTracker bt = ScanUtils.getBugTracker(controllerRequest.getAssignee(), bugType, configProvider.getJiraProperties(), controllerRequest.getBug());
FilterConfiguration filter = configProvider.getFilterFactory().getFilter(controllerRequest, configProvider.getFlowProperties());
String gitUrl = getGitUrl();
String gitAuthUrl = getGitAuthUrl(gitUrl);
ScanRequest request = ScanRequest.builder().application(application).product(p).project(controllerRequest.getProject()).team(controllerRequest.getTeam()).namespace(getNamespace()).repoName(repositoryName).repoUrl(gitUrl).repoUrlWithAuth(gitAuthUrl).repoType(ScanRequest.Repository.BITBUCKETSERVER).branch(currentBranch).refs(refId).email(emails).scanPreset(controllerRequest.getPreset()).incremental(controllerRequest.getIncremental()).excludeFolders(controllerRequest.getExcludeFolders()).excludeFiles(controllerRequest.getExcludeFiles()).bugTracker(bt).filter(filter).hash(latestCommit).build();
webhookUtils.setScmInstance(controllerRequest, request);
setBrowseUrl(request);
fillRequestWithCommonAdditionalData(request, toProjectKey, toSlug, webhookPayload);
checkForConfigAsCode(request);
request.setId(uid);
// only initiate scan/automation if target branch is applicable
if (configProvider.getHelperService().isBranch2Scan(request, branches)) {
configProvider.getFlowService().initiateAutomation(request);
}
} catch (IllegalArgumentException e) {
return webhookUtils.getBadRequestMessage(e, controllerRequest, product);
}
return webhookUtils.getSuccessMessage();
}
use of com.checkmarx.flow.dto.BugTracker in project cx-flow by checkmarx-ltd.
the class ScanUtilsTest method testCxConfigBugOverride.
@Test
public void testCxConfigBugOverride() {
BugTracker bt = BugTracker.builder().type(BugTracker.Type.CUSTOM).customBean("GitHub").build();
ScanRequest request = ScanRequest.builder().application("abc").product(ScanRequest.Product.CX).project("test").team("\\CxServer\\SP\\Checkmarx").namespace("Custodela").repoName("Riches").repoUrl("https://github.com/Custodela/Riches.git").repoType(ScanRequest.Repository.GITHUB).branch("master").refs(Constants.CX_BRANCH_PREFIX.concat("master")).email(null).incremental(true).scanPreset(Constants.CX_DEFAULT_PRESET).bugTracker(bt).build();
File file = new File(getClass().getClassLoader().getResource("CxConfig-bug.json").getFile());
CxConfig cxConfig = ScanUtils.getConfigAsCode(file);
assertNotNull(cxConfig);
configOverrider.overrideScanRequestProperties(cxConfig, request);
assertEquals("JIRA", request.getBugTracker().getType().toString());
assertEquals("APPSEC", request.getBugTracker().getProjectKey());
}
Aggregations