diff --git a/pom.xml b/pom.xml index cc8b73fc..9b25bc8b 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ 1.2.0 2.3.0 1.18.6 - 23.0.2 + 23.0.5 checkmarx-ltd_Cx-Client-Common @@ -233,7 +233,7 @@ jcommander 1.78 - + org.projectlombok lombok diff --git a/src/main/java/com/cx/restclient/CxClientDelegator.java b/src/main/java/com/cx/restclient/CxClientDelegator.java index 28a5e764..2966a037 100644 --- a/src/main/java/com/cx/restclient/CxClientDelegator.java +++ b/src/main/java/com/cx/restclient/CxClientDelegator.java @@ -19,8 +19,7 @@ import java.util.EnumMap; import java.util.Map; -import static com.cx.restclient.common.CxPARAM.PROJECT_POLICY_COMPLIANT_STATUS; -import static com.cx.restclient.common.CxPARAM.PROJECT_POLICY_VIOLATED_STATUS; +import static com.cx.restclient.common.CxPARAM.*; import static com.cx.restclient.cxArm.utils.CxARMUtils.getPoliciesNames; /** @@ -127,12 +126,11 @@ public ScanResults getLatestScanResults() { public void printIsProjectViolated(ScanResults scanResults) { if (config.getEnablePolicyViolations()) { log.info(PRINT_LINE); - log.info("Policy Management: "); + log.info("Policy Management: SAST and OSA "); log.info("--------------------"); OSAResults osaResults = (OSAResults) scanResults.get(ScannerType.OSA); SASTResults sastResults = (SASTResults) scanResults.get(ScannerType.SAST); - AstScaResults scaResults = (AstScaResults) scanResults.get(ScannerType.AST_SCA); boolean hasOsaViolations = osaResults != null && @@ -143,30 +141,44 @@ public void printIsProjectViolated(ScanResults scanResults) { if (sastResults != null && sastResults.getSastPolicies() != null && !sastResults.getSastPolicies().isEmpty()) { hasSastPolicies = true; - } - - boolean hasScaViolations = false; - if (scaResults != null && scaResults.getPolicyEvaluations() != null && !scaResults.getPolicyEvaluations().isEmpty()) { - hasScaViolations = true; } - if (!hasSastPolicies && !hasOsaViolations && !hasScaViolations) { - log.info(PROJECT_POLICY_COMPLIANT_STATUS); + if (!hasSastPolicies && !hasOsaViolations) { + log.info(PROJECT_POLICY_COMPLIANT_STATUS_SAST); log.info(PRINT_LINE); } else { - log.info(PROJECT_POLICY_VIOLATED_STATUS); + log.info(PROJECT_POLICY_VIOLATED_STATUS_SAST); if (hasSastPolicies) { log.info("SAST violated policies names: {}", getPoliciesNames(sastResults.getSastPolicies())); } if (hasOsaViolations) { log.info("OSA violated policies names: {}", getPoliciesNames(osaResults.getOsaPolicies())); } + log.info(PRINT_LINE); + } + } + if (config.getEnablePolicyViolationsSCA()) { + log.info(PRINT_LINE); + log.info("Policy Management: SCA "); + log.info("--------------------"); + + AstScaResults scaResults = (AstScaResults) scanResults.get(ScannerType.AST_SCA); + + boolean hasScaViolations = false; + if (scaResults != null && scaResults.getPolicyEvaluations() != null && !scaResults.getPolicyEvaluations().isEmpty()) { + hasScaViolations = true; + } + + if (!hasScaViolations) { + log.info(PROJECT_POLICY_COMPLIANT_STATUS_SCA); + log.info(PRINT_LINE); + } else { + log.info(PROJECT_POLICY_VIOLATED_STATUS_SCA); if (hasScaViolations) { - log.info("SCA policies are violated."); + log.info("SCA policies are violated."); } log.info(PRINT_LINE); } - } } diff --git a/src/main/java/com/cx/restclient/CxSASTClient.java b/src/main/java/com/cx/restclient/CxSASTClient.java index adf7a4e0..51e1ff48 100644 --- a/src/main/java/com/cx/restclient/CxSASTClient.java +++ b/src/main/java/com/cx/restclient/CxSASTClient.java @@ -31,10 +31,6 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.stream.Collectors; import org.apache.http.HttpEntity; @@ -59,6 +55,7 @@ import com.cx.restclient.dto.Status; import com.cx.restclient.exception.CxClientException; import com.cx.restclient.exception.CxHTTPClientException; +import com.cx.restclient.osa.dto.CVE; import com.cx.restclient.sast.dto.*; import com.cx.restclient.sast.utils.LegacyClient; import com.cx.restclient.sast.utils.SASTUtils; @@ -287,6 +284,9 @@ private void createSASTScan(long projectId) { } else { scanId = createRemoteSourceScan(projectId); } + if(config.getProjectLevelCustomFields()!=null) { + updateProjectCustomFields(); + } sastResults.setSastLanguage(language); sastResults.setScanId(scanId); log.info("SAST scan created successfully: Scan ID is {}", scanId); @@ -806,6 +806,74 @@ private boolean isScanWithSettingsSupported() { } } + public void updateProjectCustomFields() { + try { + log.info("Updating Project Custom Fields."); + if (config != null) { + String projectId = String.valueOf(this.projectId); + String apiVersion = getContentTypeAndApiVersion(config, PROJECT_PATH); + String apiVersionCustomField = getContentTypeAndApiVersion(config, CUSTOM_FIELD_PATH); + String projectCustomFieldsString = config.getProjectLevelCustomFields(); + if (projectCustomFieldsString != null && !projectCustomFieldsString.isEmpty()) { + List fetchSASTProjectCustomFields = (List) httpClient.getRequest( + CUSTOM_FIELD_PATH, apiVersionCustomField, ProjectLevelCustomFields.class, 200, SAST_SCAN, true + ); + ArrayList custObj = new ArrayList<>(); + Map projectCustomFieldMap = customFieldMap(projectCustomFieldsString); + Project getProjectRequest = httpClient.getRequest(PROJECT_PATH + projectId, CONTENT_TYPE_APPLICATION_JSON_V2, Project.class, 200, SAST_SCAN, false); + ProjectPutRequest projectPutRequest = new ProjectPutRequest(); + projectPutRequest.setName(getProjectRequest.getName()); + Integer team = Integer.parseInt(getProjectRequest.getTeamId()); + List tempCustomFields = getProjectRequest.getCustomFields(); + for (int i = 0; i < fetchSASTProjectCustomFields.size(); i++) { + if (projectCustomFieldMap.containsKey(fetchSASTProjectCustomFields.get(i).getName())) { + ProjectLevelCustomFields customProjectField = new ProjectLevelCustomFields( + fetchSASTProjectCustomFields.get(i).getId(), + projectCustomFieldMap.get(fetchSASTProjectCustomFields.get(i).getName()), + fetchSASTProjectCustomFields.get(i).getName() + ); + custObj.add(customProjectField); + } + } + List additionalCustomFields = new ArrayList<>(); + for (ProjectLevelCustomFields existingCustomField : tempCustomFields) { + String existingCustomFieldName = existingCustomField.getName(); + boolean isIdExists = projectCustomFieldMap.containsKey(existingCustomFieldName); + if (!isIdExists) { + additionalCustomFields.add(existingCustomField); + } + } + custObj.addAll(additionalCustomFields); + projectPutRequest.setOwningTeam(team); + if (!custObj.isEmpty()) { + projectPutRequest.setCustomFields(custObj); + String json = convertToJson(projectPutRequest); + StringEntity entity = new StringEntity(json); + try { + httpClient.putRequest(PROJECT_PATH + projectId, apiVersion, entity, null, 204, "define project level custom field"); + log.info("Project Level-Custom Fields updated successfully."); + } catch (CxHTTPClientException e) { + log.error("Error updating Project Level-Custom Fields: {}", e.getMessage()); + } + } + } + } + } catch (Exception ex) { + throw new CxClientException("Failed to Update Project Level-Custom Fields: " + ex.getMessage()); + } + } + + private Map customFieldMap(String projectCustomField){ + Map customFieldMap = new HashMap(); + StringTokenizer tokenizer = new StringTokenizer(projectCustomField, ","); + log.info("Project custom field: {}",projectCustomField); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + String[] keyValue = token.split(":"); + customFieldMap.put(keyValue[0], keyValue[1]); + } + return customFieldMap; + } private ScanWithSettingsResponse scanWithSettings(byte[] zipFile, long projectId, boolean isRemote) throws IOException { log.info("Uploading zip file"); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); diff --git a/src/main/java/com/cx/restclient/ast/AstClient.java b/src/main/java/com/cx/restclient/ast/AstClient.java index d21c2782..12f4b2e8 100644 --- a/src/main/java/com/cx/restclient/ast/AstClient.java +++ b/src/main/java/com/cx/restclient/ast/AstClient.java @@ -5,9 +5,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.List; -import java.util.Optional; +import java.util.*; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; @@ -101,11 +99,11 @@ private void validate(CxScanConfig config, Logger log) { protected HttpResponse sendStartScanRequest(RemoteRepositoryInfo repoInfo, SourceLocationType sourceLocation, - String projectId) throws IOException { + String projectId, String scanCustomTags) throws IOException { log.debug("Constructing the 'start scan' request"); ScanStartHandler handler = getScanStartHandler(repoInfo); - + Map scanCustomMap = customFiledMap(scanCustomTags); ProjectToScan project = ProjectToScan.builder() .id(projectId) .type(sourceLocation.getApiValue()) @@ -117,6 +115,7 @@ protected HttpResponse sendStartScanRequest(RemoteRepositoryInfo repoInfo, StartScanRequest request = StartScanRequest.builder() .project(project) .config(apiScanConfig) + .tags(scanCustomMap) .build(); StringEntity entity = HttpClientHelper.convertToStringEntity(request); @@ -125,15 +124,27 @@ protected HttpResponse sendStartScanRequest(RemoteRepositoryInfo repoInfo, return httpClient.postRequest(CREATE_SCAN, ContentType.CONTENT_TYPE_APPLICATION_JSON, entity, HttpResponse.class, HttpStatus.SC_CREATED, "start the scan"); } - - protected HttpResponse submitSourcesFromRemoteRepo(ASTConfig config, String projectId) throws IOException { + private Map customFiledMap(String scanCustomField){ + Map customFieldMap = new HashMap(); + if(!StringUtils.isEmpty(scanCustomField)) { + StringTokenizer tokenizer = new StringTokenizer(scanCustomField, ","); + log.info("scan custom Tags: {}", scanCustomField); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + String[] keyValue = token.split(":"); + customFieldMap.put(keyValue[0], keyValue[1]); + } + } + return customFieldMap; + } + protected HttpResponse submitSourcesFromRemoteRepo(ASTConfig config, String projectId,String customTags) throws IOException { log.info("Using remote repository flow."); RemoteRepositoryInfo repoInfo = config.getRemoteRepositoryInfo(); validateRepoInfo(repoInfo); URL sanitizedUrl = sanitize(repoInfo.getUrl()); log.info("Repository URL: {}", sanitizedUrl); - return sendStartScanRequest(repoInfo, SourceLocationType.REMOTE_REPOSITORY, projectId); + return sendStartScanRequest(repoInfo, SourceLocationType.REMOTE_REPOSITORY, projectId,customTags); } protected void waitForScanToFinish(String scanId) { @@ -249,7 +260,7 @@ protected void handleInitError(Exception e, Results results) { results.setException(new CxClientException(message, e)); } - protected HttpResponse initiateScanForUpload(String projectId, byte[] zipFile, ASTConfig scanConfig) throws IOException { + protected HttpResponse initiateScanForUpload(String projectId, byte[] zipFile, ASTConfig scanConfig,String scanCustomTag) throws IOException { String uploadedArchiveUrl = getSourcesUploadUrl(scanConfig); String cleanPath = uploadedArchiveUrl.split("\\?")[0]; log.info("Uploading to: {}", cleanPath); @@ -262,7 +273,7 @@ protected HttpResponse initiateScanForUpload(String projectId, byte[] zipFile, A RemoteRepositoryInfo uploadedFileInfo = new RemoteRepositoryInfo(); uploadedFileInfo.setUrl(new URL(uploadedArchiveUrl)); - return sendStartScanRequest(uploadedFileInfo, SourceLocationType.LOCAL_DIRECTORY, projectId); + return sendStartScanRequest(uploadedFileInfo, SourceLocationType.LOCAL_DIRECTORY, projectId,scanCustomTag); } private String getSourcesUploadUrl(ASTConfig scanConfig) throws IOException { diff --git a/src/main/java/com/cx/restclient/ast/AstSastClient.java b/src/main/java/com/cx/restclient/ast/AstSastClient.java index 236733b9..5a55f0cb 100644 --- a/src/main/java/com/cx/restclient/ast/AstSastClient.java +++ b/src/main/java/com/cx/restclient/ast/AstSastClient.java @@ -139,7 +139,7 @@ public Results initiateScan() { SourceLocationType locationType = astConfig.getSourceLocationType(); HttpResponse response; if (locationType == SourceLocationType.REMOTE_REPOSITORY) { - response = submitSourcesFromRemoteRepo(astConfig, config.getProjectName()); + response = submitSourcesFromRemoteRepo(astConfig, config.getProjectName(),config.getAstScaConfig().getScaScanCustomTags()); } else { response = submitAllSourcesFromLocalDir(config.getProjectName(), astConfig.getZipFilePath()); @@ -161,7 +161,7 @@ protected HttpResponse submitAllSourcesFromLocalDir(String projectId, String zip String sourceDir = config.getSourceDir(); byte[] zipFile = CxZipUtils.getZippedSources(config, filter, sourceDir, log); - return initiateScanForUpload(projectId, zipFile, config.getAstSastConfig()); + return initiateScanForUpload(projectId, zipFile, config.getAstSastConfig(),config.getAstScaConfig().getScaScanCustomTags()); } @Override diff --git a/src/main/java/com/cx/restclient/ast/AstScaClient.java b/src/main/java/com/cx/restclient/ast/AstScaClient.java index 82fe9f5c..79b28a0f 100644 --- a/src/main/java/com/cx/restclient/ast/AstScaClient.java +++ b/src/main/java/com/cx/restclient/ast/AstScaClient.java @@ -19,21 +19,16 @@ import java.nio.file.StandardCopyOption; import java.nio.file.attribute.FileAttribute; import java.sql.Timestamp; -import java.util.Date; +import java.util.*; import java.text.SimpleDateFormat; import java.text.ParseException; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import com.cx.restclient.ast.dto.sca.*; +import com.cx.restclient.sca.dto.Tags; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; @@ -102,6 +97,7 @@ public class AstScaClient extends AstClient implements Scanner { private static final String RISK_MANAGEMENT_API = properties.get("astSca.riskManagementApi"); private static final String PROJECTS = RISK_MANAGEMENT_API + properties.get("astSca.projects"); + private static final String PROJECTID = PROJECTS + properties.get("astSca.projectId"); private static final String SUMMARY_REPORT = RISK_MANAGEMENT_API + properties.get("astSca.summaryReport"); private static final String FINDINGS = RISK_MANAGEMENT_API + properties.get("astSca.findings"); private static final String PACKAGES = RISK_MANAGEMENT_API + properties.get("astSca.packages"); @@ -375,7 +371,7 @@ public Results initiateScan() { } if (locationType == SourceLocationType.REMOTE_REPOSITORY) { - response = submitSourcesFromRemoteRepo(scaConfig, projectId); + response = submitSourcesFromRemoteRepo(scaConfig, projectId,scaConfig.getScaScanCustomTags()); } else { if (scaConfig.isIncludeSources()) { response = submitAllSourcesFromLocalDir(projectId, astScaConfig.getZipFilePath()); @@ -415,7 +411,7 @@ protected HttpResponse submitAllSourcesFromLocalDir(String projectId, String zip FileUtils.deleteDirectory(configFileDestination.toFile()); - return initiateScanForUpload(projectId, zipFile, config.getAstScaConfig()); + return initiateScanForUpload(projectId, zipFile, config.getAstScaConfig(),config.getAstScaConfig().getScaScanCustomTags()); } /** @@ -510,7 +506,7 @@ private HttpResponse submitScaResolverEvidenceFile(AstScaConfig scaConfig) throw }else{ throw new CxClientException("Error while running sca resolver executable. Exit code: "+exitCode); } - return initiateScanForUpload(projectId, FileUtils.readFileToByteArray(zipFile), config.getAstScaConfig()); + return initiateScanForUpload(projectId, FileUtils.readFileToByteArray(zipFile), config.getAstScaConfig(),config.getAstScaConfig().getScaScanCustomTags()); } public boolean checkSastResultPath(AstScaConfig scaConfig) { @@ -625,7 +621,7 @@ private HttpResponse submitManifestsAndFingerprintsFromLocalDir(String projectId FileUtils.deleteDirectory(configFileDestination.toFile()); - return initiateScanForUpload(projectId, FileUtils.readFileToByteArray(zipFile), astScaConfig); + return initiateScanForUpload(projectId, FileUtils.readFileToByteArray(zipFile), astScaConfig,config.getAstScaConfig().getScaScanCustomTags()); } /** @@ -907,8 +903,8 @@ public void testScaConnection() { private String resolveRiskManagementProject() throws IOException { String projectName = config.getProjectName(); String assignedTeam = config.getAstScaConfig().getTeamPath(); - String assignedTeamId = config.getAstScaConfig().getTeamId(); - + String assignedTeamId = config.getAstScaConfig().getTeamId(); + String projectCustomTag = config.getAstScaConfig().getScaProjectCustomTags(); if (!StringUtils.isEmpty(assignedTeamId)) { assignedTeam = getTeamById(assignedTeamId); @@ -921,10 +917,11 @@ private String resolveRiskManagementProject() throws IOException { String resolvedProjectId = getRiskManagementProjectId(projectName); if (resolvedProjectId == null) { log.info("Project not found, creating a new one."); - resolvedProjectId = createRiskManagementProject(projectName, assignedTeam); + resolvedProjectId = createRiskManagementProject(projectName, assignedTeam,projectCustomTag); log.info("Created a project with ID {}", resolvedProjectId); } else { log.info("Project already exists with ID {}", resolvedProjectId); + UpdateRiskManagementProject(resolvedProjectId,projectCustomTag); } return resolvedProjectId; } @@ -1016,7 +1013,7 @@ private void getRiskManagementProjects() throws IOException { true); } - private String createRiskManagementProject(String name, String assignedTeam) throws IOException { + private String createRiskManagementProject(String name, String assignedTeam, String projectCustomTag) throws IOException { CreateProjectRequest request = new CreateProjectRequest(); request.setName(name); if(!StringUtils.isEmpty(assignedTeam)) { @@ -1024,6 +1021,13 @@ private String createRiskManagementProject(String name, String assignedTeam) thr log.info("Team name: {}", assignedTeam); } + log.info("Project level custom tag name: {}",projectCustomTag); + if(!StringUtils.isEmpty(projectCustomTag)) { + Map tagMaps = customFieldMap(projectCustomTag); + log.debug("Project level custom tags: {}",tagMaps); + request.setTags(tagMaps); + } + StringEntity entity = HttpClientHelper.convertToStringEntity(request); Project newProject = httpClient.postRequest(PROJECTS, @@ -1036,6 +1040,51 @@ private String createRiskManagementProject(String name, String assignedTeam) thr return newProject.getId(); } + private void UpdateRiskManagementProject(String projectId, String customTags) throws IOException { + Project existingProject = httpClient.getRequest(PROJECTID.replace("id",projectId),ContentType.CONTENT_TYPE_APPLICATION_JSON,Project.class, + HttpStatus.SC_OK,"got project details",false); + + UpdateProjectRequest request = new UpdateProjectRequest(); + request.setName(existingProject.getName()); + + log.info("Project level custom tag name: {}",customTags); + if(existingProject.getTags()!=null){ + Map tagMaps = (Map) existingProject.getTags(); + if(!StringUtils.isEmpty(customTags)) { + StringTokenizer tokenizer = new StringTokenizer(customTags, ","); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + String[] keyValue = token.split(":"); + tagMaps.put(keyValue[0], keyValue[1]); + } + } + request.setTags(tagMaps); + }else{ + if(!StringUtils.isEmpty(customTags)) { + Map tagMaps = customFieldMap(customTags); + + request.setTags(tagMaps); + } + } + StringEntity entity = HttpClientHelper.convertToStringEntity(request); + httpClient.putRequest(PROJECTID.replace("id",projectId),ContentType.CONTENT_TYPE_APPLICATION_JSON,entity,Project.class, + HttpStatus.SC_NO_CONTENT,"Updated project successfully"); + } + + + private Map customFieldMap(String projectCustomField){ + Map customFieldMap = new LinkedHashMap(); + if(!StringUtils.isEmpty(projectCustomField)){ + StringTokenizer tokenizer = new StringTokenizer(projectCustomField, ","); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + String[] keyValue = token.split(":"); + customFieldMap.put(keyValue[0], keyValue[1]); + } + } + return customFieldMap; + + } private AstScaResults getScanResults() { AstScaResults result; log.debug("Getting results for scan ID {}", scanId); @@ -1056,11 +1105,12 @@ private AstScaResults getScanResults() { List packages = getPackages(scanId); result.setPackages(packages); - if(config.isEnablePolicyViolations()) { - List policyEvaluations = getPolicyEvaluation(reportId); - result.setPolicyEvaluations(policyEvaluations); - printPolicyEvaluations(policyEvaluations); - determinePolicyViolations(result); + + if(config.isEnablePolicyViolationsSCA()) { + List policyEvaluations = getPolicyEvaluation(reportId); + result.setPolicyEvaluations(policyEvaluations); + printPolicyEvaluations(policyEvaluations); + determinePolicyViolations(result); } String reportLink = getWebReportLink(config.getAstScaConfig().getWebAppUrl()); diff --git a/src/main/java/com/cx/restclient/ast/dto/common/StartScanRequest.java b/src/main/java/com/cx/restclient/ast/dto/common/StartScanRequest.java index e2b6909e..c8a00382 100644 --- a/src/main/java/com/cx/restclient/ast/dto/common/StartScanRequest.java +++ b/src/main/java/com/cx/restclient/ast/dto/common/StartScanRequest.java @@ -17,4 +17,5 @@ public class StartScanRequest { * How to scan. */ private List config; + private Object tags; } diff --git a/src/main/java/com/cx/restclient/ast/dto/common/tags.java b/src/main/java/com/cx/restclient/ast/dto/common/tags.java new file mode 100644 index 00000000..481e802f --- /dev/null +++ b/src/main/java/com/cx/restclient/ast/dto/common/tags.java @@ -0,0 +1,11 @@ +package com.cx.restclient.ast.dto.common; + + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class tags { + +} diff --git a/src/main/java/com/cx/restclient/ast/dto/sca/AstScaConfig.java b/src/main/java/com/cx/restclient/ast/dto/sca/AstScaConfig.java index 528a5623..98558128 100644 --- a/src/main/java/com/cx/restclient/ast/dto/sca/AstScaConfig.java +++ b/src/main/java/com/cx/restclient/ast/dto/sca/AstScaConfig.java @@ -44,6 +44,8 @@ public class AstScaConfig extends ASTConfig implements Serializable { private Boolean isScaProxy; private String pathToScaResolver; + private String scaProjectCustomTags; + private String scaScanCustomTags; private String scaResolverAddParameters; public String getPathToScaResolver() { @@ -59,6 +61,21 @@ public void setScaResolverAddParameters(String scaResolverAddParameters) { this.scaResolverAddParameters = scaResolverAddParameters; } + public String getScaProjectCustomTags() { + return scaProjectCustomTags; + } + + public void setScaProjectCustomTags(String scaProjectCustomTags) { + this.scaProjectCustomTags = scaProjectCustomTags; + } + + public String getScaScanCustomTags() { + return scaScanCustomTags; + } + + public void setScaScanCustomTags(String scaScanCustomTags) { + this.scaScanCustomTags = scaScanCustomTags; + } private Map envVariables; private List configFilePaths; diff --git a/src/main/java/com/cx/restclient/ast/dto/sca/CreateProjectRequest.java b/src/main/java/com/cx/restclient/ast/dto/sca/CreateProjectRequest.java index ad130f14..40825995 100644 --- a/src/main/java/com/cx/restclient/ast/dto/sca/CreateProjectRequest.java +++ b/src/main/java/com/cx/restclient/ast/dto/sca/CreateProjectRequest.java @@ -1,11 +1,22 @@ package com.cx.restclient.ast.dto.sca; +import com.cx.restclient.sca.dto.Tags; + import java.util.ArrayList; import java.util.List; public class CreateProjectRequest { private String name; private List assignedTeams = new ArrayList<>(); + private Object Tags; + + public Object getTags() { + return Tags; + } + + public void setTags(Object tags) { + this.Tags = tags; + } public List getAssignedTeams() { return assignedTeams; diff --git a/src/main/java/com/cx/restclient/ast/dto/sca/Project.java b/src/main/java/com/cx/restclient/ast/dto/sca/Project.java index 7fafedea..d4284598 100644 --- a/src/main/java/com/cx/restclient/ast/dto/sca/Project.java +++ b/src/main/java/com/cx/restclient/ast/dto/sca/Project.java @@ -8,4 +8,5 @@ public class Project { private String name; private String id; + private Object Tags; } diff --git a/src/main/java/com/cx/restclient/ast/dto/sca/UpdateProjectRequest.java b/src/main/java/com/cx/restclient/ast/dto/sca/UpdateProjectRequest.java new file mode 100644 index 00000000..1aa1c5a5 --- /dev/null +++ b/src/main/java/com/cx/restclient/ast/dto/sca/UpdateProjectRequest.java @@ -0,0 +1,39 @@ +package com.cx.restclient.ast.dto.sca; + +import java.util.ArrayList; +import java.util.List; + +public class UpdateProjectRequest { + private String name; + + public void setAssignedTeams(List assignedTeams) { + this.assignedTeams = assignedTeams; + } + + private List assignedTeams = new ArrayList<>(); + private Object Tags; + + public Object getTags() { + return Tags; + } + + public void setTags(Object tags) { + this.Tags = tags; + } + + public List getAssignedTeams() { + return assignedTeams; + } + + public void addAssignedTeams(String assignedTeam) { + this.assignedTeams.add(assignedTeam); + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/cx/restclient/common/CxPARAM.java b/src/main/java/com/cx/restclient/common/CxPARAM.java index b692c562..3570ff3a 100644 --- a/src/main/java/com/cx/restclient/common/CxPARAM.java +++ b/src/main/java/com/cx/restclient/common/CxPARAM.java @@ -26,9 +26,12 @@ public abstract class CxPARAM { public static final String ORIGIN_HEADER = "cxOrigin"; public static final String ORIGIN_URL_HEADER = "cxOriginUrl"; public static final String CSRF_TOKEN_HEADER = "CXCSRFToken"; - public static final String PROJECT_POLICY_VIOLATED_STATUS = "Project policy status : violated"; - public static final String PROJECT_POLICY_COMPLIANT_STATUS = "Project policy status : compliant"; + public static final String PROJECT_POLICY_VIOLATED_STATUS_SAST = "Project policy status for SAST and OSA : violated"; + public static final String PROJECT_POLICY_VIOLATED_STATUS ="Project policy status : violated"; + public static final String PROJECT_POLICY_VIOLATED_STATUS_SCA = "Project policy status for SCA : violated"; + public static final String PROJECT_POLICY_COMPLIANT_STATUS_SAST = "Project policy status for SAST and OSA : compliant"; + public static final String PROJECT_POLICY_COMPLIANT_STATUS_SCA = "Project policy status for SCA : compliant"; public static final String DENY_NEW_PROJECT_ERROR = "Creation of the new project [{projectName}] is not authorized. " + "Please use an existing project. \nYou can enable the creation of new projects by disabling" + "" + " the Deny new Checkmarx projects creation checkbox in the Checkmarx plugin global settings.\n"; diff --git a/src/main/java/com/cx/restclient/common/summary/SummaryUtils.java b/src/main/java/com/cx/restclient/common/summary/SummaryUtils.java index 7dd5193b..a2837e0f 100644 --- a/src/main/java/com/cx/restclient/common/summary/SummaryUtils.java +++ b/src/main/java/com/cx/restclient/common/summary/SummaryUtils.java @@ -57,7 +57,7 @@ else if(config.isOsaEnabled()) boolean buildFailed = false; boolean policyViolated = false; - int policyViolatedCount; + int policyViolatedCount=0; //sast: if (config.isSastEnabled()) { if (sastResults != null && sastResults.isSastResultsReady()) { @@ -180,7 +180,7 @@ else if(config.isOsaEnabled()) } - if (config.getEnablePolicyViolations()) { + if ((config.isSastEnabled()|| config.isOsaEnabled() )&& config.getEnablePolicyViolations()) { Map policies = new HashMap<>(); @@ -204,36 +204,50 @@ else if(config.isOsaEnabled()) (left, right) -> left))); } + if(scanSummary.isPolicyViolated()) { + buildFailed = true; + policyViolated = true; + } + policyViolatedCount = policies.size(); + String policyLabel = policyViolatedCount == 1 ? "Policy" : "Policies"; + templateData.put("policyLabel", policyLabel); + + templateData.put("policyViolatedCount", policyViolatedCount); + } + + if (config.isAstScaEnabled() && config.getEnablePolicyViolationsSCA()) { + Map policies = new HashMap<>(); if(Boolean.TRUE.equals(config.isAstScaEnabled()) && scaResults != null && scaResults.getPolicyEvaluations() != null - && !scaResults.getPolicyEvaluations().isEmpty()) + && !scaResults.getPolicyEvaluations().isEmpty()) { - policyViolated = true; - - policies.putAll(scaResults.getPolicyEvaluations().stream().filter(policy -> policy.getIsViolated()).collect( + policies.putAll(scaResults.getPolicyEvaluations().stream().filter(policy -> policy.getIsViolated()).collect( Collectors.toMap(PolicyEvaluation::getName, PolicyEvaluation::getId, (left, right) -> left))); - if(policies.size()==0) + if(!policyViolated && policies.size()==0) + { + policyViolated = false; + } + else { - policyViolated = false; + policyViolated = true; } } - - + + if(scanSummary.isPolicyViolated()) { - buildFailed = true; - policyViolated = true; + buildFailed = true; + policyViolated = true; } - policyViolatedCount = policies.size(); + policyViolatedCount = policyViolatedCount+policies.size(); String policyLabel = policyViolatedCount == 1 ? "Policy" : "Policies"; templateData.put("policyLabel", policyLabel); - + templateData.put("policyViolatedCount", policyViolatedCount); } - templateData.put("policyViolated", policyViolated); - buildFailed |= policyViolated; + buildFailed = buildFailed || policyViolated; templateData.put("buildFailed", buildFailed); //generate the report: diff --git a/src/main/java/com/cx/restclient/configuration/CxScanConfig.java b/src/main/java/com/cx/restclient/configuration/CxScanConfig.java index 6dcda6bf..252ed36b 100644 --- a/src/main/java/com/cx/restclient/configuration/CxScanConfig.java +++ b/src/main/java/com/cx/restclient/configuration/CxScanConfig.java @@ -65,6 +65,7 @@ public class CxScanConfig implements Serializable { private File zipFile; private Integer engineConfigurationId; private String engineConfigurationName; + private String projectCustomFields; private boolean ignoreBenignErrors = false; private String osaFolderExclusions; @@ -75,6 +76,14 @@ public String getEngineConfigurationName() { public void setEngineConfigurationName(String engineConfigurationName) { this.engineConfigurationName = engineConfigurationName; } + + public String getprojectCustomFields() { + return projectCustomFields; + } + + public void setprojectCustomFields(String projectCustomFields) { + this.projectCustomFields = projectCustomFields; + } private String osaFilterPattern; private String osaArchiveIncludePatterns; @@ -89,6 +98,7 @@ public void setEngineConfigurationName(String engineConfigurationName) { private String osaDependenciesJson; private Boolean avoidDuplicateProjectScans = false; private boolean enablePolicyViolations = false; + private boolean enablePolicyViolationsSCA = false; private Boolean generateXmlReport = true; private String cxARMUrl; @@ -131,6 +141,8 @@ public void setEngineConfigurationName(String engineConfigurationName) { private String customFields; + private String projectLevelCustomFields; + private boolean isOverrideProjectSetting = false; public boolean isOverrideRetentionRate() { @@ -257,6 +269,14 @@ public String getCustomFields() { public void setCustomFields(String customFields) { this.customFields = customFields; } + + public String getProjectLevelCustomFields() { + return projectLevelCustomFields; + } + + public void setProjectLevelCustomFields(String projectLevelCustomFields) { + this.projectLevelCustomFields = projectLevelCustomFields; + } public String getOsaLocationPath() { return osaLocationPath; @@ -650,14 +670,34 @@ public boolean getEnablePolicyViolations() { return enablePolicyViolations; } + public boolean getEnablePolicyViolationsSCA() { + return enablePolicyViolationsSCA; + } + public void setEnablePolicyViolations(boolean enablePolicyViolations) { this.enablePolicyViolations = enablePolicyViolations; } + public void setEnablePolicyViolationsSCA(boolean enablePolicyViolationsSCA) { + this.enablePolicyViolationsSCA = enablePolicyViolationsSCA; + } + public boolean isEnablePolicyViolations() { return enablePolicyViolations; } + public boolean isEnablePolicyViolationsSCA() { + return enablePolicyViolationsSCA; + } + + public Boolean isSASTversionCompitable(){ + + if(Float.parseFloat(cxVersion.getVersion())>=9.6){ + return false; + } + return true; + } + public String getCxARMUrl() { return cxARMUrl; } diff --git a/src/main/java/com/cx/restclient/dto/scansummary/ScanSummary.java b/src/main/java/com/cx/restclient/dto/scansummary/ScanSummary.java index 5bfe90fc..4d491107 100644 --- a/src/main/java/com/cx/restclient/dto/scansummary/ScanSummary.java +++ b/src/main/java/com/cx/restclient/dto/scansummary/ScanSummary.java @@ -19,6 +19,10 @@ public class ScanSummary { private final List newResultThresholdErrors = new ArrayList<>(); private final boolean policyViolated; + private boolean policyVioletedSAST; + + private boolean policyVioletedSCA; + public ScanSummary(CxScanConfig config, SASTResults sastResults, OSAResults osaResults, AstScaResults scaResults) { addSastThresholdErrors(config, sastResults); @@ -26,7 +30,13 @@ public ScanSummary(CxScanConfig config, SASTResults sastResults, OSAResults osaR addNewResultThresholdErrors(config, sastResults); - policyViolated = determinePolicyViolation(config, sastResults, osaResults, scaResults); + policyVioletedSAST = determinePolicyViolation(config, sastResults, osaResults); + policyVioletedSCA = determinePolicyViolationSCA(config,scaResults); + if(policyVioletedSAST&&policyVioletedSCA){ + policyViolated=true; + }else{ + policyViolated=false; + } } @Override @@ -145,11 +155,15 @@ private void addNewResultThresholdErrors(CxScanConfig config, SASTResults sastRe } } - private static boolean determinePolicyViolation(CxScanConfig config, SASTResults sastResults, OSAResults osaResults, AstScaResults scaResults) { + private static boolean determinePolicyViolation(CxScanConfig config, SASTResults sastResults, OSAResults osaResults) { return config.getEnablePolicyViolations() && ((osaResults != null && !osaResults.getOsaPolicies().isEmpty()) || - (sastResults != null && !sastResults.getSastPolicies().isEmpty())) || (scaResults != null && scaResults.isBreakTheBuild() && scaResults.isPolicyViolated()); + (sastResults != null && !sastResults.getSastPolicies().isEmpty())); + } + + private static boolean determinePolicyViolationSCA(CxScanConfig config,AstScaResults scaResults) { + return config.getEnablePolicyViolationsSCA() && (scaResults != null && scaResults.isBreakTheBuild() && scaResults.isPolicyViolated()); } private void checkForThresholdError(int value, Integer threshold, ErrorSource source, Severity severity) { diff --git a/src/main/java/com/cx/restclient/httpClient/CxHttpClient.java b/src/main/java/com/cx/restclient/httpClient/CxHttpClient.java index 65e9ea43..72952c40 100644 --- a/src/main/java/com/cx/restclient/httpClient/CxHttpClient.java +++ b/src/main/java/com/cx/restclient/httpClient/CxHttpClient.java @@ -63,6 +63,9 @@ import java.io.Closeable; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.net.IDN; +import java.net.URI; +import java.net.URISyntaxException; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.security.KeyManagementException; @@ -633,7 +636,21 @@ public void addCustomHeader(String name, String value) { } private T request(HttpRequestBase httpMethod, String contentType, HttpEntity entity, Class responseType, int expectStatus, String failedMsg, boolean isCollection, boolean retry) throws IOException { - if (contentType != null) { + //Support unicode characters + if (httpMethod.getURI() != null && (StringUtils.isNotEmpty(httpMethod.getURI().getHost()) || + StringUtils.isNotEmpty(httpMethod.getURI().getAuthority()))) { + URI tmpUri = httpMethod.getURI(); + String host = StringUtils.isNotEmpty(tmpUri.getAuthority()) ? tmpUri.getAuthority() : tmpUri.getHost(); + host = IDN.toASCII(host, IDN.ALLOW_UNASSIGNED); + try { + URI uri = new URI(tmpUri.getScheme(), tmpUri.getUserInfo(), host, tmpUri.getPort(), tmpUri.getPath(), + tmpUri.getQuery(), tmpUri.getFragment()); + httpMethod.setURI(uri); + } catch (URISyntaxException e) { + log.error("Fail to convert URI: " + httpMethod.getURI().toString()); + } + } + if (contentType != null) { httpMethod.addHeader("Content-type", contentType); } if (entity != null && httpMethod instanceof HttpEntityEnclosingRequestBase) { //Entity for Post methods diff --git a/src/main/java/com/cx/restclient/osa/utils/OSAUtils.java b/src/main/java/com/cx/restclient/osa/utils/OSAUtils.java index 4d75263b..e340baf0 100644 --- a/src/main/java/com/cx/restclient/osa/utils/OSAUtils.java +++ b/src/main/java/com/cx/restclient/osa/utils/OSAUtils.java @@ -190,13 +190,13 @@ public static void writeJsonToFile(String name, Object jsonObj, File workDirecto name = name.endsWith(JSON_EXTENSION) ? name : name + JSON_EXTENSION; File jsonFile = new File(workDirectory + File.separator + name); FileUtils.writeStringToFile(jsonFile, json); - log.info(name + " saved under location: " + jsonFile); + log.info("Report '{}' saved under location: {}", name, jsonFile); } else { String now = new SimpleDateFormat("dd_MM_yyyy-HH_mm_ss").format(new Date()); String fileName = name + "_" + now + JSON_EXTENSION; File jsonFile = new File(workDirectory + CX_REPORT_LOCATION, fileName); FileUtils.writeStringToFile(jsonFile, json); - log.info(name + " saved under location: " + workDirectory + CX_REPORT_LOCATION + File.separator + fileName); + log.info("Report '{}' saved under location: {}", name, workDirectory + CX_REPORT_LOCATION + File.separator + fileName); } } catch (Exception ex) { log.warn("Failed to write OSA JSON report (" + name + ") to file: " + ex.getMessage()); diff --git a/src/main/java/com/cx/restclient/sast/dto/Project.java b/src/main/java/com/cx/restclient/sast/dto/Project.java index 22528849..f128c253 100644 --- a/src/main/java/com/cx/restclient/sast/dto/Project.java +++ b/src/main/java/com/cx/restclient/sast/dto/Project.java @@ -1,5 +1,8 @@ package com.cx.restclient.sast.dto; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; /** @@ -12,7 +15,29 @@ public class Project { private String name; private String teamId; private boolean isPublic; + private List customFields; + + public boolean isPublic() { + return isPublic; + } + public void setPublic(boolean aPublic) { + isPublic = aPublic; + } + + public ArrayList getCustomFields() { + if (customFields instanceof ArrayList) { + return (ArrayList) customFields; + } else if (customFields != null) { + return new ArrayList<>(customFields); + } else { + return new ArrayList<>(); + } + } + public void setCustomFields(ArrayList customFields) { + this.customFields = customFields; + } + public long getId() { return id; } @@ -52,4 +77,5 @@ public String getOwner() { public void setOwner(String owner) { this.owner = owner; } + } diff --git a/src/main/java/com/cx/restclient/sast/dto/ProjectLevelCustomFields.java b/src/main/java/com/cx/restclient/sast/dto/ProjectLevelCustomFields.java new file mode 100644 index 00000000..28bbba9e --- /dev/null +++ b/src/main/java/com/cx/restclient/sast/dto/ProjectLevelCustomFields.java @@ -0,0 +1,40 @@ +package com.cx.restclient.sast.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Created by Galn on 4/11/2018. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectLevelCustomFields { + @Override + public String toString() { + return "ProjectLevelCustomFields [id=" + id + ", value=" + value + ", name=" + name + "]"; + } + + private long id; + private String value; + private String name; + + public ProjectLevelCustomFields() { + } + + public ProjectLevelCustomFields(long id, String value, String name) { + this.id = id; + this.value = value; + this.name = name; + } + + public long getId() { + return id; + } + + public String getValue() { + return value; + } + + public String getName() { + return name; + } + +} diff --git a/src/main/java/com/cx/restclient/sast/dto/ProjectPutRequest.java b/src/main/java/com/cx/restclient/sast/dto/ProjectPutRequest.java new file mode 100644 index 00000000..ffac0599 --- /dev/null +++ b/src/main/java/com/cx/restclient/sast/dto/ProjectPutRequest.java @@ -0,0 +1,42 @@ +package com.cx.restclient.sast.dto; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Created by Galn on 13/02/2018. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectPutRequest { + + private String name; + private Integer owningTeam; + private List customFields; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getOwningTeam() { + return owningTeam; + } + + public void setOwningTeam(Integer owningTeam) { + this.owningTeam = owningTeam; + } + + public List getCustomFields() { + return customFields; + } + + public void setCustomFields(ArrayList custObj) { + this.customFields = custObj; + } + +} diff --git a/src/main/java/com/cx/restclient/sast/utils/LegacyClient.java b/src/main/java/com/cx/restclient/sast/utils/LegacyClient.java index 93c167c8..25bfe2a3 100644 --- a/src/main/java/com/cx/restclient/sast/utils/LegacyClient.java +++ b/src/main/java/com/cx/restclient/sast/utils/LegacyClient.java @@ -221,9 +221,9 @@ public void initiate() throws CxClientException { if (config.isSastEnabled()) { resolvePreset(); } - if (config.getEnablePolicyViolations()) { + if (config.getEnablePolicyViolations() || config.getEnablePolicyViolationsSCA()) { resolveCxARMUrl(); - } + } resolveEngineConfiguration(); resolveProjectId(); resolvePostScanAction(); diff --git a/src/main/java/com/cx/restclient/sast/utils/SASTParam.java b/src/main/java/com/cx/restclient/sast/utils/SASTParam.java index 894335d3..63e0da9b 100644 --- a/src/main/java/com/cx/restclient/sast/utils/SASTParam.java +++ b/src/main/java/com/cx/restclient/sast/utils/SASTParam.java @@ -23,6 +23,8 @@ public class SASTParam { public static final String SAST_EXCLUDE_FOLDERS_FILES_PATTERNS = "projects/%s/sourceCode/excludeSettings"; public static final String SAST_RETENTION_RATE ="projects/{id}/dataRetentionSettings"; + public static final String PROJECT_PATH = "projects/"; + public static final String CUSTOM_FIELD_PATH = "customFields"; //Once it has results public static final String SAST_SCAN_RESULTS_STATISTICS = "sast/scans/{scanId}/resultsStatistics"; diff --git a/src/main/java/com/cx/restclient/sca/dto/Tags.java b/src/main/java/com/cx/restclient/sca/dto/Tags.java new file mode 100644 index 00000000..49a2112f --- /dev/null +++ b/src/main/java/com/cx/restclient/sca/dto/Tags.java @@ -0,0 +1,5 @@ +package com.cx.restclient.sca.dto; + +public class Tags { + +} diff --git a/src/main/resources/common.properties b/src/main/resources/common.properties index b78bb8e3..b1bcc688 100644 --- a/src/main/resources/common.properties +++ b/src/main/resources/common.properties @@ -12,6 +12,7 @@ astSast.descriptionPath = /api/queries/descriptions astSca.riskManagementApi = /risk-management/ astSca.projects = projects +astSca.projectId = /id astSca.summaryReport = riskReports/%s/summary astSca.findings = riskReports/%s/vulnerabilities astSca.packages = riskReports/%s/packages