Updated exception handling so that issue #215 can be resolved

This commit is contained in:
Jeremy Long
2016-07-14 06:31:54 -04:00
parent f23003ead3
commit 6d5d5ceb7b
8 changed files with 473 additions and 137 deletions

View File

@@ -30,6 +30,8 @@ import org.owasp.dependencycheck.data.update.UpdateService;
import org.owasp.dependencycheck.data.update.exception.UpdateException; import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.exception.NoDataException; import org.owasp.dependencycheck.exception.NoDataException;
import org.owasp.dependencycheck.exception.ExceptionCollection;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.InvalidSettingException; import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -47,8 +49,10 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
* Scans files, directories, etc. for Dependencies. Analyzers are loaded and used to process the files found by the scan, if a * Scans files, directories, etc. for Dependencies. Analyzers are loaded and
* file is encountered and an Analyzer is associated with the file type then the file is turned into a dependency. * used to process the files found by the scan, if a file is encountered and an
* Analyzer is associated with the file type then the file is turned into a
* dependency.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@@ -69,7 +73,8 @@ public class Engine implements FileFilter {
private final Set<FileTypeAnalyzer> fileTypeAnalyzers = new HashSet<FileTypeAnalyzer>(); private final Set<FileTypeAnalyzer> fileTypeAnalyzers = new HashSet<FileTypeAnalyzer>();
/** /**
* The ClassLoader to use when dynamically loading Analyzer and Update services. * The ClassLoader to use when dynamically loading Analyzer and Update
* services.
*/ */
private ClassLoader serviceClassLoader = Thread.currentThread().getContextClassLoader(); private ClassLoader serviceClassLoader = Thread.currentThread().getContextClassLoader();
/** /**
@@ -80,7 +85,8 @@ public class Engine implements FileFilter {
/** /**
* Creates a new Engine. * Creates a new Engine.
* *
* @throws DatabaseException thrown if there is an error connecting to the database * @throws DatabaseException thrown if there is an error connecting to the
* database
*/ */
public Engine() throws DatabaseException { public Engine() throws DatabaseException {
initializeEngine(); initializeEngine();
@@ -90,7 +96,8 @@ public class Engine implements FileFilter {
* Creates a new Engine. * Creates a new Engine.
* *
* @param serviceClassLoader a reference the class loader being used * @param serviceClassLoader a reference the class loader being used
* @throws DatabaseException thrown if there is an error connecting to the database * @throws DatabaseException thrown if there is an error connecting to the
* database
*/ */
public Engine(ClassLoader serviceClassLoader) throws DatabaseException { public Engine(ClassLoader serviceClassLoader) throws DatabaseException {
this.serviceClassLoader = serviceClassLoader; this.serviceClassLoader = serviceClassLoader;
@@ -98,9 +105,11 @@ public class Engine implements FileFilter {
} }
/** /**
* Creates a new Engine using the specified classloader to dynamically load Analyzer and Update services. * Creates a new Engine using the specified classloader to dynamically load
* Analyzer and Update services.
* *
* @throws DatabaseException thrown if there is an error connecting to the database * @throws DatabaseException thrown if there is an error connecting to the
* database
*/ */
protected final void initializeEngine() throws DatabaseException { protected final void initializeEngine() throws DatabaseException {
ConnectionFactory.initialize(); ConnectionFactory.initialize();
@@ -115,7 +124,8 @@ public class Engine implements FileFilter {
} }
/** /**
* Loads the analyzers specified in the configuration file (or system properties). * Loads the analyzers specified in the configuration file (or system
* properties).
*/ */
private void loadAnalyzers() { private void loadAnalyzers() {
if (!analyzers.isEmpty()) { if (!analyzers.isEmpty()) {
@@ -164,8 +174,9 @@ public class Engine implements FileFilter {
} }
/** /**
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any dependencies * Scans an array of files or directories. If a directory is specified, it
* identified are added to the dependency collection. * will be scanned recursively. Any dependencies identified are added to the
* dependency collection.
* *
* @param paths an array of paths to files or directories to be analyzed * @param paths an array of paths to files or directories to be analyzed
* @return the list of dependencies scanned * @return the list of dependencies scanned
@@ -183,8 +194,9 @@ public class Engine implements FileFilter {
} }
/** /**
* Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies identified * Scans a given file or directory. If a directory is specified, it will be
* are added to the dependency collection. * scanned recursively. Any dependencies identified are added to the
* dependency collection.
* *
* @param path the path to a file or directory to be analyzed * @param path the path to a file or directory to be analyzed
* @return the list of dependencies scanned * @return the list of dependencies scanned
@@ -195,8 +207,9 @@ public class Engine implements FileFilter {
} }
/** /**
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any dependencies * Scans an array of files or directories. If a directory is specified, it
* identified are added to the dependency collection. * will be scanned recursively. Any dependencies identified are added to the
* dependency collection.
* *
* @param files an array of paths to files or directories to be analyzed. * @param files an array of paths to files or directories to be analyzed.
* @return the list of dependencies * @return the list of dependencies
@@ -214,8 +227,9 @@ public class Engine implements FileFilter {
} }
/** /**
* Scans a collection of files or directories. If a directory is specified, it will be scanned recursively. Any dependencies * Scans a collection of files or directories. If a directory is specified,
* identified are added to the dependency collection. * it will be scanned recursively. Any dependencies identified are added to
* the dependency collection.
* *
* @param files a set of paths to files or directories to be analyzed * @param files a set of paths to files or directories to be analyzed
* @return the list of dependencies scanned * @return the list of dependencies scanned
@@ -233,8 +247,9 @@ public class Engine implements FileFilter {
} }
/** /**
* Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies identified * Scans a given file or directory. If a directory is specified, it will be
* are added to the dependency collection. * scanned recursively. Any dependencies identified are added to the
* dependency collection.
* *
* @param file the path to a file or directory to be analyzed * @param file the path to a file or directory to be analyzed
* @return the list of dependencies scanned * @return the list of dependencies scanned
@@ -257,7 +272,8 @@ public class Engine implements FileFilter {
} }
/** /**
* Recursively scans files and directories. Any dependencies identified are added to the dependency collection. * Recursively scans files and directories. Any dependencies identified are
* added to the dependency collection.
* *
* @param dir the directory to scan * @param dir the directory to scan
* @return the list of Dependency objects scanned * @return the list of Dependency objects scanned
@@ -282,7 +298,8 @@ public class Engine implements FileFilter {
} }
/** /**
* Scans a specified file. If a dependency is identified it is added to the dependency collection. * Scans a specified file. If a dependency is identified it is added to the
* dependency collection.
* *
* @param file The file to scan * @param file The file to scan
* @return the scanned dependency * @return the scanned dependency
@@ -301,20 +318,38 @@ public class Engine implements FileFilter {
} }
/** /**
* Runs the analyzers against all of the dependencies. Since the mutable dependencies list is exposed via * Runs the analyzers against all of the dependencies. Since the mutable
* {@link #getDependencies()}, this method iterates over a copy of the dependencies list. Thus, the potential for * dependencies list is exposed via {@link #getDependencies()}, this method
* {@link java.util.ConcurrentModificationException}s is avoided, and analyzers may safely add or remove entries from the * iterates over a copy of the dependencies list. Thus, the potential for
* dependencies list. * {@link java.util.ConcurrentModificationException}s is avoided, and
* analyzers may safely add or remove entries from the dependencies list.
*
* Every effort is made to complete analysis on the dependencies. In some
* cases an exception will occur with part of the analysis being performed
* which may not affect the entire analysis. If an exception occurs it will
* be included in the thrown exception collection.
*
* @throws ExceptionCollection a collections of any exceptions that occurred
* during analysis
*/ */
public void analyzeDependencies() { public void analyzeDependencies() throws ExceptionCollection {
List<Throwable> exceptions = new ArrayList<Throwable>();
boolean autoUpdate = true; boolean autoUpdate = true;
try { try {
autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE); autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
} catch (InvalidSettingException ex) { } catch (InvalidSettingException ex) {
LOGGER.debug("Invalid setting for auto-update; using true."); LOGGER.debug("Invalid setting for auto-update; using true.");
exceptions.add(ex);
} }
if (autoUpdate) { if (autoUpdate) {
doUpdates(); try {
doUpdates();
} catch (UpdateException ex) {
exceptions.add(ex);
LOGGER.warn("Unable to update Cached Web DataSource, using local "
+ "data instead. Results may not include recent vulnerabilities.");
LOGGER.debug("Update Error", ex);
}
} }
//need to ensure that data exists //need to ensure that data exists
@@ -323,12 +358,13 @@ public class Engine implements FileFilter {
} catch (NoDataException ex) { } catch (NoDataException ex) {
LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage()); LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
LOGGER.debug("", ex); LOGGER.debug("", ex);
return; exceptions.add(ex);
throw new ExceptionCollection(exceptions, true);
} catch (DatabaseException ex) { } catch (DatabaseException ex) {
LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage()); LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
LOGGER.debug("", ex); LOGGER.debug("", ex);
return; exceptions.add(ex);
throw new ExceptionCollection(exceptions, true);
} }
LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------"); LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------");
@@ -340,7 +376,12 @@ public class Engine implements FileFilter {
final List<Analyzer> analyzerList = analyzers.get(phase); final List<Analyzer> analyzerList = analyzers.get(phase);
for (Analyzer a : analyzerList) { for (Analyzer a : analyzerList) {
a = initializeAnalyzer(a); try {
a = initializeAnalyzer(a);
} catch (InitializationException ex) {
exceptions.add(ex);
continue;
}
/* need to create a copy of the collection because some of the /* need to create a copy of the collection because some of the
* analyzers may modify it. This prevents ConcurrentModificationExceptions. * analyzers may modify it. This prevents ConcurrentModificationExceptions.
@@ -361,10 +402,12 @@ public class Engine implements FileFilter {
} catch (AnalysisException ex) { } catch (AnalysisException ex) {
LOGGER.warn("An error occurred while analyzing '{}'.", d.getActualFilePath()); LOGGER.warn("An error occurred while analyzing '{}'.", d.getActualFilePath());
LOGGER.debug("", ex); LOGGER.debug("", ex);
exceptions.add(ex);
} catch (Throwable ex) { } catch (Throwable ex) {
//final AnalysisException ax = new AnalysisException(axMsg, ex); //final AnalysisException ax = new AnalysisException(axMsg, ex);
LOGGER.warn("An unexpected error occurred during analysis of '{}'", d.getActualFilePath()); LOGGER.warn("An unexpected error occurred during analysis of '{}'", d.getActualFilePath());
LOGGER.debug("", ex); LOGGER.debug("", ex);
exceptions.add(ex);
} }
} }
} }
@@ -380,6 +423,9 @@ public class Engine implements FileFilter {
LOGGER.debug("\n----------------------------------------------------\nEND ANALYSIS\n----------------------------------------------------"); LOGGER.debug("\n----------------------------------------------------\nEND ANALYSIS\n----------------------------------------------------");
LOGGER.info("Analysis Complete ({} ms)", System.currentTimeMillis() - analysisStart); LOGGER.info("Analysis Complete ({} ms)", System.currentTimeMillis() - analysisStart);
if (exceptions.size() > 0) {
throw new ExceptionCollection(exceptions);
}
} }
/** /**
@@ -387,12 +433,14 @@ public class Engine implements FileFilter {
* *
* @param analyzer the analyzer to initialize * @param analyzer the analyzer to initialize
* @return the initialized analyzer * @return the initialized analyzer
* @throws InitializationException thrown when there is a problem
* initializing the analyzer
*/ */
protected Analyzer initializeAnalyzer(Analyzer analyzer) { protected Analyzer initializeAnalyzer(Analyzer analyzer) throws InitializationException {
try { try {
LOGGER.debug("Initializing {}", analyzer.getName()); LOGGER.debug("Initializing {}", analyzer.getName());
analyzer.initialize(); analyzer.initialize();
} catch (Throwable ex) { } catch (InitializationException ex) {
LOGGER.error("Exception occurred initializing {}.", analyzer.getName()); LOGGER.error("Exception occurred initializing {}.", analyzer.getName());
LOGGER.debug("", ex); LOGGER.debug("", ex);
try { try {
@@ -400,6 +448,16 @@ public class Engine implements FileFilter {
} catch (Throwable ex1) { } catch (Throwable ex1) {
LOGGER.trace("", ex1); LOGGER.trace("", ex1);
} }
throw ex;
} catch (Throwable ex) {
LOGGER.error("Unexpected exception occurred initializing {}.", analyzer.getName());
LOGGER.debug("", ex);
try {
analyzer.close();
} catch (Throwable ex1) {
LOGGER.trace("", ex1);
}
throw new InitializationException("Unexpected Exception", ex);
} }
return analyzer; return analyzer;
} }
@@ -419,28 +477,26 @@ public class Engine implements FileFilter {
} }
/** /**
* Cycles through the cached web data sources and calls update on all of them. * Cycles through the cached web data sources and calls update on all of
* them.
*
* @throws UpdateException
*/ */
public void doUpdates() { public void doUpdates() throws UpdateException {
LOGGER.info("Checking for updates"); LOGGER.info("Checking for updates");
final long updateStart = System.currentTimeMillis(); final long updateStart = System.currentTimeMillis();
final UpdateService service = new UpdateService(serviceClassLoader); final UpdateService service = new UpdateService(serviceClassLoader);
final Iterator<CachedWebDataSource> iterator = service.getDataSources(); final Iterator<CachedWebDataSource> iterator = service.getDataSources();
while (iterator.hasNext()) { while (iterator.hasNext()) {
final CachedWebDataSource source = iterator.next(); final CachedWebDataSource source = iterator.next();
try { source.update();
source.update();
} catch (UpdateException ex) {
LOGGER.warn(
"Unable to update Cached Web DataSource, using local data instead. Results may not include recent vulnerabilities.");
LOGGER.debug("Unable to update details for {}", source.getClass().getName(), ex);
}
} }
LOGGER.info("Check for updates complete ({} ms)", System.currentTimeMillis() - updateStart); LOGGER.info("Check for updates complete ({} ms)", System.currentTimeMillis() - updateStart);
} }
/** /**
* Returns a full list of all of the analyzers. This is useful for reporting which analyzers where used. * Returns a full list of all of the analyzers. This is useful for reporting
* which analyzers where used.
* *
* @return a list of Analyzers * @return a list of Analyzers
*/ */
@@ -457,7 +513,8 @@ public class Engine implements FileFilter {
* Checks all analyzers to see if an extension is supported. * Checks all analyzers to see if an extension is supported.
* *
* @param file a file extension * @param file a file extension
* @return true or false depending on whether or not the file extension is supported * @return true or false depending on whether or not the file extension is
* supported
*/ */
@Override @Override
public boolean accept(File file) { public boolean accept(File file) {
@@ -483,10 +540,12 @@ public class Engine implements FileFilter {
} }
/** /**
* Checks the CPE Index to ensure documents exists. If none exist a NoDataException is thrown. * Checks the CPE Index to ensure documents exists. If none exist a
* NoDataException is thrown.
* *
* @throws NoDataException thrown if no data exists in the CPE Index * @throws NoDataException thrown if no data exists in the CPE Index
* @throws DatabaseException thrown if there is an exception opening the database * @throws DatabaseException thrown if there is an exception opening the
* database
*/ */
private void ensureDataExists() throws NoDataException, DatabaseException { private void ensureDataExists() throws NoDataException, DatabaseException {
final CveDB cve = new CveDB(); final CveDB cve = new CveDB();

View File

@@ -27,6 +27,7 @@ import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier; import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability; import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.exception.ExceptionCollection;
import org.owasp.dependencycheck.exception.ScanAgentException; import org.owasp.dependencycheck.exception.ScanAgentException;
import org.owasp.dependencycheck.reporting.ReportGenerator; import org.owasp.dependencycheck.reporting.ReportGenerator;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
@@ -34,10 +35,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* This class provides a way to easily conduct a scan solely based on existing evidence metadata rather than collecting evidence * This class provides a way to easily conduct a scan solely based on existing
* from the files themselves. This class is based on the Ant task and Maven plugin with the exception that it takes a list of * evidence metadata rather than collecting evidence from the files themselves.
* dependencies that can be programmatically added from data in a spreadsheet, database or some other datasource and conduct a * This class is based on the Ant task and Maven plugin with the exception that
* scan based on this pre-defined evidence. * it takes a list of dependencies that can be programmatically added from data
* in a spreadsheet, database or some other datasource and conduct a scan based
* on this pre-defined evidence.
* *
* <h2>Example:</h2> * <h2>Example:</h2>
* <pre> * <pre>
@@ -138,7 +141,8 @@ public class DependencyCheckScanAgent {
} }
/** /**
* Specifies the destination directory for the generated Dependency-Check report. * Specifies the destination directory for the generated Dependency-Check
* report.
*/ */
private String reportOutputDirectory; private String reportOutputDirectory;
@@ -161,9 +165,11 @@ public class DependencyCheckScanAgent {
} }
/** /**
* Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which * Specifies if the build should be failed if a CVSS score above a specified
* 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 * level is identified. The default is 11 which means since the CVSS scores
* for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail. * are 0-10, by default the build will never fail and the CVSS score is set
* to 11. The valid range for the fail build on CVSS is 0 to 11, where
* anything above 10 will not cause the build to fail.
*/ */
private float failBuildOnCVSS = 11; private float failBuildOnCVSS = 11;
@@ -186,8 +192,8 @@ public class DependencyCheckScanAgent {
} }
/** /**
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. Default * Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not
* is true. * recommended that this be turned to false. Default is true.
*/ */
private boolean autoUpdate = true; private boolean autoUpdate = true;
@@ -233,8 +239,9 @@ public class DependencyCheckScanAgent {
} }
/** /**
* The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the * The report format to be generated (HTML, XML, VULN, ALL). This
* Site plugin unless the externalReport is set to true. Default is HTML. * configuration option has no affect if using this within the Site plugin
* unless the externalReport is set to true. Default is HTML.
*/ */
private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML; private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML;
@@ -283,7 +290,9 @@ public class DependencyCheckScanAgent {
* Get the value of proxyServer. * Get the value of proxyServer.
* *
* @return the value of proxyServer * @return the value of proxyServer
* @deprecated use {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#getProxyServer()} instead * @deprecated use
* {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#getProxyServer()}
* instead
*/ */
@Deprecated @Deprecated
public String getProxyUrl() { public String getProxyUrl() {
@@ -694,8 +703,8 @@ public class DependencyCheckScanAgent {
} }
/** /**
* Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat like ZIP * Additional ZIP File extensions to add analyze. This should be a
* files. * comma-separated list of file extensions to treat like ZIP files.
*/ */
private String zipExtensions; private String zipExtensions;
@@ -836,11 +845,17 @@ public class DependencyCheckScanAgent {
* Executes the Dependency-Check on the dependent libraries. * Executes the Dependency-Check on the dependent libraries.
* *
* @return the Engine used to scan the dependencies. * @return the Engine used to scan the dependencies.
* @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException thrown if there is an exception connecting to the database * @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException thrown if
* there is an exception connecting to the database
*/ */
private Engine executeDependencyCheck() throws DatabaseException { private Engine executeDependencyCheck() throws ExceptionCollection {
populateSettings(); populateSettings();
final Engine engine = new Engine(); final Engine engine;
try {
engine = new Engine();
} catch (DatabaseException ex) {
throw new ExceptionCollection(ex, true);
}
engine.setDependencies(this.dependencies); engine.setDependencies(this.dependencies);
engine.analyzeDependencies(); engine.analyzeDependencies();
return engine; return engine;
@@ -881,8 +896,9 @@ public class DependencyCheckScanAgent {
} }
/** /**
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties * Takes the properties supplied and updates the dependency-check settings.
* required to change the proxy server, port, and connection timeout. * Additionally, this sets the system properties required to change the
* proxy server, port, and connection timeout.
*/ */
private void populateSettings() { private void populateSettings() {
Settings.initialize(); Settings.initialize();
@@ -925,7 +941,8 @@ public class DependencyCheckScanAgent {
* Executes the dependency-check and generates the report. * Executes the dependency-check and generates the report.
* *
* @return a reference to the engine used to perform the scan. * @return a reference to the engine used to perform the scan.
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the scan. * @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if
* there is an exception executing the scan.
*/ */
public Engine execute() throws ScanAgentException { public Engine execute() throws ScanAgentException {
Engine engine = null; Engine engine = null;
@@ -940,10 +957,12 @@ public class DependencyCheckScanAgent {
if (this.failBuildOnCVSS <= 10) { if (this.failBuildOnCVSS <= 10) {
checkForFailure(engine.getDependencies()); checkForFailure(engine.getDependencies());
} }
} catch (DatabaseException ex) { } catch (ExceptionCollection ex) {
LOGGER.error( if (ex.isFatal()) {
"Unable to connect to the dependency-check database; analysis has stopped"); LOGGER.error("A fatal exception occurred during analysis; analysis has stopped. Please see the debug log for more details.");
LOGGER.debug("", ex); LOGGER.debug("", ex);
}
throw new ScanAgentException("One or more exceptions occurred during analysis; please see the debug log for more details.", ex);
} finally { } finally {
Settings.cleanup(true); Settings.cleanup(true);
if (engine != null) { if (engine != null) {
@@ -954,11 +973,12 @@ public class DependencyCheckScanAgent {
} }
/** /**
* Checks to see if a vulnerability has been identified with a CVSS score that is above the threshold set in the * Checks to see if a vulnerability has been identified with a CVSS score
* configuration. * that is above the threshold set in the configuration.
* *
* @param dependencies the list of dependency objects * @param dependencies the list of dependency objects
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the scan. * @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if
* there is an exception executing the scan.
*/ */
private void checkForFailure(List<Dependency> dependencies) throws ScanAgentException { private void checkForFailure(List<Dependency> dependencies) throws ScanAgentException {
final StringBuilder ids = new StringBuilder(); final StringBuilder ids = new StringBuilder();
@@ -986,7 +1006,8 @@ public class DependencyCheckScanAgent {
} }
/** /**
* Generates a warning message listing a summary of dependencies and their associated CPE and CVE entries. * Generates a warning message listing a summary of dependencies and their
* associated CPE and CVE entries.
* *
* @param dependencies a list of dependency objects * @param dependencies a list of dependency objects
*/ */

View File

@@ -0,0 +1,131 @@
/*
* This file is part of dependency-check-core.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2016 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.exception;
import java.util.ArrayList;
import java.util.List;
/**
* A collection of several exceptions.
*
* @author Jeremy Lomg
*/
public class ExceptionCollection extends Exception {
/**
* Instantiates a new exception collection.
*
* @param exceptions a list of exceptions
*/
public ExceptionCollection(List<Throwable> exceptions) {
super();
this.exceptions = exceptions;
}
/**
* Instantiates a new exception collection.
*
* @param exceptions a list of exceptions
* @param fatal indicates if the exception that occurred is fatal - meaning
* that no analysis was performed.
*/
public ExceptionCollection(List<Throwable> exceptions, boolean fatal) {
super();
this.exceptions = exceptions;
this.fatal = fatal;
}
/**
* Instantiates a new exception collection.
*
* @param exceptions a list of exceptions
* @param fatal indicates if the exception that occurred is fatal - meaning
* that no analysis was performed.
*/
public ExceptionCollection(Throwable exceptions, boolean fatal) {
super();
this.exceptions.add(exceptions);
this.fatal = fatal;
}
/**
* Instantiates a new exception collection.
*/
public ExceptionCollection() {
super();
this.exceptions = new ArrayList<Throwable>();
}
/**
* The serial version uid.
*/
private static final long serialVersionUID = 1L;
/**
* A collection of exceptions.
*/
private List<Throwable> exceptions;
/**
* Get the value of exceptions.
*
* @return the value of exceptions
*/
public List<Throwable> getExceptions() {
return exceptions;
}
/**
* Adds an exception to the collection.
*
* @param ex the exception to add
*/
public void addException(Throwable ex) {
this.exceptions.add(ex);
}
/**
* Adds an exception to the collection.
*
* @param ex the exception to add
*/
public void addException(Throwable ex, boolean fatal) {
addException(ex);
this.fatal = fatal;
}
/**
* Flag indicating if a fatal exception occurred that would prevent the attempt
* at completing the analysis even if exceptions occurred.
*/
private boolean fatal = false;
/**
* Get the value of fatal
*
* @return the value of fatal
*/
public boolean isFatal() {
return fatal;
}
/**
* Set the value of fatal
*
* @param fatal new value of fatal
*/
public void setFatal(boolean fatal) {
this.fatal = fatal;
}
}

View File

@@ -0,0 +1,66 @@
/*
* This file is part of dependency-check-core.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2016 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.exception;
/**
* An exception used when generating reports.
*
* @author Jeremy Long
*/
public class ReportException extends Exception {
/**
* The serial version uid.
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new ReportException.
*/
public ReportException() {
super();
}
/**
* Creates a new ReportException.
*
* @param msg a message for the exception.
*/
public ReportException(String msg) {
super(msg);
}
/**
* Creates a new ReportException.
*
* @param ex the cause of the exception.
*/
public ReportException(Throwable ex) {
super(ex);
}
/**
* Creates a new ReportException.
*
* @param msg a message for the exception.
* @param ex the cause of the exception.
*/
public ReportException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -26,6 +26,7 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
@@ -37,13 +38,16 @@ import org.apache.velocity.runtime.RuntimeConstants;
import org.owasp.dependencycheck.analyzer.Analyzer; import org.owasp.dependencycheck.analyzer.Analyzer;
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* The ReportGenerator is used to, as the name implies, generate reports. Internally the generator uses the Velocity * The ReportGenerator is used to, as the name implies, generate reports.
* Templating Engine. The ReportGenerator exposes a list of Dependencies to the template when generating the report. * Internally the generator uses the Velocity Templating Engine. The
* ReportGenerator exposes a list of Dependencies to the template when
* generating the report.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@@ -79,7 +83,7 @@ public class ReportGenerator {
/** /**
* The Velocity Engine. * The Velocity Engine.
*/ */
private final VelocityEngine engine; private final VelocityEngine velocityEngine;
/** /**
* The Velocity Engine Context. * The Velocity Engine Context.
*/ */
@@ -91,13 +95,14 @@ public class ReportGenerator {
* @param applicationName the application name being analyzed * @param applicationName the application name being analyzed
* @param dependencies the list of dependencies * @param dependencies the list of dependencies
* @param analyzers the list of analyzers used * @param analyzers the list of analyzers used
* @param properties the database properties (containing timestamps of the NVD CVE data) * @param properties the database properties (containing timestamps of the
* NVD CVE data)
*/ */
public ReportGenerator(String applicationName, List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) { public ReportGenerator(String applicationName, List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
engine = createVelocityEngine(); velocityEngine = createVelocityEngine();
context = createContext(); context = createContext();
engine.init(); velocityEngine.init();
final DateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy 'at' HH:mm:ss z"); final DateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy 'at' HH:mm:ss z");
final DateFormat dateFormatXML = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); final DateFormat dateFormatXML = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
@@ -119,19 +124,19 @@ public class ReportGenerator {
/** /**
* Creates a new Velocity Engine. * Creates a new Velocity Engine.
* *
* @return a velocity engine. * @return a velocity engine
*/ */
private VelocityEngine createVelocityEngine() { private VelocityEngine createVelocityEngine() {
final VelocityEngine engine = new VelocityEngine(); final VelocityEngine velocity = new VelocityEngine();
// Logging redirection for Velocity - Required by Jenkins and other server applications // Logging redirection for Velocity - Required by Jenkins and other server applications
engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, VelocityLoggerRedirect.class.getName()); velocity.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, VelocityLoggerRedirect.class.getName());
return engine; return velocity;
} }
/** /**
* Creates a new Velocity Context. * Creates a new Velocity Context.
* *
* @return a Velocity Context. * @return a Velocity Context
*/ */
private Context createContext() { private Context createContext() {
return new VelocityContext(); return new VelocityContext();
@@ -143,7 +148,7 @@ public class ReportGenerator {
* @param outputStream the OutputStream to send the generated report to * @param outputStream the OutputStream to send the generated report to
* @param format the format the report should be written in * @param format the format the report should be written in
* @throws IOException is thrown when the template file does not exist * @throws IOException is thrown when the template file does not exist
* @throws Exception is thrown if there is an error writing out the reports. * @throws Exception is thrown if there is an error writing out the reports
*/ */
public void generateReports(OutputStream outputStream, Format format) throws IOException, Exception { public void generateReports(OutputStream outputStream, Format format) throws IOException, Exception {
if (format == Format.XML || format == Format.ALL) { if (format == Format.XML || format == Format.ALL) {
@@ -162,10 +167,9 @@ public class ReportGenerator {
* *
* @param outputDir the path where the reports should be written * @param outputDir the path where the reports should be written
* @param format the format the report should be written in * @param format the format the report should be written in
* @throws IOException is thrown when the template file does not exist * @throws ReportException is thrown if there is an error writing out the reports
* @throws Exception is thrown if there is an error writing out the reports.
*/ */
public void generateReports(String outputDir, Format format) throws IOException, Exception { public void generateReports(String outputDir, Format format) throws ReportException {
if (format == Format.XML || format == Format.ALL) { if (format == Format.XML || format == Format.ALL) {
generateReport("XmlReport", outputDir + File.separator + "dependency-check-report.xml"); generateReport("XmlReport", outputDir + File.separator + "dependency-check-report.xml");
} }
@@ -181,11 +185,12 @@ public class ReportGenerator {
* Generates the Dependency Reports for the identified dependencies. * Generates the Dependency Reports for the identified dependencies.
* *
* @param outputDir the path where the reports should be written * @param outputDir the path where the reports should be written
* @param outputFormat the format the report should be written in (XML, HTML, ALL) * @param outputFormat the format the report should be written in (XML,
* @throws IOException is thrown when the template file does not exist * HTML, ALL)
* @throws Exception is thrown if there is an error writing out the reports. * @throws ReportException is thrown if there is an error creating out the
* reports
*/ */
public void generateReports(String outputDir, String outputFormat) throws IOException, Exception { public void generateReports(String outputDir, String outputFormat) throws ReportException {
final String format = outputFormat.toUpperCase(); final String format = outputFormat.toUpperCase();
final String pathToCheck = outputDir.toLowerCase(); final String pathToCheck = outputDir.toLowerCase();
if (format.matches("^(XML|HTML|VULN|ALL)$")) { if (format.matches("^(XML|HTML|VULN|ALL)$")) {
@@ -217,16 +222,16 @@ public class ReportGenerator {
} }
/** /**
* Generates a report from a given Velocity Template. The template name provided can be the name of a template * Generates a report from a given Velocity Template. The template name
* contained in the jar file, such as 'XmlReport' or 'HtmlReport', or the template name can be the path to a * provided can be the name of a template contained in the jar file, such as
* 'XmlReport' or 'HtmlReport', or the template name can be the path to a
* template file. * template file.
* *
* @param templateName the name of the template to load. * @param templateName the name of the template to load
* @param outputStream the OutputStream to write the report to. * @param outputStream the OutputStream to write the report to
* @throws IOException is thrown when the template file does not exist. * @throws ReportException is thrown when an exception occurs
* @throws Exception is thrown when an exception occurs.
*/ */
protected void generateReport(String templateName, OutputStream outputStream) throws IOException, Exception { protected void generateReport(String templateName, OutputStream outputStream) throws ReportException {
InputStream input = null; InputStream input = null;
String templatePath = null; String templatePath = null;
final File f = new File(templateName); final File f = new File(templateName);
@@ -235,27 +240,30 @@ public class ReportGenerator {
templatePath = templateName; templatePath = templateName;
input = new FileInputStream(f); input = new FileInputStream(f);
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
LOGGER.error("Unable to generate the report, the report template file could not be found."); throw new ReportException("Unable to locate template file: " + templateName, ex);
LOGGER.debug("", ex);
} }
} else { } else {
templatePath = "templates/" + templateName + ".vsl"; templatePath = "templates/" + templateName + ".vsl";
input = this.getClass().getClassLoader().getResourceAsStream(templatePath); input = this.getClass().getClassLoader().getResourceAsStream(templatePath);
} }
if (input == null) { if (input == null) {
throw new IOException("Template file doesn't exist"); throw new ReportException("Template file doesn't exist: " + templatePath);
} }
final InputStreamReader reader = new InputStreamReader(input, "UTF-8"); InputStreamReader reader = null;
OutputStreamWriter writer = null; OutputStreamWriter writer = null;
try { try {
reader = new InputStreamReader(input, "UTF-8");
writer = new OutputStreamWriter(outputStream, "UTF-8"); writer = new OutputStreamWriter(outputStream, "UTF-8");
if (!velocityEngine.evaluate(context, writer, templatePath, reader)) {
if (!engine.evaluate(context, writer, templatePath, reader)) { throw new ReportException("Failed to convert the template into html.");
throw new Exception("Failed to convert the template into html.");
} }
writer.flush(); writer.flush();
} catch (UnsupportedEncodingException ex) {
throw new ReportException("Unable to generate the report using UTF-8", ex);
} catch (IOException ex) {
throw new ReportException("Unable to write the report", ex);
} finally { } finally {
if (writer != null) { if (writer != null) {
try { try {
@@ -271,25 +279,27 @@ public class ReportGenerator {
LOGGER.trace("", ex); LOGGER.trace("", ex);
} }
} }
try { if (reader != null) {
reader.close(); try {
} catch (IOException ex) { reader.close();
LOGGER.trace("", ex); } catch (IOException ex) {
LOGGER.trace("", ex);
}
} }
} }
} }
/** /**
* Generates a report from a given Velocity Template. The template name provided can be the name of a template * Generates a report from a given Velocity Template. The template name
* contained in the jar file, such as 'XmlReport' or 'HtmlReport', or the template name can be the path to a * provided can be the name of a template contained in the jar file, such as
* 'XmlReport' or 'HtmlReport', or the template name can be the path to a
* template file. * template file.
* *
* @param templateName the name of the template to load. * @param templateName the name of the template to load
* @param outFileName the filename and path to write the report to. * @param outFileName the filename and path to write the report to
* @throws IOException is thrown when the template file does not exist. * @throws ReportException is thrown when the report cannot be generated
* @throws Exception is thrown when an exception occurs.
*/ */
protected void generateReport(String templateName, String outFileName) throws Exception { protected void generateReport(String templateName, String outFileName) throws ReportException {
File outFile = new File(outFileName); File outFile = new File(outFileName);
if (outFile.getParentFile() == null) { if (outFile.getParentFile() == null) {
outFile = new File(".", outFileName); outFile = new File(".", outFileName);
@@ -297,7 +307,7 @@ public class ReportGenerator {
if (!outFile.getParentFile().exists()) { if (!outFile.getParentFile().exists()) {
final boolean created = outFile.getParentFile().mkdirs(); final boolean created = outFile.getParentFile().mkdirs();
if (!created) { if (!created) {
throw new Exception("Unable to create directory '" + outFile.getParentFile().getAbsolutePath() + "'."); throw new ReportException("Unable to create directory '" + outFile.getParentFile().getAbsolutePath() + "'.");
} }
} }
@@ -305,6 +315,8 @@ public class ReportGenerator {
try { try {
outputSteam = new FileOutputStream(outFile); outputSteam = new FileOutputStream(outFile);
generateReport(templateName, outputSteam); generateReport(templateName, outputSteam);
} catch (FileNotFoundException ex) {
throw new ReportException("Unable to write to file: " + outFile, ex);
} finally { } finally {
if (outputSteam != null) { if (outputSteam != null) {
try { try {

View File

@@ -17,12 +17,19 @@
*/ */
package org.owasp.dependencycheck; package org.owasp.dependencycheck;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import org.junit.Test; import org.junit.Test;
import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
import org.owasp.dependencycheck.exception.ExceptionCollection;
import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.reporting.ReportGenerator; import org.owasp.dependencycheck.reporting.ReportGenerator;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
/** /**
@@ -34,10 +41,14 @@ public class EngineIntegrationTest extends BaseDBTestCase {
/** /**
* Test running the entire engine. * Test running the entire engine.
* *
* @throws Exception is thrown when an exception occurs. * @throws java.io.IOException
* @throws org.owasp.dependencycheck.utils.InvalidSettingException
* @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException
* @throws org.owasp.dependencycheck.exception.ReportException
* @throws org.owasp.dependencycheck.exception.ExceptionCollection
*/ */
@Test @Test
public void testEngine() throws Exception { public void testEngine() throws IOException, InvalidSettingException, DatabaseException, ReportException, ExceptionCollection {
String testClasses = "target/test-classes"; String testClasses = "target/test-classes";
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE); boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false); Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
@@ -45,7 +56,23 @@ public class EngineIntegrationTest extends BaseDBTestCase {
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate); Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
instance.scan(testClasses); instance.scan(testClasses);
assertTrue(instance.getDependencies().size() > 0); assertTrue(instance.getDependencies().size() > 0);
instance.analyzeDependencies(); try {
instance.analyzeDependencies();
} catch (ExceptionCollection ex) {
if (ex.getExceptions().size()==1 &&
(ex.getExceptions().get(0).getMessage().contains("bundle-audit") ||
ex.getExceptions().get(0).getMessage().contains("AssemblyAnalyzer"))) {
//this is fine to ignore
} else if (ex.getExceptions().size()==2 &&
((ex.getExceptions().get(0).getMessage().contains("bundle-audit") &&
ex.getExceptions().get(1).getMessage().contains("AssemblyAnalyzer")) ||
(ex.getExceptions().get(1).getMessage().contains("bundle-audit") &&
ex.getExceptions().get(0).getMessage().contains("AssemblyAnalyzer")))) {
//this is fine to ignore
} else {
throw ex;
}
}
CveDB cveDB = new CveDB(); CveDB cveDB = new CveDB();
cveDB.open(); cveDB.open();
DatabaseProperties dbProp = cveDB.getDatabaseProperties(); DatabaseProperties dbProp = cveDB.getDatabaseProperties();

View File

@@ -26,6 +26,7 @@ import java.io.File;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.logging.Level;
import org.junit.After; import org.junit.After;
import org.junit.Assume; import org.junit.Assume;
@@ -40,6 +41,7 @@ import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence; import org.owasp.dependencycheck.dependency.Evidence;
import org.owasp.dependencycheck.dependency.Identifier; import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability; import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.exception.ExceptionCollection;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -176,6 +178,7 @@ public class RubyBundleAuditAnalyzerTest extends BaseDBTestCase {
* Test Ruby dependencies and their paths. * Test Ruby dependencies and their paths.
* *
* @throws AnalysisException is thrown when an exception occurs. * @throws AnalysisException is thrown when an exception occurs.
* @throws DatabaseException thrown when an exception occurs
*/ */
@Test @Test
public void testDependenciesPath() throws AnalysisException, DatabaseException { public void testDependenciesPath() throws AnalysisException, DatabaseException {
@@ -187,6 +190,8 @@ public class RubyBundleAuditAnalyzerTest extends BaseDBTestCase {
} catch (NullPointerException ex) { } catch (NullPointerException ex) {
LOGGER.error("NPE", ex); LOGGER.error("NPE", ex);
throw ex; throw ex;
} catch (ExceptionCollection ex) {
Assume.assumeNoException("Exception setting up RubyBundleAuditAnalyzer; bundle audit may not be installed, or property \"analyzer.bundle.audit.path\" may not be set.", ex);
} }
List<Dependency> dependencies = engine.getDependencies(); List<Dependency> dependencies = engine.getDependencies();
LOGGER.info(dependencies.size() + " dependencies found."); LOGGER.info(dependencies.size() + " dependencies found.");

View File

@@ -23,13 +23,16 @@ import org.owasp.dependencycheck.analyzer.Analyzer;
import org.owasp.dependencycheck.analyzer.CPEAnalyzer; import org.owasp.dependencycheck.analyzer.CPEAnalyzer;
import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer; import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.exception.ExceptionCollection;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* A modified version of the core engine specifically designed to persist some data between multiple executions of a multi-module * A modified version of the core engine specifically designed to persist some
* Maven project. * data between multiple executions of a multi-module Maven project.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@@ -52,16 +55,19 @@ public class Engine extends org.owasp.dependencycheck.Engine {
*/ */
private List<MavenProject> reactorProjects; private List<MavenProject> reactorProjects;
/** /**
* Key used in the MavenProject context values to note whether or not an update has been executed. * Key used in the MavenProject context values to note whether or not an
* update has been executed.
*/ */
public static final String UPDATE_EXECUTED_FLAG = "dependency-check-update-executed"; public static final String UPDATE_EXECUTED_FLAG = "dependency-check-update-executed";
/** /**
* Creates a new Engine to perform anyalsis on dependencies. * Creates a new Engine to perform analysis on dependencies.
* *
* @param project the current Maven project * @param project the current Maven project
* @param reactorProjects the reactor projects for the current Maven execution * @param reactorProjects the reactor projects for the current Maven
* @throws DatabaseException thrown if there is an issue connecting to the database * execution
* @throws DatabaseException thrown if there is an issue connecting to the
* database
*/ */
public Engine(MavenProject project, List<MavenProject> reactorProjects) throws DatabaseException { public Engine(MavenProject project, List<MavenProject> reactorProjects) throws DatabaseException {
this.currentProject = project; this.currentProject = project;
@@ -71,9 +77,12 @@ public class Engine extends org.owasp.dependencycheck.Engine {
/** /**
* Runs the analyzers against all of the dependencies. * Runs the analyzers against all of the dependencies.
*
* @throws ExceptionCollection thrown if an exception occurred; contains a
* collection of exceptions that occurred during analysis.
*/ */
@Override @Override
public void analyzeDependencies() { public void analyzeDependencies() throws ExceptionCollection {
final MavenProject root = getExecutionRoot(); final MavenProject root = getExecutionRoot();
if (root != null) { if (root != null) {
LOGGER.debug("Checking root project, {}, if updates have already been completed", root.getArtifactId()); LOGGER.debug("Checking root project, {}, if updates have already been completed", root.getArtifactId());
@@ -91,8 +100,10 @@ public class Engine extends org.owasp.dependencycheck.Engine {
/** /**
* Runs the update steps of dependency-check. * Runs the update steps of dependency-check.
*
* @throws UpdateException thrown if there is an exception
*/ */
public void update() { public void update() throws UpdateException {
final MavenProject root = getExecutionRoot(); final MavenProject root = getExecutionRoot();
if (root != null && root.getContextValue(UPDATE_EXECUTED_FLAG) != null) { if (root != null && root.getContextValue(UPDATE_EXECUTED_FLAG) != null) {
System.setProperty(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE.toString()); System.setProperty(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE.toString());
@@ -103,20 +114,21 @@ public class Engine extends org.owasp.dependencycheck.Engine {
/** /**
* This constructor should not be called. Use Engine(MavenProject) instead. * This constructor should not be called. Use Engine(MavenProject) instead.
* *
* @throws DatabaseException thrown if there is an issue connecting to the database * @throws DatabaseException thrown if there is an issue connecting to the
* database
*/ */
private Engine() throws DatabaseException { private Engine() throws DatabaseException {
} }
/** /**
* Initializes the given analyzer. This skips the initialization of the CPEAnalyzer if it has been initialized by a previous * Initializes the given analyzer. This skips the initialization of the
* execution. * CPEAnalyzer if it has been initialized by a previous execution.
* *
* @param analyzer the analyzer to initialize * @param analyzer the analyzer to initialize
* @return the initialized analyzer * @return the initialized analyzer
*/ */
@Override @Override
protected Analyzer initializeAnalyzer(Analyzer analyzer) { protected Analyzer initializeAnalyzer(Analyzer analyzer) throws InitializationException {
if (analyzer instanceof CPEAnalyzer) { if (analyzer instanceof CPEAnalyzer) {
CPEAnalyzer cpe = getPreviouslyLoadedCPEAnalyzer(); CPEAnalyzer cpe = getPreviouslyLoadedCPEAnalyzer();
if (cpe != null && cpe.isOpen()) { if (cpe != null && cpe.isOpen()) {
@@ -129,7 +141,8 @@ public class Engine extends org.owasp.dependencycheck.Engine {
} }
/** /**
* Releases resources used by the analyzers by calling close() on each analyzer. * Releases resources used by the analyzers by calling close() on each
* analyzer.
*/ */
@Override @Override
public void cleanup() { public void cleanup() {
@@ -216,8 +229,10 @@ public class Engine extends org.owasp.dependencycheck.Engine {
} }
/** /**
* Resets the file type analyzers so that they can be re-used to scan additional directories. Without the reset the analyzer * Resets the file type analyzers so that they can be re-used to scan
* might be disabled because the first scan/analyze did not identify any files that could be processed by the analyzer. * additional directories. Without the reset the analyzer might be disabled
* because the first scan/analyze did not identify any files that could be
* processed by the analyzer.
*/ */
public void resetFileTypeAnalyzers() { public void resetFileTypeAnalyzers() {
for (FileTypeAnalyzer a : getFileTypeAnalyzers()) { for (FileTypeAnalyzer a : getFileTypeAnalyzers()) {