diff --git a/pom.xml b/pom.xml index dc8960ce..fd60df89 100644 --- a/pom.xml +++ b/pom.xml @@ -1,105 +1,163 @@ - 4.0.0 - - HCL AppScan - - HCL - https://www.hcl.com/ - - - https://github.com/jenkinsci/appscan-plugin - - - - Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 - - - - - - mattmurp - Matt Murphy - matthew.murphy@hcl.com - - - - - org.jenkins-ci.plugins - plugin - 3.2 - - - - - 1.7.26 - 8 - 2.222.4 - false - - - com.hcl.security - appscan - 1.0.10-SNAPSHOT - This plugin allows you to execute security scans with HCL AppScan - hpi - - - - repo.jenkins-ci.org - https://repo.jenkins-ci.org/public/ - - - - - - repo.jenkins-ci.org - https://repo.jenkins-ci.org/public/ - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.5.1 - - 1.7 - 1.7 - - - - - org.jenkins-ci.tools - maven-hpi-plugin - - - - - - - com.hcl - appscan.sdk - 1.0.24 - - - org.apache.wink - wink-json4j - 1.4 - - - org.jenkins-ci.plugins - credentials - 2.3.19 - - - - - scm:git:ssh://github.com/jenkinsci/appscan-plugin.git - scm:git:ssh://git@github.com/jenkinsci/appscan-plugin.git - https://github.com/jenkinsci/appscan-plugin - HEAD - + 4.0.0 + + HCL AppScan + + HCL + https://www.hcl.com/ + + + https://github.com/jenkinsci/appscan-plugin + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + + + + + + mattmurp + Matt Murphy + matthew.murphy@hcl.com + + + + + org.jenkins-ci.plugins + plugin + 4.16 + + + + + 2.277.1 + 8 + + + com.hcl.security + appscan + 1.0.8-v11 + This plugin allows you to execute security scans with HCL AppScan + hpi + + + + repo.jenkins-ci.org + https://repo.jenkins-ci.org/public/ + + + + + + + repo.jenkins-ci.org + https://repo.jenkins-ci.org/public/ + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.7 + 1.7 + + + + + org.jenkins-ci.tools + maven-hpi-plugin + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + + + org.codehaus.mojo.signature + java18 + + + + + test + + check + + + + + + + + + + + + org.apache.wink + wink-json4j + 1.4 + + + org.jenkins-ci.plugins + credentials + + + + org.jenkins-ci.plugins + structs + + + org.jenkins-ci.plugins.workflow + workflow-cps + test + + + org.jenkins-ci.plugins.workflow + workflow-job + test + + + org.jenkins-ci.plugins.workflow + workflow-basic-steps + test + + + org.jenkins-ci.plugins.workflow + workflow-durable-task-step + test + + + + + + + + io.jenkins.tools.bom + bom-2.277.x + 25 + import + pom + + + + + + scm:git:ssh://github.com/jenkinsci/appscan-plugin.git + scm:git:ssh://git@github.com/jenkinsci/appscan-plugin.git + https://github.com/jenkinsci/appscan-plugin + HEAD + diff --git a/src/main/java/com/hcl/appscan/jenkins/plugin/actions/AppScanAction.java b/src/main/java/com/hcl/appscan/jenkins/plugin/actions/AppScanAction.java index 9e3cfc0d..6e3d48f0 100644 --- a/src/main/java/com/hcl/appscan/jenkins/plugin/actions/AppScanAction.java +++ b/src/main/java/com/hcl/appscan/jenkins/plugin/actions/AppScanAction.java @@ -13,7 +13,7 @@ public abstract class AppScanAction implements Action { protected static final String ICON = "/plugin/appscan/images/ASoC.ico"; //$NON-NLS-1$ protected static final String URL = "https://cloud.appscan.com"; //$NON-NLS-1$ - protected final Job m_project; + transient protected final Job m_project; public AppScanAction (Job project) { m_project = project; diff --git a/src/main/java/com/hcl/appscan/jenkins/plugin/actions/ResultsRetriever.java b/src/main/java/com/hcl/appscan/jenkins/plugin/actions/ResultsRetriever.java index 3dab4c2a..0cab41b1 100644 --- a/src/main/java/com/hcl/appscan/jenkins/plugin/actions/ResultsRetriever.java +++ b/src/main/java/com/hcl/appscan/jenkins/plugin/actions/ResultsRetriever.java @@ -6,29 +6,32 @@ package com.hcl.appscan.jenkins.plugin.actions; +import com.hcl.appscan.jenkins.plugin.Messages; import com.hcl.appscan.jenkins.plugin.util.ExecutorUtil; import com.hcl.appscan.sdk.CoreConstants; import com.hcl.appscan.sdk.scanners.ScanConstants; import hudson.model.Action; import hudson.model.Run; -import java.io.IOException; +import java.io.*; + import java.util.Collection; import java.util.HashSet; -import java.util.concurrent.Callable; -import java.util.concurrent.Future; +import java.util.Scanner; +import java.util.concurrent.*; import jenkins.model.RunAction2; import jenkins.tasks.SimpleBuildStep; +import org.apache.wink.json4j.JSONException; +import org.apache.wink.json4j.JSONObject; import org.kohsuke.stapler.DataBoundConstructor; import com.hcl.appscan.sdk.results.IResultsProvider; -import com.hcl.appscan.jenkins.plugin.Messages; public class ResultsRetriever extends AppScanAction implements RunAction2, SimpleBuildStep.LastBuildAction { - private final Run m_build; + private final Run m_build; private IResultsProvider m_provider; private String m_name; private String m_status; @@ -37,9 +40,25 @@ public class ResultsRetriever extends AppScanAction implements RunAction2, Simpl private String m_label; transient private Future futureTask = null; private Boolean m_resultsAvailable; + private String m_application; + private String m_reportsPath; + + private String m_jobId; + private String m_jobStatus; + private String m_netScanTime=""; + private String m_secEntitiesFound=""; + private String m_secEntitiesTested=""; + private String m_scanStartTime=""; + private String m_pagesFound=""; + private String m_pagesScanned=""; + private String m_scanningPhase=""; + private String m_requestsSent=""; + private String m_secIssueVariants=""; + private ScheduledExecutorService executorService; + @DataBoundConstructor - public ResultsRetriever(Run build, IResultsProvider provider, String scanName, String scanServerUrl, String label) { + public ResultsRetriever(Run build, IResultsProvider provider, String scanName, String scanServerUrl, String label, String applicationId, String reportsPath) { super(build.getParent()); m_build = build; m_provider = provider; @@ -47,6 +66,8 @@ public ResultsRetriever(Run build, IResultsProvider provider, String scanNa m_resultsAvailable = false; m_scanServerUrl = scanServerUrl; m_label = label; + m_application = applicationId; + m_reportsPath = reportsPath; } @Override @@ -83,6 +104,40 @@ public boolean getFailed() { return CoreConstants.FAILED.equalsIgnoreCase(m_status); } + public String getJobId() { + return m_jobId; + } + public String getStatus() { + return m_jobStatus; + } + public String getNetScanTime() { + return m_netScanTime; + } + public String getSecEntitiesFound() { + return m_secEntitiesFound; + } + public String getSecEntitiesTested() { + return m_secEntitiesTested; + } + public String getScanStartTime() { + return m_scanStartTime; + } + public String getPagesFound() { + return m_pagesFound; + } + public String getPagesTested() { + return m_pagesScanned; + } + public String getScanningPhase() { + return m_scanningPhase; + } + public String getReqSent() { + return m_requestsSent; + } + public String getSecIssueVariants() { + return m_secIssueVariants; + } + public String getMessage() { return m_message; } @@ -92,67 +147,164 @@ public String getScanType() { return m_provider.getType(); } - public boolean checkResults(Run r) { - boolean results = false; - if (m_resultsAvailable != null && m_resultsAvailable) return true; - if (futureTask != null && futureTask.isDone()) { + public File getReport() { + File path = (m_reportsPath != null && m_reportsPath.length()>0) ? new File(m_reportsPath) : m_build.getRootDir(); + File report = new File(path, "statistics_"+m_build.getId()+".json"); + if(!report.isFile()) + m_provider.getResultsFile(report, "json"); + return report; + } + + public JSONObject getStatistics() + { + JSONObject statsObject = m_provider.getStatistics(); + + if (statsObject == null) + { + File path = (m_reportsPath != null && m_reportsPath.length()>0) ? new File(m_reportsPath) : m_build.getRootDir(); + File statReport = new File(path, "statistics_"+m_build.getId()+".json"); + if(statReport.exists()) + { + try + { + String myJson = new Scanner(statReport).useDelimiter("\\Z").next(); + if (myJson != null && myJson.length()>0) + statsObject = new JSONObject(myJson); + } + catch (IOException | JSONException e) + { + e.printStackTrace(); + } + } + } + return statsObject; + } + + private void populateStatsData() + { + JSONObject statsObject = getStatistics(); + if (statsObject != null) + { try { - results = futureTask.get(); - m_resultsAvailable = results; - } catch (Exception e) { + m_jobId = statsObject.getString("baseJob"); + m_jobStatus = statsObject.getString("status"); + m_netScanTime = statsObject.getString("net-scan-time"); + m_secEntitiesFound = statsObject.getString("security-entities-found"); + m_secEntitiesTested = statsObject.getString("security-entities-tested"); + m_scanStartTime = statsObject.getString("run-start"); + m_pagesFound = statsObject.getString("pages-found"); + m_pagesScanned = statsObject.getString("pages-scanned"); + m_scanningPhase = statsObject.getString("scanning-phase"); + m_requestsSent = statsObject.getString("requests-sent"); + m_secIssueVariants = statsObject.getString("security-issue-variants"); + } catch (JSONException e) { + e.printStackTrace(); } - } else if (futureTask != null) return false; + } + } - if (!results) { + public boolean checkResults(Run r) + { + if (m_resultsAvailable != null && m_resultsAvailable) + return true; + + if (futureTask != null && futureTask.isDone()) + { + try { + m_resultsAvailable = futureTask.get(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + //e.printStackTrace(); + } catch (java.util.NoSuchElementException e){ + e.printStackTrace(); + } + + } + else if (futureTask != null) + return false; + + if (!m_resultsAvailable) + { final Run rTemp = r; - Callable callableTask = new Callable() { + + Callable callableTask = new Callable() + { @Override - public Boolean call() throws Exception { - String status = null; - if (rTemp.getAllActions().contains(ResultsRetriever.this) && CoreConstants.FAILED.equalsIgnoreCase(status = m_provider.getStatus())) { - String message = com.hcl.appscan.sdk.Messages.getMessage(ScanConstants.SCAN_FAILED, " Scan Name: " + m_name); - if (m_provider.getMessage() != null && m_provider.getMessage().trim().length() > 0) message += ", " + m_provider.getMessage(); + public Boolean call() { + + populateStatsData(); + + ResultsRetriever.this.m_status = m_provider.getStatus(); + ResultsRetriever.this.m_message = m_provider.getMessage(); + - ResultsRetriever.this.m_status = status; + if (rTemp.getAllActions().contains(ResultsRetriever.this) && CoreConstants.FAILED.equalsIgnoreCase(ResultsRetriever.this.m_jobStatus)) { + String message = com.hcl.appscan.sdk.Messages.getMessage(ScanConstants.SCAN_FAILED, " Scan Name: " + m_name); + if (m_provider.getMessage() != null && m_provider.getMessage().trim().length() > 0) + message += ", " + m_provider.getMessage(); ResultsRetriever.this.m_message = message; return true; - } else if (rTemp.getAllActions().contains(ResultsRetriever.this) && m_provider.hasResults()) { - rTemp.getActions().remove(ResultsRetriever.this); //We need to remove this action from the build, but getAllActions() returns a read-only list. + } + else if (rTemp.getAllActions().contains(ResultsRetriever.this) && m_provider.hasResults()) { + m_resultsAvailable = true; + try + { + rTemp.getActions().remove(ResultsRetriever.this); + } + catch (Exception e) + { + System.out.println(e.getMessage()); + } + rTemp.addAction(createResults()); - try { + try + { rTemp.save(); - } catch (IOException e) { } - - ResultsRetriever.this.m_status = status; + catch (Exception e) + { + System.out.println(e.getMessage()); + } return true; } - - if (m_provider.getMessage() != null) { - ResultsRetriever.this.m_message = m_provider.getMessage(); - } - return false; } }; + futureTask = (Future) ExecutorUtil.submitTask(callableTask); } - return results; + return m_resultsAvailable; } private ScanResults createResults() { return new ScanResults( - m_build, - m_provider, - m_name, - m_provider.getStatus(), - m_provider.getFindingsCount(), - m_provider.getHighCount(), - m_provider.getMediumCount(), - m_provider.getLowCount(), - m_provider.getInfoCount(), - m_scanServerUrl, - m_label); + m_build, + m_provider, + m_name, + m_provider.getStatus(), + m_provider.getFindingsCount(), + m_provider.getHighCount(), + m_provider.getMediumCount(), + m_provider.getLowCount(), + m_provider.getInfoCount(), + m_scanServerUrl, + m_label, + m_application, + m_reportsPath, + + m_jobId, + m_jobStatus, + m_netScanTime, + m_secEntitiesFound, + m_secEntitiesTested, + m_scanStartTime, + m_pagesFound, + m_pagesScanned, + m_scanningPhase, + m_requestsSent, + m_secIssueVariants + ); } } diff --git a/src/main/java/com/hcl/appscan/jenkins/plugin/actions/ScanResults.java b/src/main/java/com/hcl/appscan/jenkins/plugin/actions/ScanResults.java index e0af3e56..8f02227b 100644 --- a/src/main/java/com/hcl/appscan/jenkins/plugin/actions/ScanResults.java +++ b/src/main/java/com/hcl/appscan/jenkins/plugin/actions/ScanResults.java @@ -6,8 +6,8 @@ package com.hcl.appscan.jenkins.plugin.actions; -import hudson.model.Action; -import hudson.model.Run; +import com.hcl.appscan.jenkins.plugin.Messages; +import hudson.model.*; import java.io.File; import java.io.IOException; @@ -17,6 +17,7 @@ import javax.servlet.ServletException; +import jenkins.model.Jenkins; import jenkins.tasks.SimpleBuildStep; import org.kohsuke.stapler.DataBoundConstructor; @@ -25,13 +26,9 @@ import com.hcl.appscan.sdk.CoreConstants; import com.hcl.appscan.sdk.results.IResultsProvider; -import com.hcl.appscan.jenkins.plugin.Messages; public class ScanResults extends AppScanAction implements SimpleBuildStep.LastBuildAction { - - private static final String REPORT_SUFFIX = "_report"; //$NON-NLS-1$ - - private final Run m_build; + private final Run m_build; private IResultsProvider m_provider; private String m_name; private String m_status; @@ -42,10 +39,57 @@ public class ScanResults extends AppScanAction implements SimpleBuildStep.LastBu private int m_mediumCount; private int m_lowCount; private int m_infoCount; - + private String m_application; + private String m_reportsPath; + + + private String m_jobId; + private String m_jobStatus; + private String m_netScanTime; + private String m_secEntitiesFound; + private String m_secEntitiesTested; + private String m_scanStartTime; + private String m_pagesFound; + private String m_pagesScanned; + private String m_scanningPhase; + private String m_requestsSent; + private String m_secIssueVariants; + + public ScanResults(Run build, IResultsProvider provider, String name, String status, + int totalFindings, int highCount, int mediumCount, int lowCount, int infoCount, String scanServerUrl, String label,String applicationId, String reportsPath, + String jobId, String jobStatus, String netScanTime, String secEntitiesFound, String secEntitiesTested, String scanStartTime, String pagesFound, + String pagesScanned, String scanningPhase, String requestsSent, String secIssueVariants) { + super(build.getParent()); + m_build = build; + m_provider = provider; + m_name = name; + m_status = status; + m_totalFindings = totalFindings; + m_highCount = highCount; + m_mediumCount = mediumCount; + m_lowCount = lowCount; + m_infoCount = infoCount; + m_label = label; + m_scanServerUrl = scanServerUrl; + m_application = applicationId; + m_reportsPath = reportsPath; + + m_jobId = jobId; + m_jobStatus = jobStatus; + m_netScanTime = netScanTime; + m_secEntitiesFound = secEntitiesFound; + m_secEntitiesTested = secEntitiesTested; + m_scanStartTime = scanStartTime; + m_pagesFound = pagesFound; + m_pagesScanned = pagesScanned; + m_scanningPhase = scanningPhase; + m_requestsSent = requestsSent; + m_secIssueVariants = secIssueVariants; + } + @DataBoundConstructor public ScanResults(Run build, IResultsProvider provider, String name, String status, - int totalFindings, int highCount, int mediumCount, int lowCount, int infoCount, String scanServerUrl, String label) { + int totalFindings, int highCount, int mediumCount, int lowCount, int infoCount, String scanServerUrl, String label,String applicationId) { super(build.getParent()); m_build = build; m_provider = provider; @@ -58,13 +102,15 @@ public ScanResults(Run build, IResultsProvider provider, String name, Strin m_infoCount = infoCount; m_label = label; m_scanServerUrl = scanServerUrl; - getReport(); + m_application = applicationId; } - + @Override public String getUrlName() { - return getReportName(); + return getPDFReport(); } + + public String getXMLReportName(){ return getXMLReport();} @Override public String getDisplayName() { @@ -118,6 +164,10 @@ public boolean getFailed() { String status = m_status == null ? m_provider.getStatus() : m_status; return status.equalsIgnoreCase(CoreConstants.FAILED); } + public boolean getRunning() { + String status = m_status == null ? m_provider.getStatus() : m_status; + return status.equalsIgnoreCase(CoreConstants.RUNNING); + } public String getScanServerUrl() { return m_scanServerUrl; @@ -132,21 +182,39 @@ public boolean isBetterThanLast() { } public void doDynamic(StaplerRequest request, StaplerResponse response) throws MalformedURLException, ServletException, IOException { - File report = getReport(); - if(report.isFile()) + File report = null; + File path = (m_reportsPath != null && m_reportsPath.length()>0) ? new File(m_reportsPath) : m_build.getRootDir(); + + if (request.getParameter("type").equalsIgnoreCase("pdf")) { + report = new File(path, getPDFReport()); + } + if (request.getParameter("type").equalsIgnoreCase("xml")) { + report = new File(path, getXMLReport()); + } + + if(report!= null && report.isFile()) response.serveFile(request, report.toURI().toURL()); } - + public File getReport() { - File report = new File(m_build.getRootDir(), getReportName()); + File path = (m_reportsPath != null && m_reportsPath.length()>0) ? new File(m_reportsPath) : m_build.getRootDir(); + File report = new File(path, getReportName()); if(!report.isFile()) m_provider.getResultsFile(report, null); return report; } - + + private String getPDFReport() + { + return "Report_"+m_build.getId()+".pdf"; + } + + private String getXMLReport() { + return "Report_"+m_build.getId()+".xml"; + } + private String getReportName() { - String name = (getScanType() + getName()).replaceAll(" ", ""); //$NON-NLS-1$ //$NON-NLS-2$ - return name + REPORT_SUFFIX + "." + m_provider.getResultsFormat().toLowerCase(); //$NON-NLS-1$ + return "Report_"+m_build.getId()+".pdf"; } private int getLastFindingsCount() { @@ -154,4 +222,43 @@ private int getLastFindingsCount() { return m_project.getLastSuccessfulBuild().getAction(ScanResults.class).getTotalFindings(); return Integer.MAX_VALUE; } + + public String getJobId() { + return m_jobId; + } + + public String getStatus() { + if (m_jobStatus.equalsIgnoreCase(CoreConstants.READY)) + return "Completed"; + else + return m_jobStatus; + } + + public String getNetScanTime() { + return m_netScanTime; + } + public String getSecEntitiesFound() { + return m_secEntitiesFound; + } + public String getSecEntitiesTested() { + return m_secEntitiesTested; + } + public String getScanStartTime() { + return m_scanStartTime; + } + public String getPagesFound() { + return m_pagesFound; + } + public String getPagesTested() { + return m_pagesScanned; + } + public String getScanningPhase() { + return m_scanningPhase; + } + public String getReqSent() { + return m_requestsSent; + } + public String getSecIssueVariants() { + return m_secIssueVariants; + } } diff --git a/src/main/java/com/hcl/appscan/jenkins/plugin/actions/ScanResultsTrend.java b/src/main/java/com/hcl/appscan/jenkins/plugin/actions/ScanResultsTrend.java index 13003742..86e89103 100644 --- a/src/main/java/com/hcl/appscan/jenkins/plugin/actions/ScanResultsTrend.java +++ b/src/main/java/com/hcl/appscan/jenkins/plugin/actions/ScanResultsTrend.java @@ -6,6 +6,7 @@ package com.hcl.appscan.jenkins.plugin.actions; +import com.hcl.appscan.jenkins.plugin.Messages; import hudson.model.Run; import java.io.File; @@ -20,8 +21,6 @@ import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; -import com.hcl.appscan.jenkins.plugin.Messages; - public class ScanResultsTrend extends AppScanAction { private String m_type; diff --git a/src/main/java/com/hcl/appscan/jenkins/plugin/auth/ASECredentials.java b/src/main/java/com/hcl/appscan/jenkins/plugin/auth/ASECredentials.java index 53783e65..9f80bd4e 100644 --- a/src/main/java/com/hcl/appscan/jenkins/plugin/auth/ASECredentials.java +++ b/src/main/java/com/hcl/appscan/jenkins/plugin/auth/ASECredentials.java @@ -8,10 +8,8 @@ import com.cloudbees.plugins.credentials.CredentialsDescriptor; import com.cloudbees.plugins.credentials.CredentialsScope; import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl; -import com.hcl.appscan.jenkins.plugin.Messages; -import com.hcl.appscan.sdk.CoreConstants; -import com.hcl.appscan.sdk.utils.SystemUtil; +import com.hcl.appscan.jenkins.plugin.Messages; import hudson.Extension; import hudson.util.FormValidation; import hudson.util.Secret; diff --git a/src/main/java/com/hcl/appscan/jenkins/plugin/builders/AppScanBuildStep.java b/src/main/java/com/hcl/appscan/jenkins/plugin/builders/AppScanBuildStep.java index 655c7c35..1689a34a 100644 --- a/src/main/java/com/hcl/appscan/jenkins/plugin/builders/AppScanBuildStep.java +++ b/src/main/java/com/hcl/appscan/jenkins/plugin/builders/AppScanBuildStep.java @@ -1,6 +1,6 @@ /** * @ Copyright IBM Corporation 2016. - * @ Copyright HCL Technologies Ltd. 2017, 2020, 2021. + * @ Copyright HCL Technologies Ltd. 2017, 2020. * LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0 */ @@ -20,6 +20,7 @@ import javax.annotation.Nonnull; +import com.hcl.appscan.jenkins.plugin.Messages; import com.hcl.appscan.sdk.scanners.ScanConstants; import org.jenkinsci.Symbol; import org.jenkinsci.remoting.RoleChecker; @@ -43,7 +44,6 @@ import com.hcl.appscan.sdk.scan.IScan; import com.hcl.appscan.sdk.utils.SystemUtil; -import com.hcl.appscan.jenkins.plugin.Messages; import com.hcl.appscan.jenkins.plugin.ScanFactory; import com.hcl.appscan.jenkins.plugin.actions.ResultsRetriever; import com.hcl.appscan.jenkins.plugin.auth.ASoCCredentials; @@ -67,7 +67,6 @@ import hudson.model.AbstractProject; import hudson.model.BuildListener; import hudson.model.ItemGroup; -import hudson.model.Result; import hudson.model.Items; import hudson.model.Run; import hudson.model.TaskListener; @@ -235,13 +234,18 @@ protected Object readResolve() { } private Map getScanProperties(Run build, TaskListener listener) { - VariableResolver resolver = build instanceof AbstractBuild ? new BuildVariableResolver((AbstractBuild)build, listener) : null; + VariableResolver resolver = null; + String scanName = m_name; + if (build instanceof AbstractBuild) { + resolver = new BuildVariableResolver((AbstractBuild)build, listener); + scanName = Util.replaceMacro(m_name, resolver); + } Map properties = m_scanner.getProperties(resolver); properties.put(CoreConstants.SCANNER_TYPE, m_scanner.getType()); properties.put(CoreConstants.APP_ID, m_application); - properties.put(CoreConstants.SCAN_NAME, resolver == null ? m_name : Util.replaceMacro(m_name, resolver) + "_" + SystemUtil.getTimeStamp()); //$NON-NLS-1$ + properties.put(CoreConstants.SCAN_NAME, scanName + "_" + SystemUtil.getTimeStamp()); //$NON-NLS-1$ properties.put(CoreConstants.EMAIL_NOTIFICATION, Boolean.toString(m_emailNotification)); - properties.put("APPSCAN_IRGEN_CLIENT", "Jenkins"); + properties.put("APPSCAN_IRGEN_CLIENT", "jenkins"); properties.put("APPSCAN_CLIENT_VERSION", Jenkins.VERSION); properties.put("IRGEN_CLIENT_PLUGIN_VERSION", getPluginVersion()); properties.put("ClientType", "jenkins-" + SystemUtil.getOS() + "-" + getPluginVersion()); @@ -261,7 +265,7 @@ private String getPluginVersion() { private void shouldFailBuild(IResultsProvider provider,Run build) throws AbortException, IOException{ if(!m_failBuild && !m_failBuildNonCompliance) return ; - String failureMessage=Messages.error_threshold_exceeded(); + String failureMessage= Messages.error_threshold_exceeded(); try { List failureConditions=m_failureConditions; if (m_failBuildNonCompliance){ @@ -306,14 +310,9 @@ public IResultsProvider call() throws AbortException { progress.setStatus(new Message(Message.INFO, Messages.analysis_running())); m_scanStatus = provider.getStatus(); - int requestCounter=0; - while(m_scanStatus != null && (m_scanStatus.equalsIgnoreCase(CoreConstants.INQUEUE) || m_scanStatus.equalsIgnoreCase(CoreConstants.RUNNING) || m_scanStatus.equalsIgnoreCase(CoreConstants.UNKNOWN)) && requestCounter<10) { - Thread.sleep(60000); - if(m_scanStatus.equalsIgnoreCase(CoreConstants.UNKNOWN)) - requestCounter++; // In case of internet disconnect, polling the server 10 times to check the connection has established - else - requestCounter=0; - m_scanStatus = provider.getStatus(); + while(m_scanStatus != null && (m_scanStatus.equalsIgnoreCase(CoreConstants.INQUEUE) || m_scanStatus.equalsIgnoreCase(CoreConstants.RUNNING))) { + Thread.sleep(60000); + m_scanStatus = provider.getStatus(); } } @@ -324,9 +323,6 @@ public IResultsProvider call() throws AbortException { } } }); - - if(suspend && m_scanStatus == null) // to address the status in association with Master and Slave congifuration - m_scanStatus = provider.getStatus(); if (CoreConstants.FAILED.equalsIgnoreCase(m_scanStatus)) { String message = com.hcl.appscan.sdk.Messages.getMessage(ScanConstants.SCAN_FAILED, " Scan Name: " + scan.getName()); @@ -337,21 +333,18 @@ public IResultsProvider call() throws AbortException { throw new AbortException(com.hcl.appscan.sdk.Messages.getMessage(ScanConstants.SCAN_FAILED, (" Scan Id: " + scan.getScanId() + ", Scan Name: " + scan.getName()))); } - else if (CoreConstants.UNKNOWN.equalsIgnoreCase(m_scanStatus)) { // In case of internet disconnect Status is set to unstable. - progress.setStatus(new Message(Message.ERROR, Messages.error_server_unavailable() + " "+ Messages.check_server(m_authProvider.getServer()))); - build.setDescription(Messages.error_server_unavailable()); - build.setResult(Result.UNSTABLE); - } - else { provider.setProgress(new StdOutProgress()); //Avoid serialization problem with StreamBuildListener. - VariableResolver resolver = build instanceof AbstractBuild ? new BuildVariableResolver((AbstractBuild)build, listener) : null; + String scanName = m_name; + if (build instanceof AbstractBuild) { + VariableResolver resolver = new BuildVariableResolver((AbstractBuild)build, listener); + scanName = Util.replaceMacro(m_name, resolver); + } String asocAppUrl = m_authProvider.getServer() + "/serviceui/main/myapps/portfolio"; - build.addAction(new ResultsRetriever(build, provider, resolver == null ? m_name : Util.replaceMacro(m_name, resolver), asocAppUrl, Messages.label_asoc_homepage())); + build.addAction(new ResultsRetriever(build, provider, scanName, asocAppUrl, Messages.label_asoc_homepage(), m_application, "")); if(m_wait) shouldFailBuild(provider,build); } - } private void setInstallDir() { if (SystemUtil.isWindows() && System.getProperty("user.home").toLowerCase().indexOf("system32")>=0) { diff --git a/src/main/java/com/hcl/appscan/jenkins/plugin/builders/AppScanEnterpriseBuildStep.java b/src/main/java/com/hcl/appscan/jenkins/plugin/builders/AppScanEnterpriseBuildStep.java index 3c26d379..58c0ab97 100644 --- a/src/main/java/com/hcl/appscan/jenkins/plugin/builders/AppScanEnterpriseBuildStep.java +++ b/src/main/java/com/hcl/appscan/jenkins/plugin/builders/AppScanEnterpriseBuildStep.java @@ -20,8 +20,13 @@ import java.util.Comparator; import java.util.HashMap; +import com.hcl.appscan.jenkins.plugin.Messages; +import com.hcl.appscan.jenkins.plugin.util.ExecutorUtil; import com.hcl.appscan.sdk.scanners.ScanConstants; +import groovy.ui.SystemOutputInterceptor; +import hudson.model.*; import org.apache.commons.lang.StringEscapeUtils; +import org.apache.wink.json4j.JSONObject; import org.jenkinsci.Symbol; import org.jenkinsci.remoting.RoleChecker; import org.kohsuke.stapler.AncestorInPath; @@ -47,7 +52,6 @@ import com.hcl.appscan.sdk.scan.IScan; import com.hcl.appscan.sdk.utils.SystemUtil; -import com.hcl.appscan.jenkins.plugin.Messages; import com.hcl.appscan.jenkins.plugin.ScanFactory; import com.hcl.appscan.jenkins.plugin.actions.ResultsRetriever; import com.hcl.appscan.jenkins.plugin.auth.ASEJenkinsAuthenticationProvider; @@ -61,14 +65,7 @@ import hudson.Extension; import hudson.FilePath; import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.AbstractProject; -import hudson.model.BuildListener; -import hudson.model.ItemGroup; -import hudson.model.Run; -import hudson.model.TaskListener; import jenkins.model.Jenkins; -import hudson.model.AutoCompletionCandidates; import hudson.remoting.Callable; import hudson.security.ACL; import hudson.tasks.BuildStepDescriptor; @@ -86,8 +83,13 @@ public class AppScanEnterpriseBuildStep extends Builder implements SimpleBuildSt private static final String SHOW_ALL = "Show All"; private String m_credentials; - private String m_application; + private String m_applicationId; + private String m_applicationName; private String m_target; + + private boolean m_newJob; + private String m_reportsPath; + private String m_additionalDomains; private String m_folder; private String m_testPolicy; private String m_template; @@ -112,13 +114,16 @@ public class AppScanEnterpriseBuildStep extends Builder implements SimpleBuildSt private IAuthenticationProvider m_authProvider; private static final File JENKINS_INSTALL_DIR = new File(System.getProperty("user.dir"), ".appscan"); //$NON-NLS-1$ //$NON-NLS-2$ + private static final String pluginVersion = "1.0.8-v11"; @DataBoundConstructor public AppScanEnterpriseBuildStep(String credentials, String folder, String testPolicy, String template, String jobName) { m_credentials = credentials; - m_application = ""; + m_applicationId = ""; + m_applicationName = ""; m_target = ""; + m_newJob = false; // Post autocomplete feature, we need to explicitly map // folder name to folder id before saving it in // job configuration file. @@ -197,7 +202,8 @@ public void setApplication(String application) { // Post autocomplete feature, we need to explicitly map // application name to application id before saving it in // job configuration file. - m_application = getDescriptor().getApplicationId(application); + m_applicationId = getDescriptor().getApplicationId(application); + m_applicationName = application; } public String getApplication() { @@ -205,12 +211,12 @@ public String getApplication() { // id to application name before displaying the value in jenkins's job // configuration. if (getDescriptor().applicationMap != null && - getDescriptor().applicationMap.get(m_application) != null) { + getDescriptor().applicationMap.get(m_applicationId) != null) { String appName = StringEscapeUtils.unescapeHtml( - getDescriptor().applicationMap.get(m_application)); + getDescriptor().applicationMap.get(m_applicationId)); return appName; } - return m_application; + return m_applicationId; } @DataBoundSetter @@ -221,7 +227,24 @@ public void setTarget(String target) { public String getTarget() { return m_target; } - + + @DataBoundSetter + public void setNewJob(boolean newJob) { + this.m_newJob = newJob; + } + + public boolean getNewJob() { + return this.m_newJob; + } + + @DataBoundSetter + public void setReportsPath(String reportsPath){ this.m_reportsPath = reportsPath; } + public String getReportsPath(){ return m_reportsPath; } + + @DataBoundSetter + public void setAdditionalDomains(String additionalDomains){ this.m_additionalDomains = additionalDomains; } + public String getAdditionalDomains(){ return m_additionalDomains; } + @DataBoundSetter public void setLoginType(String loginType) { m_loginType = loginType; @@ -387,8 +410,10 @@ private Map getScanProperties(Run build, TaskListener list Map properties = new HashMap(); properties.put(CoreConstants.SCANNER_TYPE, ASE_DYNAMIC_ANALYZER); properties.put("credentials", m_credentials); - properties.put("application", m_application); + properties.put("application", m_applicationId); + properties.put("applicationName", m_applicationName); properties.put("startingURL", m_target); + properties.put("newJob", m_newJob ? "true":"false"); properties.put("folder", m_folder); properties.put("testPolicyId", m_testPolicy); properties.put("templateId", m_template); @@ -405,7 +430,12 @@ private Map getScanProperties(Run build, TaskListener list } properties.put("scanType", m_scanType); properties.put("testOptimization", m_testOptimization); - properties.put(CoreConstants.SCAN_NAME, m_jobName + "_" + SystemUtil.getTimeStamp()); + properties.put("additionalDomains", m_additionalDomains); + if (m_newJob) + properties.put(CoreConstants.SCAN_NAME, m_jobName+ "_" + SystemUtil.getTimeStamp()); + else + properties.put(CoreConstants.SCAN_NAME, m_jobName); + properties.put(CoreConstants.EMAIL_NOTIFICATION, Boolean.toString(m_email)); return properties; } @@ -427,12 +457,18 @@ private void shouldFailBuild(IResultsProvider provider, Run build) throws private void performScan(Run build, Launcher launcher, TaskListener listener) throws InterruptedException, IOException { + Map properties = getScanProperties(build, listener); + m_authProvider = new ASEJenkinsAuthenticationProvider(properties.get("credentials"), build.getParent().getParent()); final IProgress progress = new ScanProgress(listener); - final boolean suspend = m_wait; final IScan scan = ScanFactory.createScan(properties, progress, m_authProvider); // Call ASEScanFactory directly + final File buildRootDir = build.getRootDir(); + final String buildNumber = build.getId(); + + progress.setStatus(new Message(Message.INFO, "Plugin Version: "+pluginVersion)); + //progress.setStatus(new Message(Message.INFO, "Reports path = "+getReportsPath())); IResultsProvider provider = launcher.getChannel().call(new Callable() { private static final long serialVersionUID = 1L; @@ -446,36 +482,42 @@ public IResultsProvider call() throws AbortException { try { setInstallDir(); scan.run(); - + File reportsPath = (m_reportsPath != null && m_reportsPath.length()>0) ? new File(m_reportsPath) : buildRootDir; IResultsProvider provider = new ASEResultsProvider(scan.getScanId(), scan.getType(), - scan.getServiceProvider(), progress, scan.getName()); + scan.getServiceProvider(), progress, scan.getName(), scan.getServiceProvider().getApplicationId(), reportsPath, buildNumber); provider.setReportFormat(scan.getReportFormat()); + + try { String ASE_SCAN_STATS = "/Jobs/QuickScanStats.aspx?fiid=%s"; URL url = new URL(m_authProvider.getServer() + String.format(ASE_SCAN_STATS, scan.getScanId())); progress.setStatus(new Message(Message.INFO, Messages.logs_link(scan.getScanId(), new URL(url.getProtocol(), url.getHost(), url.getFile()).toString()))); + + if (m_wait) { + progress.setStatus(new Message(Message.INFO, "The Scan job status will be fetched from AppScan every 60 seconds....")); + provider.run(); + } + else { + progress.setStatus(new Message(Message.INFO, "Check the scan status in 'Status' page. Once the scan job completes its run, download reports from 'Status' page.")); + ExecutorUtil.executeTask(provider); + Thread.sleep(10000); + } + } catch (MalformedURLException e) { progress.setStatus(new Message(Message.ERROR, Messages.error_malformed_url(m_authProvider.getServer()))); + } catch (InterruptedException e) { + e.printStackTrace(); } - if (suspend) { - progress.setStatus(new Message(Message.INFO, Messages.analysis_running())); - m_scanStatus = provider.getStatus(); - - while(m_scanStatus != null && (m_scanStatus.equalsIgnoreCase("Waiting to Auto Run") || m_scanStatus.equalsIgnoreCase("Waiting to Run") - || m_scanStatus.equalsIgnoreCase("Starting") || m_scanStatus.equalsIgnoreCase("Running") - || m_scanStatus.equals("Post Processing") || m_scanStatus.equals("Waiting to Generate Results") || m_scanStatus.equals("Generating Results"))) { - Thread.sleep(60000); - m_scanStatus = provider.getStatus(); - } - } + return provider; - } catch (ScannerException | InvalidTargetException | InterruptedException e) { + }catch (ScannerException | InvalidTargetException e) { progress.setStatus(new Message(Message.INFO, Messages.label_ase_homepage() + ": " + m_authProvider.getServer())); throw new AbortException(Messages.error_running_scan(e.getLocalizedMessage())); } } }); + m_scanStatus = provider.getStatus(); if (CoreConstants.FAILED.equalsIgnoreCase(m_scanStatus)) { String message = com.hcl.appscan.sdk.Messages.getMessage(ScanConstants.SCAN_FAILED, " Scan Name: " + scan.getName()); if (provider.getMessage() != null && provider.getMessage().trim().length() > 0) { @@ -489,15 +531,20 @@ public IResultsProvider call() throws AbortException { provider.setProgress(new StdOutProgress()); // Avoid serialization problem with StreamBuildListener. String aseScanUrl = m_authProvider.getServer(); String label = Messages.label_ase_homepage(); - if (m_application != null && m_application.trim().length() > 0) { + if (m_applicationId != null && m_applicationId.trim().length() > 0) { String applicationUrl = "/api/pages/applications.html#appProfile/%s/issues"; - aseScanUrl += String.format(applicationUrl, m_application); + aseScanUrl += String.format(applicationUrl, m_applicationId); label = Messages.label_ase_application(); } - build.addAction(new ResultsRetriever(build, provider, m_jobName, aseScanUrl, label)); + ResultsRetriever resultsRetriever = new ResultsRetriever(build, provider, m_jobName, aseScanUrl, label, m_applicationId, m_reportsPath); + build.addAction(resultsRetriever); - if (m_wait) + if (m_wait) { shouldFailBuild(provider, build); + } + else { + Thread.sleep(30000); + } } private void setInstallDir() { @@ -716,7 +763,7 @@ private String getApplicationId(String application) { } } } - return application; + return ""; } /** diff --git a/src/main/java/com/hcl/appscan/jenkins/plugin/util/ExecutorUtil.java b/src/main/java/com/hcl/appscan/jenkins/plugin/util/ExecutorUtil.java index f11f0d53..78bd0f02 100644 --- a/src/main/java/com/hcl/appscan/jenkins/plugin/util/ExecutorUtil.java +++ b/src/main/java/com/hcl/appscan/jenkins/plugin/util/ExecutorUtil.java @@ -16,4 +16,8 @@ public class ExecutorUtil { public static Future submitTask(Callable task) { return executorService.submit(task); } + + public static void executeTask(Runnable task) { + executorService.execute(task); + } } diff --git a/src/main/java/com/ibm/appscan/jenkins/plugin/actions/ScanResults.java b/src/main/java/com/ibm/appscan/jenkins/plugin/actions/ScanResults.java index abe493b1..5aa006d7 100644 --- a/src/main/java/com/ibm/appscan/jenkins/plugin/actions/ScanResults.java +++ b/src/main/java/com/ibm/appscan/jenkins/plugin/actions/ScanResults.java @@ -13,6 +13,6 @@ public class ScanResults extends com.hcl.appscan.jenkins.plugin.actions.ScanResu public ScanResults(Run build, IResultsProvider provider, String name, String status, int totalFindings, int highCount, int mediumCount, int lowCount, int infoCount) { - super(build, provider, name, status, totalFindings, highCount, mediumCount, lowCount, infoCount, null, null); + super(build, provider, name, status, totalFindings, highCount, mediumCount, lowCount, infoCount, null, null, null); } } \ No newline at end of file diff --git a/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ResultsRetriever/statistics.jelly b/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ResultsRetriever/statistics.jelly new file mode 100644 index 00000000..91dabcee --- /dev/null +++ b/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ResultsRetriever/statistics.jelly @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Scan Statistics

+

(While the scan is running the data is updated every minute)

+
Scan Job Id${it.jobId}
Status${it.status}
Net scan time${it.netScanTime}
Securities entities found${it.secEntitiesFound}
Securities entities tested${it.secEntitiesTested}
Scan start time${it.scanStartTime}
Pages found${it.pagesFound}
Pages scanned${it.pagesTested}
Scanning phase${it.scanningPhase}
Requests sent${it.reqSent}
+
diff --git a/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ResultsRetriever/summary.jelly b/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ResultsRetriever/summary.jelly index 18581bcc..a9c1e31c 100644 --- a/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ResultsRetriever/summary.jelly +++ b/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ResultsRetriever/summary.jelly @@ -10,6 +10,8 @@ LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0 ${it.displayName} ${it.message} + + @@ -24,4 +26,9 @@ LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0 +





+ +
+ +
diff --git a/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ScanResults/findingsTable.jelly b/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ScanResults/findingsTable.jelly index 46e4a527..8add923d 100644 --- a/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ScanResults/findingsTable.jelly +++ b/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ScanResults/findingsTable.jelly @@ -5,7 +5,10 @@ LICENSE: Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0 --> -

${it.displayName}

+

${it.displayName} - + PDF + XML +

diff --git a/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ScanResults/statistics.jelly b/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ScanResults/statistics.jelly new file mode 100644 index 00000000..91dabcee --- /dev/null +++ b/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ScanResults/statistics.jelly @@ -0,0 +1,60 @@ + + + + +
${%Total Issues} ${%High}
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Scan Statistics

+

(While the scan is running the data is updated every minute)

+
Scan Job Id${it.jobId}
Status${it.status}
Net scan time${it.netScanTime}
Securities entities found${it.secEntitiesFound}
Securities entities tested${it.secEntitiesTested}
Scan start time${it.scanStartTime}
Pages found${it.pagesFound}
Pages scanned${it.pagesTested}
Scanning phase${it.scanningPhase}
Requests sent${it.reqSent}
+ diff --git a/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ScanResults/summary.jelly b/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ScanResults/summary.jelly index 47305f29..4285bdcf 100644 --- a/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ScanResults/summary.jelly +++ b/src/main/resources/com/hcl/appscan/jenkins/plugin/actions/ScanResults/summary.jelly @@ -15,6 +15,11 @@ - + +





+ +
+ +
diff --git a/src/main/resources/com/hcl/appscan/jenkins/plugin/builders/AppScanEnterpriseBuildStep/config.jelly b/src/main/resources/com/hcl/appscan/jenkins/plugin/builders/AppScanEnterpriseBuildStep/config.jelly index 5fb0237a..0e87883f 100644 --- a/src/main/resources/com/hcl/appscan/jenkins/plugin/builders/AppScanEnterpriseBuildStep/config.jelly +++ b/src/main/resources/com/hcl/appscan/jenkins/plugin/builders/AppScanEnterpriseBuildStep/config.jelly @@ -14,6 +14,14 @@ } + + + + + + + + @@ -48,6 +56,11 @@ + + + + + @@ -157,7 +170,7 @@ - +