From 2333bee5fd2063abb7d660ff62a3a4fe27621485 Mon Sep 17 00:00:00 2001 From: Charlie Fairchild Date: Wed, 16 Nov 2016 11:25:21 -0500 Subject: [PATCH] Adds a command line option for the CLI tool to pick what CVSS error to fail on --- .../java/org/owasp/dependencycheck/App.java | 25 ++++++-- .../org/owasp/dependencycheck/CliParser.java | 29 +++++++++- .../owasp/dependencycheck/CliParserTest.java | 57 +++++++++++++++++++ 3 files changed, 105 insertions(+), 6 deletions(-) diff --git a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java index cddb8a3dc..7b195b7d8 100644 --- a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java +++ b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java @@ -33,6 +33,7 @@ import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; import org.owasp.dependencycheck.dependency.Dependency; import org.apache.tools.ant.DirectoryScanner; +import org.owasp.dependencycheck.dependency.Vulnerability; import org.owasp.dependencycheck.reporting.ReportGenerator; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; @@ -161,8 +162,8 @@ public class App { try { final String[] scanFiles = cli.getScanFiles(); if (scanFiles != null) { - runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getProjectName(), scanFiles, - cli.getExcludeList(), cli.getSymLinkDepth()); + exitCode = runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getProjectName(), scanFiles, + cli.getExcludeList(), cli.getSymLinkDepth(), cli.getFailOnCVSS()); } else { LOGGER.error("No scan files configured"); } @@ -203,6 +204,7 @@ public class App { * @param files the files/directories to scan * @param excludes the patterns for files/directories to exclude * @param symLinkDepth the depth that symbolic links will be followed + * @param cvssFailScore the score to fail on if a vulnerability is found * * @throws InvalidScanPathException thrown if the path to scan starts with * "//" @@ -213,9 +215,10 @@ public class App { * analysis; there may be multiple exceptions contained within the * collection. */ - private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files, - String[] excludes, int symLinkDepth) throws InvalidScanPathException, DatabaseException, ExceptionCollection, ReportException { + private int runScan(String reportDirectory, String outputFormat, String applicationName, String[] files, + String[] excludes, int symLinkDepth, int cvssFailScore) throws InvalidScanPathException, DatabaseException, ExceptionCollection, ReportException { Engine engine = null; + int retCode = 0; try { engine = new Engine(); final List antStylePaths = new ArrayList(); @@ -302,12 +305,24 @@ public class App { if (exCol != null && exCol.getExceptions().size() > 0) { throw exCol; } + + //Set the exit code based on whether we found a high enough vulnerability + for (Dependency dep : dependencies) { + if (dep.getVulnerabilities().size() != 0) { + for(Vulnerability vuln : dep.getVulnerabilities()) { + LOGGER.debug("VULNERABILITY FOUND " + dep.getDisplayFileName()); + if(vuln.getCvssScore() > cvssFailScore) + retCode = 1; + } + } + } + + return retCode; } finally { if (engine != null) { engine.cleanup(); } } - } /** diff --git a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/CliParser.java b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/CliParser.java index 863c58a90..5386744ca 100644 --- a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/CliParser.java +++ b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/CliParser.java @@ -289,6 +289,10 @@ public final class CliParser { .desc("Enables the experimental analzers.") .build(); + final Option failOnCVSS = Option.builder().hasArg().longOpt(ARGUMENT.FAIL_ON_CVSS) + .desc("Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11; since the CVSS scores are 0-10, by default the build will never fail.") + .build(); + //This is an option group because it can be specified more then once. final OptionGroup og = new OptionGroup(); og.addOption(path); @@ -311,7 +315,8 @@ public final class CliParser { .addOption(suppressionFile) .addOption(hintsFile) .addOption(cveValidForHours) - .addOption(experimentalEnabled); + .addOption(experimentalEnabled) + .addOption(failOnCVSS); } /** @@ -1105,6 +1110,24 @@ public final class CliParser { return line.hasOption(ARGUMENT.EXPERIMENTAL); } + /** + * Returns the CVSS value to fail on + * + * @return 11 if nothing is set. Otherwise it returns the int passed from the command line arg + */ + public int getFailOnCVSS() { + if(line.hasOption(ARGUMENT.FAIL_ON_CVSS)) { + String value = line.getOptionValue(ARGUMENT.FAIL_ON_CVSS); + try { + return Integer.parseInt(value); + } catch (NumberFormatException nfe) { + return 11; + } + } else { + return 11; + } + } + /** * A collection of static final strings that represent the possible command * line arguments. @@ -1408,5 +1431,9 @@ public final class CliParser { * The CLI argument to enable the experimental analyzers. */ private static final String EXPERIMENTAL = "enableExperimental"; + /** + * The CLI argument to enable the experimental analyzers. + */ + private static final String FAIL_ON_CVSS = "failOnCVSS"; } } diff --git a/dependency-check-cli/src/test/java/org/owasp/dependencycheck/CliParserTest.java b/dependency-check-cli/src/test/java/org/owasp/dependencycheck/CliParserTest.java index f9ab754ac..977971c66 100644 --- a/dependency-check-cli/src/test/java/org/owasp/dependencycheck/CliParserTest.java +++ b/dependency-check-cli/src/test/java/org/owasp/dependencycheck/CliParserTest.java @@ -115,6 +115,63 @@ public class CliParserTest { } + /** + * Test of parse method with failOnCVSS without an argument + * + * @throws Exception thrown when an exception occurs. + */ + @Test + public void testParse_failOnCVSSNoArg() throws Exception { + + String[] args = {"--failOnCVSS"}; + + CliParser instance = new CliParser(); + try { + instance.parse(args); + } catch (ParseException ex) { + Assert.assertTrue(ex.getMessage().contains("Missing argument")); + } + Assert.assertFalse(instance.isGetVersion()); + Assert.assertFalse(instance.isGetHelp()); + Assert.assertFalse(instance.isRunScan()); + } + + /** + * Test of parse method with failOnCVSS invalid argument. It should default to 11 + * + * @throws Exception thrown when an exception occurs. + */ + @Test + public void testParse_failOnCVSSInvalidArgument() throws Exception { + + String[] args = {"--failOnCVSS","bad"}; + + CliParser instance = new CliParser(); + instance.parse(args); + Assert.assertEquals("Default should be 11", 11, instance.getFailOnCVSS()); + Assert.assertFalse(instance.isGetVersion()); + Assert.assertFalse(instance.isGetHelp()); + Assert.assertFalse(instance.isRunScan()); + } + + /** + * Test of parse method with failOnCVSS invalid argument. It should default to 11 + * + * @throws Exception thrown when an exception occurs. + */ + @Test + public void testParse_failOnCVSSValidArgument() throws Exception { + + String[] args = {"--failOnCVSS","6"}; + + CliParser instance = new CliParser(); + instance.parse(args); + Assert.assertEquals(6, instance.getFailOnCVSS()); + Assert.assertFalse(instance.isGetVersion()); + Assert.assertFalse(instance.isGetHelp()); + Assert.assertFalse(instance.isRunScan()); + } + /** * Test of parse method with jar and cpe args, of class CliParser. *