diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java index 303437b85..b3f014904 100644 --- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java +++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/AggregateMojo.java @@ -59,23 +59,15 @@ public class AggregateMojo extends BaseDependencyCheckMojo { private String name = "dependency-check:aggregate"; /** - * Executes the aggregate dependency-check goal. This runs dependency-check - * and generates the subsequent reports. + * Scans the dependencies of the projects in aggregate. * - * @throws MojoExecutionException thrown if there is ane exception running - * the Mojo - * @throws MojoFailureException thrown if dependency-check is configured to - * fail the build + * @param engine the engine used to perform the scanning + * @return a collection of exceptions + * @throws MojoExecutionException thrown if a fatal exception occurs */ @Override - public void runCheck() throws MojoExecutionException, MojoFailureException { - final Engine engine = loadEngine(); - if (engine == null) { - return; - } - + protected ExceptionCollection scanDependencies(final Engine engine) throws MojoExecutionException { ExceptionCollection exCol = scanArtifacts(getProject(), engine); - for (MavenProject childProject : getDescendants(this.getProject())) { final ExceptionCollection ex = scanArtifacts(childProject, engine); if (ex != null) { @@ -96,61 +88,7 @@ public class AggregateMojo extends BaseDependencyCheckMojo { } } } - - try { - engine.analyzeDependencies(); - } catch (ExceptionCollection ex) { - if (exCol == null) { - exCol = ex; - } else if (ex.isFatal()) { - exCol.setFatal(true); - exCol.getExceptions().addAll(ex.getExceptions()); - } - if (exCol.isFatal()) { - final String msg = String.format("Fatal exception(s) analyzing %s", getProject().getName()); - if (this.isFailOnError()) { - throw new MojoExecutionException(msg, exCol); - } - getLog().error(msg); - if (getLog().isDebugEnabled()) { - getLog().debug(exCol); - } - return; - } else { - final String msg = String.format("Exception(s) analyzing %s", getProject().getName()); - if (getLog().isDebugEnabled()) { - getLog().debug(msg, exCol); - } - } - } - File outputDir = getCorrectOutputDirectory(this.getProject()); - if (outputDir == null) { - //in some regards we shouldn't be writing this, but we are anyway. - //we shouldn't write this because nothing is configured to generate this report. - outputDir = new File(this.getProject().getBuild().getDirectory()); - } - try { - final MavenProject p = this.getProject(); - engine.writeReports(p.getName(), p.getGroupId(), p.getArtifactId(), p.getVersion(), outputDir, getFormat()); - } catch (ReportException ex) { - if (exCol == null) { - exCol = new ExceptionCollection("Error writing aggregate report", ex); - } else { - exCol.addException(ex); - } - if (this.isFailOnError()) { - throw new MojoExecutionException("One or more exceptions occurred during dependency-check analysis", exCol); - } else { - getLog().debug("One or more exceptions occurred during dependency-check analysis", exCol); - } - } - showSummary(this.getProject(), engine.getDependencies()); - checkForFailure(engine.getDependencies()); - if (exCol != null && this.isFailOnError()) { - throw new MojoExecutionException("One or more exceptions occurred during dependency-check analysis", exCol); - } - engine.close(); - getSettings().cleanup(); + return exCol; } /** @@ -242,32 +180,6 @@ public class AggregateMojo extends BaseDependencyCheckMojo { return "pom".equals(mavenProject.getPackaging()); } - /** - * Initializes the engine. - * - * @return the Engine used to execute dependency-check - * @throws MojoExecutionException thrown if there is an exception running - * the Mojo - * @throws MojoFailureException thrown if dependency-check is configured to - * fail the build if severe CVEs are identified. - */ - protected Engine loadEngine() throws MojoExecutionException, MojoFailureException { - Engine engine = null; - try { - engine = initializeEngine(); - } catch (DatabaseException ex) { - if (getLog().isDebugEnabled()) { - getLog().debug("Database connection error", ex); - } - final String msg = "An exception occurred connecting to the local database. Please see the log file for more details."; - if (this.isFailOnError()) { - throw new MojoExecutionException(msg, ex); - } - getLog().error(msg, ex); - } - return engine; - } - @Override public boolean canGenerateReport() { return true; //aggregate always returns true for now - we can look at a more complicated/accurate solution later diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java index 8b83f510c..7ee9bef3b 100644 --- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java +++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java @@ -59,6 +59,7 @@ import org.owasp.dependencycheck.dependency.Identifier; import org.owasp.dependencycheck.dependency.Vulnerability; import org.owasp.dependencycheck.exception.DependencyNotFoundException; import org.owasp.dependencycheck.exception.ExceptionCollection; +import org.owasp.dependencycheck.exception.ReportException; import org.owasp.dependencycheck.utils.Filter; import org.owasp.dependencycheck.utils.Settings; import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher; @@ -902,7 +903,102 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma * @throws MojoFailureException thrown if dependency-check is configured to * fail the build */ - public abstract void runCheck() throws MojoExecutionException, MojoFailureException; + protected void runCheck() throws MojoExecutionException, MojoFailureException { + try (Engine engine = initializeEngine()) { + ExceptionCollection exCol = scanDependencies(engine); + try { + engine.analyzeDependencies(); + } catch (ExceptionCollection ex) { + exCol = handleAnalysisExceptions(exCol, ex); + } + if (exCol == null || !exCol.isFatal()) { + + File outputDir = getCorrectOutputDirectory(this.getProject()); + if (outputDir == null) { + //in some regards we shouldn't be writing this, but we are anyway. + //we shouldn't write this because nothing is configured to generate this report. + outputDir = new File(this.getProject().getBuild().getDirectory()); + } + try { + final MavenProject p = this.getProject(); + engine.writeReports(p.getName(), p.getGroupId(), p.getArtifactId(), p.getVersion(), outputDir, getFormat()); + } catch (ReportException ex) { + if (exCol == null) { + exCol = new ExceptionCollection("Error writing aggregate report", ex); + } else { + exCol.addException(ex); + } + if (this.isFailOnError()) { + throw new MojoExecutionException("One or more exceptions occurred during dependency-check analysis", exCol); + } else { + getLog().debug("Error writting the report", ex); + } + } + showSummary(this.getProject(), engine.getDependencies()); + checkForFailure(engine.getDependencies()); + if (exCol != null && this.isFailOnError()) { + throw new MojoExecutionException("One or more exceptions occurred during dependency-check analysis", exCol); + } + } + } catch (DatabaseException ex) { + if (getLog().isDebugEnabled()) { + getLog().debug("Database connection error", ex); + } + final String msg = "An exception occurred connecting to the local database. Please see the log file for more details."; + if (this.isFailOnError()) { + throw new MojoExecutionException(msg, ex); + } + getLog().error(msg, ex); + } finally { + getSettings().cleanup(); + } + } + + /** + * Combines the two exception collections and if either are fatal, throw an + * MojoExecutionException + * + * @param currentEx the primary exception collection + * @param newEx the new exception collection to add + * @return the combined exception collection + * @throws MojoExecutionException + */ + private ExceptionCollection handleAnalysisExceptions(ExceptionCollection currentEx, ExceptionCollection newEx) throws MojoExecutionException { + ExceptionCollection returnEx = currentEx; + if (returnEx == null) { + returnEx = newEx; + } else { + returnEx.getExceptions().addAll(newEx.getExceptions()); + if (newEx.isFatal()) { + returnEx.setFatal(true); + } + } + if (returnEx.isFatal()) { + final String msg = String.format("Fatal exception(s) analyzing %s", getProject().getName()); + if (this.isFailOnError()) { + throw new MojoExecutionException(msg, returnEx); + } + getLog().error(msg); + if (getLog().isDebugEnabled()) { + getLog().debug(returnEx); + } + } else { + final String msg = String.format("Exception(s) analyzing %s", getProject().getName()); + if (getLog().isDebugEnabled()) { + getLog().debug(msg, returnEx); + } + } + return returnEx; + } + + /** + * Scans the dependencies of the projects in aggregate. + * + * @param engine the engine used to perform the scanning + * @return a collection of exceptions + * @throws MojoExecutionException thrown if a fatal exception occurs + */ + protected abstract ExceptionCollection scanDependencies(final Engine engine) throws MojoExecutionException; /** * Sets the Reporting output directory. @@ -979,7 +1075,9 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma // /** - * Initializes a new Engine that can be used for scanning. + * Initializes a new Engine that can be used for scanning. This + * method should only be called in a try-with-resources to ensure that the + * engine is properly closed. * * @return a newly instantiated Engine * @throws DatabaseException thrown if there is a database exception diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/CheckMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/CheckMojo.java index a91f9b45d..c4e9b472a 100644 --- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/CheckMojo.java +++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/CheckMojo.java @@ -72,67 +72,6 @@ public class CheckMojo extends BaseDependencyCheckMojo { return isCapable; } - /** - * Executes the dependency-check engine on the project's dependencies and - * generates the report. - * - * @throws MojoExecutionException thrown if there is an exception executing - * the goal - * @throws MojoFailureException thrown if dependency-check is configured to - * fail the build - */ - @Override - public void runCheck() throws MojoExecutionException, MojoFailureException { - Engine engine = null; - try { - engine = initializeEngine(); - } catch (DatabaseException ex) { - if (getLog().isDebugEnabled()) { - getLog().debug("Database connection error", ex); - } - final String msg = "An exception occurred connecting to the local database. Please see the log file for more details."; - if (this.isFailOnError()) { - throw new MojoExecutionException(msg, ex); - } - getLog().error(msg); - } - if (engine != null) { - ExceptionCollection exCol = scanArtifacts(getProject(), engine); - if (engine.getDependencies().length == 0) { - getLog().info("No dependencies were identified that could be analyzed by dependency-check"); - } - try { - engine.analyzeDependencies(); - } catch (ExceptionCollection ex) { - if (this.isFailOnError() && ex.isFatal()) { - throw new MojoExecutionException("One or more exceptions occurred during analysis", ex); - } - exCol = ex; - } - if (exCol == null || !exCol.isFatal()) { - try { - final MavenProject p = this.getProject(); - engine.writeReports(p.getName(), p.getGroupId(), p.getArtifactId(), p.getVersion(), getCorrectOutputDirectory(), getFormat()); - } catch (ReportException ex) { - if (this.isFailOnError()) { - if (exCol != null) { - exCol.addException(ex); - } else { - exCol = new ExceptionCollection("Unable to write the dependency-check report", ex); - } - } - } - showSummary(getProject(), engine.getDependencies()); - checkForFailure(engine.getDependencies()); - if (exCol != null && this.isFailOnError()) { - throw new MojoExecutionException("One or more exceptions occurred during dependency-check analysis", exCol); - } - } - engine.close(); - } - getSettings().cleanup(); - } - /** * Returns the report name. * @@ -156,5 +95,17 @@ public class CheckMojo extends BaseDependencyCheckMojo { return "Generates a report providing details on any published vulnerabilities within project dependencies. " + "This report is a best effort and may contain false positives and false negatives."; } + + /** + * Scans the dependencies of the project. + * + * @param engine the engine used to perform the scanning + * @return a collection of exceptions + * @throws MojoExecutionException thrown if a fatal exception occurs + */ + @Override + protected ExceptionCollection scanDependencies(final Engine engine) throws MojoExecutionException { + return scanArtifacts(getProject(), engine); + } } diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/PurgeMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/PurgeMojo.java index 8839fd33d..1361e02a1 100644 --- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/PurgeMojo.java +++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/PurgeMojo.java @@ -25,6 +25,8 @@ import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.ResolutionScope; +import org.owasp.dependencycheck.Engine; +import org.owasp.dependencycheck.exception.ExceptionCollection; import org.owasp.dependencycheck.utils.Settings; /** @@ -61,7 +63,7 @@ public class PurgeMojo extends BaseDependencyCheckMojo { * fail the build */ @Override - public void runCheck() throws MojoExecutionException, MojoFailureException { + protected void runCheck() throws MojoExecutionException, MojoFailureException { if (getConnectionString() != null && !getConnectionString().isEmpty()) { final String msg = "Unable to purge the local NVD when using a non-default connection string"; @@ -125,4 +127,15 @@ public class PurgeMojo extends BaseDependencyCheckMojo { return "Purges the local cache of the NVD dataT."; } + /** + * Throws an exception if called. The purge mojo does not scan dependencies. + * + * @param engine the engine used to scan + * @return a collection of exceptions + * @throws MojoExecutionException thrown if there is an exception + */ + @Override + protected ExceptionCollection scanDependencies(Engine engine) throws MojoExecutionException { + throw new UnsupportedOperationException("Operation not supported"); + } } diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/UpdateMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/UpdateMojo.java index 51b2ee77c..cef9226da 100644 --- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/UpdateMojo.java +++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/UpdateMojo.java @@ -26,6 +26,7 @@ import org.apache.maven.plugins.annotations.ResolutionScope; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.data.update.exception.UpdateException; +import org.owasp.dependencycheck.exception.ExceptionCollection; /** * Maven Plugin that checks the project dependencies to see if they have any @@ -63,7 +64,7 @@ public class UpdateMojo extends BaseDependencyCheckMojo { * fail the build */ @Override - public void runCheck() throws MojoExecutionException, MojoFailureException { + protected void runCheck() throws MojoExecutionException, MojoFailureException { try (Engine engine = initializeEngine()) { engine.doUpdates(); } catch (DatabaseException ex) { @@ -106,4 +107,17 @@ public class UpdateMojo extends BaseDependencyCheckMojo { public String getDescription(Locale locale) { return "Updates the local cache of the NVD data from NIST."; } + + /** + * Throws an exception if called. The update mojo does not scan + * dependencies. + * + * @param engine the engine used to scan + * @return a collection of exceptions + * @throws MojoExecutionException thrown if there is an exception + */ + @Override + protected ExceptionCollection scanDependencies(Engine engine) throws MojoExecutionException { + throw new UnsupportedOperationException("Operation not supported"); + } } diff --git a/dependency-check-maven/src/test/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojoTest.java b/dependency-check-maven/src/test/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojoTest.java index ec6831730..2277e59d1 100644 --- a/dependency-check-maven/src/test/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojoTest.java +++ b/dependency-check-maven/src/test/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojoTest.java @@ -37,6 +37,7 @@ import org.junit.Assume; import org.junit.Test; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.data.nvdcve.DatabaseException; +import org.owasp.dependencycheck.exception.ExceptionCollection; import org.owasp.dependencycheck.utils.InvalidSettingException; import org.owasp.dependencycheck.utils.Settings; @@ -113,8 +114,8 @@ public class BaseDependencyCheckMojoTest extends BaseTest { public class BaseDependencyCheckMojoImpl extends BaseDependencyCheckMojo { @Override - public void runCheck() throws MojoExecutionException, MojoFailureException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + protected void runCheck() throws MojoExecutionException, MojoFailureException { + throw new UnsupportedOperationException("Operation not supported"); } @Override @@ -129,7 +130,12 @@ public class BaseDependencyCheckMojoTest extends BaseTest { @Override public boolean canGenerateReport() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Operation not supported"); + } + + @Override + protected ExceptionCollection scanDependencies(Engine engine) throws MojoExecutionException { + throw new UnsupportedOperationException("Operation not supported"); } } }