updated to address issue #193

Former-commit-id: 8361c2fdbec4191e52db16b870406e3e45d97d0d
This commit is contained in:
Jeremy Long
2015-02-07 18:16:07 -05:00
parent a841027d48
commit d5753b9589
3 changed files with 74 additions and 60 deletions

View File

@@ -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 <jeremy.long@owasp.org>
*/
@@ -73,21 +73,27 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
if (getProject() == getReactorProjects().get(getReactorProjects().size() - 1)) {
final Map<MavenProject, Set<MavenProject>> children = buildAggregateInfo();
boolean hasOrchestration = false;
for (MavenProject current : getReactorProjects()) {
final List<Dependency> dependencies = readDataFile(current);
final List<MavenProject> 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<Dependency> dependencies = readDataFile(current);
final List<MavenProject> 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;
}

View File

@@ -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;
// </editor-fold>
//<editor-fold defaultstate="collapsed" desc="Base Maven implementation">
@@ -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 <code>@Component MavenProject project;</code>
* 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 <code>@Component MavenProject project;</code> 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<Dependency> dependencies) {
protected void showSummary(MavenProject mp, List<Dependency> 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
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Methods to read/write the serialized data file">
/**
* Returns the key used to store the path to the data file that is saved by <code>writeDataFile()</code>. This key
* is used in the <code>MavenProject.(set|get)ContextValue</code>.
* Returns the key used to store the path to the data file that is saved by <code>writeDataFile()</code>. This key is used in
* the <code>MavenProject.(set|get)ContextValue</code>.
*
* @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<Dependency> 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<Dependency> 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 <code>Engine</code> object populated with dependencies if the serialized data file exists; otherwise

View File

@@ -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();