Compare commits

...

11 Commits

Author SHA1 Message Date
Jeremy Long
3e4d012a69 Merge branch 'master' into reportGeneration 2017-05-23 21:02:49 -04:00
Jeremy Long
dccbd659ed Merge pull request #741 from sethjackson/patch-1
Update Windows usage.
2017-05-23 21:02:41 -04:00
Jeremy Long
1b84095c0e Merge branch 'master' into reportGeneration 2017-05-23 21:01:34 -04:00
Jeremy Long
c96ef88222 Moved report generation into the engine, cleaned up code, etc. 2017-05-23 21:00:40 -04:00
Jeremy Long
0540474e0c Merge pull request #742 from sethjackson/patch-2
Fix wording.
2017-05-23 20:31:17 -04:00
Seth Jackson
2dbfba9ac5 Fix wording. 2017-05-23 16:01:11 -04:00
Seth Jackson
8eff628303 Update Windows usage.
So that the example invocation works in PowerShell and cmd.
2017-05-23 14:43:02 -04:00
Jeremy Long
519167bf0f Merge pull request #739 from jeremylong/issue696-cli
Fix Boolean Properties in CLI
2017-05-21 19:32:38 -04:00
Jeremy Long
e8e06d12c7 updated for code coverage 2017-05-21 07:25:42 -04:00
Jeremy Long
006224b52c Merge branch 'master' into issue696-cli 2017-05-20 07:38:12 -04:00
Jeremy Long
6007be1b5f updated to resolve issue #696 2017-05-20 07:37:46 -04:00
22 changed files with 532 additions and 410 deletions

View File

@@ -29,8 +29,8 @@ $ ./bin/dependency-check.sh --project Testing --out . --scan [path to jar files
```
On Windows
```
> bin/dependency-check.bat -h
> bin/dependency-check.bat --project Testing --out . --scan [path to jar files to be scanned]
> .\bin\dependency-check.bat -h
> .\bin\dependency-check.bat --project Testing --out . --scan [path to jar files to be scanned]
```
On Mac with [Homebrew](http://brew.sh)
```

View File

@@ -940,16 +940,7 @@ public class Check extends Update {
throw new BuildException(ex);
}
}
DatabaseProperties prop = null;
try (CveDB cve = CveDB.getInstance()) {
prop = cve.getDatabaseProperties();
} catch (DatabaseException ex) {
//TODO shouldn't this be a fatal exception
log("Unable to retrieve DB Properties", ex, Project.MSG_DEBUG);
}
final ReportGenerator reporter = new ReportGenerator(getProjectName(), engine.getDependencies(), engine.getAnalyzers(), prop);
reporter.generateReports(reportOutputDirectory, reportFormat);
engine.writeReports(getProjectName(),new File(reportOutputDirectory), reportFormat);
if (this.failBuildOnCVSS <= 10) {
checkForFailure(engine.getDependencies());

View File

@@ -281,18 +281,9 @@ public class App {
}
exCol = ex;
}
final List<Dependency> dependencies = engine.getDependencies();
DatabaseProperties prop = null;
try (CveDB cve = CveDB.getInstance()) {
prop = cve.getDatabaseProperties();
} catch (DatabaseException ex) {
//TODO shouldn't this be a fatal exception
LOGGER.debug("Unable to retrieve DB Properties", ex);
}
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, engine.getAnalyzers(), prop);
try {
report.generateReports(reportDirectory, outputFormat);
engine.writeReports(applicationName, new File(reportDirectory), outputFormat);
} catch (ReportException ex) {
if (exCol != null) {
exCol.addException(ex);
@@ -306,7 +297,7 @@ public class App {
}
//Set the exit code based on whether we found a high enough vulnerability
for (Dependency dep : dependencies) {
for (Dependency dep : engine.getDependencies()) {
if (!dep.getVulnerabilities().isEmpty()) {
for (Vulnerability vuln : dep.getVulnerabilities()) {
LOGGER.debug("VULNERABILITY FOUND " + dep.getDisplayFileName());
@@ -316,7 +307,6 @@ public class App {
}
}
}
return retCode;
} finally {
if (engine != null) {
@@ -353,8 +343,7 @@ public class App {
* @throws InvalidSettingException thrown when a user defined properties
* file is unable to be loaded.
*/
private void populateSettings(CliParser cli) throws InvalidSettingException {
final boolean autoUpdate = cli.isAutoUpdate();
protected void populateSettings(CliParser cli) throws InvalidSettingException {
final String connectionTimeout = cli.getConnectionTimeout();
final String proxyServer = cli.getProxyServer();
final String proxyPort = cli.getProxyPort();
@@ -377,7 +366,8 @@ public class App {
final String cveBase12 = cli.getBaseCve12Url();
final String cveBase20 = cli.getBaseCve20Url();
final Integer cveValidForHours = cli.getCveValidForHours();
final boolean experimentalEnabled = cli.isExperimentalEnabled();
final Boolean autoUpdate = cli.isAutoUpdate();
final Boolean experimentalEnabled = cli.isExperimentalEnabled();
if (propertiesFile != null) {
try {
@@ -390,7 +380,7 @@ public class App {
}
// We have to wait until we've merged the properties before attempting to set whether we use
// the proxy for Nexus since it could be disabled in the properties, but not explicitly stated
// on the command line
// on the command line. This is true of other boolean values set below not using the setBooleanIfNotNull.
final boolean nexusUsesProxy = cli.isNexusUsesProxy();
if (dataDirectory != null) {
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
@@ -404,7 +394,7 @@ public class App {
final File dataDir = new File(base, sub);
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
}
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
Settings.setBooleanIfNotNull(Settings.KEYS.AUTO_UPDATE, autoUpdate);
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUser);
@@ -415,7 +405,8 @@ public class App {
Settings.setIntIfNotNull(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours);
//File Type Analyzer Settings
Settings.setBoolean(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, experimentalEnabled);
Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, experimentalEnabled);
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, !cli.isJarDisabled());
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, !cli.isArchiveDisabled());
Settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, !cli.isPythonDistributionDisabled());

View File

@@ -567,6 +567,32 @@ public final class CliParser {
return value;
}
/**
* Utility method to determine if one of the disable options has been set.
* If not set, this method will check the currently configured settings for
* the current value to return.
*
* Example given `--disableArchive` on the command line would cause this
* method to return true for the disable archive setting.
*
* @param argument the command line argument
* @param setting the corresponding settings key
* @return true if the disable option was set, if not set the currently
* configured value will be returned
*/
private boolean hasDisableOption(String argument, String setting) {
if (line == null || !line.hasOption(argument)) {
try {
return !Settings.getBoolean(setting);
} catch (InvalidSettingException ise) {
LOGGER.warn("Invalid property setting '{}' defaulting to false", setting);
return false;
}
} else {
return true;
}
}
/**
* Returns true if the disableJar command line argument was specified.
*
@@ -574,7 +600,7 @@ public final class CliParser {
* otherwise false
*/
public boolean isJarDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_JAR);
return hasDisableOption(ARGUMENT.DISABLE_JAR, Settings.KEYS.ANALYZER_JAR_ENABLED);
}
/**
@@ -584,7 +610,7 @@ public final class CliParser {
* otherwise false
*/
public boolean isArchiveDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ARCHIVE);
return hasDisableOption(ARGUMENT.DISABLE_ARCHIVE, Settings.KEYS.ANALYZER_ARCHIVE_ENABLED);
}
/**
@@ -594,7 +620,7 @@ public final class CliParser {
* otherwise false
*/
public boolean isNuspecDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NUSPEC);
return hasDisableOption(ARGUMENT.DISABLE_NUSPEC, Settings.KEYS.ANALYZER_NUSPEC_ENABLED);
}
/**
@@ -604,7 +630,7 @@ public final class CliParser {
* otherwise false
*/
public boolean isAssemblyDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ASSEMBLY);
return hasDisableOption(ARGUMENT.DISABLE_ASSEMBLY, Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED);
}
/**
@@ -615,7 +641,7 @@ public final class CliParser {
* specified; otherwise false
*/
public boolean isBundleAuditDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_BUNDLE_AUDIT);
return hasDisableOption(ARGUMENT.DISABLE_BUNDLE_AUDIT, Settings.KEYS.ANALYZER_BUNDLE_AUDIT_ENABLED);
}
/**
@@ -625,7 +651,7 @@ public final class CliParser {
* otherwise false
*/
public boolean isPythonDistributionDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_PY_DIST);
return hasDisableOption(ARGUMENT.DISABLE_PY_DIST, Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED);
}
/**
@@ -635,7 +661,7 @@ public final class CliParser {
* otherwise false
*/
public boolean isPythonPackageDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_PY_PKG);
return hasDisableOption(ARGUMENT.DISABLE_PY_PKG, Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED);
}
/**
@@ -645,7 +671,7 @@ public final class CliParser {
* argument was specified; otherwise false
*/
public boolean isRubyGemspecDisabled() {
return (null != line) && line.hasOption(ARGUMENT.DISABLE_RUBYGEMS);
return hasDisableOption(ARGUMENT.DISABLE_RUBYGEMS, Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED);
}
/**
@@ -655,7 +681,7 @@ public final class CliParser {
* otherwise false
*/
public boolean isCmakeDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_CMAKE);
return hasDisableOption(ARGUMENT.DISABLE_CMAKE, Settings.KEYS.ANALYZER_CMAKE_ENABLED);
}
/**
@@ -665,7 +691,7 @@ public final class CliParser {
* otherwise false
*/
public boolean isAutoconfDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_AUTOCONF);
return hasDisableOption(ARGUMENT.DISABLE_AUTOCONF, Settings.KEYS.ANALYZER_AUTOCONF_ENABLED);
}
/**
@@ -675,7 +701,7 @@ public final class CliParser {
* otherwise false
*/
public boolean isComposerDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_COMPOSER);
return hasDisableOption(ARGUMENT.DISABLE_COMPOSER, Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED);
}
/**
@@ -685,7 +711,7 @@ public final class CliParser {
* otherwise false
*/
public boolean isNexusDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NEXUS);
return hasDisableOption(ARGUMENT.DISABLE_NEXUS, Settings.KEYS.ANALYZER_NEXUS_ENABLED);
}
/**
@@ -695,7 +721,7 @@ public final class CliParser {
* otherwise false
*/
public boolean isOpenSSLDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_OPENSSL);
return hasDisableOption(ARGUMENT.DISABLE_OPENSSL, Settings.KEYS.ANALYZER_OPENSSL_ENABLED);
}
/**
@@ -705,7 +731,7 @@ public final class CliParser {
* otherwise false
*/
public boolean isNodeJsDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NODE_JS);
return hasDisableOption(ARGUMENT.DISABLE_NODE_JS, Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED);
}
/**
@@ -716,7 +742,7 @@ public final class CliParser {
* specified; otherwise false
*/
public boolean isCocoapodsAnalyzerDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_COCOAPODS);
return hasDisableOption(ARGUMENT.DISABLE_COCOAPODS, Settings.KEYS.ANALYZER_COCOAPODS_ENABLED);
}
/**
@@ -727,7 +753,7 @@ public final class CliParser {
* argument was specified; otherwise false
*/
public boolean isSwiftPackageAnalyzerDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_SWIFT);
return hasDisableOption(ARGUMENT.DISABLE_SWIFT, Settings.KEYS.ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED);
}
/**
@@ -737,7 +763,7 @@ public final class CliParser {
* otherwise false
*/
public boolean isCentralDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_CENTRAL);
return hasDisableOption(ARGUMENT.DISABLE_CENTRAL, Settings.KEYS.ANALYZER_CENTRAL_ENABLED);
}
/**
@@ -1029,10 +1055,10 @@ public final class CliParser {
* disabled via the command line this will return false.
*
* @return <code>true</code> if auto-update is allowed; otherwise
* <code>false</code>
* <code>null</code>
*/
public boolean isAutoUpdate() {
return line != null && !line.hasOption(ARGUMENT.DISABLE_AUTO_UPDATE);
public Boolean isAutoUpdate() {
return (line != null && line.hasOption(ARGUMENT.DISABLE_AUTO_UPDATE)) ? false : null;
}
/**
@@ -1134,10 +1160,10 @@ public final class CliParser {
/**
* Returns true if the experimental analyzers are enabled.
*
* @return true if the experimental analyzers are enabled; otherwise false
* @return true if the experimental analyzers are enabled; otherwise null
*/
public boolean isExperimentalEnabled() {
return line.hasOption(ARGUMENT.EXPERIMENTAL);
public Boolean isExperimentalEnabled() {
return (line != null && line.hasOption(ARGUMENT.EXPERIMENTAL)) ? true : null;
}
/**

View File

@@ -13,18 +13,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2015 The OWASP Foundatio. All Rights Reserved.
* Copyright (c) 2017 The OWASP Foundatio. All Rights Reserved.
*/
package org.owasp.dependencycheck;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.UnrecognizedOptionException;
import org.junit.Test;
import static org.junit.Assert.*;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
/**
*
* @author jeremy
*/
public class AppTest {
/**
* Test of ensureCanonicalPath method, of class App.
*/
@@ -35,17 +45,83 @@ public class AppTest {
String result = instance.ensureCanonicalPath(file);
assertFalse(result.contains(".."));
assertTrue(result.endsWith("*.jar"));
}
/**
* Test of ensureCanonicalPath method, of class App.
*/
@Test
public void testEnsureCanonicalPath2() {
String file = "../some/skip/../path/file.txt";
App instance = new App();
file = "../some/skip/../path/file.txt";
String expResult = "/some/path/file.txt";
String result = instance.ensureCanonicalPath(file);
result = instance.ensureCanonicalPath(file);
assertTrue("result=" + result, result.endsWith(expResult));
}
@Test(expected = UnrecognizedOptionException.class)
public void testPopulateSettingsException() throws FileNotFoundException, ParseException, InvalidSettingException, URISyntaxException {
String[] args = {"-invalidPROPERTY"};
assertTrue(testBooleanProperties(args, null));
}
@Test
public void testPopulateSettings() throws FileNotFoundException, ParseException, InvalidSettingException, URISyntaxException {
File prop = new File(this.getClass().getClassLoader().getResource("sample.properties").toURI().getPath());
String[] args = {"-P", prop.getAbsolutePath()};
Map<String, Boolean> expected = new HashMap<>();
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.TRUE);
assertTrue(testBooleanProperties(args, expected));
String[] args2 = {"-n"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.TRUE);
assertTrue(testBooleanProperties(args2, expected));
String[] args3 = {"-h"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.TRUE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.TRUE);
assertTrue(testBooleanProperties(args3, expected));
String[] args4 = {"--disableArchive"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.TRUE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
assertTrue(testBooleanProperties(args4, expected));
String[] args5 = {"-P", prop.getAbsolutePath(), "--disableArchive"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
assertTrue(testBooleanProperties(args5, expected));
prop = new File(this.getClass().getClassLoader().getResource("sample2.properties").toURI().getPath());
String[] args6 = {"-P", prop.getAbsolutePath(), "--disableArchive"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.TRUE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
assertTrue(testBooleanProperties(args6, expected));
String[] args7 = {"-P", prop.getAbsolutePath(), "--noupdate"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
assertTrue(testBooleanProperties(args7, expected));
String[] args8 = {"-P", prop.getAbsolutePath(), "--noupdate", "--disableArchive"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
assertTrue(testBooleanProperties(args8, expected));
}
private boolean testBooleanProperties(String[] args, Map<String, Boolean> expected) throws URISyntaxException, FileNotFoundException, ParseException, InvalidSettingException {
Settings.initialize();
try {
final CliParser cli = new CliParser();
cli.parse(args);
App instance = new App();
instance.populateSettings(cli);
boolean results = true;
for (Map.Entry<String, Boolean> entry : expected.entrySet()) {
results &= Settings.getBoolean(entry.getKey()) == entry.getValue();
}
return results;
} finally {
Settings.cleanup();
}
}
}

View File

@@ -0,0 +1,33 @@
autoupdate=false
analyzer.experimental.enabled=false
analyzer.jar.enabled=true
analyzer.archive.enabled=true
analyzer.node.package.enabled=true
analyzer.composer.lock.enabled=true
analyzer.python.distribution.enabled=true
analyzer.python.package.enabled=true
analyzer.ruby.gemspec.enabled=true
analyzer.autoconf.enabled=true
analyzer.cmake.enabled=true
analyzer.assembly.enabled=true
analyzer.nuspec.enabled=true
analyzer.openssl.enabled=true
analyzer.central.enabled=true
analyzer.nexus.enabled=false
analyzer.cocoapods.enabled=true
analyzer.swift.package.manager.enabled=true
#whether the nexus analyzer uses the proxy
analyzer.nexus.proxy=true
analyzer.cpe.enabled=true
analyzer.cpesuppression.enabled=true
analyzer.dependencybundling.enabled=true
analyzer.dependencymerging.enabled=true
analyzer.falsepositive.enabled=true
analyzer.filename.enabled=true
analyzer.hint.enabled=true
analyzer.nvdcve.enabled=true
analyzer.vulnerabilitysuppression.enabled=true
updater.nvdcve.enabled=true
updater.versioncheck.enabled=true
analyzer.versionfilter.enabled=true

View File

@@ -0,0 +1,33 @@
autoupdate=true
analyzer.experimental.enabled=true
analyzer.jar.enabled=false
analyzer.archive.enabled=false
analyzer.node.package.enabled=false
analyzer.composer.lock.enabled=false
analyzer.python.distribution.enabled=false
analyzer.python.package.enabled=false
analyzer.ruby.gemspec.enabled=false
analyzer.autoconf.enabled=false
analyzer.cmake.enabled=false
analyzer.assembly.enabled=false
analyzer.nuspec.enabled=false
analyzer.openssl.enabled=false
analyzer.central.enabled=false
analyzer.nexus.enabled=true
analyzer.cocoapods.enabled=false
analyzer.swift.package.manager.enabled=false
#whether the nexus analyzer uses the proxy
analyzer.nexus.proxy=false
analyzer.cpe.enabled=false
analyzer.cpesuppression.enabled=false
analyzer.dependencybundling.enabled=false
analyzer.dependencymerging.enabled=false
analyzer.falsepositive.enabled=false
analyzer.filename.enabled=false
analyzer.hint.enabled=false
analyzer.nvdcve.enabled=false
analyzer.vulnerabilitysuppression.enabled=false
updater.nvdcve.enabled=false
updater.versioncheck.enabled=false
analyzer.versionfilter.enabled=false

View File

@@ -54,6 +54,9 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.reporting.ReportGenerator;
/**
* Scans files, directories, etc. for Dependencies. Analyzers are loaded and
@@ -796,4 +799,42 @@ public class Engine implements FileFilter {
exceptions.add(throwable);
throw new ExceptionCollection(message, exceptions, true);
}
/**
* Writes the report to the given output directory.
*
* @param applicationName the name of the application/project
* @param groupId the Maven groupId
* @param artifactId the Maven artifactId
* @param version the Maven version
* @param outputDir the path to the output directory (can include the full
* file name if the format is not ALL)
* @param format the report format (ALL, HTML, CSV, JSON, etc.)
* @throws ReportException thrown if there is an error generating the report
*/
public void writeReports(String applicationName, String groupId, String artifactId,
String version, File outputDir, String format) throws ReportException {
DatabaseProperties prop = database.getDatabaseProperties();
final ReportGenerator r = new ReportGenerator(applicationName, groupId, artifactId, version, dependencies, getAnalyzers(), prop);
try {
r.write(outputDir.getAbsolutePath(), format);
} catch (ReportException ex) {
final String msg = String.format("Error generating the report for %s", applicationName);
throw new ReportException(msg, ex);
}
}
/**
* Writes the report to the given output directory.
*
* @param applicationName the name of the application/project
* @param outputDir the path to the output directory (can include the full
* file name if the format is not ALL)
* @param format the report format (ALL, HTML, CSV, JSON, etc.)
* @throws ReportException thrown if there is an error generating the report
*/
public void writeReports(String applicationName, File outputDir, String format) throws ReportException {
writeReports(applicationName, null, null, null, outputDir, format);
}
}

View File

@@ -840,21 +840,15 @@ public class DependencyCheckScanAgent {
*
* @param engine a dependency-check engine
* @param outDirectory the directory to write the reports to
* @throw ScanAgentException thrown if there is an error generating the
* report
*/
private void generateExternalReports(Engine engine, File outDirectory) {
DatabaseProperties prop = null;
try (CveDB cve = CveDB.getInstance()) {
prop = cve.getDatabaseProperties();
} catch (DatabaseException ex) {
//TODO shouldn't this be a fatal exception
LOGGER.debug("Unable to retrieve DB Properties", ex);
}
final ReportGenerator r = new ReportGenerator(this.applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
private void generateExternalReports(Engine engine, File outDirectory) throws ScanAgentException {
try {
r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
} catch (IOException | ReportException ex) {
LOGGER.error("Unexpected exception occurred during analysis; please see the verbose error log for more details.");
LOGGER.debug("", ex);
engine.writeReports(applicationName, outDirectory, this.reportFormat.name());
} catch (ReportException ex) {
LOGGER.debug("Unexpected exception occurred during analysis; please see the verbose error log for more details.", ex);
throw new ScanAgentException("Error generating the report", ex);
}
}

View File

@@ -107,29 +107,8 @@ public class ReportGenerator {
*/
public ReportGenerator(String applicationName, List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
velocityEngine = createVelocityEngine();
context = createContext();
velocityEngine.init();
final EscapeTool enc = new EscapeTool();
final DateTime dt = new DateTime();
final DateTimeFormatter dateFormat = DateTimeFormat.forPattern("MMM d, yyyy 'at' HH:mm:ss z");
final DateTimeFormatter dateFormatXML = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
// final Date d = new Date();
// 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 String scanDate = dateFormat.print(dt);
final String scanDateXML = dateFormatXML.print(dt);
context.put("applicationName", applicationName);
context.put("dependencies", dependencies);
context.put("analyzers", analyzers);
context.put("properties", properties);
context.put("scanDate", scanDate);
context.put("scanDateXML", scanDateXML);
context.put("enc", enc);
context.put("version", Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
context = createContext(applicationName, dependencies, analyzers, properties);
}
/**
@@ -148,9 +127,15 @@ public class ReportGenerator {
List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
this(applicationName, dependencies, analyzers, properties);
context.put("applicationVersion", version);
context.put("artifactID", artifactID);
context.put("groupID", groupID);
if (version != null) {
context.put("applicationVersion", version);
}
if (artifactID != null) {
context.put("artifactID", artifactID);
}
if (groupID != null) {
context.put("groupID", groupID);
}
}
/**
@@ -166,67 +151,235 @@ public class ReportGenerator {
}
/**
* Creates a new Velocity Context.
* Constructs the velocity context used to generate the dependency-check
* reports.
*
* @return a Velocity Context
* @param applicationName the application name being analyzed
* @param dependencies the list of dependencies
* @param analyzers the list of analyzers used
* @param properties the database properties (containing timestamps of the
* NVD CVE data)
* @return the velocity context
*/
private Context createContext() {
return new VelocityContext();
private VelocityContext createContext(String applicationName, List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
final DateTime dt = new DateTime();
final DateTimeFormatter dateFormat = DateTimeFormat.forPattern("MMM d, yyyy 'at' HH:mm:ss z");
final DateTimeFormatter dateFormatXML = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
final String scanDate = dateFormat.print(dt);
final String scanDateXML = dateFormatXML.print(dt);
VelocityContext ctxt = new VelocityContext();
ctxt.put("applicationName", applicationName);
ctxt.put("dependencies", dependencies);
ctxt.put("analyzers", analyzers);
ctxt.put("properties", properties);
ctxt.put("scanDate", scanDate);
ctxt.put("scanDateXML", scanDateXML);
ctxt.put("enc", new EscapeTool());
ctxt.put("version", Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
return ctxt;
}
/**
* Generates the Dependency Reports for the identified dependencies.
* Writes the dependency-check report to the given output location.
*
* @param outputStream the OutputStream to send the generated report to
* @param format the format the report should be written in
* @throws IOException is thrown when the template file does not exist
* @throws Exception is thrown if there is an error writing out the reports
*/
public void generateReports(OutputStream outputStream, Format format) throws IOException, Exception {
if (format == Format.XML || format == Format.ALL) {
generateReport("XmlReport", outputStream);
}
if (format == Format.HTML || format == Format.ALL) {
generateReport("HtmlReport", outputStream);
}
if (format == Format.VULN || format == Format.ALL) {
generateReport("VulnerabilityReport", outputStream);
}
if (format == Format.JSON || format == Format.ALL) {
generateReport("JsonReport", outputStream);
}
if (format == Format.CSV || format == Format.ALL) {
generateReport("CsvReport", outputStream);
}
}
/**
* Generates the Dependency Reports for the identified dependencies.
*
* @param outputDir the path where the reports should be written
* @param format the format the report should be written in
* @throws ReportException is thrown if there is an error writing out the
* @param outputLocation the path where the reports should be written
* @param format the format the report should be written in (XML, HTML,
* JSON, CSV, ALL) or even the path to a custom velocity template (either
* fully qualified or the template name on the class path).
* @throws ReportException is thrown if there is an error creating out the
* reports
*/
public void generateReports(String outputDir, Format format) throws ReportException {
if (format == Format.XML || format == Format.ALL) {
generateReport("XmlReport", outputDir + File.separator + "dependency-check-report.xml");
public void write(String outputLocation, String format) throws ReportException {
Format reportFormat = null;
try {
reportFormat = Format.valueOf(format.toUpperCase());
} catch (IllegalArgumentException ex) {
LOGGER.trace("ignore this exception", ex);
}
if (format == Format.JSON || format == Format.ALL) {
generateReport("JsonReport", outputDir + File.separator + "dependency-check-report.json");
pretifyJson(outputDir + File.separator + "dependency-check-report.json");
if (reportFormat != null) {
write(outputLocation, reportFormat);
} else {
File out = getReportFile(outputLocation, null);
if (out.isDirectory()) {
throw new ReportException("Unable to write non-standard VSL output to a directory, please specify a file name");
}
processTemplate(format, out);
}
if (format == Format.CSV || format == Format.ALL) {
generateReport("CsvReport", outputDir + File.separator + "dependency-check-report.csv");
}
if (format == Format.HTML || format == Format.ALL) {
generateReport("HtmlReport", outputDir + File.separator + "dependency-check-report.html");
}
if (format == Format.VULN || format == Format.ALL) {
generateReport("VulnerabilityReport", outputDir + File.separator + "dependency-check-vulnerability.html");
}
/**
* Writes the dependency-check report(s).
*
* @param outputLocation the path where the reports should be written
* @param format the format the report should be written in (XML, HTML, ALL)
* @throws ReportException is thrown if there is an error creating out the
* reports
*/
public void write(String outputLocation, Format format) throws ReportException {
if (format == Format.ALL) {
for (Format f : Format.values()) {
if (f != Format.ALL) {
write(outputLocation, f);
}
}
} else {
final File out = getReportFile(outputLocation, format);
final String templateName = format.toString().toLowerCase() + "Report";
processTemplate(templateName, out);
if (format == Format.JSON) {
pretifyJson(out.getPath());
}
}
}
// /**
// * Writes the dependency-check report(s).
// *
// * @param outputStream the OutputStream to send the generated report to
// * @param format the format the report should be written in
// * @throws ReportException thrown if the report format is ALL
// * @throws IOException is thrown when the template file does not exist
// * @throws Exception is thrown if there is an error writing out the reports
// */
// public void write(OutputStream outputStream, Format format) throws ReportException, IOException, Exception {
// if (format == Format.ALL) {
// throw new ReportException("Unable to write ALL reports to a single output stream, please check the API");
// }
// final String templateName = format.toString().toLowerCase() + "Report";
// processTemplate(templateName, outputStream);
// }
/**
* Determines the report file name based on the give output location and
* format. If the output location contains a full file name that has the
* correct extension for the given report type then the output location is
* returned. However, if the output location is a directory, this method
* will generate the correct name for the given output format.
*
* @param outputLocation the specified output location
* @param format the report format
* @return the report File
*/
protected File getReportFile(String outputLocation, Format format) {
File outFile = new File(outputLocation);
if (outFile.getParentFile() == null) {
outFile = new File(".", outputLocation);
}
final String pathToCheck = outputLocation.toLowerCase();
if (format == Format.XML && !pathToCheck.endsWith(".xml")) {
return new File(outFile, "dependency-check-report.xml");
}
if (format == Format.HTML && !pathToCheck.endsWith(".html") && !pathToCheck.endsWith(".htm")) {
return new File(outFile, "dependency-check-report.html");
}
if (format == Format.VULN && !pathToCheck.endsWith(".html") && !pathToCheck.endsWith(".htm")) {
return new File(outFile, "dependency-check-vulnerability.html");
}
if (format == Format.JSON && !pathToCheck.endsWith(".json")) {
return new File(outFile, "dependency-check-report.json");
}
if (format == Format.CSV && !pathToCheck.endsWith(".csv")) {
return new File(outFile, "dependency-check-report.csv");
}
return outFile;
}
/**
* Generates a report from a given Velocity Template. The template name
* 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.
*
* @param template the name of the template to load
* @param file the output file to write the report to
* @throws ReportException is thrown when the report cannot be generated
*/
protected void processTemplate(String template, File file) throws ReportException {
ensureParentDirectoryExists(file);
try (OutputStream output = new FileOutputStream(file)) {
processTemplate(template, output);
} catch (IOException ex) {
throw new ReportException(String.format("Unable to write to file: %s", file), ex);
}
}
/**
* Generates a report from a given Velocity Template. The template name
* 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.
*
* @param templateName the name of the template to load
* @param outputStream the OutputStream to write the report to
* @throws ReportException is thrown when an exception occurs
*/
protected void processTemplate(String templateName, OutputStream outputStream) throws ReportException {
InputStream input = null;
String logTag = null;
final File f = new File(templateName);
try {
if (f.isFile()) {
try {
logTag = templateName;
input = new FileInputStream(f);
} catch (FileNotFoundException ex) {
throw new ReportException("Unable to locate template file: " + templateName, ex);
}
} else {
logTag = "templates/" + templateName + ".vsl";
input = this.getClass().getClassLoader().getResourceAsStream(logTag);
}
if (input == null) {
logTag = templateName;
input = this.getClass().getClassLoader().getResourceAsStream(templateName);
}
if (input == null) {
throw new ReportException("Template file doesn't exist: " + logTag);
}
try (InputStreamReader reader = new InputStreamReader(input, "UTF-8");
OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8")) {
if (!velocityEngine.evaluate(context, writer, logTag, reader)) {
throw new ReportException("Failed to convert the template into html.");
}
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 {
if (input != null) {
try {
input.close();
} catch (IOException ex) {
LOGGER.trace("Error closing input", ex);
}
}
}
}
/**
* Validates that the given file's parent directory exists. If the directory
* does not exist an attempt to create the necessary path is made; if that
* fails a ReportException will be raised.
*
* @param file the file or directory directory
* @throws ReportException thrown if the parent directory does not exist and
* cannot be created
*/
private void ensureParentDirectoryExists(File file) throws ReportException {
if (!file.getParentFile().exists()) {
final boolean created = file.getParentFile().mkdirs();
if (!created) {
final String msg = String.format("Unable to create directory '%s'.", file.getParentFile().getAbsolutePath());
throw new ReportException(msg);
}
}
}
/**
* Reformats the given JSON file.
*
@@ -311,139 +464,4 @@ public class ReportGenerator {
}
}
}
/**
* Generates the Dependency Reports for the identified dependencies.
*
* @param outputDir the path where the reports should be written
* @param outputFormat the format the report should be written in (XML,
* HTML, ALL)
* @throws ReportException is thrown if there is an error creating out the
* reports
*/
public void generateReports(String outputDir, String outputFormat) throws ReportException {
final String format = outputFormat.toUpperCase();
final String pathToCheck = outputDir.toLowerCase();
if (format.matches("^(XML|HTML|VULN|JSON|ALL)$")) {
if ("XML".equalsIgnoreCase(format)) {
if (pathToCheck.endsWith(".xml")) {
generateReport("XmlReport", outputDir);
} else {
generateReports(outputDir, Format.XML);
}
}
if ("HTML".equalsIgnoreCase(format)) {
if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
generateReport("HtmlReport", outputDir);
} else {
generateReports(outputDir, Format.HTML);
}
}
if ("VULN".equalsIgnoreCase(format)) {
if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
generateReport("VulnReport", outputDir);
} else {
generateReports(outputDir, Format.VULN);
}
}
if ("JSON".equalsIgnoreCase(format)) {
if (pathToCheck.endsWith(".json")) {
generateReport("JsonReport", outputDir);
pretifyJson(outputDir);
} else {
generateReports(outputDir, Format.JSON);
}
}
if ("CSV".equalsIgnoreCase(format)) {
if (pathToCheck.endsWith(".csv")) {
generateReport("CsvReport", outputDir);
} else {
generateReports(outputDir, Format.JSON);
}
}
if ("ALL".equalsIgnoreCase(format)) {
generateReports(outputDir, Format.ALL);
}
}
}
/**
* Generates a report from a given Velocity Template. The template name
* 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.
*
* @param templateName the name of the template to load
* @param outputStream the OutputStream to write the report to
* @throws ReportException is thrown when an exception occurs
*/
protected void generateReport(String templateName, OutputStream outputStream) throws ReportException {
InputStream input = null;
String templatePath = null;
final File f = new File(templateName);
try {
if (f.exists() && f.isFile()) {
try {
templatePath = templateName;
input = new FileInputStream(f);
} catch (FileNotFoundException ex) {
throw new ReportException("Unable to locate template file: " + templateName, ex);
}
} else {
templatePath = "templates/" + templateName + ".vsl";
input = this.getClass().getClassLoader().getResourceAsStream(templatePath);
}
if (input == null) {
throw new ReportException("Template file doesn't exist: " + templatePath);
}
try (InputStreamReader reader = new InputStreamReader(input, "UTF-8");
OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8")) {
if (!velocityEngine.evaluate(context, writer, templatePath, reader)) {
throw new ReportException("Failed to convert the template into html.");
}
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 {
if (input != null) {
try {
input.close();
} catch (IOException ex) {
LOGGER.trace("Error closing input", ex);
}
}
}
}
/**
* Generates a report from a given Velocity Template. The template name
* 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.
*
* @param templateName the name of the template to load
* @param outFileName the filename and path to write the report to
* @throws ReportException is thrown when the report cannot be generated
*/
protected void generateReport(String templateName, String outFileName) throws ReportException {
File outFile = new File(outFileName);
if (outFile.getParentFile() == null) {
outFile = new File(".", outFileName);
}
if (!outFile.getParentFile().exists()) {
final boolean created = outFile.getParentFile().mkdirs();
if (!created) {
throw new ReportException("Unable to create directory '" + outFile.getParentFile().getAbsolutePath() + "'.");
}
}
try (OutputStream outputSteam = new FileOutputStream(outFile)) {
generateReport(templateName, outputSteam);
} catch (IOException ex) {
throw new ReportException("Unable to write to file: " + outFile, ex);
}
}
}

View File

@@ -17,6 +17,7 @@
*/
package org.owasp.dependencycheck;
import java.io.File;
import java.io.IOException;
import static org.junit.Assert.assertTrue;
@@ -72,12 +73,7 @@ public class EngineIT extends BaseDBTestCase {
throw ex;
}
}
DatabaseProperties prop = null;
try (CveDB cve = CveDB.getInstance()) {
prop = cve.getDatabaseProperties();
}
ReportGenerator rg = new ReportGenerator("DependencyCheck", instance.getDependencies(), instance.getAnalyzers(), prop);
rg.generateReports("./target/", "ALL");
instance.writeReports("dependency-check sample", new File("./target/"), "ALL");
instance.cleanup();
}
}

View File

@@ -25,15 +25,12 @@ import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.owasp.dependencycheck.BaseDBTestCase;
import org.owasp.dependencycheck.BaseTest;
import org.owasp.dependencycheck.Engine;
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.exception.ExceptionCollection;
import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.utils.InvalidSettingException;
@@ -47,67 +44,6 @@ import static org.junit.Assert.fail;
*/
public class ReportGeneratorIT extends BaseDBTestCase {
/**
* Test of generateReport method, of class ReportGenerator.
*
* @throws Exception is thrown when an exception occurs.
*/
@Test
public void testGenerateReport() throws Exception {
// String templateName = "HtmlReport";
// File f = new File("target/test-reports");
// if (!f.exists()) {
// f.mkdir();
// }
// String writeTo = "target/test-reports/Report.html";
// Map<String, Object> properties = new HashMap<String, Object>();
// Dependency d = new Dependency();
// d.setFileName("FileName.jar");
// d.setActualFilePath("lib/FileName.jar");
// d.addCPEentry("cpe://a:/some:cpe:1.0");
//
// List<Dependency> dependencies = new ArrayList<Dependency>();
// d.getProductEvidence().addEvidence("jar","filename","<test>test", Confidence.HIGH);
// d.getProductEvidence().addEvidence("manifest","vendor","<test>test", Confidence.HIGH);
//
// for (Evidence e : d.getProductEvidence().iterator(Confidence.HIGH)) {
// String t = e.getValue();
// }
// dependencies.add(d);
//
// Dependency d2 = new Dependency();
// d2.setFileName("Another.jar");
// d2.setActualFilePath("lib/Another.jar");
// d2.addCPEentry("cpe://a:/another:cpe:1.0");
// d2.addCPEentry("cpe://a:/another:cpe:1.1");
// d2.addCPEentry("cpe://a:/another:cpe:1.2");
// d2.getProductEvidence().addEvidence("jar","filename","another.jar", Confidence.HIGH);
// d2.getProductEvidence().addEvidence("manifest","vendor","Company A", Confidence.MEDIUM);
//
// for (Evidence e : d2.getProductEvidence().iterator(Confidence.HIGH)) {
// String t = e.getValue();
// }
//
// dependencies.add(d2);
//
// Dependency d3 = new Dependency();
// d3.setFileName("Third.jar");
// d3.setActualFilePath("lib/Third.jar");
// d3.getProductEvidence().addEvidence("jar","filename","third.jar", Confidence.HIGH);
//
// for (Evidence e : d3.getProductEvidence().iterator(Confidence.HIGH)) {
// String t = e.getValue();
// }
//
// dependencies.add(d3);
//
// properties.put("dependencies",dependencies);
//
// ReportGenerator instance = new ReportGenerator();
// instance.generateReport(templateName, writeTo, properties);
//assertTrue("need to add a real check here", false);
}
/**
* Generates an XML report containing known vulnerabilities and realistic
* data and validates the generated XML document against the XSD.
@@ -115,7 +51,7 @@ public class ReportGeneratorIT extends BaseDBTestCase {
* @throws Exception
*/
@Test
public void testGenerateXMLReport() {
public void testGenerateReport() {
try {
String templateName = "XmlReport";
@@ -123,7 +59,7 @@ public class ReportGeneratorIT extends BaseDBTestCase {
if (!f.exists()) {
f.mkdir();
}
String writeTo = "target/test-reports/Report.xml";
File writeTo = new File("target/test-reports/Report.xml");
File suppressionFile = BaseTest.getResourceAsFile(this, "incorrectSuppressions.xml");
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile.getAbsolutePath());
@@ -135,29 +71,20 @@ public class ReportGeneratorIT extends BaseDBTestCase {
//File jetty = new File(this.getClass().getClassLoader().getResource("org.mortbay.jetty.jar").getPath());
File jetty = BaseTest.getResourceAsFile(this, "org.mortbay.jetty.jar");
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
Engine engine = new Engine();
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
engine.scan(struts);
engine.scan(axis);
engine.scan(jetty);
engine.analyzeDependencies();
CveDB cveDB = CveDB.getInstance();
DatabaseProperties dbProp = cveDB.getDatabaseProperties();
ReportGenerator generator = new ReportGenerator("Test Report", "org.owasp", "dependency-check-core", "1.4.7",
engine.getDependencies(), engine.getAnalyzers(), dbProp);
generator.generateReport(templateName, writeTo);
cveDB.close();
engine.writeReports("Test Report", "org.owasp", "dependency-check-core", "1.4.7", writeTo, "XML");
engine.cleanup();
InputStream xsdStream = ReportGenerator.class.getClassLoader().getResourceAsStream("schema/dependency-check.1.5.xsd");
StreamSource xsdSource = new StreamSource(xsdStream);
StreamSource xmlSource = new StreamSource(new File(writeTo));
StreamSource xmlSource = new StreamSource(writeTo);
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(xsdSource);
Validator validator = schema.newValidator();

View File

@@ -123,7 +123,8 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
outputDir = new File(this.getProject().getBuild().getDirectory());
}
try {
writeReports(engine, this.getProject(), outputDir);
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);

View File

@@ -1069,35 +1069,6 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
return format;
}
/**
* Generates the reports for a given dependency-check engine.
*
* @param engine a dependency-check engine
* @param p the Maven project
* @param outputDir the directory path to write the report(s)
* @throws ReportException thrown if there is an error writing the report
*/
protected void writeReports(Engine engine, MavenProject p, File outputDir) throws ReportException {
DatabaseProperties prop = null;
try (CveDB cve = CveDB.getInstance()) {
prop = cve.getDatabaseProperties();
} catch (DatabaseException ex) {
//TODO shouldn't this throw an exception?
if (getLog().isDebugEnabled()) {
getLog().debug("Unable to retrieve DB Properties", ex);
}
}
final ReportGenerator r = new ReportGenerator(p.getName(), p.getGroupId(), p.getArtifactId(), p.getVersion(),
engine.getDependencies(), engine.getAnalyzers(), prop);
try {
r.generateReports(outputDir.getAbsolutePath(), format);
} catch (ReportException ex) {
final String msg = String.format("Error generating the report for %s", p.getName());
throw new ReportException(msg, ex);
}
}
//<editor-fold defaultstate="collapsed" desc="Methods to fail build or show summary">
/**
* Checks to see if a vulnerability has been identified with a CVSS score

View File

@@ -25,6 +25,7 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.exception.ExceptionCollection;
@@ -99,19 +100,19 @@ public class CheckMojo extends BaseDependencyCheckMojo {
ExceptionCollection exCol = scanArtifacts(getProject(), engine);
if (engine.getDependencies().isEmpty()) {
getLog().info("No dependencies were identified that could be analyzed by dependency-check");
} else {
try {
engine.analyzeDependencies();
} catch (ExceptionCollection ex) {
if (this.isFailOnError() && ex.isFatal()) {
throw new MojoExecutionException("One or more exceptions occurred during analysis", ex);
}
exCol = ex;
}
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 {
writeReports(engine, getProject(), getCorrectOutputDirectory());
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) {

27
pom.xml
View File

@@ -288,7 +288,7 @@ Copyright (c) 2012 - Jeremy Long
<goal>prepare-agent</goal>
</goals>
<configuration>
<!--destFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</destFile-->
<destFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</destFile>
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
@@ -299,12 +299,31 @@ Copyright (c) 2012 - Jeremy Long
<goal>prepare-agent</goal>
</goals>
<configuration>
<!--destFile>${project.build.directory}/coverage-reports/jacoco-it.exec</destFile-->
<destFile>${project.build.directory}/coverage-reports/jacoco-it.exec</destFile>
<propertyName>failsafeArgLine</propertyName>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>add-dynamic-properties</id>
<phase>pre-integration-test</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
project.properties['invoker.mavenOpts']=project.properties.failsafeArgLine
</source>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
@@ -578,6 +597,10 @@ Copyright (c) 2012 - Jeremy Long
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.9</version>
<configuration>
<dataFileIncludes>
<dataFileInclude>target/coverage-reports/jacoco-ut.exec</dataFileInclude>
<dataFileInclude>target/coverage-reports/jacoco-it.exec</dataFileInclude>
</dataFileIncludes>
</configuration>
<reportSets>
<reportSet>

View File

@@ -20,8 +20,8 @@ To setup a centralized database the following generalized steps can be used:
<ol><li>Create the database and tables using either <a href="https://github.com/jeremylong/DependencyCheck/blob/master/dependency-check-core/src/main/resources/data/initialize.sql">initialize.sql</a>
or one of the other initialization scripts <a href="https://github.com/jeremylong/DependencyCheck/tree/master/dependency-check-core/src/main/resources/data">found here</a>.</li>
<li>The account that the clients will connect using must have select granted on the tables.
<ul><li>Note, if the clients performing the scans should run with the noupdate setting. A single
instance of the dependency-check client should be setup with update enabled and the account
<ul><li>Note, the clients performing the scans should run with the noupdate setting. A single
instance of the dependency-check client should be setup with updates enabled and the account
used during the update process will need to be granted update rights on the tables.
</li></ul>
</li><li>Dependency-check clients running scans will need to be configured to use the central database: