diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java index e5ffd45afd6..6c00b1648aa 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java +++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java @@ -229,12 +229,12 @@ public class Check extends Update { */ private Boolean autoUpdate; /** - * The report format to be generated (HTML, XML, JUNIT, CSV, JSON, SARIF, + * The report format to be generated (HTML, XML, JUNIT, CSV, JSON, SARIF, JENKINS, * ALL). Default is HTML. */ private String reportFormat = "HTML"; /** - * The report format to be generated (HTML, XML, JUNIT, CSV, JSON, SARIF, + * The report format to be generated (HTML, XML, JUNIT, CSV, JSON, SARIF, JENKINS, * ALL). Default is HTML. */ private final List reportFormats = new ArrayList<>(); @@ -2111,7 +2111,7 @@ private void checkForFailure(Dependency[] dependencies) throws BuildException { /** * An enumeration of supported report formats: "ALL", "HTML", "XML", "CSV", - * "JSON", "JUNIT", "SARIF", etc.. + * "JSON", "JUNIT", "SARIF", 'JENkINS', etc.. */ public static class ReportFormats extends EnumeratedAttribute { diff --git a/cli/src/main/java/org/owasp/dependencycheck/CliParser.java b/cli/src/main/java/org/owasp/dependencycheck/CliParser.java index 1f4db8905ff..f6094499982 100644 --- a/cli/src/main/java/org/owasp/dependencycheck/CliParser.java +++ b/cli/src/main/java/org/owasp/dependencycheck/CliParser.java @@ -64,7 +64,7 @@ public final class CliParser { /** * The supported reported formats. */ - private static final String SUPPORTED_FORMATS = "HTML, XML, CSV, JSON, JUNIT, SARIF, or ALL"; + private static final String SUPPORTED_FORMATS = "HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, or ALL"; /** * Constructs a new CLI Parser object with the configured settings. diff --git a/core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java b/core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java index 1af42aa55f7..3bd43054484 100644 --- a/core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java +++ b/core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java @@ -116,6 +116,10 @@ public enum Format { * Generate Sarif report. */ SARIF, + /** + * Generate HTML report without script or non-vulnerable libraries for Jenkins. + */ + JENKINS, /** * Generate JUNIT report. */ @@ -373,6 +377,9 @@ public static File getReportFile(String outputLocation, Format format) { if (format == Format.HTML && !pathToCheck.endsWith(".html") && !pathToCheck.endsWith(".htm")) { return new File(outFile, "dependency-check-report.html"); } + if (format == Format.JENKINS && !pathToCheck.endsWith(".html") && !pathToCheck.endsWith(".htm")) { + return new File(outFile, "dependency-check-jenkins.html"); + } if (format == Format.JSON && !pathToCheck.endsWith(".json")) { return new File(outFile, "dependency-check-report.json"); } diff --git a/core/src/main/resources/templates/jenkinsReport.vsl b/core/src/main/resources/templates/jenkinsReport.vsl new file mode 100644 index 00000000000..f93b1655aeb --- /dev/null +++ b/core/src/main/resources/templates/jenkinsReport.vsl @@ -0,0 +1,794 @@ +#** +This file is part of dependency-check-core. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Copyright (c) 2012 Jeremy Long. All Rights Reserved. + +@author Jeremy Long +@version 1.4 +*# + + +#[[ + + + + Dependency-Check Report + + + + + +
+ +

Dependency-Check is an open source tool performing a best effort analysis of 3rd party dependencies; +false positives and false negatives may exist in the analysis performed by the tool. Use of the tool and +the reporting provided constitutes acceptance for use in an AS IS condition, and there are NO warranties, +implied or otherwise, with regard to the analysis or its use. Any use of the tool and the reporting provided +is at the user’s risk. In no event shall the copyright holder or OWASP be held liable for any damages whatsoever +arising out of or in connection with the use of this tool, the analysis performed, or the resulting report.

+

How to read the report | +Suppressing false positives | +Getting Help: github issues

+ Sponsor

+]]# +

Project: $enc.html($applicationName)

+ #if ($groupID && $artifactID && $applicationVersion) +

$enc.html($groupID):$enc.html($artifactID):$enc.html($applicationVersion)

+ #end +
+ #set($depCount=$dependencies.size()) + #set($vulnDepCount=0) + #set($vulnCount=0) + #set($vulnSuppressedCount=0) + #set($cpeSuppressedCount=0) + + #foreach($dependency in $dependencies) + #set($depCount=$depCount+$dependency.getRelatedDependencies().size()) + #if($dependency.getVulnerabilities().size()>0) + #set($vulnDepCount=$vulnDepCount+1) + #set($vulnCount=$vulnCount+$dependency.getVulnerabilities().size()) + #end + #if($dependency.getSuppressedIdentifiers().size()>0) + #set($cpeSuppressedCount=$cpeSuppressedCount+1) + #end + #if($dependency.getSuppressedVulnerabilities().size()>0) + #set($vulnSuppressedCount=$vulnSuppressedCount+$dependency.getSuppressedVulnerabilities().size()) + #end + #end + Scan Information:
+
    +
  • dependency-check version: $version
  • +
  • Report Generated On: $scanDate
  • +
  • Dependencies Scanned: $depCount ($dependencies.size() unique)
  • +
  • Vulnerable Dependencies$vulnDepCount
  • +
  • Vulnerabilities Found: $vulnCount
  • +
  • Vulnerabilities Suppressed: $vulnSuppressedCount
  • +

+ #set($cnt=0) +#if($exceptions) + #macro( writeHtmlException $type $ex $depth) + #set($cnt=$cnt+1) +

$enc.html($ex.getMessage())

+
+ $type: $enc.html($ex.toString()) + #if($ex.getStackTrace()) +
+            #foreach($t in $ex.getStackTrace())
+                $enc.html($t.toString())
+ #end +
+ #end + #if($ex.getCause() && $depth<20) + #set($cause="cause") + #set($currentDepth=$depth+1) + #writeHtmlException($cause $ex.getCause() $currentDepth) + #end +
+ #end +

Analysis Exceptions

+ #foreach($ex in $exceptions) + #set($type="exception") + #set($d=0) + #writeHtmlException($type $ex $d) + #end +
+#end +

Summary

+ #set($lnkcnt=0) + + + + + + + + + + + #foreach($dependency in $dependencies) + #if($dependency.getVulnerabilities().size()>0) + #set($lnkcnt=$lnkcnt+1) + + + #set($mavenlink="") + #set($cpeIdCount=0) + #set($cpeIdConf="") + #set($sortValue="") + #foreach($id in $dependency.getVulnerableSoftwareIdentifiers()) + #set($sortValue=$sortValue+$id.value) + #end + + #foreach($id in $dependency.getSoftwareIdentifiers()) + #set($sortValue=$sortValue+$id.value) + #end + + #set($cveImpact=-1) + #set($cveSeverity=" ") + #if($dependency.getVulnerabilities().size()>0) + #set($severestVuln=$dependency.getVulnerabilities(true).iterator().next()) + ## yes - we are mixing v2 and v3... no consistency in data so doing the best we can + ## with a set sorted approximately on descending severity + #if ($severestVuln.cvssV3) + #set($cveImpact=$severestVuln.cvssV3.baseScore) + #elseif ($severestVuln.cvssV2) + #set($cveImpact=$severestVuln.cvssV2.score) + #end + #set($cveSeverity=$enc.html($severestVuln.highestSeverityText)) + #end + #set($sortValue=$cveImpact*10) + + + + + + #end + #end +
DependencyVulnerability IDsPackageHighest SeverityCVE CountConfidenceEvidence Count
$enc.html($dependency.DisplayFileName) + #set($sortValue="") + #set($cpeSort=0) + #foreach($id in $dependency.getVulnerableSoftwareIdentifiers()) + #if ($cpeIdCount>=1) +
+ #end + #if( $id.url ) + $enc.html($id.value) + #else + $enc.html($id.value) + #end + #if ($cpeIdConf == "") + #set($cpeIdConf=$id.confidence) + #set($cpeSort=$id.confidence.ordinal()) + #elseif ($cpeIdConf.compareTo($id.confidence)>0) + #set($cpeIdConf=$id.confidence) + #set($cpeSort=$id.confidence.ordinal()) + #end + #set($cpeIdCount=$cpeIdCount+1) + #end +
+ #set($sortValue="") + #set($idCount=0) + #foreach($id in $dependency.getSoftwareIdentifiers()) + #if ($idCount>=1) +
+ #end + #if( $id.url ) + $enc.html($id.value) + #else + $enc.html($id.value) + #end + #set($idCount=$idCount+1) + #end
$cveSeverity$dependency.getVulnerabilities().size()$WordUtils.capitalizeFully($cpeIdConf.toString())$dependency.size()
+

Dependencies

+ #set($lnkcnt=0) + #set($vsctr=0) ##counter to create unique groups for vulnerable software + #foreach($dependency in $dependencies) + #if($dependency.getVulnerabilities().size()>0) + #set($lnkcnt=$lnkcnt+1) +

$enc.html($dependency.DisplayFileName)

+
+ #if ($dependency.description) +

Description:

$enc.html($dependency.description)

+ #end +

+ #if ($dependency.license) + #if ($dependency.license.startsWith("http://")) + License:

$enc.html($dependency.license)
+ #else + License:
$enc.html($dependency.license)
+ #end + #end + File Path: $enc.html($dependency.FilePath)
+ #if(!$dependency.isVirtual()) + MD5: $enc.html($dependency.Md5sum)
+ SHA1: $enc.html($dependency.Sha1sum)
+ SHA256:$enc.html($dependency.Sha256sum) + #end + #if ($dependency.projectReferences.size()==1) +
Referenced In Project/Scope: $enc.html($dependency.projectReferences.iterator().next()) + #end + #if ($dependency.projectReferences.size()>1) +
Referenced In Projects/Scopes:
    + #foreach($ref in $dependency.projectReferences) +
  • $enc.html($ref)
  • + #end +
+ #end + #if ($dependency.includedBy && $dependency.includedBy.size()==1) +
$enc.html($dependency.DisplayFileName) is in the transitive dependency tree of the listed items.Included by: $enc.html($dependency.includedBy.iterator().next()) + #end + #if ($dependency.includedBy && $dependency.includedBy.size()>1) +
$enc.html($dependency.DisplayFileName) is in the transitive dependency tree of the listed items.Included by:
    + #foreach($parent in $dependency.includedBy) +
  • $enc.html($parent)
  • + #end +
+ #end +

+ #if($dependency.getRelatedDependencies().size()>0) + #set($cnt=$cnt+1) +

Related Dependencies

+
+
    + #foreach($related in $dependency.getRelatedDependencies()) +
  • $enc.html($related.DisplayFileName) +
      +
    • File Path: $enc.html($related.FilePath)
    • + #if(!$related.isVirtual()) +
    • MD5: $enc.html($related.Md5sum)
    • +
    • SHA1: $enc.html($related.Sha1sum)
    • +
    • SHA256: $enc.html($related.Sha256sum)
    • + #end + #foreach($id in $related.getSoftwareIdentifiers()) + #if( $id.url ) + ##yes, we are HTML Encoding the href. this is okay. We can't URL encode as we have to trust the analyzer here... +
    • $enc.html($id.value)
    • + #else +
    • $enc.html($id.value)
    • + #end + #end +
    +
  • + #end +
+
+ #end + #set($cnt=$cnt+1) +

Identifiers

+ ##: $enc.html($cpevalue) +
+ #if ($dependency.getSoftwareIdentifiers().size()==0 && $dependency.getVulnerableSoftwareIdentifiers().size()==0) +
  • None
+ #else +
    + #foreach($id in $dependency.getSoftwareIdentifiers()) + #if( $id.url ) +
  • $enc.html($id.value) + #else +
  • $enc.html($id.value) + #end + #if ($id.confidence) +   (Confidence:$WordUtils.capitalizeFully($id.confidence.toString())) + #end + #if ($id.notes) +
    • Notes: $enc.html($id.notes)
    + #end +
  • + #end + #foreach($id in $dependency.getVulnerableSoftwareIdentifiers()) + #if( $id.url ) +
  • $enc.html($id.value) + #else +
  • $enc.html($id.value) + #end + #if ($id.confidence) +   (Confidence:$WordUtils.capitalizeFully($id.confidence.toString())) + #end + #if ($id.notes) +
    • Notes: $enc.html($id.notes)
    + #end +
  • + #end +
+ #end +
+ #set($cnt=$cnt+1) +

Published Vulnerabilities

+
+ #foreach($vuln in $dependency.getVulnerabilities(true)) + #set($vsctr=$vsctr+1) + #if($vuln.getSource().name().equals("NVD")) +

$enc.html($vuln.name)

+ #elseif($vuln.getSource().name().equals("NPM")) +

NPM-$enc.html($vuln.name)

+ #else +

$enc.html($vuln.name) ($vuln.getSource().name())

+ #end +

#if($vuln.description) +

$enc.html($vuln.description)
+ #end + #if ($vuln.cwes.toString()) + $vuln.cwes.toString()

+ #end + #if ($vuln.notes) + Notes: $enc.html($vuln.notes)

+ #end + #if($vuln.getCvssV2()) + CVSSv2: +
  • Base Score: $enc.html($vuln.getCvssV2().getSeverity()) ($vuln.getCvssV2().getScore())
  • +
  • Vector: $enc.html($vuln.getCvssV2().toString())
+ #end + #if($vuln.getCvssV3()) + CVSSv3: +
  • Base Score: $enc.html($vuln.getCvssV3().getBaseSeverity()) ($vuln.getCvssV3().getBaseScore())
  • +
  • Vector: $enc.html($vuln.getCvssV3().toString())
+ #end + #if ($vuln.unscoredSeverity) + Unscored: +
  • Severity: #if($vuln.unscoredSeverity.equals("0.0"))Unknown#else$enc.html($vuln.unscoredSeverity)#end
+ #end + #if ($vuln.getReferences().size()>0) +
References:
    + #foreach($ref in $vuln.getReferences(true)) + #if ($ref.url) +
  • $enc.html($ref.source) - $enc.html($ref.name)
  • + #else +
  • $enc.html($ref.source) - $enc.html($ref.name)
  • + #end + #end +
+ #end +

+ #if ($vuln.getSource().name().equals("NVD") && $vuln.matchedVulnerableSoftware) + #if ($vuln.getVulnerableSoftware().size()<2) +

Vulnerable Software & Versions:

+ #else +

Vulnerable Software & Versions:

+ #end + #elseif ($vuln.getVulnerableSoftware().size()!=0) +

Vulnerable Software & Versions ($vuln.getSource().name()): +

    + #foreach($vs in $vuln.getVulnerableSoftware(true)) +
  • $enc.html($vs.toString())
  • + #end +
+

+ #end + #end +
+ #end +
+ #end +
+
+
+

+ This report contains data retrieved from the National Vulnerability Database. +
+ This report may contain data retrieved from the NPM Public Advisories. +
+ This report may contain data retrieved from RetireJS. +
+ This report may contain data retrieved from the Sonatype OSS Index. +
+ + diff --git a/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java b/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java index 1379d6c2853..d7dae3190ae 100644 --- a/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java +++ b/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java @@ -289,7 +289,7 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma @Parameter(property = "dependency-check.virtualSnapshotsFromReactor", defaultValue = "true") private Boolean virtualSnapshotsFromReactor; /** - * The report format to be generated (HTML, XML, JUNIT, CSV, JSON, SARIF, + * The report format to be generated (HTML, XML, JUNIT, CSV, JSON, SARIF, JENKINS, * ALL). Multiple formats can be selected using a comma delineated list. */ @SuppressWarnings("CanBeFinal") @@ -303,7 +303,7 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma @Parameter(property = "prettyPrint") private Boolean prettyPrint; /** - * The report format to be generated (HTML, XML, JUNIT, CSV, JSON, SARIF, + * The report format to be generated (HTML, XML, JUNIT, CSV, JSON, SARIF, JENKINS, * ALL). Multiple formats can be selected using a comma delineated list. */ @Parameter(property = "formats", required = true) @@ -1978,12 +1978,16 @@ public String getOutputName() { final Set selectedFormats = getFormats(); if (selectedFormats.contains("HTML") || selectedFormats.contains("ALL") || selectedFormats.size() > 1) { return "dependency-check-report"; + } else if (selectedFormats.contains("JENKINS")) { + return "dependency-check-jenkins.html"; } else if (selectedFormats.contains("XML")) { return "dependency-check-report.xml"; } else if (selectedFormats.contains("JUNIT")) { return "dependency-check-junit.xml"; } else if (selectedFormats.contains("JSON")) { return "dependency-check-report.json"; + } else if (selectedFormats.contains("SARIF")) { + return "dependency-check-report.sarif"; } else if (selectedFormats.contains("CSV")) { return "dependency-check-report.csv"; } else {