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