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 = true;
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     private boolean updateOnly = false;
271 
272     /**
273      * Get the value of updateOnly.
274      *
275      * @return the value of updateOnly
276      */
277     public boolean isUpdateOnly() {
278         return updateOnly;
279     }
280 
281     /**
282      * Set the value of updateOnly.
283      *
284      * @param updateOnly new value of updateOnly
285      */
286     public void setUpdateOnly(boolean updateOnly) {
287         this.updateOnly = updateOnly;
288     }
289 
290     /**
291      * The report format to be generated (HTML, XML, VULN, ALL). Default is HTML.
292      */
293     private String reportFormat = "HTML";
294 
295     /**
296      * Get the value of reportFormat.
297      *
298      * @return the value of reportFormat
299      */
300     public String getReportFormat() {
301         return reportFormat;
302     }
303 
304     /**
305      * Set the value of reportFormat.
306      *
307      * @param reportFormat new value of reportFormat
308      */
309     public void setReportFormat(ReportFormats reportFormat) {
310         this.reportFormat = reportFormat.getValue();
311     }
312     /**
313      * The path to the suppression file.
314      */
315     private String suppressionFile;
316 
317     /**
318      * Get the value of suppressionFile.
319      *
320      * @return the value of suppressionFile
321      */
322     public String getSuppressionFile() {
323         return suppressionFile;
324     }
325 
326     /**
327      * Set the value of suppressionFile.
328      *
329      * @param suppressionFile new value of suppressionFile
330      */
331     public void setSuppressionFile(String suppressionFile) {
332         this.suppressionFile = suppressionFile;
333     }
334     /**
335      * flag indicating whether or not to show a summary of findings.
336      */
337     private boolean showSummary = true;
338 
339     /**
340      * Get the value of showSummary.
341      *
342      * @return the value of showSummary
343      */
344     public boolean isShowSummary() {
345         return showSummary;
346     }
347 
348     /**
349      * Set the value of showSummary.
350      *
351      * @param showSummary new value of showSummary
352      */
353     public void setShowSummary(boolean showSummary) {
354         this.showSummary = showSummary;
355     }
356 
357     /**
358      * Whether or not the Jar Analyzer is enabled.
359      */
360     private boolean jarAnalyzerEnabled = true;
361 
362     /**
363      * Returns whether or not the analyzer is enabled.
364      *
365      * @return true if the analyzer is enabled
366      */
367     public boolean isJarAnalyzerEnabled() {
368         return jarAnalyzerEnabled;
369     }
370 
371     /**
372      * Sets whether or not the analyzer is enabled.
373      *
374      * @param jarAnalyzerEnabled the value of the new setting
375      */
376     public void setJarAnalyzerEnabled(boolean jarAnalyzerEnabled) {
377         this.jarAnalyzerEnabled = jarAnalyzerEnabled;
378     }
379     /**
380      * Whether or not the Archive Analyzer is enabled.
381      */
382     private boolean archiveAnalyzerEnabled = true;
383 
384     /**
385      * Returns whether or not the analyzer is enabled.
386      *
387      * @return true if the analyzer is enabled
388      */
389     public boolean isArchiveAnalyzerEnabled() {
390         return archiveAnalyzerEnabled;
391     }
392     /**
393      * Whether or not the .NET Assembly Analyzer is enabled.
394      */
395     private boolean assemblyAnalyzerEnabled = true;
396 
397     /**
398      * Sets whether or not the analyzer is enabled.
399      *
400      * @param archiveAnalyzerEnabled the value of the new setting
401      */
402     public void setArchiveAnalyzerEnabled(boolean archiveAnalyzerEnabled) {
403         this.archiveAnalyzerEnabled = archiveAnalyzerEnabled;
404     }
405 
406     /**
407      * Returns whether or not the analyzer is enabled.
408      *
409      * @return true if the analyzer is enabled
410      */
411     public boolean isAssemblyAnalyzerEnabled() {
412         return assemblyAnalyzerEnabled;
413     }
414 
415     /**
416      * Sets whether or not the analyzer is enabled.
417      *
418      * @param assemblyAnalyzerEnabled the value of the new setting
419      */
420     public void setAssemblyAnalyzerEnabled(boolean assemblyAnalyzerEnabled) {
421         this.assemblyAnalyzerEnabled = assemblyAnalyzerEnabled;
422     }
423     /**
424      * Whether or not the .NET Nuspec Analyzer is enabled.
425      */
426     private boolean nuspecAnalyzerEnabled = true;
427 
428     /**
429      * Returns whether or not the analyzer is enabled.
430      *
431      * @return true if the analyzer is enabled
432      */
433     public boolean isNuspecAnalyzerEnabled() {
434         return nuspecAnalyzerEnabled;
435     }
436 
437     /**
438      * Sets whether or not the analyzer is enabled.
439      *
440      * @param nuspecAnalyzerEnabled the value of the new setting
441      */
442     public void setNuspecAnalyzerEnabled(boolean nuspecAnalyzerEnabled) {
443         this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
444     }
445     /**
446      * Whether or not the PHP Composer Analyzer is enabled.
447      */
448     private boolean composerAnalyzerEnabled = true;
449 
450     /**
451      * Get the value of composerAnalyzerEnabled.
452      *
453      * @return the value of composerAnalyzerEnabled
454      */
455     public boolean isComposerAnalyzerEnabled() {
456         return composerAnalyzerEnabled;
457     }
458 
459     /**
460      * Set the value of composerAnalyzerEnabled.
461      *
462      * @param composerAnalyzerEnabled new value of composerAnalyzerEnabled
463      */
464     public void setComposerAnalyzerEnabled(boolean composerAnalyzerEnabled) {
465         this.composerAnalyzerEnabled = composerAnalyzerEnabled;
466     }
467     /**
468      * Whether the autoconf analyzer should be enabled.
469      */
470     private boolean autoconfAnalyzerEnabled = true;
471 
472     /**
473      * Get the value of autoconfAnalyzerEnabled.
474      *
475      * @return the value of autoconfAnalyzerEnabled
476      */
477     public boolean isAutoconfAnalyzerEnabled() {
478         return autoconfAnalyzerEnabled;
479     }
480 
481     /**
482      * Set the value of autoconfAnalyzerEnabled.
483      *
484      * @param autoconfAnalyzerEnabled new value of autoconfAnalyzerEnabled
485      */
486     public void setAutoconfAnalyzerEnabled(boolean autoconfAnalyzerEnabled) {
487         this.autoconfAnalyzerEnabled = autoconfAnalyzerEnabled;
488     }
489     /**
490      * Whether the CMake analyzer should be enabled.
491      */
492     private boolean cmakeAnalyzerEnabled = true;
493 
494     /**
495      * Get the value of cmakeAnalyzerEnabled.
496      *
497      * @return the value of cmakeAnalyzerEnabled
498      */
499     public boolean isCMakeAnalyzerEnabled() {
500         return cmakeAnalyzerEnabled;
501     }
502 
503     /**
504      * Set the value of cmakeAnalyzerEnabled.
505      *
506      * @param cmakeAnalyzerEnabled new value of cmakeAnalyzerEnabled
507      */
508     public void setCMakeAnalyzerEnabled(boolean cmakeAnalyzerEnabled) {
509         this.cmakeAnalyzerEnabled = cmakeAnalyzerEnabled;
510     }
511     /**
512      * Whether or not the openssl analyzer is enabled.
513      */
514     private boolean opensslAnalyzerEnabled = true;
515 
516     /**
517      * Get the value of opensslAnalyzerEnabled.
518      *
519      * @return the value of opensslAnalyzerEnabled
520      */
521     public boolean isOpensslAnalyzerEnabled() {
522         return opensslAnalyzerEnabled;
523     }
524 
525     /**
526      * Set the value of opensslAnalyzerEnabled.
527      *
528      * @param opensslAnalyzerEnabled new value of opensslAnalyzerEnabled
529      */
530     public void setOpensslAnalyzerEnabled(boolean opensslAnalyzerEnabled) {
531         this.opensslAnalyzerEnabled = opensslAnalyzerEnabled;
532     }
533     /**
534      * Whether or not the Node.js Analyzer is enabled.
535      */
536     private boolean nodeAnalyzerEnabled = true;
537 
538     /**
539      * Get the value of nodeAnalyzerEnabled.
540      *
541      * @return the value of nodeAnalyzerEnabled
542      */
543     public boolean isNodeAnalyzerEnabled() {
544         return nodeAnalyzerEnabled;
545     }
546 
547     /**
548      * Set the value of nodeAnalyzerEnabled.
549      *
550      * @param nodeAnalyzerEnabled new value of nodeAnalyzerEnabled
551      */
552     public void setNodeAnalyzerEnabled(boolean nodeAnalyzerEnabled) {
553         this.nodeAnalyzerEnabled = nodeAnalyzerEnabled;
554     }
555     /**
556      * Whether the ruby gemspec analyzer should be enabled.
557      */
558     private boolean rubygemsAnalyzerEnabled = true;
559 
560     /**
561      * Get the value of rubygemsAnalyzerEnabled.
562      *
563      * @return the value of rubygemsAnalyzerEnabled
564      */
565     public boolean isRubygemsAnalyzerEnabled() {
566         return rubygemsAnalyzerEnabled;
567     }
568 
569     /**
570      * Set the value of rubygemsAnalyzerEnabled.
571      *
572      * @param rubygemsAnalyzerEnabled new value of rubygemsAnalyzerEnabled
573      */
574     public void setRubygemsAnalyzerEnabled(boolean rubygemsAnalyzerEnabled) {
575         this.rubygemsAnalyzerEnabled = rubygemsAnalyzerEnabled;
576     }
577     /**
578      * Whether the python package analyzer should be enabled.
579      */
580     private boolean pyPackageAnalyzerEnabled = true;
581 
582     /**
583      * Get the value of pyPackageAnalyzerEnabled.
584      *
585      * @return the value of pyPackageAnalyzerEnabled
586      */
587     public boolean isPyPackageAnalyzerEnabled() {
588         return pyPackageAnalyzerEnabled;
589     }
590 
591     /**
592      * Set the value of pyPackageAnalyzerEnabled.
593      *
594      * @param pyPackageAnalyzerEnabled new value of pyPackageAnalyzerEnabled
595      */
596     public void setPyPackageAnalyzerEnabled(boolean pyPackageAnalyzerEnabled) {
597         this.pyPackageAnalyzerEnabled = pyPackageAnalyzerEnabled;
598     }
599 
600     /**
601      * Whether the python distribution analyzer should be enabled.
602      */
603     private boolean pyDistributionAnalyzerEnabled = true;
604 
605     /**
606      * Get the value of pyDistributionAnalyzerEnabled.
607      *
608      * @return the value of pyDistributionAnalyzerEnabled
609      */
610     public boolean isPyDistributionAnalyzerEnabled() {
611         return pyDistributionAnalyzerEnabled;
612     }
613 
614     /**
615      * Set the value of pyDistributionAnalyzerEnabled.
616      *
617      * @param pyDistributionAnalyzerEnabled new value of pyDistributionAnalyzerEnabled
618      */
619     public void setPyDistributionAnalyzerEnabled(boolean pyDistributionAnalyzerEnabled) {
620         this.pyDistributionAnalyzerEnabled = pyDistributionAnalyzerEnabled;
621     }
622 
623     /**
624      * Whether or not the central analyzer is enabled.
625      */
626     private boolean centralAnalyzerEnabled = false;
627 
628     /**
629      * Get the value of centralAnalyzerEnabled.
630      *
631      * @return the value of centralAnalyzerEnabled
632      */
633     public boolean isCentralAnalyzerEnabled() {
634         return centralAnalyzerEnabled;
635     }
636 
637     /**
638      * Set the value of centralAnalyzerEnabled.
639      *
640      * @param centralAnalyzerEnabled new value of centralAnalyzerEnabled
641      */
642     public void setCentralAnalyzerEnabled(boolean centralAnalyzerEnabled) {
643         this.centralAnalyzerEnabled = centralAnalyzerEnabled;
644     }
645 
646     /**
647      * Whether or not the nexus analyzer is enabled.
648      */
649     private boolean nexusAnalyzerEnabled = true;
650 
651     /**
652      * Get the value of nexusAnalyzerEnabled.
653      *
654      * @return the value of nexusAnalyzerEnabled
655      */
656     public boolean isNexusAnalyzerEnabled() {
657         return nexusAnalyzerEnabled;
658     }
659 
660     /**
661      * Set the value of nexusAnalyzerEnabled.
662      *
663      * @param nexusAnalyzerEnabled new value of nexusAnalyzerEnabled
664      */
665     public void setNexusAnalyzerEnabled(boolean nexusAnalyzerEnabled) {
666         this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
667     }
668 
669     /**
670      * The URL of a Nexus server's REST API end point (http://domain/nexus/service/local).
671      */
672     private String nexusUrl;
673 
674     /**
675      * Get the value of nexusUrl.
676      *
677      * @return the value of nexusUrl
678      */
679     public String getNexusUrl() {
680         return nexusUrl;
681     }
682 
683     /**
684      * Set the value of nexusUrl.
685      *
686      * @param nexusUrl new value of nexusUrl
687      */
688     public void setNexusUrl(String nexusUrl) {
689         this.nexusUrl = nexusUrl;
690     }
691     /**
692      * Whether or not the defined proxy should be used when connecting to Nexus.
693      */
694     private boolean nexusUsesProxy = true;
695 
696     /**
697      * Get the value of nexusUsesProxy.
698      *
699      * @return the value of nexusUsesProxy
700      */
701     public boolean isNexusUsesProxy() {
702         return nexusUsesProxy;
703     }
704 
705     /**
706      * Set the value of nexusUsesProxy.
707      *
708      * @param nexusUsesProxy new value of nexusUsesProxy
709      */
710     public void setNexusUsesProxy(boolean nexusUsesProxy) {
711         this.nexusUsesProxy = nexusUsesProxy;
712     }
713 
714     /**
715      * Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat like ZIP
716      * files.
717      */
718     private String zipExtensions;
719 
720     /**
721      * Get the value of zipExtensions.
722      *
723      * @return the value of zipExtensions
724      */
725     public String getZipExtensions() {
726         return zipExtensions;
727     }
728 
729     /**
730      * Set the value of zipExtensions.
731      *
732      * @param zipExtensions new value of zipExtensions
733      */
734     public void setZipExtensions(String zipExtensions) {
735         this.zipExtensions = zipExtensions;
736     }
737 
738     /**
739      * The path to Mono for .NET assembly analysis on non-windows systems.
740      */
741     private String pathToMono;
742 
743     /**
744      * Get the value of pathToMono.
745      *
746      * @return the value of pathToMono
747      */
748     public String getPathToMono() {
749         return pathToMono;
750     }
751 
752     /**
753      * Set the value of pathToMono.
754      *
755      * @param pathToMono new value of pathToMono
756      */
757     public void setPathToMono(String pathToMono) {
758         this.pathToMono = pathToMono;
759     }
760 
761     @Override
762     public void execute() throws BuildException {
763         dealWithReferences();
764         validateConfiguration();
765         populateSettings();
766         Engine engine = null;
767         try {
768             engine = new Engine(Check.class.getClassLoader());
769             if (isUpdateOnly()) {
770                 log("Deprecated 'UpdateOnly' property set; please use the UpdateTask instead", Project.MSG_WARN);
771                 engine.doUpdates();
772             } else {
773                 try {
774                     for (Resource resource : path) {
775                         final FileProvider provider = resource.as(FileProvider.class);
776                         if (provider != null) {
777                             final File file = provider.getFile();
778                             if (file != null && file.exists()) {
779                                 engine.scan(file);
780                             }
781                         }
782                     }
783 
784                     engine.analyzeDependencies();
785                     DatabaseProperties prop = null;
786                     CveDB cve = null;
787                     try {
788                         cve = new CveDB();
789                         cve.open();
790                         prop = cve.getDatabaseProperties();
791                     } catch (DatabaseException ex) {
792                         log("Unable to retrieve DB Properties", ex, Project.MSG_DEBUG);
793                     } finally {
794                         if (cve != null) {
795                             cve.close();
796                         }
797                     }
798                     final ReportGenerator reporter = new ReportGenerator(getProjectName(), engine.getDependencies(), engine.getAnalyzers(), prop);
799                     reporter.generateReports(reportOutputDirectory, reportFormat);
800 
801                     if (this.failBuildOnCVSS <= 10) {
802                         checkForFailure(engine.getDependencies());
803                     }
804                     if (this.showSummary) {
805                         showSummary(engine.getDependencies());
806                     }
807                 } catch (IOException ex) {
808                     log("Unable to generate dependency-check report", ex, Project.MSG_DEBUG);
809                     throw new BuildException("Unable to generate dependency-check report", ex);
810                 } catch (Exception ex) {
811                     log("An exception occurred; unable to continue task", ex, Project.MSG_DEBUG);
812                     throw new BuildException("An exception occurred; unable to continue task", ex);
813                 }
814             }
815         } catch (DatabaseException ex) {
816             log("Unable to connect to the dependency-check database; analysis has stopped", ex, Project.MSG_ERR);
817         } finally {
818             Settings.cleanup(true);
819             if (engine != null) {
820                 engine.cleanup();
821             }
822         }
823     }
824 
825     /**
826      * Validate the configuration to ensure the parameters have been properly configured/initialized.
827      *
828      * @throws BuildException if the task was not configured correctly.
829      */
830     private void validateConfiguration() throws BuildException {
831         if (path == null) {
832             throw new BuildException("No project dependencies have been defined to analyze.");
833         }
834         if (failBuildOnCVSS < 0 || failBuildOnCVSS > 11) {
835             throw new BuildException("Invalid configuration, failBuildOnCVSS must be between 0 and 11.");
836         }
837     }
838 
839     /**
840      * Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
841      * required to change the proxy server, port, and connection timeout.
842      */
843     @Override
844     protected void populateSettings() {
845         super.populateSettings();
846         Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
847 
848         if (suppressionFile != null && !suppressionFile.isEmpty()) {
849             Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
850         }
851 
852         Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
853 
854         Settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, pyDistributionAnalyzerEnabled);
855         Settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED, pyPackageAnalyzerEnabled);
856         Settings.setBoolean(Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED, rubygemsAnalyzerEnabled);
857         Settings.setBoolean(Settings.KEYS.ANALYZER_OPENSSL_ENABLED, opensslAnalyzerEnabled);
858         Settings.setBoolean(Settings.KEYS.ANALYZER_CMAKE_ENABLED, cmakeAnalyzerEnabled);
859         Settings.setBoolean(Settings.KEYS.ANALYZER_AUTOCONF_ENABLED, autoconfAnalyzerEnabled);
860         Settings.setBoolean(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED, composerAnalyzerEnabled);
861         Settings.setBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED, nodeAnalyzerEnabled);
862 
863         Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
864         Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
865         Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
866         if (nexusUrl != null && !nexusUrl.isEmpty()) {
867             Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
868         }
869         Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
870         Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled);
871         if (zipExtensions != null && !zipExtensions.isEmpty()) {
872             Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
873         }
874         Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled);
875         if (pathToMono != null && !pathToMono.isEmpty()) {
876             Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
877         }
878     }
879 
880     /**
881      * Checks to see if a vulnerability has been identified with a CVSS score that is above the threshold set in the
882      * configuration.
883      *
884      * @param dependencies the list of dependency objects
885      * @throws BuildException thrown if a CVSS score is found that is higher then the threshold set
886      */
887     private void checkForFailure(List<Dependency> dependencies) throws BuildException {
888         final StringBuilder ids = new StringBuilder();
889         for (Dependency d : dependencies) {
890             for (Vulnerability v : d.getVulnerabilities()) {
891                 if (v.getCvssScore() >= failBuildOnCVSS) {
892                     if (ids.length() == 0) {
893                         ids.append(v.getName());
894                     } else {
895                         ids.append(", ").append(v.getName());
896                     }
897                 }
898             }
899         }
900         if (ids.length() > 0) {
901             final String msg = String.format("%n%nDependency-Check Failure:%n"
902                     + "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
903                     + "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
904             throw new BuildException(msg);
905         }
906     }
907 
908     /**
909      * Generates a warning message listing a summary of dependencies and their associated CPE and CVE entries.
910      *
911      * @param dependencies a list of dependency objects
912      */
913     private void showSummary(List<Dependency> dependencies) {
914         final StringBuilder summary = new StringBuilder();
915         for (Dependency d : dependencies) {
916             boolean firstEntry = true;
917             final StringBuilder ids = new StringBuilder();
918             for (Vulnerability v : d.getVulnerabilities()) {
919                 if (firstEntry) {
920                     firstEntry = false;
921                 } else {
922                     ids.append(", ");
923                 }
924                 ids.append(v.getName());
925             }
926             if (ids.length() > 0) {
927                 summary.append(d.getFileName()).append(" (");
928                 firstEntry = true;
929                 for (Identifier id : d.getIdentifiers()) {
930                     if (firstEntry) {
931                         firstEntry = false;
932                     } else {
933                         summary.append(", ");
934                     }
935                     summary.append(id.getValue());
936                 }
937                 summary.append(") : ").append(ids).append(NEW_LINE);
938             }
939         }
940         if (summary.length() > 0) {
941             final String msg = String.format("%n%n"
942                     + "One or more dependencies were identified with known vulnerabilities:%n%n%s"
943                     + "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
944             log(msg, Project.MSG_WARN);
945         }
946     }
947 
948     /**
949      * An enumeration of supported report formats: "ALL", "HTML", "XML", "VULN", etc..
950      */
951     public static class ReportFormats extends EnumeratedAttribute {
952 
953         /**
954          * Returns the list of values for the report format.
955          *
956          * @return the list of values for the report format
957          */
958         @Override
959         public String[] getValues() {
960             int i = 0;
961             final Format[] formats = Format.values();
962             final String[] values = new String[formats.length];
963             for (Format format : formats) {
964                 values[i++] = format.name();
965             }
966             return values;
967         }
968     }
969 }