From d5753b95894e154c7d50d1264106194076d7f88e Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sat, 7 Feb 2015 18:16:07 -0500 Subject: [PATCH] updated to address issue #193 Former-commit-id: 8361c2fdbec4191e52db16b870406e3e45d97d0d --- .../dependencycheck/maven/AggregateMojo.java | 42 +++++---- .../maven/BaseDependencyCheckMojo.java | 88 +++++++++++-------- .../dependencycheck/maven/CheckMojo.java | 4 +- 3 files changed, 74 insertions(+), 60 deletions(-) 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 cff72167b..beb508a2e 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 @@ -41,8 +41,8 @@ import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.utils.Settings; /** - * Maven Plugin that checks project dependencies and the dependencies of all child modules to see if they have any known - * published vulnerabilities. + * Maven Plugin that checks project dependencies and the dependencies of all child modules to see if they have any known published + * vulnerabilities. * * @author Jeremy Long */ @@ -73,21 +73,27 @@ public class AggregateMojo extends BaseDependencyCheckMojo { if (getProject() == getReactorProjects().get(getReactorProjects().size() - 1)) { final Map> children = buildAggregateInfo(); - boolean hasOrchestration = false; + for (MavenProject current : getReactorProjects()) { - final List dependencies = readDataFile(current); - final List childProjects = getAllChildren(current, children); - //check for orchestration build - execution root with no children or dependencies - if ((dependencies == null || dependencies.isEmpty()) && childProjects.isEmpty() && current.isExecutionRoot()) { - hasOrchestration = true; + final File outputDir = getCorrectOutputDirectory(current); + if (outputDir == null) { //dc was never run on this project. write the ser to the target. + engine.getDependencies().clear(); + engine.resetFileTypeAnalyzers(); + scanArtifacts(current, engine); + engine.analyzeDependencies(); + final File target = new File(current.getBuild().getOutputDirectory()).getParentFile(); + writeDataFile(current, target, engine.getDependencies()); + showSummary(current, engine.getDependencies()); } } for (MavenProject current : getReactorProjects()) { List dependencies = readDataFile(current); final List childProjects = getAllChildren(current, children); + //check for orchestration build - execution root with no children or dependencies if ((dependencies == null || dependencies.isEmpty()) && childProjects.isEmpty() && current.isExecutionRoot()) { + engine.getDependencies().clear(); engine.resetFileTypeAnalyzers(); for (MavenProject mod : getReactorProjects()) { scanArtifacts(mod, engine); @@ -113,14 +119,13 @@ public class AggregateMojo extends BaseDependencyCheckMojo { LOGGER.log(Level.FINE, "Bundling Exception", ex); } } - try { - final File outputDir = getCorrectOutputDirectory(current); - writeReports(engine, current, outputDir); - } catch (MojoExecutionException ex) { - if (!hasOrchestration) { - throw ex; - } // else ignore this + File outputDir = getCorrectOutputDirectory(current); + if (outputDir == null) { + //in some regards we shouldn't be writting this, but we are anyway. + //we shouldn't write this because nothing is configured to generate this report. + outputDir = new File(current.getBuild().getOutputDirectory()).getParentFile(); } + writeReports(engine, current, outputDir); } } engine.cleanup(); @@ -183,8 +188,7 @@ public class AggregateMojo extends BaseDependencyCheckMojo { * * @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. + * @throws MojoFailureException thrown if dependency-check is configured to fail the build if severe CVEs are identified. */ protected Engine generateDataFile() throws MojoExecutionException, MojoFailureException { final Engine engine; @@ -196,8 +200,8 @@ public class AggregateMojo extends BaseDependencyCheckMojo { } scanArtifacts(getProject(), engine); engine.analyzeDependencies(); - writeDataFile(engine.getDependencies()); - showSummary(engine.getDependencies()); + writeDataFile(getProject(), null, engine.getDependencies()); + showSummary(getProject(), engine.getDependencies()); checkForFailure(engine.getDependencies()); return engine; } 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 c75ed37fb..0cb3ff678 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 @@ -101,21 +101,29 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma @SuppressWarnings("CanBeFinal") @Parameter(property = "logFile", defaultValue = "") private String logFile = null; + + //"project.reporting.outputDirectory" /** * The output directory. This generally maps to "target". */ @Parameter(defaultValue = "${project.build.directory}", required = true) private File outputDirectory; /** - * Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 - * which means since the CVSS scores are 0-10, by default the build will never fail. + * Specifies the destination directory for the generated Dependency-Check report. This generally maps to "target/site". + */ + //Parameter(property = "reportOutputDirectory", defaultValue = "${project.reporting.outputDirectory}", required = true) + @Parameter(property = "project.reporting.outputDirectory", required = true) + private File reportOutputDirectory; + /** + * Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which + * means since the CVSS scores are 0-10, by default the build will never fail. */ @SuppressWarnings("CanBeFinal") @Parameter(property = "failBuildOnCVSS", defaultValue = "11", required = true) private float failBuildOnCVSS = 11; /** - * Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to - * false. Default is true. + * Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. Default + * is true. */ @SuppressWarnings("CanBeFinal") @Parameter(property = "autoupdate", defaultValue = "true", required = true) @@ -129,8 +137,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma @Deprecated private boolean aggregate; /** - * The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this - * within the Site plug-in unless the externalReport is set to true. Default is HTML. + * The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the + * Site plug-in unless the externalReport is set to true. Default is HTML. */ @SuppressWarnings("CanBeFinal") @Parameter(property = "format", defaultValue = "HTML", required = true) @@ -317,13 +325,6 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma @Parameter(property = "externalReport") @Deprecated private String externalReport = null; - - /** - * Specifies the destination directory for the generated Dependency-Check report. This generally maps to - * "target/site". - */ - @Parameter(property = "reportOutputDirectory", defaultValue = "${project.reporting.outputDirectory}", required = true) - private File reportOutputDirectory; // // @@ -341,8 +342,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma } /** - * Checks if the aggregate configuration parameter has been set to true. If it has a MojoExecutionException is - * thrown because the aggregate configuration parameter is no longer supported. + * Checks if the aggregate configuration parameter has been set to true. If it has a MojoExecutionException is thrown because + * the aggregate configuration parameter is no longer supported. * * @throws MojoExecutionException thrown if aggregate is set to true */ @@ -405,15 +406,13 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma * * @param current the Maven project to get the output directory from * @return the directory to write the report(s) - * @throws MojoExecutionException thrown if there is an error loading the file path */ - protected File getCorrectOutputDirectory(MavenProject current) throws MojoExecutionException { + protected File getCorrectOutputDirectory(MavenProject current) { final Object obj = current.getContextValue(getOutputDirectoryContextKey()); if (obj != null && obj instanceof File) { return (File) obj; - } else { - throw new MojoExecutionException(String.format("Unable to determine output directory for '%s'", current.getName())); } + return null; } /** @@ -526,15 +525,19 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma * @throws DatabaseException thrown if there is a database exception */ protected Engine initializeEngine() throws DatabaseException { - final InputStream in = BaseDependencyCheckMojo.class.getClassLoader().getResourceAsStream(LOG_PROPERTIES_FILE); + final InputStream in = BaseDependencyCheckMojo.class + .getClassLoader().getResourceAsStream(LOG_PROPERTIES_FILE); LogUtils.prepareLogger(in, logFile); + populateSettings(); - return new Engine(this.project, this.reactorProjects); + + return new Engine(this.project, + this.reactorProjects); } /** - * Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system - * properties required to change the proxy url, port, and connection timeout. + * Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties + * required to change the proxy url, port, and connection timeout. */ private void populateSettings() { Settings.initialize(); @@ -699,9 +702,9 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma /** * Returns a reference to the current project. This method is used instead of auto-binding the project via component - * annotation in concrete implementations of this. If the child has a @Component MavenProject project; - * defined then the abstract class (i.e. this class) will not have access to the current project (just the way Maven - * works with the binding). + * annotation in concrete implementations of this. If the child has a @Component MavenProject project; defined + * then the abstract class (i.e. this class) will not have access to the current project (just the way Maven works with the + * binding). * * @return returns a reference to the current project */ @@ -799,9 +802,10 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma /** * Generates a warning message listing a summary of dependencies and their associated CPE and CVE entries. * + * @param mp the Maven project for which the summary is shown * @param dependencies a list of dependency objects */ - protected void showSummary(List dependencies) { + protected void showSummary(MavenProject mp, List dependencies) { if (showSummary) { final StringBuilder summary = new StringBuilder(); for (Dependency d : dependencies) { @@ -830,8 +834,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma } } if (summary.length() > 0) { - final String msg = String.format("%n%n" + "One or more dependencies were identified with known vulnerabilities:%n%n%s" - + "%n%nSee the dependency-check report for more details.%n%n", summary.toString()); + final String msg = String.format("%n%n" + "One or more dependencies were identified with known vulnerabilities in %s:%n%n%s" + + "%n%nSee the dependency-check report for more details.%n%n", mp.getName(), summary.toString()); LOGGER.log(Level.WARNING, msg); } } @@ -840,8 +844,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma // // /** - * Returns the key used to store the path to the data file that is saved by writeDataFile(). This key - * is used in the MavenProject.(set|get)ContextValue. + * Returns the key used to store the path to the data file that is saved by writeDataFile(). This key is used in + * the MavenProject.(set|get)ContextValue. * * @return the key used to store the path to the data file */ @@ -862,12 +866,18 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma /** * Writes the scan data to disk. This is used to serialize the scan data between the "check" and "aggregate" phase. * + * @param mp the mMven project for which the data file was created + * @param writeTo the directory to write the data file * @param dependencies the list of dependencies to serialize */ - protected void writeDataFile(List dependencies) { - File file = null; - if (dependencies != null && project.getContextValue(this.getDataFileContextKey()) == null) { - file = new File(project.getBuild().getDirectory(), dataFileName); + protected void writeDataFile(MavenProject mp, File writeTo, List dependencies) { + File file; + if (dependencies != null && mp.getContextValue(this.getDataFileContextKey()) == null) { + if (writeTo != null) { + file = new File(mp.getBuild().getDirectory(), dataFileName); + } else { + file = new File(writeTo, dataFileName); + } OutputStream os = null; OutputStream bos = null; ObjectOutputStream out = null; @@ -881,8 +891,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma //call reset to prevent resource leaks per //https://www.securecoding.cert.org/confluence/display/java/SER10-J.+Avoid+memory+and+resource+leaks+during+serialization out.reset(); - project.setContextValue(this.getDataFileContextKey(), file.getAbsolutePath()); - LOGGER.fine(String.format("Serialized data file written to '%s'", file.getAbsolutePath())); + mp.setContextValue(this.getDataFileContextKey(), file.getAbsolutePath()); + LOGGER.fine(String.format("Serialized data file written to '%s' for %s", file.getAbsolutePath(), mp.getName())); } catch (IOException ex) { LOGGER.log(Level.WARNING, "Unable to create data file used for report aggregation; " + "if report aggregation is being used the results may be incomplete."); @@ -914,8 +924,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma } /** - * Reads the serialized scan data from disk. This is used to serialize the scan data between the "check" and - * "aggregate" phase. + * Reads the serialized scan data from disk. This is used to serialize the scan data between the "check" and "aggregate" + * phase. * * @param project the Maven project to read the data file from * @return a Engine object populated with dependencies if the serialized data file exists; otherwise 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 2ecb2bc63..063cb0c95 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 @@ -86,8 +86,8 @@ public class CheckMojo extends BaseDependencyCheckMojo { } else { engine.analyzeDependencies(); writeReports(engine, getProject(), getCorrectOutputDirectory()); - writeDataFile(engine.getDependencies()); - showSummary(engine.getDependencies()); + writeDataFile(getProject(), null, engine.getDependencies()); + showSummary(getProject(), engine.getDependencies()); checkForFailure(engine.getDependencies()); } engine.cleanup();