From 24f9020ad5d2af87bf265156d4ae7d2ba621b5fc Mon Sep 17 00:00:00 2001 From: swatipersistent <99341045+swatipersistent@users.noreply.github.com> Date: Mon, 10 Apr 2023 02:16:29 -0700 Subject: [PATCH 1/3] Report with results of both SCA and SAST from Jenkins Plugin --- .../com/checkmarx/jenkins/CxScanBuilder.java | 121 +++++++++++++++++- .../jenkins/DependencyScanConfig.java | 5 +- .../checkmarx/jenkins/ScaReportFormat.java | 15 +++ .../jenkins/CxScanBuilder/config.jelly | 16 ++- .../CxScanBuilder/help-generateScaReport.html | 3 + 5 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/checkmarx/jenkins/ScaReportFormat.java create mode 100644 src/main/resources/com/checkmarx/jenkins/CxScanBuilder/help-generateScaReport.html diff --git a/src/main/java/com/checkmarx/jenkins/CxScanBuilder.java b/src/main/java/com/checkmarx/jenkins/CxScanBuilder.java index 91414ee7..177e7faa 100644 --- a/src/main/java/com/checkmarx/jenkins/CxScanBuilder.java +++ b/src/main/java/com/checkmarx/jenkins/CxScanBuilder.java @@ -155,6 +155,7 @@ public class CxScanBuilder extends Builder implements SimpleBuildStep { private boolean failBuildOnNewResults; private String failBuildOnNewSeverity; private boolean generatePdfReport; + private boolean generateScaReport; private boolean enableProjectPolicyEnforcement; @Nullable private Integer osaHighThreshold; @@ -194,6 +195,7 @@ public class CxScanBuilder extends Builder implements SimpleBuildStep { CxLoggerAdapter log; private JobStatusOnError jobStatusOnError; + private ScaReportFormat scaReportFormat; private String exclusionsSetting; private String thresholdSettings; private Result vulnerabilityThresholdResult; @@ -223,6 +225,7 @@ public CxScanBuilder( Boolean sastEnabled, @Nullable String preset, JobStatusOnError jobStatusOnError, + ScaReportFormat scaReportFormat, boolean presetSpecified, String exclusionsSetting, @Nullable String excludeFolders, @@ -245,6 +248,7 @@ public CxScanBuilder( @Nullable Integer osaMediumThreshold, @Nullable Integer osaLowThreshold, boolean generatePdfReport, + boolean generateScaReport, boolean enableProjectPolicyEnforcement, String thresholdSettings, String vulnerabilityThresholdResult, @@ -271,6 +275,7 @@ public CxScanBuilder( this.sastEnabled = sastEnabled; this.preset = (preset != null && !preset.startsWith("Provide Checkmarx")) ? preset : null; this.jobStatusOnError = jobStatusOnError; + this.scaReportFormat = scaReportFormat; this.presetSpecified = presetSpecified; this.exclusionsSetting = exclusionsSetting; this.globalExclusions = "global".equals(exclusionsSetting); @@ -294,6 +299,7 @@ public CxScanBuilder( this.osaMediumThreshold = osaMediumThreshold; this.osaLowThreshold = osaLowThreshold; this.generatePdfReport = generatePdfReport; + this.generateScaReport = generateScaReport; this.enableProjectPolicyEnforcement = enableProjectPolicyEnforcement; this.thresholdSettings = thresholdSettings; if (vulnerabilityThresholdResult != null) { @@ -590,6 +596,10 @@ public void setOsaInstallBeforeScan(boolean osaInstallBeforeScan) { public boolean isGeneratePdfReport() { return generatePdfReport; } + + public boolean isGenerateScaReport() { + return generateScaReport; + } public boolean isEnableProjectPolicyEnforcement() { return enableProjectPolicyEnforcement; @@ -747,6 +757,11 @@ public void setLowThreshold(@Nullable Integer lowThreshold) { public void setGeneratePdfReport(boolean generatePdfReport) { this.generatePdfReport = generatePdfReport; } + + @DataBoundSetter + public void setGenerateScaReport(boolean generateScaReport) { + this.generateScaReport = generateScaReport; + } @DataBoundSetter public void setEnableProjectPolicyEnforcement(boolean enableProjectPolicyEnforcement) { @@ -911,8 +926,10 @@ public void perform(@Nonnull Run run, @Nonnull FilePath workspace, @Nonnul EnvVars env = run.getEnvironment(listener); setJvmVars(env); Map fsaVars = getAllFsaVars(env); - CxScanConfig config = resolveConfiguration(run, descriptor, env, log); - + CxScanConfig config; + try { + config = resolveConfiguration(run, descriptor, env, log); + if (configAsCode) { try { overrideConfigAsCode(config, workspace); @@ -975,6 +992,30 @@ public void perform(@Nonnull Run run, @Nonnull FilePath workspace, @Nonnul scanResults.getSastResults().setSastPDFLink(pdfUrl); } } + + if (config.isGenerateScaReport()) { + if(config.getScaReportFormat() != null) { + String path = ""; + // run.getUrl() returns a URL path similar to job/MyJobName/124/ + //getRootUrl() will return the value of "Manage Jenkins->configuration->Jenkins URL" + String baseUrl = Jenkins.getInstance().getRootUrl(); + if (StringUtils.isNotEmpty(baseUrl)) { + URL parsedUrl = new URL(baseUrl); + path = parsedUrl.getPath(); + } + if (!(path.equals("/"))) { + //to handle this Jenkins root url,EX: http://localhost:8081/jenkins + Path pdfUrlPath = Paths.get(path, run.getUrl(), PDF_URL); + scanResults.getScaResults().setScaPDFLink(pdfUrlPath.toString()); + } else { + //to handle this Jenkins root url,EX: http://localhost:8081/ + String pdfUrl = String.format(PDF_URL_TEMPLATE, run.getUrl()); + scanResults.getScaResults().setScaPDFLink(pdfUrl); + } + } + } + + //in case of async mode, do not create reports (only the report of the latest scan) //and don't assert threshold vulnerabilities @@ -1004,7 +1045,7 @@ public void perform(@Nonnull Run run, @Nonnull FilePath workspace, @Nonnul if (osaResults != null && osaResults.isOsaResultsReady()) { createOsaReports(osaResults, checkmarxBuildDir); } else if (scaResults != null && scaResults.isScaResultReady()) { - createScaReports(scaResults, checkmarxBuildDir); + createScaReports(scaResults, checkmarxBuildDir, workspace); } return; } @@ -1015,7 +1056,11 @@ public void perform(@Nonnull Run run, @Nonnull FilePath workspace, @Nonnul cxScanResult.setHtmlReportName(reportName); } run.addAction(cxScanResult); + } catch (ConfigurationException e1) { + e1.printStackTrace(); + } } + private void overrideConfigAsCode(CxScanConfig config, FilePath workspace) throws ConfigurationException { String configFilePath = @@ -1242,10 +1287,19 @@ private void mapSastConfiguration(Optional sast, CxScanConfig scanCo } - private void createScaReports(AstScaResults scaResults, File checkmarxBuildDir) { + private void createScaReports(AstScaResults scaResults, File checkmarxBuildDir, @Nonnull FilePath workspace) { writeJsonObjectToFile(scaResults.getSummary(), new File(checkmarxBuildDir, SCA_SUMMERY_JSON), "OSA summary json report"); writeJsonObjectToFile(scaResults.getPackages(), new File(checkmarxBuildDir, SCA_LIBRARIES_JSON), "OSA libraries json report"); writeJsonObjectToFile(scaResults.getFindings(), new File(checkmarxBuildDir, SCA_VULNERABILITIES_JSON), "OSA vulnerabilities json report"); + + if (scaResults.getPDFReport() != null) { + File pdfReportFile = new File(checkmarxBuildDir, CxScanResult.PDF_REPORT_NAME); + try { + FileUtils.writeByteArrayToFile(pdfReportFile, scaResults.getPDFReport()); + } catch (IOException e) { + log.warn("Failed to write SCA PDF report to workspace: " + e.getMessage()); + } + } } /** @@ -1330,7 +1384,7 @@ private Boolean verifyCustomCharacters(String inputString) { } return true; } - private CxScanConfig resolveConfiguration(Run run, DescriptorImpl descriptor, EnvVars env, CxLoggerAdapter log) throws IOException { + private CxScanConfig resolveConfiguration(Run run, DescriptorImpl descriptor, EnvVars env, CxLoggerAdapter log) throws IOException, ConfigurationException { CxScanConfig ret = new CxScanConfig(); ret.setIsOverrideProjectSetting(overrideProjectSetting); @@ -1498,6 +1552,20 @@ private CxScanConfig resolveConfiguration(Run run, DescriptorImpl descript } ret.setEnablePolicyViolations(enableProjectPolicyEnforcement); + if (!ret.isAstScaEnabled() && !ret.getSynchronous()) { + generateScaReport = false; + } + if (ret.isAstScaEnabled()) { + ret.setGenerateScaReport(generateScaReport); + ret.setScaReportFormat(scaReportFormat.name()); + if (ret.getScaReportFormat() != null && !ret.getScaReportFormat().isEmpty()) { + ret.setGenerateScaReport(true); + } else { + ret.setGenerateScaReport(false); + throw new ConfigurationException("Invalid SCA report format:" + scaReportFormat + "."); + } + } + // Set the Continue build flag to Configuration object if Option from UI is choosen as useContinueBuildOnError if (useContinueBuildOnError(getDescriptor())) { ret.setContinueBuild(Boolean.TRUE); @@ -1791,6 +1859,7 @@ private void printConfiguration(CxScanConfig config, CxLoggerAdapter log) { log.info("CxSCA web app URL: " + config.getAstScaConfig().getWebAppUrl()); log.info("Account: " + config.getAstScaConfig().getTenant()); log.info("Team: " + config.getAstScaConfig().getTeamPath()); + log.info("is generate SCA report: "+ config.isGenerateScaReport()); } } @@ -2139,8 +2208,19 @@ protected Object readResolve() { public DescriptorImpl getDescriptor() { return (DescriptorImpl) super.getDescriptor(); } + + public ScaReportFormat getScaReportFormat() { + return scaReportFormat; + } + + @DataBoundSetter + public void setScaReportFormat(ScaReportFormat scaReportFormat) { + this.scaReportFormat = scaReportFormat; + } - @Extension + + + @Extension public static final class DescriptorImpl extends BuildStepDescriptor { public static final String DEFAULT_FILTER_PATTERNS = CxConfig.defaultFilterPattern(); @@ -2642,6 +2722,20 @@ public FormValidation doCheckIncremental(@QueryParameter boolean value, @QueryPa return FormValidation.ok(); } + @POST + public FormValidation doCheckGenerateScaReport(@QueryParameter boolean value, @QueryParameter boolean dependencyScanConfig, @QueryParameter boolean generateScaReport,@AncestorInPath Item item) { + if (item == null) { + return FormValidation.ok(); + } + item.checkPermission(Item.CONFIGURE); + if (!dependencyScanConfig && value) { + generateScaReport=false; + dependencyScanConfig = false; + return FormValidation.error("Enable dependency scanner as SCA"); + } + + return FormValidation.ok(); + } @POST public FormValidation doTestScaSASTConnection(@QueryParameter final String scaSastServerUrl, @QueryParameter final String password, @@ -3068,6 +3162,19 @@ public ListBoxModel doFillVulnerabilityThresholdResultItems(@AncestorInPath Item return listBoxModel; } + + @POST + public ListBoxModel doFillScaReportFormat(@AncestorInPath Item item) { + if (item == null) { + return new ListBoxModel(); + } + item.checkPermission(Item.CONFIGURE); + ListBoxModel listBoxModel = new ListBoxModel(); + for (ScaReportFormat status : ScaReportFormat.values()) { + listBoxModel.add(new ListBoxModel.Option(status.getDisplayNames(), status.name())); + } + return listBoxModel; + } /* @@ -3371,4 +3478,4 @@ public void setDependencyScanConfig(DependencyScanConfig dependencyScanConfig) { this.dependencyScanConfig = dependencyScanConfig; } } -} +} \ No newline at end of file diff --git a/src/main/java/com/checkmarx/jenkins/DependencyScanConfig.java b/src/main/java/com/checkmarx/jenkins/DependencyScanConfig.java index a083cb06..ac17c0b6 100644 --- a/src/main/java/com/checkmarx/jenkins/DependencyScanConfig.java +++ b/src/main/java/com/checkmarx/jenkins/DependencyScanConfig.java @@ -77,6 +77,9 @@ public class DependencyScanConfig { @DataBoundSetter public Integer scaTimeout; + @DataBoundSetter + public boolean generateScaReport; + @DataBoundSetter public boolean isIncludeSources; @@ -98,4 +101,4 @@ public class DependencyScanConfig { @DataBoundConstructor public DependencyScanConfig() { } -} +} \ No newline at end of file diff --git a/src/main/java/com/checkmarx/jenkins/ScaReportFormat.java b/src/main/java/com/checkmarx/jenkins/ScaReportFormat.java new file mode 100644 index 00000000..14106bc7 --- /dev/null +++ b/src/main/java/com/checkmarx/jenkins/ScaReportFormat.java @@ -0,0 +1,15 @@ +package com.checkmarx.jenkins; + +public enum ScaReportFormat { + PDF("PDF"), XML("XML"), CSV("CSV"), JSON("JSON"), cyclonedxjson("cyclonedxjson"), cyclonedxxml("cyclonedxxml"); + + private final String displayNames; + + ScaReportFormat(String displayNames) { + this.displayNames = displayNames; + } + + public String getDisplayNames() { + return displayNames; + } +} \ No newline at end of file diff --git a/src/main/resources/com/checkmarx/jenkins/CxScanBuilder/config.jelly b/src/main/resources/com/checkmarx/jenkins/CxScanBuilder/config.jelly index 3514ccc1..9c0cab0a 100644 --- a/src/main/resources/com/checkmarx/jenkins/CxScanBuilder/config.jelly +++ b/src/main/resources/com/checkmarx/jenkins/CxScanBuilder/config.jelly @@ -1,6 +1,3 @@ - - - @@ -242,7 +239,7 @@ - + @@ -310,7 +307,16 @@ - + + + + + + ${it.displayNames} + + + diff --git a/src/main/resources/com/checkmarx/jenkins/CxScanBuilder/help-generateScaReport.html b/src/main/resources/com/checkmarx/jenkins/CxScanBuilder/help-generateScaReport.html new file mode 100644 index 00000000..cd10e4df --- /dev/null +++ b/src/main/resources/com/checkmarx/jenkins/CxScanBuilder/help-generateScaReport.html @@ -0,0 +1,3 @@ +
+ Downloads a report with scan results from the Checkmarx server. The report is available via a link on "Checkmarx Scan Results" page. +
\ No newline at end of file From c22c67dbbc508c6cee69793fbce0629a89054364 Mon Sep 17 00:00:00 2001 From: swatipersistent <99341045+swatipersistent@users.noreply.github.com> Date: Thu, 20 Apr 2023 23:34:52 -0700 Subject: [PATCH 2/3] removed unwanted code changes --- src/main/java/com/checkmarx/jenkins/CxScanBuilder.java | 2 +- .../java/com/checkmarx/jenkins/ScaReportFormat.java | 10 +++++----- .../com/checkmarx/jenkins/CxScanBuilder/config.jelly | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/checkmarx/jenkins/CxScanBuilder.java b/src/main/java/com/checkmarx/jenkins/CxScanBuilder.java index 177e7faa..d9c57076 100644 --- a/src/main/java/com/checkmarx/jenkins/CxScanBuilder.java +++ b/src/main/java/com/checkmarx/jenkins/CxScanBuilder.java @@ -3171,7 +3171,7 @@ public ListBoxModel doFillScaReportFormat(@AncestorInPath Item item) { item.checkPermission(Item.CONFIGURE); ListBoxModel listBoxModel = new ListBoxModel(); for (ScaReportFormat status : ScaReportFormat.values()) { - listBoxModel.add(new ListBoxModel.Option(status.getDisplayNames(), status.name())); + listBoxModel.add(new ListBoxModel.Option(status.getDisplayName(), status.name())); } return listBoxModel; } diff --git a/src/main/java/com/checkmarx/jenkins/ScaReportFormat.java b/src/main/java/com/checkmarx/jenkins/ScaReportFormat.java index 14106bc7..8da51a05 100644 --- a/src/main/java/com/checkmarx/jenkins/ScaReportFormat.java +++ b/src/main/java/com/checkmarx/jenkins/ScaReportFormat.java @@ -3,13 +3,13 @@ public enum ScaReportFormat { PDF("PDF"), XML("XML"), CSV("CSV"), JSON("JSON"), cyclonedxjson("cyclonedxjson"), cyclonedxxml("cyclonedxxml"); - private final String displayNames; + private final String displayName; - ScaReportFormat(String displayNames) { - this.displayNames = displayNames; + ScaReportFormat(String displayName) { + this.displayName = displayName; } - public String getDisplayNames() { - return displayNames; + public String getDisplayName() { + return displayName; } } \ No newline at end of file diff --git a/src/main/resources/com/checkmarx/jenkins/CxScanBuilder/config.jelly b/src/main/resources/com/checkmarx/jenkins/CxScanBuilder/config.jelly index 9c0cab0a..8aca5e79 100644 --- a/src/main/resources/com/checkmarx/jenkins/CxScanBuilder/config.jelly +++ b/src/main/resources/com/checkmarx/jenkins/CxScanBuilder/config.jelly @@ -313,7 +313,7 @@ checked="${instance.dependencyScanConfig.dependencyScannerType == 'SCA'}"> - ${it.displayNames} + ${it.displayName}
From 290071d5ee2deec2009d608af84e971ad2f7e7b5 Mon Sep 17 00:00:00 2001 From: swatipersistent <99341045+swatipersistent@users.noreply.github.com> Date: Thu, 18 May 2023 23:10:54 -0700 Subject: [PATCH 3/3] Removed unwanted code changes --- src/main/java/com/checkmarx/jenkins/CxScanBuilder.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/checkmarx/jenkins/CxScanBuilder.java b/src/main/java/com/checkmarx/jenkins/CxScanBuilder.java index d9c57076..2a548b0f 100644 --- a/src/main/java/com/checkmarx/jenkins/CxScanBuilder.java +++ b/src/main/java/com/checkmarx/jenkins/CxScanBuilder.java @@ -1045,7 +1045,7 @@ public void perform(@Nonnull Run run, @Nonnull FilePath workspace, @Nonnul if (osaResults != null && osaResults.isOsaResultsReady()) { createOsaReports(osaResults, checkmarxBuildDir); } else if (scaResults != null && scaResults.isScaResultReady()) { - createScaReports(scaResults, checkmarxBuildDir, workspace); + createScaReports(scaResults, checkmarxBuildDir); } return; } @@ -1287,7 +1287,7 @@ private void mapSastConfiguration(Optional sast, CxScanConfig scanCo } - private void createScaReports(AstScaResults scaResults, File checkmarxBuildDir, @Nonnull FilePath workspace) { + private void createScaReports(AstScaResults scaResults, File checkmarxBuildDir) { writeJsonObjectToFile(scaResults.getSummary(), new File(checkmarxBuildDir, SCA_SUMMERY_JSON), "OSA summary json report"); writeJsonObjectToFile(scaResults.getPackages(), new File(checkmarxBuildDir, SCA_LIBRARIES_JSON), "OSA libraries json report"); writeJsonObjectToFile(scaResults.getFindings(), new File(checkmarxBuildDir, SCA_VULNERABILITIES_JSON), "OSA vulnerabilities json report"); @@ -1552,7 +1552,7 @@ private CxScanConfig resolveConfiguration(Run run, DescriptorImpl descript } ret.setEnablePolicyViolations(enableProjectPolicyEnforcement); - if (!ret.isAstScaEnabled() && !ret.getSynchronous()) { + if (!ret.isAstScaEnabled() || !ret.getSynchronous()) { generateScaReport = false; } if (ret.isAstScaEnabled()) {