View Javadoc
1   /*
2    * This file is part of dependency-check-ant.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Copyright (c) 2013 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.taskdefs;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.util.List;
23  import org.apache.tools.ant.BuildException;
24  import org.apache.tools.ant.Project;
25  import org.apache.tools.ant.types.EnumeratedAttribute;
26  import org.apache.tools.ant.types.Reference;
27  import org.apache.tools.ant.types.Resource;
28  import org.apache.tools.ant.types.ResourceCollection;
29  import org.apache.tools.ant.types.resources.FileProvider;
30  import org.apache.tools.ant.types.resources.Resources;
31  import org.owasp.dependencycheck.Engine;
32  import org.owasp.dependencycheck.data.nvdcve.CveDB;
33  import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
34  import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
35  import org.owasp.dependencycheck.dependency.Dependency;
36  import org.owasp.dependencycheck.dependency.Identifier;
37  import org.owasp.dependencycheck.dependency.Vulnerability;
38  import org.owasp.dependencycheck.reporting.ReportGenerator;
39  import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
40  import org.owasp.dependencycheck.utils.Settings;
41  import org.slf4j.impl.StaticLoggerBinder;
42  
43  /**
44   * An Ant task definition to execute dependency-check during an Ant build.
45   *
46   * @author Jeremy Long
47   */
48  public class Check extends Update {
49  
50      /**
51       * System specific new line character.
52       */
53      private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
54  
55      /**
56       * Construct a new DependencyCheckTask.
57       */
58      public Check() {
59          super();
60          // Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from
61          // core end up coming through this tasks logger
62          StaticLoggerBinder.getSingleton().setTask(this);
63      }
64      //The following code was copied Apache Ant PathConvert
65      //BEGIN COPY from org.apache.tools.ant.taskdefs.PathConvert
66      /**
67       * Path to be converted
68       */
69      private Resources path = null;
70      /**
71       * Reference to path/fileset to convert
72       */
73      private Reference refid = null;
74  
75      /**
76       * Add an arbitrary ResourceCollection.
77       *
78       * @param rc the ResourceCollection to add.
79       * @since Ant 1.7
80       */
81      public void add(ResourceCollection rc) {
82          if (isReference()) {
83              throw new BuildException("Nested elements are not allowed when using the refid attribute.");
84          }
85          getPath().add(rc);
86      }
87  
88      /**
89       * Returns the path. If the path has not been initialized yet, this class is synchronized, and will instantiate the path
90       * object.
91       *
92       * @return the path
93       */
94      private synchronized Resources getPath() {
95          if (path == null) {
96              path = new Resources(getProject());
97              path.setCache(true);
98          }
99          return path;
100     }
101 
102     /**
103      * Learn whether the refid attribute of this element been set.
104      *
105      * @return true if refid is valid.
106      */
107     public boolean isReference() {
108         return refid != null;
109     }
110 
111     /**
112      * Add a reference to a Path, FileSet, DirSet, or FileList defined elsewhere.
113      *
114      * @param r the reference to a path, fileset, dirset or filelist.
115      */
116     public void setRefid(Reference r) {
117         if (path != null) {
118             throw new BuildException("Nested elements are not allowed when using the refid attribute.");
119         }
120         refid = r;
121     }
122 
123     /**
124      * If this is a reference, this method will add the referenced resource collection to the collection of paths.
125      *
126      * @throws BuildException if the reference is not to a resource collection
127      */
128     private void dealWithReferences() throws BuildException {
129         if (isReference()) {
130             final Object o = refid.getReferencedObject(getProject());
131             if (!(o instanceof ResourceCollection)) {
132                 throw new BuildException("refid '" + refid.getRefId()
133                         + "' does not refer to a resource collection.");
134             }
135             getPath().add((ResourceCollection) o);
136         }
137     }
138     // END COPY from org.apache.tools.ant.taskdefs
139     /**
140      * The application name for the report.
141      *
142      * @deprecated use projectName instead.
143      */
144     @Deprecated
145     private String applicationName = null;
146 
147     /**
148      * Get the value of applicationName.
149      *
150      * @return the value of applicationName
151      *
152      * @deprecated use projectName instead.
153      */
154     @Deprecated
155     public String getApplicationName() {
156         return applicationName;
157     }
158 
159     /**
160      * Set the value of applicationName.
161      *
162      * @param applicationName new value of applicationName
163      * @deprecated use projectName instead.
164      */
165     @Deprecated
166     public void setApplicationName(String applicationName) {
167         this.applicationName = applicationName;
168     }
169     /**
170      * The name of the project being analyzed.
171      */
172     private String projectName = "dependency-check";
173 
174     /**
175      * Get the value of projectName.
176      *
177      * @return the value of projectName
178      */
179     public String getProjectName() {
180         if (applicationName != null) {
181             log("Configuration 'applicationName' has been deprecated, please use 'projectName' instead", Project.MSG_WARN);
182             if ("dependency-check".equals(projectName)) {
183                 projectName = applicationName;
184             }
185         }
186         return projectName;
187     }
188 
189     /**
190      * Set the value of projectName.
191      *
192      * @param projectName new value of projectName
193      */
194     public void setProjectName(String projectName) {
195         this.projectName = projectName;
196     }
197 
198     /**
199      * Specifies the destination directory for the generated Dependency-Check report.
200      */
201     private String reportOutputDirectory = ".";
202 
203     /**
204      * Get the value of reportOutputDirectory.
205      *
206      * @return the value of reportOutputDirectory
207      */
208     public String getReportOutputDirectory() {
209         return reportOutputDirectory;
210     }
211 
212     /**
213      * Set the value of reportOutputDirectory.
214      *
215      * @param reportOutputDirectory new value of reportOutputDirectory
216      */
217     public void setReportOutputDirectory(String reportOutputDirectory) {
218         this.reportOutputDirectory = reportOutputDirectory;
219     }
220     /**
221      * Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which
222      * means since the CVSS scores are 0-10, by default the build will never fail and the CVSS score is set to 11. The valid range
223      * for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
224      */
225     private float failBuildOnCVSS = 11;
226 
227     /**
228      * Get the value of failBuildOnCVSS.
229      *
230      * @return the value of failBuildOnCVSS
231      */
232     public float getFailBuildOnCVSS() {
233         return failBuildOnCVSS;
234     }
235 
236     /**
237      * Set the value of failBuildOnCVSS.
238      *
239      * @param failBuildOnCVSS new value of failBuildOnCVSS
240      */
241     public void setFailBuildOnCVSS(float failBuildOnCVSS) {
242         this.failBuildOnCVSS = failBuildOnCVSS;
243     }
244     /**
245      * Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. Default
246      * is true.
247      */
248     private Boolean autoUpdate;
249 
250     /**
251      * Get the value of autoUpdate.
252      *
253      * @return the value of autoUpdate
254      */
255     public Boolean isAutoUpdate() {
256         return autoUpdate;
257     }
258 
259     /**
260      * Set the value of autoUpdate.
261      *
262      * @param autoUpdate new value of autoUpdate
263      */
264     public void setAutoUpdate(Boolean autoUpdate) {
265         this.autoUpdate = autoUpdate;
266     }
267     /**
268      * Whether only the update phase should be executed.
269      *
270      * @deprecated Use the update task instead
271      */
272     @Deprecated
273     private boolean updateOnly = false;
274 
275     /**
276      * Get the value of updateOnly.
277      *
278      * @return the value of updateOnly
279      * @deprecated Use the update task instead
280      */
281     @Deprecated
282     public boolean isUpdateOnly() {
283         return updateOnly;
284     }
285 
286     /**
287      * Set the value of updateOnly.
288      *
289      * @param updateOnly new value of updateOnly
290      * @deprecated Use the update task instead
291      */
292     @Deprecated
293     public void setUpdateOnly(boolean updateOnly) {
294         this.updateOnly = updateOnly;
295     }
296 
297     /**
298      * The report format to be generated (HTML, XML, VULN, ALL). Default is HTML.
299      */
300     private String reportFormat = "HTML";
301 
302     /**
303      * Get the value of reportFormat.
304      *
305      * @return the value of reportFormat
306      */
307     public String getReportFormat() {
308         return reportFormat;
309     }
310 
311     /**
312      * Set the value of reportFormat.
313      *
314      * @param reportFormat new value of reportFormat
315      */
316     public void setReportFormat(ReportFormats reportFormat) {
317         this.reportFormat = reportFormat.getValue();
318     }
319     /**
320      * The path to the suppression file.
321      */
322     private String suppressionFile;
323 
324     /**
325      * Get the value of suppressionFile.
326      *
327      * @return the value of suppressionFile
328      */
329     public String getSuppressionFile() {
330         return suppressionFile;
331     }
332 
333     /**
334      * Set the value of suppressionFile.
335      *
336      * @param suppressionFile new value of suppressionFile
337      */
338     public void setSuppressionFile(String suppressionFile) {
339         this.suppressionFile = suppressionFile;
340     }
341     /**
342      * flag indicating whether or not to show a summary of findings.
343      */
344     private boolean showSummary = true;
345 
346     /**
347      * Get the value of showSummary.
348      *
349      * @return the value of showSummary
350      */
351     public boolean isShowSummary() {
352         return showSummary;
353     }
354 
355     /**
356      * Set the value of showSummary.
357      *
358      * @param showSummary new value of showSummary
359      */
360     public void setShowSummary(boolean showSummary) {
361         this.showSummary = showSummary;
362     }
363 
364     /**
365      * Whether or not the Jar Analyzer is enabled.
366      */
367     private Boolean jarAnalyzerEnabled;
368 
369     /**
370      * Returns whether or not the analyzer is enabled.
371      *
372      * @return true if the analyzer is enabled
373      */
374     public Boolean isJarAnalyzerEnabled() {
375         return jarAnalyzerEnabled;
376     }
377 
378     /**
379      * Sets whether or not the analyzer is enabled.
380      *
381      * @param jarAnalyzerEnabled the value of the new setting
382      */
383     public void setJarAnalyzerEnabled(Boolean jarAnalyzerEnabled) {
384         this.jarAnalyzerEnabled = jarAnalyzerEnabled;
385     }
386     /**
387      * Whether or not the Archive Analyzer is enabled.
388      */
389     private Boolean archiveAnalyzerEnabled;
390 
391     /**
392      * Returns whether or not the analyzer is enabled.
393      *
394      * @return true if the analyzer is enabled
395      */
396     public Boolean isArchiveAnalyzerEnabled() {
397         return archiveAnalyzerEnabled;
398     }
399     /**
400      * Whether or not the .NET Assembly Analyzer is enabled.
401      */
402     private Boolean assemblyAnalyzerEnabled;
403 
404     /**
405      * Sets whether or not the analyzer is enabled.
406      *
407      * @param archiveAnalyzerEnabled the value of the new setting
408      */
409     public void setArchiveAnalyzerEnabled(Boolean archiveAnalyzerEnabled) {
410         this.archiveAnalyzerEnabled = archiveAnalyzerEnabled;
411     }
412 
413     /**
414      * Returns whether or not the analyzer is enabled.
415      *
416      * @return true if the analyzer is enabled
417      */
418     public Boolean isAssemblyAnalyzerEnabled() {
419         return assemblyAnalyzerEnabled;
420     }
421 
422     /**
423      * Sets whether or not the analyzer is enabled.
424      *
425      * @param assemblyAnalyzerEnabled the value of the new setting
426      */
427     public void setAssemblyAnalyzerEnabled(Boolean assemblyAnalyzerEnabled) {
428         this.assemblyAnalyzerEnabled = assemblyAnalyzerEnabled;
429     }
430     /**
431      * Whether or not the .NET Nuspec Analyzer is enabled.
432      */
433     private Boolean nuspecAnalyzerEnabled;
434 
435     /**
436      * Returns whether or not the analyzer is enabled.
437      *
438      * @return true if the analyzer is enabled
439      */
440     public Boolean isNuspecAnalyzerEnabled() {
441         return nuspecAnalyzerEnabled;
442     }
443 
444     /**
445      * Sets whether or not the analyzer is enabled.
446      *
447      * @param nuspecAnalyzerEnabled the value of the new setting
448      */
449     public void setNuspecAnalyzerEnabled(Boolean nuspecAnalyzerEnabled) {
450         this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
451     }
452     /**
453      * Whether or not the PHP Composer Analyzer is enabled.
454      */
455     private Boolean composerAnalyzerEnabled;
456 
457     /**
458      * Get the value of composerAnalyzerEnabled.
459      *
460      * @return the value of composerAnalyzerEnabled
461      */
462     public Boolean isComposerAnalyzerEnabled() {
463         return composerAnalyzerEnabled;
464     }
465 
466     /**
467      * Set the value of composerAnalyzerEnabled.
468      *
469      * @param composerAnalyzerEnabled new value of composerAnalyzerEnabled
470      */
471     public void setComposerAnalyzerEnabled(Boolean composerAnalyzerEnabled) {
472         this.composerAnalyzerEnabled = composerAnalyzerEnabled;
473     }
474     /**
475      * Whether the autoconf analyzer should be enabled.
476      */
477     private Boolean autoconfAnalyzerEnabled;
478 
479     /**
480      * Get the value of autoconfAnalyzerEnabled.
481      *
482      * @return the value of autoconfAnalyzerEnabled
483      */
484     public Boolean isAutoconfAnalyzerEnabled() {
485         return autoconfAnalyzerEnabled;
486     }
487 
488     /**
489      * Set the value of autoconfAnalyzerEnabled.
490      *
491      * @param autoconfAnalyzerEnabled new value of autoconfAnalyzerEnabled
492      */
493     public void setAutoconfAnalyzerEnabled(Boolean autoconfAnalyzerEnabled) {
494         this.autoconfAnalyzerEnabled = autoconfAnalyzerEnabled;
495     }
496     /**
497      * Whether the CMake analyzer should be enabled.
498      */
499     private Boolean cmakeAnalyzerEnabled;
500 
501     /**
502      * Get the value of cmakeAnalyzerEnabled.
503      *
504      * @return the value of cmakeAnalyzerEnabled
505      */
506     public Boolean isCMakeAnalyzerEnabled() {
507         return cmakeAnalyzerEnabled;
508     }
509 
510     /**
511      * Set the value of cmakeAnalyzerEnabled.
512      *
513      * @param cmakeAnalyzerEnabled new value of cmakeAnalyzerEnabled
514      */
515     public void setCMakeAnalyzerEnabled(Boolean cmakeAnalyzerEnabled) {
516         this.cmakeAnalyzerEnabled = cmakeAnalyzerEnabled;
517     }
518     /**
519      * Whether or not the openssl analyzer is enabled.
520      */
521     private Boolean opensslAnalyzerEnabled;
522 
523     /**
524      * Get the value of opensslAnalyzerEnabled.
525      *
526      * @return the value of opensslAnalyzerEnabled
527      */
528     public Boolean isOpensslAnalyzerEnabled() {
529         return opensslAnalyzerEnabled;
530     }
531 
532     /**
533      * Set the value of opensslAnalyzerEnabled.
534      *
535      * @param opensslAnalyzerEnabled new value of opensslAnalyzerEnabled
536      */
537     public void setOpensslAnalyzerEnabled(Boolean opensslAnalyzerEnabled) {
538         this.opensslAnalyzerEnabled = opensslAnalyzerEnabled;
539     }
540     /**
541      * Whether or not the Node.js Analyzer is enabled.
542      */
543     private Boolean nodeAnalyzerEnabled;
544 
545     /**
546      * Get the value of nodeAnalyzerEnabled.
547      *
548      * @return the value of nodeAnalyzerEnabled
549      */
550     public Boolean isNodeAnalyzerEnabled() {
551         return nodeAnalyzerEnabled;
552     }
553 
554     /**
555      * Set the value of nodeAnalyzerEnabled.
556      *
557      * @param nodeAnalyzerEnabled new value of nodeAnalyzerEnabled
558      */
559     public void setNodeAnalyzerEnabled(Boolean nodeAnalyzerEnabled) {
560         this.nodeAnalyzerEnabled = nodeAnalyzerEnabled;
561     }
562     /**
563      * Whether the ruby gemspec analyzer should be enabled.
564      */
565     private Boolean rubygemsAnalyzerEnabled;
566 
567     /**
568      * Get the value of rubygemsAnalyzerEnabled.
569      *
570      * @return the value of rubygemsAnalyzerEnabled
571      */
572     public Boolean isRubygemsAnalyzerEnabled() {
573         return rubygemsAnalyzerEnabled;
574     }
575 
576     /**
577      * Set the value of rubygemsAnalyzerEnabled.
578      *
579      * @param rubygemsAnalyzerEnabled new value of rubygemsAnalyzerEnabled
580      */
581     public void setRubygemsAnalyzerEnabled(Boolean rubygemsAnalyzerEnabled) {
582         this.rubygemsAnalyzerEnabled = rubygemsAnalyzerEnabled;
583     }
584     /**
585      * Whether the python package analyzer should be enabled.
586      */
587     private Boolean pyPackageAnalyzerEnabled;
588 
589     /**
590      * Get the value of pyPackageAnalyzerEnabled.
591      *
592      * @return the value of pyPackageAnalyzerEnabled
593      */
594     public Boolean isPyPackageAnalyzerEnabled() {
595         return pyPackageAnalyzerEnabled;
596     }
597 
598     /**
599      * Set the value of pyPackageAnalyzerEnabled.
600      *
601      * @param pyPackageAnalyzerEnabled new value of pyPackageAnalyzerEnabled
602      */
603     public void setPyPackageAnalyzerEnabled(Boolean pyPackageAnalyzerEnabled) {
604         this.pyPackageAnalyzerEnabled = pyPackageAnalyzerEnabled;
605     }
606 
607     /**
608      * Whether the python distribution analyzer should be enabled.
609      */
610     private Boolean pyDistributionAnalyzerEnabled;
611 
612     /**
613      * Get the value of pyDistributionAnalyzerEnabled.
614      *
615      * @return the value of pyDistributionAnalyzerEnabled
616      */
617     public Boolean isPyDistributionAnalyzerEnabled() {
618         return pyDistributionAnalyzerEnabled;
619     }
620 
621     /**
622      * Set the value of pyDistributionAnalyzerEnabled.
623      *
624      * @param pyDistributionAnalyzerEnabled new value of pyDistributionAnalyzerEnabled
625      */
626     public void setPyDistributionAnalyzerEnabled(Boolean pyDistributionAnalyzerEnabled) {
627         this.pyDistributionAnalyzerEnabled = pyDistributionAnalyzerEnabled;
628     }
629 
630     /**
631      * Whether or not the central analyzer is enabled.
632      */
633     private Boolean centralAnalyzerEnabled;
634 
635     /**
636      * Get the value of centralAnalyzerEnabled.
637      *
638      * @return the value of centralAnalyzerEnabled
639      */
640     public Boolean isCentralAnalyzerEnabled() {
641         return centralAnalyzerEnabled;
642     }
643 
644     /**
645      * Set the value of centralAnalyzerEnabled.
646      *
647      * @param centralAnalyzerEnabled new value of centralAnalyzerEnabled
648      */
649     public void setCentralAnalyzerEnabled(Boolean centralAnalyzerEnabled) {
650         this.centralAnalyzerEnabled = centralAnalyzerEnabled;
651     }
652 
653     /**
654      * Whether or not the nexus analyzer is enabled.
655      */
656     private Boolean nexusAnalyzerEnabled;
657 
658     /**
659      * Get the value of nexusAnalyzerEnabled.
660      *
661      * @return the value of nexusAnalyzerEnabled
662      */
663     public Boolean isNexusAnalyzerEnabled() {
664         return nexusAnalyzerEnabled;
665     }
666 
667     /**
668      * Set the value of nexusAnalyzerEnabled.
669      *
670      * @param nexusAnalyzerEnabled new value of nexusAnalyzerEnabled
671      */
672     public void setNexusAnalyzerEnabled(Boolean nexusAnalyzerEnabled) {
673         this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
674     }
675 
676     /**
677      * The URL of a Nexus server's REST API end point (http://domain/nexus/service/local).
678      */
679     private String nexusUrl;
680 
681     /**
682      * Get the value of nexusUrl.
683      *
684      * @return the value of nexusUrl
685      */
686     public String getNexusUrl() {
687         return nexusUrl;
688     }
689 
690     /**
691      * Set the value of nexusUrl.
692      *
693      * @param nexusUrl new value of nexusUrl
694      */
695     public void setNexusUrl(String nexusUrl) {
696         this.nexusUrl = nexusUrl;
697     }
698     /**
699      * Whether or not the defined proxy should be used when connecting to Nexus.
700      */
701     private Boolean nexusUsesProxy;
702 
703     /**
704      * Get the value of nexusUsesProxy.
705      *
706      * @return the value of nexusUsesProxy
707      */
708     public Boolean isNexusUsesProxy() {
709         return nexusUsesProxy;
710     }
711 
712     /**
713      * Set the value of nexusUsesProxy.
714      *
715      * @param nexusUsesProxy new value of nexusUsesProxy
716      */
717     public void setNexusUsesProxy(Boolean nexusUsesProxy) {
718         this.nexusUsesProxy = nexusUsesProxy;
719     }
720 
721     /**
722      * Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat like ZIP
723      * files.
724      */
725     private String zipExtensions;
726 
727     /**
728      * Get the value of zipExtensions.
729      *
730      * @return the value of zipExtensions
731      */
732     public String getZipExtensions() {
733         return zipExtensions;
734     }
735 
736     /**
737      * Set the value of zipExtensions.
738      *
739      * @param zipExtensions new value of zipExtensions
740      */
741     public void setZipExtensions(String zipExtensions) {
742         this.zipExtensions = zipExtensions;
743     }
744 
745     /**
746      * The path to Mono for .NET assembly analysis on non-windows systems.
747      */
748     private String pathToMono;
749 
750     /**
751      * Get the value of pathToMono.
752      *
753      * @return the value of pathToMono
754      */
755     public String getPathToMono() {
756         return pathToMono;
757     }
758 
759     /**
760      * Set the value of pathToMono.
761      *
762      * @param pathToMono new value of pathToMono
763      */
764     public void setPathToMono(String pathToMono) {
765         this.pathToMono = pathToMono;
766     }
767 
768     @Override
769     public void execute() throws BuildException {
770         dealWithReferences();
771         validateConfiguration();
772         populateSettings();
773         Engine engine = null;
774         try {
775             engine = new Engine(Check.class.getClassLoader());
776             if (isUpdateOnly()) {
777                 log("Deprecated 'UpdateOnly' property set; please use the UpdateTask instead", Project.MSG_WARN);
778                 engine.doUpdates();
779             } else {
780                 try {
781                     for (Resource resource : path) {
782                         final FileProvider provider = resource.as(FileProvider.class);
783                         if (provider != null) {
784                             final File file = provider.getFile();
785                             if (file != null && file.exists()) {
786                                 engine.scan(file);
787                             }
788                         }
789                     }
790 
791                     engine.analyzeDependencies();
792                     DatabaseProperties prop = null;
793                     CveDB cve = null;
794                     try {
795                         cve = new CveDB();
796                         cve.open();
797                         prop = cve.getDatabaseProperties();
798                     } catch (DatabaseException ex) {
799                         log("Unable to retrieve DB Properties", ex, Project.MSG_DEBUG);
800                     } finally {
801                         if (cve != null) {
802                             cve.close();
803                         }
804                     }
805                     final ReportGenerator reporter = new ReportGenerator(getProjectName(), engine.getDependencies(), engine.getAnalyzers(), prop);
806                     reporter.generateReports(reportOutputDirectory, reportFormat);
807 
808                     if (this.failBuildOnCVSS <= 10) {
809                         checkForFailure(engine.getDependencies());
810                     }
811                     if (this.showSummary) {
812                         showSummary(engine.getDependencies());
813                     }
814                 } catch (IOException ex) {
815                     log("Unable to generate dependency-check report", ex, Project.MSG_DEBUG);
816                     throw new BuildException("Unable to generate dependency-check report", ex);
817                 } catch (Exception ex) {
818                     log("An exception occurred; unable to continue task", ex, Project.MSG_DEBUG);
819                     throw new BuildException("An exception occurred; unable to continue task", ex);
820                 }
821             }
822         } catch (DatabaseException ex) {
823             log("Unable to connect to the dependency-check database; analysis has stopped", ex, Project.MSG_ERR);
824         } finally {
825             Settings.cleanup(true);
826             if (engine != null) {
827                 engine.cleanup();
828             }
829         }
830     }
831 
832     /**
833      * Validate the configuration to ensure the parameters have been properly configured/initialized.
834      *
835      * @throws BuildException if the task was not configured correctly.
836      */
837     private void validateConfiguration() throws BuildException {
838         if (path == null) {
839             throw new BuildException("No project dependencies have been defined to analyze.");
840         }
841         if (failBuildOnCVSS < 0 || failBuildOnCVSS > 11) {
842             throw new BuildException("Invalid configuration, failBuildOnCVSS must be between 0 and 11.");
843         }
844     }
845 
846     /**
847      * Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
848      * required to change the proxy server, port, and connection timeout.
849      *
850      * @throws BuildException thrown when an invalid setting is configured.
851      */
852     @Override
853     protected void populateSettings() throws BuildException {
854         super.populateSettings();
855         Settings.setBooleanIfNotNull(Settings.KEYS.AUTO_UPDATE, autoUpdate);
856         Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
857         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
858         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, pyDistributionAnalyzerEnabled);
859         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED, pyPackageAnalyzerEnabled);
860         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED, rubygemsAnalyzerEnabled);
861         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_OPENSSL_ENABLED, opensslAnalyzerEnabled);
862         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_CMAKE_ENABLED, cmakeAnalyzerEnabled);
863         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_AUTOCONF_ENABLED, autoconfAnalyzerEnabled);
864         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED, composerAnalyzerEnabled);
865         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED, nodeAnalyzerEnabled);
866         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
867         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
868         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
869         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled);
870         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled);
871         Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
872         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
873         Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
874         Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
875     }
876 
877     /**
878      * Checks to see if a vulnerability has been identified with a CVSS score that is above the threshold set in the
879      * configuration.
880      *
881      * @param dependencies the list of dependency objects
882      * @throws BuildException thrown if a CVSS score is found that is higher then the threshold set
883      */
884     private void checkForFailure(List<Dependency> dependencies) throws BuildException {
885         final StringBuilder ids = new StringBuilder();
886         for (Dependency d : dependencies) {
887             for (Vulnerability v : d.getVulnerabilities()) {
888                 if (v.getCvssScore() >= failBuildOnCVSS) {
889                     if (ids.length() == 0) {
890                         ids.append(v.getName());
891                     } else {
892                         ids.append(", ").append(v.getName());
893                     }
894                 }
895             }
896         }
897         if (ids.length() > 0) {
898             final String msg = String.format("%n%nDependency-Check Failure:%n"
899                     + "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
900                     + "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
901             throw new BuildException(msg);
902         }
903     }
904 
905     /**
906      * Generates a warning message listing a summary of dependencies and their associated CPE and CVE entries.
907      *
908      * @param dependencies a list of dependency objects
909      */
910     private void showSummary(List<Dependency> dependencies) {
911         final StringBuilder summary = new StringBuilder();
912         for (Dependency d : dependencies) {
913             boolean firstEntry = true;
914             final StringBuilder ids = new StringBuilder();
915             for (Vulnerability v : d.getVulnerabilities()) {
916                 if (firstEntry) {
917                     firstEntry = false;
918                 } else {
919                     ids.append(", ");
920                 }
921                 ids.append(v.getName());
922             }
923             if (ids.length() > 0) {
924                 summary.append(d.getFileName()).append(" (");
925                 firstEntry = true;
926                 for (Identifier id : d.getIdentifiers()) {
927                     if (firstEntry) {
928                         firstEntry = false;
929                     } else {
930                         summary.append(", ");
931                     }
932                     summary.append(id.getValue());
933                 }
934                 summary.append(") : ").append(ids).append(NEW_LINE);
935             }
936         }
937         if (summary.length() > 0) {
938             final String msg = String.format("%n%n"
939                     + "One or more dependencies were identified with known vulnerabilities:%n%n%s"
940                     + "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
941             log(msg, Project.MSG_WARN);
942         }
943     }
944 
945     /**
946      * An enumeration of supported report formats: "ALL", "HTML", "XML", "VULN", etc..
947      */
948     public static class ReportFormats extends EnumeratedAttribute {
949 
950         /**
951          * Returns the list of values for the report format.
952          *
953          * @return the list of values for the report format
954          */
955         @Override
956         public String[] getValues() {
957             int i = 0;
958             final Format[] formats = Format.values();
959             final String[] values = new String[formats.length];
960             for (Format format : formats) {
961                 values[i++] = format.name();
962             }
963             return values;
964         }
965     }
966 }