diff --git a/Dockerfile b/Dockerfile index c311a3b6b..ecd4b02ee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,13 +2,28 @@ FROM java:8 MAINTAINER Timo Pagel -RUN wget -O /tmp/current.txt http://jeremylong.github.io/DependencyCheck/current.txt && current=$(cat /tmp/current.txt) && wget https://dl.bintray.com/jeremy-long/owasp/dependency-check-$current-release.zip && unzip dependency-check-$current-release.zip && mv dependency-check /usr/share/ +ENV user=dependencycheck +ENV version_url=https://jeremylong.github.io/DependencyCheck/current.txt +ENV download_url=https://dl.bintray.com/jeremy-long/owasp -RUN useradd -ms /bin/bash dockeruser && chown -R dockeruser:dockeruser /usr/share/dependency-check && mkdir /report && chown -R dockeruser:dockeruser /report -USER dockeruser +RUN wget -O /tmp/current.txt ${version_url} && \ + version=$(cat /tmp/current.txt) && \ + file="dependency-check-${version}-release.zip" && \ + wget "$download_url/$file" && \ + unzip ${file} && \ + rm ${file} && \ + mv dependency-check /usr/share/ -VOLUME "/src /usr/share/dependency-check/data /report" +RUN useradd -ms /bin/bash ${user} && \ + chown -R ${user}:${user} /usr/share/dependency-check && \ + mkdir /report && \ + chown -R ${user}:${user} /report + +USER ${user} + +VOLUME ["/src" "/usr/share/dependency-check/data" "/report"] WORKDIR /report -ENTRYPOINT ["/usr/share/dependency-check/bin/dependency-check.sh", "--scan", "/src"] +CMD ["--help"] +ENTRYPOINT ["/usr/share/dependency-check/bin/dependency-check.sh"] diff --git a/README.md b/README.md index 87a68fc54..f14f03c16 100644 --- a/README.md +++ b/README.md @@ -93,40 +93,46 @@ $ ./dependency-check-cli/target/release/bin/dependency-check.sh --project Testin On Windows ``` > mvn install -> dependency-check-cli/target/release/bin/dependency-check.bat -h -> dependency-check-cli/target/release/bin/dependency-check.bat --project Testing --out . --scan ./src/test/resources +> .\dependency-check-cli\target\release\bin\dependency-check.bat -h +> .\dependency-check-cli\target\release\bin\dependency-check.bat --project Testing --out . --scan ./src/test/resources ``` Then load the resulting 'DependencyCheck-Report.html' into your favorite browser. ### Docker -In the following example it is assumed that the source to be checked is in the actual directory. A persistent data directory and a persistent report directory is used so that the container can be destroyed after running it to make sure that you use the newest version, always. -``` -# After the first run, feel free to change the owner of the directories to the owner of the created files and the permissions to 744 -DATA_DIRECTORY=$HOME/OWASP-Dependency-Check/data -REPORT_DIRECTORY=/$HOME/OWASP-Dependency-Check/reports +In the following example it is assumed that the source to be checked is in the current working directory. Persistent data and report directories are used, allowing you to destroy the container after running. -if [ ! -d $DATA_DIRECTORY ]; then - echo "Initially creating persistent directories" - mkdir -p $DATA_DIRECTORY - chmod -R 777 $DATA_DIRECTORY - - mkdir -p $REPORT_DIRECTORY - chmod -R 777 $REPORT_DIRECTORY +``` +#!/bin/sh + +OWASPDC_DIRECTORY=$HOME/OWASP-Dependency-Check +DATA_DIRECTORY="$OWASPDC_DIRECTORY/data" +REPORT_DIRECTORY="$OWASPDC_DIRECTORY/reports" + +if [ ! -d "$DATA_DIRECTORY" ]; then + echo "Initially creating persistent directories" + mkdir -p "$DATA_DIRECTORY" + chmod -R 777 "$DATA_DIRECTORY" + + mkdir -p "$REPORT_DIRECTORY" + chmod -R 777 "$REPORT_DIRECTORY" fi -docker pull owasp/dependency-check # Make sure it is the actual version +# Make sure we are using the latest version +docker pull owasp/dependency-check docker run --rm \ - --volume $(pwd):/src \ - --volume $DATA_DIRECTORY:/usr/share/dependency-check/data \ - --volume $REPORT_DIRECTORY:/report \ - --name dependency-check \ - dc \ - --suppression "/src/security/dependency-check-suppression.xml"\ - --format "ALL" \ - --project "My OWASP Dependency Check Project" \ + --volume $(pwd):/src \ + --volume "$DATA_DIRECTORY":/usr/share/dependency-check/data \ + --volume "$REPORT_DIRECTORY":/report \ + owasp/dependency-check \ + --scan /src \ + --format "ALL" \ + --project "My OWASP Dependency Check Project" + # Use suppression like this: (/src == $pwd) + # --suppression "/src/security/dependency-check-suppression.xml" + ``` diff --git a/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java b/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java index 5cc1e8226..d69b3ecbe 100644 --- a/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java +++ b/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java @@ -146,7 +146,7 @@ public class Check extends Update { private boolean updateOnly = false; /** - * The report format to be generated (HTML, XML, VULN, ALL). Default is + * The report format to be generated (HTML, XML, VULN, CSV, JSON, ALL). Default is * HTML. */ private String reportFormat = "HTML"; @@ -1102,7 +1102,7 @@ public class Check extends Update { } /** - * An enumeration of supported report formats: "ALL", "HTML", "XML", "VULN", + * An enumeration of supported report formats: "ALL", "HTML", "XML", "CSV", "JSON", "VULN", * etc.. */ public static class ReportFormats extends EnumeratedAttribute { diff --git a/dependency-check-ant/src/site/markdown/configuration.md b/dependency-check-ant/src/site/markdown/configuration.md index c7639323a..8b0b84634 100644 --- a/dependency-check-ant/src/site/markdown/configuration.md +++ b/dependency-check-ant/src/site/markdown/configuration.md @@ -36,11 +36,11 @@ cveValidForHours | Sets the number of hours to wait before checking for new failBuildOnCVSS | 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. | 11 failOnError | Whether the build should fail if there is an error executing the dependency-check analysis | true projectName | The name of the project being scanned. | Dependency-Check -reportFormat | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML +reportFormat | The report format to be generated (HTML, XML, CSV, JSON, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML reportOutputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target' suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html) |   -hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) |   -proxyServer | The Proxy Server; see the [proxy configuration](../data/proxy.html) page for more information. |   +hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) |   +proxyServer | The Proxy Server; see the [proxy configuration](../data/proxy.html) page for more information. |   proxyPort | The Proxy Port. |   proxyUsername | Defines the proxy user name. |   proxyPassword | Defines the proxy password. |   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 5be1c2d92..c259e50d0 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 @@ -120,7 +120,7 @@ public final class CliParser { Format.valueOf(format); } catch (IllegalArgumentException ex) { final String msg = String.format("An invalid 'format' of '%s' was specified. " - + "Supported output formats are XML, HTML, VULN, or ALL", format); + + "Supported output formats are HTML, XML, CSV, JSON, VULN, or ALL", format); throw new ParseException(msg); } } @@ -262,7 +262,7 @@ public final class CliParser { .build(); final Option outputFormat = Option.builder(ARGUMENT.OUTPUT_FORMAT_SHORT).argName("format").hasArg().longOpt(ARGUMENT.OUTPUT_FORMAT) - .desc("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.") + .desc("The output format to write to (XML, JSON, HTML, VULN, ALL). The default is HTML.") .build(); final Option verboseLog = Option.builder(ARGUMENT.VERBOSE_LOG_SHORT).argName("file").hasArg().longOpt(ARGUMENT.VERBOSE_LOG) diff --git a/dependency-check-cli/src/site/markdown/arguments.md b/dependency-check-cli/src/site/markdown/arguments.md index 48ca5b765..048c1f193 100644 --- a/dependency-check-cli/src/site/markdown/arguments.md +++ b/dependency-check-cli/src/site/markdown/arguments.md @@ -4,22 +4,22 @@ Command Line Arguments The following table lists the command line arguments: Short | Argument Name   | Parameter | Description | Requirement --------|-----------------------|-----------------|-------------|------------ - | \-\-project | \ | The name of the project being scanned. | Required - \-s | \-\-scan | \ | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. directory/**/*.jar). | Required - | \-\-exclude | \ | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**). | Optional - | \-\-symLink | \ | The depth that symbolic links will be followed; the default is 0 meaning symbolic links will not be followed. | Optional - \-o | \-\-out | \ | The folder to write reports to. This defaults to the current directory. If the format is not set to ALL one could specify a specific file name. | Optional - \-f | \-\-format | \ | The output format to write to (XML, HTML, VULN, ALL). The default is HTML. | Required - | \-\-failOnCvss | \ | If the score set between 0 and 10 the exit code from dependency-check will indicate if a vulnerability with a CVSS score equal to or higher was identified. | Optional - \-l | \-\-log | \ | The file path to write verbose logging information. | Optional - \-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional - | \-\-suppression | \ | The file path to the suppression XML file; used to suppress [false positives](../general/suppression.html). | Optional - \-h | \-\-help | | Print the help message. | Optional - | \-\-advancedHelp | | Print the advanced help message. | Optional - \-v | \-\-version | | Print the version information. | Optional - | \-\-cveValidForHours | \ | The number of hours to wait before checking for new updates from the NVD. The default is 4 hours. | Optional - | \-\-experimental | | Enable the [experimental analyzers](../analyzers/index.html). If not set the analyzers marked as experimental below will not be loaded or used. | Optional +-------|------------------------|-----------------|-------------|------------ + | \-\-project | \ | The name of the project being scanned. | Required + \-s | \-\-scan | \ | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. directory/**/*.jar). | Required + | \-\-exclude | \ | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**). | Optional + | \-\-symLink | \ | The depth that symbolic links will be followed; the default is 0 meaning symbolic links will not be followed. | Optional + \-o | \-\-out | \ | The folder to write reports to. This defaults to the current directory. If the format is not set to ALL one could specify a specific file name. | Optional + \-f | \-\-format | \ | The output format to write to (XML, HTML, CSV, JSON, VULN, ALL). The default is HTML. | Required + | \-\-failOnCvss | \ | If the score set between 0 and 10 the exit code from dependency-check will indicate if a vulnerability with a CVSS score equal to or higher was identified. | Optional + \-l | \-\-log | \ | The file path to write verbose logging information. | Optional + \-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional + | \-\-suppression | \ | The file path to the suppression XML file; used to suppress [false positives](../general/suppression.html). | Optional + \-h | \-\-help | | Print the help message. | Optional + | \-\-advancedHelp | | Print the advanced help message. | Optional + \-v | \-\-version | | Print the version information. | Optional + | \-\-cveValidForHours | \ | The number of hours to wait before checking for new updates from the NVD. The default is 4 hours. | Optional + | \-\-enableExperimental | | Enable the [experimental analyzers](../analyzers/index.html). If not set the analyzers marked as experimental below will not be loaded or used. | Optional Advanced Options ================ diff --git a/dependency-check-core/pom.xml b/dependency-check-core/pom.xml index 7cb0cee7f..47db9f89c 100644 --- a/dependency-check-core/pom.xml +++ b/dependency-check-core/pom.xml @@ -253,6 +253,10 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. com.sun.mail mailapi + + com.google.code.gson + gson + org.apache.maven.scm @@ -383,6 +387,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. test true + @@ -571,13 +576,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. test true - - com.google.code.gson - gson - 2.3.1 - test - true - com.google.gerrit gerrit-extension-api diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java index 60b577582..5659a4376 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java @@ -182,8 +182,8 @@ public class NvdCveUpdater implements CachedWebDataSource { LOGGER.trace("Ignorable exception", ex); } } - if (lockFile != null) { - lockFile.delete(); + if (lockFile != null && lockFile.isFile() && !lockFile.delete()) { + LOGGER.error("Lock file '{}' was unable to be deleted. Please manually delete this file.", lockFile.toString()); } } } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/DependencyNotFoundException.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/DependencyNotFoundException.java new file mode 100644 index 000000000..3406b9900 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/exception/DependencyNotFoundException.java @@ -0,0 +1,66 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2017 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.exception; + +/** + * An exception used when a dependency could not be found. + * + * @author Jeremy Long + */ +public class DependencyNotFoundException extends Exception { + + /** + * The serial version uid. + */ + private static final long serialVersionUID = 1L; + + /** + * Creates a new DependencyNotFoundException. + */ + public DependencyNotFoundException() { + super(); + } + + /** + * Creates a new DependencyNotFoundException. + * + * @param msg a message for the exception. + */ + public DependencyNotFoundException(String msg) { + super(msg); + } + + /** + * Creates a new DependencyNotFoundException. + * + * @param ex the cause of the exception. + */ + public DependencyNotFoundException(Throwable ex) { + super(ex); + } + + /** + * Creates a new DependencyNotFoundException. + * + * @param msg a message for the exception. + * @param ex the cause of the exception. + */ + public DependencyNotFoundException(String msg, Throwable ex) { + super(msg, ex); + } +} diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/reporting/EscapeTool.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/reporting/EscapeTool.java index 4a7a2b491..48014183a 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/reporting/EscapeTool.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/reporting/EscapeTool.java @@ -19,13 +19,16 @@ package org.owasp.dependencycheck.reporting; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.util.Set; import org.apache.commons.lang3.StringEscapeUtils; +import org.owasp.dependencycheck.dependency.Identifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * An extremely simple wrapper around various escape utils to perform URL and HTML encoding within the reports. This class was - * created to simplify the velocity configuration and avoid using the "built-in" escape tool. + * An extremely simple wrapper around various escape utils to perform URL and + * HTML encoding within the reports. This class was created to simplify the + * velocity configuration and avoid using the "built-in" escape tool. * * @author Jeremy Long */ @@ -80,4 +83,84 @@ public class EscapeTool { } return StringEscapeUtils.escapeXml11(text); } + + /** + * JSON Encodes the provided text. + * + * @param text the text to encode + * @return the JSON encoded text + */ + public String json(String text) { + if (text == null || text.isEmpty()) { + return text; + } + return StringEscapeUtils.escapeJson(text); + } + + /** + * Formats text for CSV format. This includes trimming whitespace, replace + * line breaks with spaces, and if necessary quotes the text and/or escapes + * contained quotes. + * + * @param text the text to escape and quote + * @return the escaped and quoted text + */ + public String csv(String text) { + if (text == null || text.isEmpty()) { + return text; + } + return StringEscapeUtils.escapeCsv(text.trim().replace("\n", " ")); + } + + /** + * Takes a set of Identifiers, filters them to none CPE, and formats them + * for display in a CSV. + * + * @param ids the set of identifiers + * @return the formated list of none CPE identifiers + */ + public String csvIdentifiers(Set ids) { + if (ids == null || ids.isEmpty()) { + return ""; + } + boolean addComma = false; + StringBuilder sb = new StringBuilder(); + for (Identifier id : ids) { + if (!"cpe".equals(id.getType())) { + if (addComma) { + sb.append(", "); + } else { + addComma = true; + } + sb.append(id.getValue()); + } + } + return StringEscapeUtils.escapeCsv(sb.toString()); + } + + /** + * Takes a set of Identifiers, filters them to just CPEs, and formats them + * for display in a CSV. + * + * @param ids the set of identifiers + * @return the formated list of CPE identifiers + */ + public String csvCpe(Set ids) { + if (ids == null || ids.isEmpty()) { + return ""; + } + boolean addComma = false; + StringBuilder sb = new StringBuilder(); + for (Identifier id : ids) { + if ("cpe".equals(id.getType())) { + if (addComma) { + sb.append(", "); + } else { + addComma = true; + } + sb.append(id.getValue()); + } + } + return StringEscapeUtils.escapeCsv(sb.toString()); + } } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java index 539cbbc85..b8acd2557 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java @@ -17,17 +17,16 @@ */ package org.owasp.dependencycheck.reporting; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.UnsupportedEncodingException; +import java.io.*; import java.util.List; + +import com.google.gson.JsonSyntaxException; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import static com.google.gson.stream.JsonToken.*; +import com.google.gson.stream.JsonWriter; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.context.Context; @@ -78,7 +77,15 @@ public class ReportGenerator { /** * Generate HTML Vulnerability report. */ - VULN + VULN, + /** + * Generate JSON report. + */ + JSON, + /** + * Generate CSV report. + */ + CSV } /** * The Velocity Engine. @@ -129,24 +136,23 @@ public class ReportGenerator { * Constructs a new ReportGenerator. * * @param applicationName the application name being analyzed - * @param applicationVersion the application version being analyzed - * @param artifactID the application version being analyzed - * @param applicationVersion the application version being analyzed + * @param groupID the group id of the project being analyzed + * @param artifactID the application id of the project being analyzed + * @param version the application version of the project 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) */ + public ReportGenerator(String applicationName, String groupID, String artifactID, String version, + List dependencies, List analyzers, DatabaseProperties properties) { - public ReportGenerator(String applicationName,String applicationVersion,String artifactID,String groupID, List dependencies, List analyzers, DatabaseProperties properties) { - - this(applicationName,dependencies,analyzers,properties); - context.put("applicationVersion",applicationVersion); - context.put("artifactID",artifactID); - context.put("groupID",groupID); + this(applicationName, dependencies, analyzers, properties); + context.put("applicationVersion", version); + context.put("artifactID", artifactID); + context.put("groupID", groupID); } - /** * Creates a new Velocity Engine. * @@ -186,6 +192,12 @@ public class ReportGenerator { 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); + } } /** @@ -200,6 +212,13 @@ public class ReportGenerator { if (format == Format.XML || format == Format.ALL) { generateReport("XmlReport", outputDir + File.separator + "dependency-check-report.xml"); } + 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 (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"); } @@ -208,6 +227,91 @@ public class ReportGenerator { } } + /** + * Reformats the given JSON file. + * + * @param pathToJson the path to the JSON file to be reformatted + * @throws JsonSyntaxException thrown if the given JSON file is malformed + */ + private void pretifyJson(String pathToJson) throws JsonSyntaxException { + final String outputPath = pathToJson + ".pretty"; + final File in = new File(pathToJson); + final File out = new File(outputPath); + try (JsonReader reader = new JsonReader(new InputStreamReader(new FileInputStream(in), StandardCharsets.UTF_8)); + JsonWriter writer = new JsonWriter(new OutputStreamWriter(new FileOutputStream(out), StandardCharsets.UTF_8))) { + prettyPrint(reader, writer); + } catch (IOException ex) { + LOGGER.error("Unable to generate pretty report, caused by: ", ex.getMessage()); + return; + } + if (out.isFile() && in.isFile() && in.delete()) { + try { + org.apache.commons.io.FileUtils.moveFile(out, in); + } catch (IOException ex) { + LOGGER.error("Unable to generate pretty report, caused by: ", ex.getMessage()); + } + } + } + + /** + * Streams from a json reader to a json writer and performs pretty printing. + * + * This function is copied from https://sites.google.com/site/gson/streaming + * + * @param reader json reader + * @param writer json writer + * @throws IOException thrown if the json is malformed + */ + private static void prettyPrint(JsonReader reader, JsonWriter writer) throws IOException { + writer.setIndent(" "); + while (true) { + final JsonToken token = reader.peek(); + switch (token) { + case BEGIN_ARRAY: + reader.beginArray(); + writer.beginArray(); + break; + case END_ARRAY: + reader.endArray(); + writer.endArray(); + break; + case BEGIN_OBJECT: + reader.beginObject(); + writer.beginObject(); + break; + case END_OBJECT: + reader.endObject(); + writer.endObject(); + break; + case NAME: + final String name = reader.nextName(); + writer.name(name); + break; + case STRING: + final String s = reader.nextString(); + writer.value(s); + break; + case NUMBER: + final String n = reader.nextString(); + writer.value(new BigDecimal(n)); + break; + case BOOLEAN: + final boolean b = reader.nextBoolean(); + writer.value(b); + break; + case NULL: + reader.nextNull(); + writer.nullValue(); + break; + case END_DOCUMENT: + return; + default: + LOGGER.debug("Unexpected JSON toekn {}", token.toString()); + break; + } + } + } + /** * Generates the Dependency Reports for the identified dependencies. * @@ -220,7 +324,7 @@ public class ReportGenerator { 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|ALL)$")) { + if (format.matches("^(XML|HTML|VULN|JSON|ALL)$")) { if ("XML".equalsIgnoreCase(format)) { if (pathToCheck.endsWith(".xml")) { generateReport("XmlReport", outputDir); @@ -242,6 +346,21 @@ public class ReportGenerator { 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); } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomParser.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomParser.java index 3b81e1591..8de5bcb2e 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomParser.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomParser.java @@ -62,7 +62,7 @@ public class PomParser { return parse(fis); } catch (IOException ex) { LOGGER.debug("", ex); - throw new PomParseException(ex); + throw new PomParseException(String.format("Unable to parse pom '%s'", file.toString()), ex); } } diff --git a/dependency-check-core/src/main/resources/dependencycheck-base-suppression.xml b/dependency-check-core/src/main/resources/dependencycheck-base-suppression.xml index 481048c12..2234195fa 100644 --- a/dependency-check-core/src/main/resources/dependencycheck-base-suppression.xml +++ b/dependency-check-core/src/main/resources/dependencycheck-base-suppression.xml @@ -1,5 +1,13 @@ + + + .*EntityFramework\.SqlServer*\.dll + cpe:/a:microsoft:server:6.0.0.0 + cpe:/a:microsoft:sql_server:6.0 + ^org\.springframework\.boot:spring-boot-starter-data-jpa:.*$ CVE-2016-6652 + + + ^com\.splunk:splunk:.*$ + cpe:/a:splunk:splunk + + + + ^org\.openid4java:openid4java:.*$ + cpe:/a:openid:openid + cpe:/a:openid:openid4java + + + + ^org\.springframework\.cloud:spring-cloud-netflix-core:.*$ + cpe:/a:pivotal:spring_framework + cpe:/a:pivotal_software:spring_framework + + + + ^org\.springframework\.cloud:spring-cloud-.*$ + cpe:/a:pivotal:spring_framework + cpe:/a:pivotal_software:spring_framework + cpe:/a:context_project:context + diff --git a/dependency-check-core/src/main/resources/templates/CsvReport.vsl b/dependency-check-core/src/main/resources/templates/CsvReport.vsl new file mode 100644 index 000000000..99c2758a1 --- /dev/null +++ b/dependency-check-core/src/main/resources/templates/CsvReport.vsl @@ -0,0 +1,27 @@ +#** +This file is part of Dependency-Check. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Copyright (c) 2017 Jeremy Long. All Rights Reserved. + +@author Jeremy Long +@version 1 *### +"Project","ScanDate","DependencyName","DependencyPath","Description","License","Md5","Sha1","Identifiers","CPE","CVE","CWE","Vulnerability","Severity","CVSSv2" +#macro(writeSev $score)#if($score<4.0)"Low"#elseif($score>=7.0)"High"#else"Medium"#end#end +#foreach($dependency in $dependencies)#if($dependency.getVulnerabilities().size()>0) +#foreach($vuln in $dependency.getVulnerabilities()) +$enc.csv($applicationName),$enc.csv($scanDate),$enc.csv($dependency.DisplayFileName),#if($dependency.FilePath)$enc.csv($dependency.FilePath)#end,#if($dependency.description)$enc.csv($dependency.description)#end,#if($dependency.license)$enc.csv($dependency.license)#end,#if($dependency.Md5sum)$enc.csv($dependency.Md5sum)#end,#if($dependency.Sha1sum)$enc.csv($dependency.Sha1sum)#end,#if($dependency.identifiers)$enc.csvIdentifiers($dependency.identifiers)#end,#if($dependency.identifiers)$enc.csvCpe($dependency.identifiers)#end,#if($vuln.name)$enc.csv($vuln.name)#end,#if($dependency.cwe)$enc.csv($vuln.cwe)#end,#if($vuln.description)$enc.csv($vuln.description)#end,#writeSev($vuln.cvssScore),$vuln.cvssScore +#end +#end +#end \ No newline at end of file diff --git a/dependency-check-core/src/main/resources/templates/HtmlReport.vsl b/dependency-check-core/src/main/resources/templates/HtmlReport.vsl index 8283a443a..b065e8a58 100644 --- a/dependency-check-core/src/main/resources/templates/HtmlReport.vsl +++ b/dependency-check-core/src/main/resources/templates/HtmlReport.vsl @@ -632,7 +632,7 @@ Getting Help: - $enc.html($dependency.DisplayFileName) + $enc.html($dependency.DisplayFileName) #set($mavenlink="") #set($cpeIdCount=0) #set($cpeIdConf="") @@ -673,9 +673,9 @@ Getting Help: #else - #if( $mavenlink.url ) + #if( $mavenlink.url ) ##yes, we are HTML Encoding the href. This is okay. We can't URL encode as we have to trust the analyzer here... - $enc.html($mavenlink.value) + $enc.html($mavenlink.value)  #elseif ($mavenlink.value) $enc.html($mavenlink.value) #end @@ -762,10 +762,10 @@ Getting Help: SHA1: $enc.html($related.Sha1sum)
  • MD5: $enc.html($related.Md5sum)
  • #foreach($id in $related.getIdentifiers()) - #if ($id.type=="maven") - #if( $id.url ) + #if( $id.url ) + #if ($id.type=="maven") ##yes, we are HTML Encoding the href. this is okay. We can't URL encode as we have to trust the analyzer here... -
  • $enc.html($id.type): $enc.html($id.value) +
  • $enc.html($id.type): $enc.html($id.value)  #else
  • $enc.html($id.type): $enc.html($id.value) #end @@ -800,8 +800,12 @@ Getting Help: $enc.html($id.type): $enc.html($id.value)  + #else
  • $enc.html($id.type): $enc.html($id.value) + #end #else
  • $enc.html($id.type): $enc.html($id.value) #end @@ -949,8 +953,12 @@ Getting Help: #foreach($id in $dependency.getSuppressedIdentifiers()) #if( $id.url ) + #if($id.type=="maven") ##yes, we are HTML Encoding the href. this is okay. We can't URL encode as we have to trust the analyzer here... +
  • $enc.html($id.type): $enc.html($id.value)   suppressed + #else
  • $enc.html($id.type): $enc.html($id.value)  suppressed + #end #else
  • $enc.html($id.type): $enc.html($id.value)  suppressed #end diff --git a/dependency-check-core/src/main/resources/templates/JsonReport.vsl b/dependency-check-core/src/main/resources/templates/JsonReport.vsl new file mode 100644 index 000000000..5bf5c1aad --- /dev/null +++ b/dependency-check-core/src/main/resources/templates/JsonReport.vsl @@ -0,0 +1,198 @@ +{ + "reportSchema": "1.0", + "analysis": { + "scanInfo": { + "engineVersion": "$version", + "dataSource": [ + #foreach($prop in $properties.getMetaData().entrySet()) + #if($foreach.count > 1),#end{ + "name": "$enc.json($prop.key)", + "timestamp": "$enc.json($prop.value)" + } + #end + ] + }, + "projectInfo": { + "name": "$enc.json($applicationName)", + #if($groupID)"groupID":"$enc.json($groupID)",#end + #if($artifactID)"artifactID":"$enc.json($artifactID)",#end + #if($version)"version":"$enc.json($version)",#end + "reportDate": "$scanDateXML", + "credits": "This report contains data retrieved from the National Vulnerability Database: http://nvd.nist.gov" + }, + "dependencies": [ + #foreach($dependency in $dependencies)#if($foreach.count > 1),#end{ + "fileName": "$enc.json($dependency.DisplayFileName)", + "filePath": "$enc.json($dependency.FilePath)", + "md5": "$enc.json($dependency.Md5sum)", + "sha1": "$enc.json($dependency.Sha1sum)" + #if($dependency.description),"description": "$enc.json($dependency.description)"#end + #if($dependency.license),"license": "$enc.json($dependency.license)"#end + #if ($dependency.getRelatedDependencies().size()>0) + ,"relatedDependencies": [ + #foreach($related in $dependency.getRelatedDependencies()) #if($foreach.count > 1),#end { + "filePath": "$enc.json($related.FilePath)", + "sha1": "$enc.json($related.Sha1sum)", + "md5": "$enc.json($related.Md5sum)"#if($related.getIdentifiers()),#end + "identifiers": [ + #foreach($id in $related.getIdentifiers()) + #if ($id.type=="maven") + { + "type": "$enc.json($id.type)", + "name": "$id.value" + #if( $id.url ),"url": "$enc.json($id.url)"#end + #if ($id.notes),"notes": "$enc.json($id.notes)"#end + } + #end + #end + ] + } + #end + ] + #end + ,"evidenceCollected": { + "vendorEvidence": [ + #foreach($evidence in $dependency.getVendorEvidence()) + #if($foreach.count > 1),#end{ + "type": "vendor", + "confidence": "$enc.json($evidence.getConfidence().toString())", + "source": "$enc.json($evidence.getSource())", + "name": "$enc.json($evidence.getName())", + "value": "$enc.json($evidence.getValue().trim())" + } + #end + ], + "productEvidence": [ + #foreach($evidence in $dependency.getProductEvidence()) + #if($foreach.count > 1),#end{ + "type": "product", + "confidence": "$enc.json($evidence.getConfidence().toString())", + "source": "$enc.json($evidence.getSource())", + "name": "$enc.json($evidence.getName())", + "value": "$enc.json($evidence.getValue().trim())" + } + #end + ], + "versionEvidence": [ + #foreach($evidence in $dependency.getVersionEvidence()) + #if($foreach.count > 1),#end{ + "type": "version", + "confidence": "$enc.json($evidence.getConfidence().toString())", + "source": "$enc.json($evidence.getSource())", + "name": "$enc.json($evidence.getName())", + "value": "$enc.json($evidence.getValue().trim())" + } + #end + ] + }, + "identifiers": [ + #foreach($id in $dependency.getIdentifiers())#if($foreach.count > 1),#end{ + "name": "$id.value", + "type": "$enc.json($id.type)", + #if($id.confidence)"confidence": "$id.confidence",#end + #if($id.url)"url": "$enc.json($id.url)",#end + #if($id.description )"description": "$enc.json($id.description)",#end + #if ($id.notes)"notes": "$enc.json($id.notes)",#end + "suppressedIdentifiers": [ + #foreach($id in $dependency.getSuppressedIdentifiers()) + #if($foreach.count > 1),#end{ + "type": "$enc.json($id.type)", + #if($id.confidence)"confidence": "$id.confidence",#end + "name": "$id.value", + #if($id.url)"url": "$enc.json($id.url),"#end + #if($id.description)"description": "$enc.json($id.description)",#end + #if ($id.notes)"notes": "$enc.json($id.notes)"#end + } + #end + ] + } + #end + ] + #if($dependency.getVulnerabilities().size()>0 || $dependency.getSuppressedVulnerabilities().size()>0) + ,"vulnerabilities": [ + #foreach($vuln in $dependency.getVulnerabilities()) + #if($foreach.count > 1),#end { + "name": "$enc.json($vuln.name)", + "cvssScore": "$vuln.cvssScore", + "cvssAccessVector": "$enc.json($vuln.cvssAccessVector)", + "cvssAccessComplexity": "$enc.json($vuln.cvssAccessComplexity)", + "cvssAuthenticationr": "$enc.json($vuln.cvssAuthentication)", + "cvssConfidentialImpact": "$enc.json($vuln.cvssConfidentialityImpact)", + "cvssIntegrityImpact": "$enc.json($vuln.cvssIntegrityImpact)", + "cvssAvailabilityImpact": "$enc.json($vuln.cvssAvailabilityImpact)", + #if ($vuln.cvssScore<4.0) + "severity": "Low", + #elseif ($vuln.cvssScore>=7.0) + "severity": "High", + #else + "severity": "Medium", + #end + #if($vuln.cwe)"cwe": "$enc.json($vuln.cwe)",#end + "description": "$enc.json($vuln.description)", + #if ($vuln.notes)"notes": "$enc.json($vuln.notes)"#end + "references": [ + #foreach($ref in $vuln.getReferences()) + #if($foreach.count > 1),#end { + "source": "$enc.json($ref.source)", + "url": "$enc.json($ref.url)", + "name": "$enc.json($ref.name)" + } + #end + ], + "vulnerableSoftware": [ + #foreach($vs in $vuln.getVulnerableSoftware()) + #if($foreach.count > 1),#end { + #if($vs.hasPreviousVersion()) "allPreviousVersion": "true",#end + "software": "$enc.json($vs.name)" + } + #end + ] + }#end + ] + #end + + #if($dependency.getSuppressedVulnerabilities().size()>0 || $dependency.getSuppressedVulnerabilities().size()>0) + ,"suppressedVulnerabilities": [ + #foreach($vuln in $dependency.getSuppressedVulnerabilities())#if($foreach.count > 1),#end { + "name": "$enc.json($vuln.name)", + "cvssScore": "$vuln.cvssScore", + "cvssAccessVector": "$enc.json($vuln.cvssAccessVector)", + "cvssAccessComplexity": "$enc.json($vuln.cvssAccessComplexity)", + "cvssAuthenticationr": "$enc.json($vuln.cvssAuthentication)", + "cvssConfidentialImpact": "$enc.json($vuln.cvssConfidentialityImpact)", + "cvssIntegrityImpact": "$enc.json($vuln.cvssIntegrityImpact)", + "cvssAvailabilityImpact": "$enc.json($vuln.cvssAvailabilityImpact)", + #if ($vuln.cvssScore<4.0) "severity": "Low", + #elseif ($vuln.cvssScore>=7.0) "severity": "High", + #else "severity": "Medium", + #end + #if ($vuln.cwe)"cwe": "$enc.json($vuln.cwe)",#end + "description": "$enc.json($vuln.description)" + #if ($vuln.notes),"notes": "$enc.json($vuln.notes)"#end + ,"references": [ + #foreach($ref in $vuln.getReferences()) + #if($foreach.count > 1),#end { + "source": "$enc.json($ref.source)", + "url": "$enc.json($ref.url)", + "name": "$enc.json($ref.name)" + } + #end + ], + "vulnerableSoftware": [ + #foreach($vs in $vuln.getVulnerableSoftware()) + #if($foreach.count > 1),#end { + #if($vs.hasPreviousVersion()) "allPreviousVersion": "true",#end + "name": "$enc.json($vs.name)" + } + #end + ] + } + #end + ] + #end + + } + #end + ] + } +} diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/reporting/EscapeToolTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/reporting/EscapeToolTest.java new file mode 100644 index 000000000..04eda668c --- /dev/null +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/reporting/EscapeToolTest.java @@ -0,0 +1,231 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2017 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.reporting; + +import java.util.HashSet; +import java.util.Set; +import org.junit.Test; +import static org.junit.Assert.*; +import org.owasp.dependencycheck.dependency.Identifier; + +/** + * + * @author jerem + */ +public class EscapeToolTest { + + /** + * Test of url method, of class EscapeTool. + */ + @Test + public void testUrl() { + String text = null; + EscapeTool instance = new EscapeTool(); + String expResult = null; + String result = instance.url(text); + assertEquals(expResult, result); + + text = ""; + expResult = ""; + result = instance.url(text); + assertEquals(expResult, result); + + text = " "; + expResult = "+"; + result = instance.url(text); + assertEquals(expResult, result); + } + + /** + * Test of html method, of class EscapeTool. + */ + @Test + public void testHtml() { + EscapeTool instance = new EscapeTool(); + String text = null; + String expResult = null; + String result = instance.html(text); + assertEquals(expResult, result); + + text = ""; + expResult = ""; + result = instance.html(text); + assertEquals(expResult, result); + + text = "
    "; + expResult = "<div>"; + result = instance.html(text); + assertEquals(expResult, result); + } + + /** + * Test of xml method, of class EscapeTool. + */ + @Test + public void testXml() { + EscapeTool instance = new EscapeTool(); + String text = null; + String expResult = null; + String result = instance.xml(text); + assertEquals(expResult, result); + + text = ""; + expResult = ""; + result = instance.xml(text); + assertEquals(expResult, result); + + text = "
    "; + expResult = "<div>"; + result = instance.xml(text); + assertEquals(expResult, result); + } + + /** + * Test of json method, of class EscapeTool. + */ + @Test + public void testJson() { + String text = null; + EscapeTool instance = new EscapeTool(); + String expResult = null; + String result = instance.json(text); + assertEquals(expResult, result); + + text = ""; + expResult = ""; + result = instance.json(text); + assertEquals(expResult, result); + + text = "test \"quote\"\""; + expResult = "test \\\"quote\\\"\\\""; + result = instance.json(text); + assertEquals(expResult, result); + } + + /** + * Test of csv method, of class EscapeTool. + */ + @Test + public void testCsv() { + String text = null; + EscapeTool instance = new EscapeTool(); + String expResult = null; + String result = instance.csv(text); + assertEquals(expResult, result); + + text = ""; + expResult = ""; + result = instance.csv(text); + assertEquals(expResult, result); + + text = "one, two"; + expResult = "\"one, two\""; + result = instance.csv(text); + assertEquals(expResult, result); + } + + /** + * Test of csvIdentifiers method, of class EscapeTool. + */ + @Test + public void testCsvIdentifiers() { + EscapeTool instance = new EscapeTool(); + Set ids = null; + String expResult = ""; + String result = instance.csvIdentifiers(ids); + assertEquals(expResult, result); + + ids = new HashSet<>(); + expResult = ""; + result = instance.csvIdentifiers(ids); + assertEquals(expResult, result); + + ids = new HashSet<>(); + ids.add(new Identifier("cpe", "cpe:/a:somegroup:something:1.0", "")); + expResult = ""; + result = instance.csvIdentifiers(ids); + assertEquals(expResult, result); + + ids = new HashSet<>(); + ids.add(new Identifier("gav", "somegroup:something:1.0", "")); + expResult = "somegroup:something:1.0"; + result = instance.csvIdentifiers(ids); + assertEquals(expResult, result); + + ids = new HashSet<>(); + ids.add(new Identifier("cpe", "cpe:/a:somegroup:something:1.0", "")); + ids.add(new Identifier("gav", "somegroup:something:1.0", "")); + expResult = "somegroup:something:1.0"; + result = instance.csvIdentifiers(ids); + assertEquals(expResult, result); + + ids = new HashSet<>(); + ids.add(new Identifier("cpe", "cpe:/a:somegroup:something:1.0", "")); + ids.add(new Identifier("gav", "somegroup:something:1.0", "")); + ids.add(new Identifier("gav", "somegroup2:something:1.2", "")); + expResult = "\"somegroup:something:1.0, somegroup2:something:1.2\""; + String expResult2 = "\"somegroup2:something:1.2, somegroup:something:1.0\""; + result = instance.csvIdentifiers(ids); + assertTrue(expResult.equals(result) || expResult2.equals(result)); + } + + /** + * Test of csvCpe method, of class EscapeTool. + */ + @Test + public void testCsvCpe() { + EscapeTool instance = new EscapeTool(); + Set ids = null; + String expResult = ""; + String result = instance.csvCpe(ids); + assertEquals(expResult, result); + + ids = new HashSet<>(); + expResult = ""; + result = instance.csvCpe(ids); + assertEquals(expResult, result); + + ids = new HashSet<>(); + ids.add(new Identifier("gav", "somegroup:something:1.0", "")); + expResult = ""; + result = instance.csvCpe(ids); + assertEquals(expResult, result); + + ids = new HashSet<>(); + ids.add(new Identifier("cpe", "cpe:/a:somegroup:something:1.0", "")); + expResult = "cpe:/a:somegroup:something:1.0"; + result = instance.csvCpe(ids); + assertEquals(expResult, result); + + ids = new HashSet<>(); + ids.add(new Identifier("cpe", "cpe:/a:somegroup:something:1.0", "")); + ids.add(new Identifier("gav", "somegroup:something:1.0", "")); + expResult = "cpe:/a:somegroup:something:1.0"; + result = instance.csvCpe(ids); + assertEquals(expResult, result); + + ids = new HashSet<>(); + ids.add(new Identifier("cpe", "cpe:/a:somegroup:something:1.0", "")); + ids.add(new Identifier("gav", "somegroup:something:1.0", "")); + ids.add(new Identifier("cpe", "cpe:/a:somegroup2:something:1.2", "")); + expResult = "\"cpe:/a:somegroup:something:1.0, cpe:/a:somegroup2:something:1.2\""; + String expResult2 = "\"cpe:/a:somegroup2:something:1.2, cpe:/a:somegroup:something:1.0\""; + result = instance.csvCpe(ids); + assertTrue(expResult.equals(result) || expResult2.equals(result)); + } +} diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/reporting/ReportGeneratorIT.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/reporting/ReportGeneratorIT.java index 131baf78c..e472c1e63 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/reporting/ReportGeneratorIT.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/reporting/ReportGeneratorIT.java @@ -109,8 +109,8 @@ public class ReportGeneratorIT extends BaseDBTestCase { } /** - * Generates an XML report containing known vulnerabilities and realistic data and validates the generated XML document - * against the XSD. + * Generates an XML report containing known vulnerabilities and realistic + * data and validates the generated XML document against the XSD. * * @throws Exception */ @@ -118,42 +118,43 @@ public class ReportGeneratorIT extends BaseDBTestCase { public void testGenerateXMLReport() { try { String templateName = "XmlReport"; - + File f = new File("target/test-reports"); if (!f.exists()) { f.mkdir(); } String writeTo = "target/test-reports/Report.xml"; File suppressionFile = BaseTest.getResourceAsFile(this, "incorrectSuppressions.xml"); - + Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile.getAbsolutePath()); - + //File struts = new File(this.getClass().getClassLoader().getResource("struts2-core-2.1.2.jar").getPath()); File struts = BaseTest.getResourceAsFile(this, "struts2-core-2.1.2.jar"); //File axis = new File(this.getClass().getClassLoader().getResource("axis2-adb-1.4.1.jar").getPath()); File axis = BaseTest.getResourceAsFile(this, "axis2-adb-1.4.1.jar"); //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","1.4.7","dependency-check-core","org.owasp", engine.getDependencies(), engine.getAnalyzers(), dbProp); + 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.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)); diff --git a/dependency-check-maven/pom.xml b/dependency-check-maven/pom.xml index ec672c570..8f03b9bb0 100644 --- a/dependency-check-maven/pom.xml +++ b/dependency-check-maven/pom.xml @@ -227,6 +227,13 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-invoker-plugin 2.0.0 + + + org.codehaus.groovy + groovy-all + 2.4.11 + + diff --git a/dependency-check-maven/src/it/729-system-scope-resolved/invoker.properties b/dependency-check-maven/src/it/729-system-scope-resolved/invoker.properties new file mode 100644 index 000000000..135fb86f1 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-resolved/invoker.properties @@ -0,0 +1,19 @@ +# +# This file is part of dependency-check-maven. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Copyright (c) 2017 Jeremy Long. All Rights Reserved. +# + +invoker.goals = install ${project.groupId}:${project.artifactId}:${project.version}:check -e -Dformat=JSON diff --git a/dependency-check-maven/src/it/729-system-scope-resolved/pom.xml b/dependency-check-maven/src/it/729-system-scope-resolved/pom.xml new file mode 100644 index 000000000..6f2d06950 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-resolved/pom.xml @@ -0,0 +1,34 @@ + + + + 4.0.0 + org.owasp.test + test-system-scope + 1.0.0-SNAPSHOT + jar + + + system + com.sun + tools + 1.8 + ${java.home}/../lib/tools.jar + + + \ No newline at end of file diff --git a/dependency-check-maven/src/it/729-system-scope-resolved/postbuild.groovy b/dependency-check-maven/src/it/729-system-scope-resolved/postbuild.groovy new file mode 100644 index 000000000..c1d6476e4 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-resolved/postbuild.groovy @@ -0,0 +1,30 @@ +/* + * This file is part of dependency-check-maven. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2017 Jeremy Long. All Rights Reserved. + */ + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; +import java.nio.charset.Charset; +import groovy.json.JsonSlurper; + +def slurper = new JsonSlurper() +def json = slurper.parse(new File(basedir, "target/dependency-check-report.json"), "UTF-8") + +assert json instanceof Map +assert json.analysis.dependencies instanceof List +assert json.analysis.dependencies.size()==1 +return true; diff --git a/dependency-check-maven/src/it/729-system-scope-resolved/prebuild.groovy b/dependency-check-maven/src/it/729-system-scope-resolved/prebuild.groovy new file mode 100644 index 000000000..9ec3a0a91 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-resolved/prebuild.groovy @@ -0,0 +1,17 @@ +/* + * This file is part of dependency-check-maven. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2017 Jeremy Long. All Rights Reserved. + */ diff --git a/dependency-check-maven/src/it/729-system-scope-skipped/invoker.properties b/dependency-check-maven/src/it/729-system-scope-skipped/invoker.properties new file mode 100644 index 000000000..b41bc60f9 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-skipped/invoker.properties @@ -0,0 +1,19 @@ +# +# This file is part of dependency-check-maven. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Copyright (c) 2014 Jeremy Long. All Rights Reserved. +# + +invoker.goals = install ${project.groupId}:${project.artifactId}:${project.version}:check -DskipSystemScope=true -Dformat=JSON diff --git a/dependency-check-maven/src/it/729-system-scope-skipped/pom.xml b/dependency-check-maven/src/it/729-system-scope-skipped/pom.xml new file mode 100644 index 000000000..6f2d06950 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-skipped/pom.xml @@ -0,0 +1,34 @@ + + + + 4.0.0 + org.owasp.test + test-system-scope + 1.0.0-SNAPSHOT + jar + + + system + com.sun + tools + 1.8 + ${java.home}/../lib/tools.jar + + + \ No newline at end of file diff --git a/dependency-check-maven/src/it/729-system-scope-skipped/postbuild.groovy b/dependency-check-maven/src/it/729-system-scope-skipped/postbuild.groovy new file mode 100644 index 000000000..335aaa589 --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-skipped/postbuild.groovy @@ -0,0 +1,30 @@ +/* + * This file is part of dependency-check-maven. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2017 Jeremy Long. All Rights Reserved. + */ + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; +import java.nio.charset.Charset; +import groovy.json.JsonSlurper; + +def slurper = new JsonSlurper() +def json = slurper.parse(new File(basedir, "target/dependency-check-report.json"), "UTF-8") + +assert json instanceof Map +assert json.analysis.dependencies instanceof List +assert json.analysis.dependencies.size()==0 +return true; diff --git a/dependency-check-maven/src/it/729-system-scope-skipped/prebuild.groovy b/dependency-check-maven/src/it/729-system-scope-skipped/prebuild.groovy new file mode 100644 index 000000000..9eff4bb5c --- /dev/null +++ b/dependency-check-maven/src/it/729-system-scope-skipped/prebuild.groovy @@ -0,0 +1,17 @@ +/* + * This file is part of dependency-check-maven. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2014 Jeremy Long. All Rights Reserved. + */ diff --git a/dependency-check-maven/src/it/false-positives/pom.xml b/dependency-check-maven/src/it/false-positives/pom.xml index 646ca1a47..079ab7818 100644 --- a/dependency-check-maven/src/it/false-positives/pom.xml +++ b/dependency-check-maven/src/it/false-positives/pom.xml @@ -22,6 +22,19 @@ Copyright (c) 2017 Jeremy Long. All Rights Reserved. test-dataformat-jackson 1.0.0-SNAPSHOT jar + + + redhat + redhat + https://maven.repository.redhat.com/ga/ + + + spring + spring + http://repo.spring.io/plugins-release/ + + + @@ -29,6 +42,37 @@ Copyright (c) 2017 Jeremy Long. All Rights Reserved. spring-boot 1.4.3.RELEASE - + + + + com.splunk + splunk + 1.6.2.0 + + + + + org.springframework.cloud + spring-cloud-netflix-core + 1.2.5.RELEASE + + + org.springframework.cloud + spring-cloud-commons + 1.1.7.RELEASE + + + org.springframework.cloud + spring-cloud-context + 1.1.7.RELEASE + + + + + org.openid4java + openid4java + 0.9.7 + + \ No newline at end of file diff --git a/dependency-check-maven/src/it/false-positives/postbuild.groovy b/dependency-check-maven/src/it/false-positives/postbuild.groovy index 4ce83a609..7c58af5af 100644 --- a/dependency-check-maven/src/it/false-positives/postbuild.groovy +++ b/dependency-check-maven/src/it/false-positives/postbuild.groovy @@ -20,16 +20,6 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import java.nio.charset.Charset; -// Save NVD-CVE for next IT (if not already done) -File datasDwl = new File("target/local-repo/org/owasp/dependency-check-data/3.0", "dc.h2.db"); -File datasSave = new File("target/nvd-cve-backup", "dc.h2.db"); -if (datasDwl.exists() && !datasSave.exists()){ - System.out.println("Save NVD-CVE into backup"); - FileUtils.copyFile(datasDwl, datasSave); -} - - - // Check to see if jackson-dataformat-xml-2.4.5.jar was identified. //TODO change this to xpath and check for CVE-2016-3720 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 547f68fb5..99b3a401f 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 @@ -55,6 +55,7 @@ import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; 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.reporting.ReportGenerator; @@ -117,7 +118,7 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma * The Maven Session. */ @Parameter(defaultValue = "${session}", readonly = true, required = true) - protected MavenSession session; + private MavenSession session; /** * Remote repositories which will be searched for artifacts. @@ -403,6 +404,13 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma @SuppressWarnings("CanBeFinal") @Parameter(property = "skipProvidedScope", defaultValue = "false", required = false) private boolean skipProvidedScope = false; + + /** + * Skip Analysis for Provided Scope Dependencies. + */ + @SuppressWarnings("CanBeFinal") + @Parameter(property = "skipSystemScope", defaultValue = "false", required = false) + private boolean skipSystemScope = false; /** * The data directory, hold DC SQL DB. */ @@ -627,24 +635,54 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma * @return a collection of exceptions that may have occurred while resolving * and scanning the dependencies */ - private ExceptionCollection collectDependencies(Engine engine, MavenProject project, List nodes, ProjectBuildingRequest buildingRequest) { + private ExceptionCollection collectDependencies(Engine engine, MavenProject project, + List nodes, ProjectBuildingRequest buildingRequest) { ExceptionCollection exCol = null; for (DependencyNode dependencyNode : nodes) { - exCol = collectDependencies(engine, project, dependencyNode.getChildren(), buildingRequest); if (excludeFromScan(dependencyNode.getArtifact().getScope())) { continue; } + exCol = collectDependencies(engine, project, dependencyNode.getChildren(), buildingRequest); try { - final ArtifactCoordinate coordinate = TransferUtils.toArtifactCoordinate(dependencyNode.getArtifact()); - final Artifact result = artifactResolver.resolveArtifact(buildingRequest, coordinate).getArtifact(); - if (result.isResolved() && result.getFile() != null) { - final List deps = engine.scan(result.getFile().getAbsoluteFile(), + boolean isResolved = false; + File artifactFile = null; + String artifactId = null; + String groupId = null; + String version = null; + if (org.apache.maven.artifact.Artifact.SCOPE_SYSTEM.equals(dependencyNode.getArtifact().getScope())) { + for (org.apache.maven.model.Dependency d : project.getDependencies()) { + Artifact a = dependencyNode.getArtifact(); + if (d.getSystemPath() != null && artifactsMatch(d, a)) { + + artifactFile = new File(d.getSystemPath()); + isResolved = artifactFile.isFile(); + groupId = a.getGroupId(); + artifactId = a.getArtifactId(); + version = a.getVersion(); + break; + } + } + if (!isResolved) { + getLog().error("Unable to resolve system scoped dependency: " + dependencyNode.toNodeString()); + exCol.addException(new DependencyNotFoundException("Unable to resolve system scoped dependency: " + dependencyNode.toNodeString())); + } + } else { + final ArtifactCoordinate coordinate = TransferUtils.toArtifactCoordinate(dependencyNode.getArtifact()); + final Artifact result = artifactResolver.resolveArtifact(buildingRequest, coordinate).getArtifact(); + isResolved = result.isResolved(); + artifactFile = result.getFile(); + groupId = result.getGroupId(); + artifactId = result.getArtifactId(); + version = result.getVersion(); + } + if (isResolved && artifactFile != null) { + final List deps = engine.scan(artifactFile.getAbsoluteFile(), project.getName() + ":" + dependencyNode.getArtifact().getScope()); if (deps != null) { if (deps.size() == 1) { final Dependency d = deps.get(0); if (d != null) { - final MavenArtifact ma = new MavenArtifact(result.getGroupId(), result.getArtifactId(), result.getVersion()); + final MavenArtifact ma = new MavenArtifact(groupId, artifactId, version); d.addAsEvidence("pom", ma, Confidence.HIGHEST); if (getLog().isDebugEnabled()) { getLog().debug(String.format("Adding project reference %s on dependency %s", @@ -682,6 +720,33 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma return exCol; } + /** + * Determines if the groupId, artifactId, and version of the Maven + * dependency and artifact match. + * + * @param d the Maven dependency + * @param a the Maven artifact + * @return true if the groupId, artifactId, and version match + */ + private static boolean artifactsMatch(org.apache.maven.model.Dependency d, Artifact a) { + return (isEqualOrNull(a.getArtifactId(), d.getArtifactId())) + && (isEqualOrNull(a.getGroupId(), d.getGroupId())) + && (isEqualOrNull(a.getVersion(), d.getVersion())); + } + + /** + * Compares two strings for equality; if both strings are null they are + * considered equal. + * + * @param left the first string to compare + * @param right the second string to compare + * @return true if the strings are equal or if they are both null; otherwise + * false. + */ + private static boolean isEqualOrNull(String left, String right) { + return (left != null && left.equals(right)) || (left == null && right == null); + } + /** * @return Returns a new ProjectBuildingRequest populated from the current * session and the current project remote repositories, used to resolve @@ -756,6 +821,10 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma return "dependency-check-report.xml#"; } else if ("VULN".equalsIgnoreCase(this.format)) { return "dependency-check-vulnerability"; + } else if ("JSON".equalsIgnoreCase(this.format)) { + return "dependency-check-report.json"; + } else if ("CSV".equalsIgnoreCase(this.format)) { + return "dependency-check-report.csv"; } else { getLog().warn("Unknown report format used during site generation."); return "dependency-check-report"; @@ -962,6 +1031,9 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma if (skipProvidedScope && org.apache.maven.artifact.Artifact.SCOPE_PROVIDED.equals(scope)) { return true; } + if (skipSystemScope && org.apache.maven.artifact.Artifact.SCOPE_SYSTEM.equals(scope)) { + return true; + } return skipRuntimeScope && !org.apache.maven.artifact.Artifact.SCOPE_RUNTIME.equals(scope); } @@ -1015,7 +1087,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma getLog().debug("Unable to retrieve DB Properties", ex); } } - final ReportGenerator r = new ReportGenerator(p.getName(),p.getVersion(),p.getArtifactId(),p.getGroupId(), engine.getDependencies(), engine.getAnalyzers(), prop); + 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) { 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 b566cc306..cb95628db 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 @@ -108,24 +108,23 @@ public class CheckMojo extends BaseDependencyCheckMojo { } exCol = ex; } - if (exCol == null || !exCol.isFatal()) { - try { - writeReports(engine, getProject(), getCorrectOutputDirectory()); - } catch (ReportException ex) { - if (this.isFailOnError()) { - if (exCol != null) { - exCol.addException(ex); - } else { - exCol = new ExceptionCollection("Unable to write the dependency-check report", ex); - } + } + if (exCol == null || !exCol.isFatal()) { + try { + writeReports(engine, getProject(), getCorrectOutputDirectory()); + } catch (ReportException ex) { + if (this.isFailOnError()) { + if (exCol != null) { + exCol.addException(ex); + } else { + exCol = new ExceptionCollection("Unable to write the dependency-check report", ex); } } - //writeDataFile(getProject(), null, engine.getDependencies()); - 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); - } + } + 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.cleanup(); diff --git a/dependency-check-maven/src/site/markdown/configuration.md b/dependency-check-maven/src/site/markdown/configuration.md index c43075f2e..72168e591 100644 --- a/dependency-check-maven/src/site/markdown/configuration.md +++ b/dependency-check-maven/src/site/markdown/configuration.md @@ -19,13 +19,14 @@ cveValidForHours | Sets the number of hours to wait before checking f failBuildOnCVSS | 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. | 11 failBuildOnAnyVulnerability | Specific that if any vulnerability is identified, the build will fail. | false failOnError | Whether the build should fail if there is an error executing the dependency-check analysis. | true -format | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML +format | The report format to be generated (HTML, XML, CSV, JSON, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML name | The name of the report in the site. | dependency-check or dependency-check:aggregate outputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build. | 'target' skip | Skips the dependency-check analysis. | false -skipTestScope | Skip analysis for artifacts with Test Scope. | true skipProvidedScope | Skip analysis for artifacts with Provided Scope. | false skipRuntimeScope | Skip analysis for artifacts with Runtime Scope. | false +skipSystemScope | Skip analysis for artifacts with System Scope. | false +skipTestScope | Skip analysis for artifacts with Test Scope. | true suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html). |   hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html). |   enableExperimental | Enable the [experimental analyzers](../analyzers/index.html). If not enabled the experimental analyzers (see below) will not be loaded or used. | false diff --git a/pom.xml b/pom.xml index 448a901c2..370e4c9fd 100644 --- a/pom.xml +++ b/pom.xml @@ -644,6 +644,11 @@ Copyright (c) 2012 - Jeremy Long annotations 3.0.1u2 + + com.google.code.gson + gson + 2.3.1 + com.h2database h2 diff --git a/src/site/markdown/dependency-check-gradle/configuration.md b/src/site/markdown/dependency-check-gradle/configuration.md index f33730a01..9268b9487 100644 --- a/src/site/markdown/dependency-check-gradle/configuration.md +++ b/src/site/markdown/dependency-check-gradle/configuration.md @@ -17,7 +17,7 @@ autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is ena cveValidForHours | Sets the number of hours to wait before checking for new updates from the NVD. | 4 failOnError | Fails the build if an error occurs during the dependency-check analysis. | true failBuildOnCVSS | 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. | 11 -format | The report format to be generated (HTML, XML, VULN, ALL). | HTML +format | The report format to be generated (HTML, XML, CSV, JSON, VULN, ALL). | HTML outputDirectory | The location to write the report(s). This directory will be located in the build directory. | build/reports skipTestGroups | When set to true (the default) all dependency groups that being with 'test' will be skipped. | true suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html) |