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