From b63cc60a3d1afb365eca3a73c817557d7b3575e5 Mon Sep 17 00:00:00 2001 From: ftiercelin Date: Wed, 4 Dec 2024 11:02:19 +0000 Subject: [PATCH 1/7] turn into UTC the last modified date retrieved from database as required by NvdCveClientBuilder#withLastModifiedFilter replace minusDays(-120) with plusDays(120) when calculating end date for increased legibility --- .../owasp/dependencycheck/data/update/NvdApiDataSource.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java b/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java index 1e1b62c42ef..acf9adf7f2a 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java @@ -306,7 +306,9 @@ private boolean processApi() throws UpdateException { builder.withEndpoint(endpoint); } if (lastModifiedRequest != null) { - final ZonedDateTime end = lastModifiedRequest.minusDays(-120); + // make it UTC as required by NvdCveClientBuilder#withLastModifiedFilter + lastModifiedRequest=lastModifiedRequest.withZoneSameInstant( ZoneId.of("UTC") ); + final ZonedDateTime end = lastModifiedRequest.plusDays(120); builder.withLastModifiedFilter(lastModifiedRequest, end); } final String key = settings.getString(Settings.KEYS.NVD_API_KEY); From 24c8e5af4453a7f6810900034d7e05abc559eb82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Tiercelin?= Date: Wed, 4 Dec 2024 11:10:59 +0000 Subject: [PATCH 2/7] Update NvdApiDataSource.java fix indentation --- .../owasp/dependencycheck/data/update/NvdApiDataSource.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java b/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java index acf9adf7f2a..19aa42ba7fd 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java @@ -306,8 +306,8 @@ private boolean processApi() throws UpdateException { builder.withEndpoint(endpoint); } if (lastModifiedRequest != null) { - // make it UTC as required by NvdCveClientBuilder#withLastModifiedFilter - lastModifiedRequest=lastModifiedRequest.withZoneSameInstant( ZoneId.of("UTC") ); + // make it UTC as required by NvdCveClientBuilder#withLastModifiedFilter + lastModifiedRequest=lastModifiedRequest.withZoneSameInstant(ZoneId.of("UTC")); final ZonedDateTime end = lastModifiedRequest.plusDays(120); builder.withLastModifiedFilter(lastModifiedRequest, end); } From db522c5a0e7150e03c920eb6a5854157039f8dc1 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Wed, 4 Dec 2024 06:40:54 -0500 Subject: [PATCH 3/7] style: checkstyle would complain... --- .../org/owasp/dependencycheck/data/update/NvdApiDataSource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java b/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java index 19aa42ba7fd..78f7fc56c00 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java @@ -307,7 +307,7 @@ private boolean processApi() throws UpdateException { } if (lastModifiedRequest != null) { // make it UTC as required by NvdCveClientBuilder#withLastModifiedFilter - lastModifiedRequest=lastModifiedRequest.withZoneSameInstant(ZoneId.of("UTC")); + lastModifiedRequest = lastModifiedRequest.withZoneSameInstant(ZoneId.of("UTC")); final ZonedDateTime end = lastModifiedRequest.plusDays(120); builder.withLastModifiedFilter(lastModifiedRequest, end); } From 8466ad4d706745977d9c7f7f680d7ea40e050312 Mon Sep 17 00:00:00 2001 From: ftiercelin Date: Wed, 11 Dec 2024 19:09:34 +0000 Subject: [PATCH 4/7] add a flag to fail when one or more suppression rules are not used --- ant/src/site/markdown/configuration.md | 43 ++--- .../agent/DependencyCheckScanAgent.java | 23 +++ .../UnusedSuppressionRuleAnalyzer.java | 61 ++++++- .../main/resources/dependencycheck.properties | 1 + .../UnusedSuppressionRuleAnalyzerTest.java | 157 ++++++++++++++++++ .../maven/BaseDependencyCheckMojo.java | 7 + maven/src/site/markdown/configuration.md | 57 +++---- .../owasp/dependencycheck/utils/Settings.java | 4 + 8 files changed, 298 insertions(+), 55 deletions(-) create mode 100644 core/src/test/java/org/owasp/dependencycheck/analyzer/UnusedSuppressionRuleAnalyzerTest.java diff --git a/ant/src/site/markdown/configuration.md b/ant/src/site/markdown/configuration.md index 125c975dfa2..6d1fe3a0b75 100644 --- a/ant/src/site/markdown/configuration.md +++ b/ant/src/site/markdown/configuration.md @@ -30,27 +30,28 @@ Configuration: dependency-check Task -------------------- The following properties can be set on the dependency-check task. -Property | Description | Default Value -----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------- -autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true -failOnError | Whether the build should fail if there is an error executing the dependency-check analysis | true -failBuildOnCVSS | Specifies if the build should be failed if a CVSS score equal to or 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. More information on CVSS scores can be found at the [NVD](https://nvd.nist.gov/vuln-metrics/cvss)| 11 -junitFailOnCVSS | If using the JUNIT report format the junitFailOnCVSS sets the CVSS score threshold that is considered a failure. | 0 -prettyPrint | Whether the XML and JSON formatted reports should be pretty printed. | false -projectName | The name of the project being scanned. | Dependency-Check -reportFormat | The report format to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, GITLAB, ALL). | 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' -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. |   -nonProxyHosts | Defines the hosts that will not be proxied. |   -connectionTimeout | The URL Connection Timeout. |   -enableExperimental | Enable the [experimental analyzers](../analyzers/index.html). If not enabled the experimental analyzers (see below) will not be loaded or used. | false -enableRetired | Enable the [retired analyzers](../analyzers/index.html). If not enabled the retired analyzers (see below) will not be loaded or used. | false -suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html). The parameter value can be a local file path, a URL to a suppression file, or even a reference to a file on the class path (see https://github.com/jeremylong/DependencyCheck/issues/1878#issuecomment-487533799) |   -junitFailOnCVSS | If using the JUNIT report format the junitFailOnCVSS sets the CVSS score threshold that is considered a failure. | 0 +Property | Description | Default Value +---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------- +autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true +failOnError | Whether the build should fail if there is an error executing the dependency-check analysis | true +failBuildOnCVSS | Specifies if the build should be failed if a CVSS score equal to or 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. More information on CVSS scores can be found at the [NVD](https://nvd.nist.gov/vuln-metrics/cvss)| 11 +junitFailOnCVSS | If using the JUNIT report format the junitFailOnCVSS sets the CVSS score threshold that is considered a failure. | 0 +prettyPrint | Whether the XML and JSON formatted reports should be pretty printed. | false +projectName | The name of the project being scanned. | Dependency-Check +reportFormat | The report format to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, GITLAB, ALL). | 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' +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. |   +nonProxyHosts | Defines the hosts that will not be proxied. |   +connectionTimeout | The URL Connection Timeout. |   +enableExperimental | Enable the [experimental analyzers](../analyzers/index.html). If not enabled the experimental analyzers (see below) will not be loaded or used. | false +enableRetired | Enable the [retired analyzers](../analyzers/index.html). If not enabled the retired analyzers (see below) will not be loaded or used. | false +suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html). The parameter value can be a local file path, a URL to a suppression file, or even a reference to a file on the class path (see https://github.com/jeremylong/DependencyCheck/issues/1878#issuecomment-487533799) |   +junitFailOnCVSS | If using the JUNIT report format the junitFailOnCVSS sets the CVSS score threshold that is considered a failure. | 0 +failBuildOnUnusedSuppressionRule | Specifies that if any unused suppression rule is found, the build will fail. | false The following nested elements can be set on the dependency-check task. diff --git a/core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java b/core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java index 5343585b4f9..a6c1ada92d8 100644 --- a/core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java +++ b/core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java @@ -177,6 +177,10 @@ public class DependencyCheckScanAgent { * Whether the Maven Central analyzer is enabled. */ private boolean centralAnalyzerEnabled = true; + /** + * Whether the build should fail if there are unused suppression rules. + */ + private boolean failOnUnusedSuppressionRule = false; /** * The URL of Maven Central. */ @@ -619,6 +623,24 @@ public String getCpeStartsWithFilter() { return cpeStartsWithFilter; } + /** + * Get the value of failOnUnusedSuppressionRule. + * + * @return the value of failOnUnusedSuppressionRule + */ + public boolean isFailOnUnusedSuppressionRule() { + return failOnUnusedSuppressionRule; + } + + /** + * Set the value of failOnUnusedSuppressionRule. + * + * @param failOnUnusedSuppressionRule new value of failOnUnusedSuppressionRule + */ + public void setFailOnUnusedSuppressionRule(boolean failOnUnusedSuppressionRule) { + this.failOnUnusedSuppressionRule = failOnUnusedSuppressionRule; + } + /** * Get the value of centralAnalyzerEnabled. * @@ -952,6 +974,7 @@ private void populateSettings() { settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions); settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_KEY, nvdApiKey); settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_DOTNET_PATH, pathToCore); + settings.setBoolean(Settings.KEYS.FAIL_ON_UNUSED_SUPPRESSION_RULE, failOnUnusedSuppressionRule); } /** diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/UnusedSuppressionRuleAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/UnusedSuppressionRuleAnalyzer.java index 4c95fdbb78d..4cdec670050 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/UnusedSuppressionRuleAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/UnusedSuppressionRuleAnalyzer.java @@ -33,7 +33,8 @@ * @author Jeremy Long */ public class UnusedSuppressionRuleAnalyzer extends AbstractAnalyzer { - + protected static final String EXCEPTION_MSG = "There are %d unused suppression rule(s): check logs."; + /** * The Logger for use throughout the class. */ @@ -43,27 +44,54 @@ public class UnusedSuppressionRuleAnalyzer extends AbstractAnalyzer { * been reported. */ private boolean reported = false; + /** + * A flag indicating whether build should fail on unused suppression rule + */ + private boolean shouldFailForUnusedSuppressionRule = false; + /** + * unused suppression rule count + */ + private int unusedSuppressionRuleCount = 0; + + @Override + public synchronized void initialize(Settings settings) { + super.initialize(settings); + if (settings.getBoolean(Settings.KEYS.FAIL_ON_UNUSED_SUPPRESSION_RULE, false)) { + this.shouldFailForUnusedSuppressionRule = true; + } + } @Override protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException { if (!reported) { - logUnusedRules(engine); - reported = true; + checkUnusedRules(engine); + reported = true; + if(unusedSuppressionRuleCount > 0 && failsForUnusedSuppressionRule()) { + final String message = String.format(EXCEPTION_MSG, unusedSuppressionRuleCount); + LOGGER.error(message); + throw new AnalysisException(message); + } } } /** - * Logs unused suppression RULES. + * check unused suppression RULES. * * @param engine a reference to the ODC engine */ - private void logUnusedRules(Engine engine) { + protected void checkUnusedRules(Engine engine) { if (engine.hasObject(SUPPRESSION_OBJECT_KEY)) { @SuppressWarnings("unchecked") final List rules = (List) engine.getObject(SUPPRESSION_OBJECT_KEY); rules.forEach((rule) -> { if (!rule.isMatched() && !rule.isBase()) { - LOGGER.info("Suppression Rule had zero matches: {}", rule.toString()); + final String message = String.format("Suppression Rule had zero matches: %s", rule); + if(failsForUnusedSuppressionRule()) { + LOGGER.error(message); + } else { + LOGGER.info(message); + } + increaseUnusedSuppressionRuleCount(); } }); } @@ -89,4 +117,25 @@ public AnalysisPhase getAnalysisPhase() { public boolean supportsParallelProcessing() { return false; } + + /** + * increases the count of unused suppression rules + */ + public void increaseUnusedSuppressionRuleCount() { + unusedSuppressionRuleCount++; + } + + /** + * @return the count of unused suppression rules + */ + public int getUnusedSuppressionRuleCount() { + return unusedSuppressionRuleCount; + } + + /** + * @return whether the analyzer will fail for a unused suppression rule + */ + public boolean failsForUnusedSuppressionRule() { + return shouldFailForUnusedSuppressionRule; + } } diff --git a/core/src/main/resources/dependencycheck.properties b/core/src/main/resources/dependencycheck.properties index 8e11c5837ef..9281923db66 100644 --- a/core/src/main/resources/dependencycheck.properties +++ b/core/src/main/resources/dependencycheck.properties @@ -164,6 +164,7 @@ database.batchinsert.maxsize=1000 analyzer.artifactory.enabled=false analyzer.libman.enabled=true odc.reports.pretty.print=false +analyzer.suppression.unused.fail=false hosted.suppressions.enabled=true hosted.suppressions.url=https://jeremylong.github.io/DependencyCheck/suppressions/publishedSuppressions.xml diff --git a/core/src/test/java/org/owasp/dependencycheck/analyzer/UnusedSuppressionRuleAnalyzerTest.java b/core/src/test/java/org/owasp/dependencycheck/analyzer/UnusedSuppressionRuleAnalyzerTest.java new file mode 100644 index 00000000000..4eb933b8431 --- /dev/null +++ b/core/src/test/java/org/owasp/dependencycheck/analyzer/UnusedSuppressionRuleAnalyzerTest.java @@ -0,0 +1,157 @@ +package org.owasp.dependencycheck.analyzer; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import org.owasp.dependencycheck.BaseTest; +import org.owasp.dependencycheck.Engine; +import static org.owasp.dependencycheck.analyzer.AbstractSuppressionAnalyzer.SUPPRESSION_OBJECT_KEY; +import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import static org.owasp.dependencycheck.analyzer.UnusedSuppressionRuleAnalyzer.EXCEPTION_MSG; +import org.owasp.dependencycheck.dependency.Confidence; +import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.naming.Identifier; +import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; +import org.owasp.dependencycheck.utils.Settings; +import org.owasp.dependencycheck.xml.suppression.SuppressionRule; +import org.owasp.dependencycheck.xml.suppression.PropertyType; + +public class UnusedSuppressionRuleAnalyzerTest extends BaseTest { + private static final String NAME = "Unused Suppression Rule Analyzer"; + private static final String PACKAGE_NAME = "CoolAsACucumber"; + private static final String EXPECTED_EX = "should have thrown an AnalysisException"; + + @Test + public void testGetName() { + UnusedSuppressionRuleAnalyzer analyzer = new UnusedSuppressionRuleAnalyzer(); + assertEquals(NAME, analyzer.getName()); + } + + @Test + public void testException() throws Exception { + boolean shouldFail = true; + Dependency dependency10 = getDependency("1.0"); + Dependency dependency11 = getDependency("1.1"); + + UnusedSuppressionRuleAnalyzer analyzer = getAnalyzer(shouldFail); + Engine engine = getEngine(true, false, dependency10, dependency11); + try { + analyzer.analyzeDependency(dependency10, engine); + throw new Exception("should have thrown an AnalysisException"); + } catch(AnalysisException ok){ + assertEquals(String.format(EXCEPTION_MSG, 1), ok.getMessage()); + } + + // no exception + shouldFail = false; + analyzer = getAnalyzer(shouldFail); + engine = getEngine(true, false, dependency10, dependency11); + analyzer.analyzeDependency(dependency10, engine); + assertEquals(1, analyzer.getUnusedSuppressionRuleCount()); + } + + @Test + public void testCheckUnusedRules() throws Exception { + // flag unset + boolean shouldFail = false; + Dependency dependency10 = getDependency("1.0"); + Dependency dependency11 = getDependency("1.1"); + + // a run without any suppression rule ➫ no unused suppression + checkUnusedRules(shouldFail, 0, false, false, dependency10); + + // a run without no matching rule ➫ one unused suppression + checkUnusedRules(shouldFail, 1, true, false, dependency10, dependency11); + + // a run with the vulnerable package ➫ no unused suppression + checkUnusedRules(shouldFail, 0, true, true, dependency10, dependency11); + + + // set flag + shouldFail = true; + + // a run without any suppression rule ➫ no unused suppression + checkUnusedRules(shouldFail, 0, false, false, dependency10); + + // a run without no matching rule ➫ one unused suppression + checkUnusedRules(shouldFail, 1, true, false, dependency10, dependency11); + + // a run with the vulnerable package ➫ no unused suppression + checkUnusedRules(shouldFail, 0, true, true, dependency10, dependency11); + } + + private void checkUnusedRules(boolean shouldFail, int expectedCount, + boolean withSuppressionRules, boolean matching, + Dependency ... dependencies) throws Exception { + UnusedSuppressionRuleAnalyzer analyzer = getAnalyzer(shouldFail); + assertNotNull(analyzer); + Engine engine = getEngine(withSuppressionRules, matching, dependencies); + analyzer.checkUnusedRules(engine); + assertEquals(expectedCount, analyzer.getUnusedSuppressionRuleCount()); + } + + + private Dependency getDependency(String type, String namespace, String name, String version) throws Exception { + Dependency dependency = new Dependency(); + Identifier id = new PurlIdentifier(type,namespace,name,version,Confidence.HIGHEST); + dependency.addSoftwareIdentifier(id); + return dependency; + } + + private Dependency getDependency(String version) throws Exception { + return getDependency("maven", "test", PACKAGE_NAME, version); + } + + + private Engine getEngine(boolean hasSuppressionRules, boolean matching, Dependency ... dependencies) throws Exception { + Engine engine = new Engine(getSettings()); + List dependencyList = new ArrayList<>(); + if (dependencies!=null) { + for(Dependency d : dependencies) + dependencyList.add(d); + } + engine.setDependencies(dependencyList); + if(!hasSuppressionRules) return engine; + List rules = new ArrayList<>(); + rules.add(getSuppressionRule(matching)); + engine.putObject(SUPPRESSION_OBJECT_KEY,rules); + return engine; + } + + private UnusedSuppressionRuleAnalyzer getAnalyzer(boolean flag) throws AnalysisException { + UnusedSuppressionRuleAnalyzer analyzer = new UnusedSuppressionRuleAnalyzer(); + assertNotNull(analyzer); + + Settings settings = getSettings(); + settings.setBoolean(Settings.KEYS.FAIL_ON_UNUSED_SUPPRESSION_RULE, flag); + analyzer.initialize(settings); + assertEquals(flag, analyzer.failsForUnusedSuppressionRule()); + assertEquals(0, analyzer.getUnusedSuppressionRuleCount()); + + return analyzer; + } + + private SuppressionRule getSuppressionRule(boolean matching) { + SuppressionRule instance = new SuppressionRule(); + instance.addVulnerabilityName(getPropertyType("CVE-2023-5072", false, false)); + instance.setPackageUrl(getPropertyType("^pkg:maven/test." + PACKAGE_NAME + "." + matching, false, false)); + instance.addCpe(getPropertyType(PACKAGE_NAME, false, false)); + instance.setBase(false); + instance.setMatched(matching); + return instance; + } + + private PropertyType getPropertyType(String value, boolean regex, boolean caseSensitive) { + PropertyType property = new PropertyType(); + property.setValue(value); + property.setRegex(regex); + property.setCaseSensitive(caseSensitive); + return property; + } + + +} diff --git a/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java b/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java index 4778b26565b..2e05a2c2fc8 100644 --- a/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java +++ b/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java @@ -685,6 +685,12 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma @SuppressWarnings("CanBeFinal") @Parameter(property = "artifactoryAnalyzerParallelAnalysis", defaultValue = "true") private Boolean artifactoryAnalyzerParallelAnalysis; + /** + * Whether the Unused Suppression Rule analyzer should fail if there are unused rules. + */ + @SuppressWarnings("CanBeFinal") + @Parameter(property = "failBuildOnUnusedSuppressionRule", defaultValue = "false") + private Boolean failBuildOnUnusedSuppressionRule; /** * Whether or not the Nexus Analyzer is enabled. */ @@ -2268,6 +2274,7 @@ protected void populateSettings() { settings.setStringIfNotNull(Settings.KEYS.ANALYZER_ARTIFACTORY_URL, artifactoryAnalyzerUrl); settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARTIFACTORY_USES_PROXY, artifactoryAnalyzerUseProxy); settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARTIFACTORY_PARALLEL_ANALYSIS, artifactoryAnalyzerParallelAnalysis); + settings.setBooleanIfNotNull(Settings.KEYS.FAIL_ON_UNUSED_SUPPRESSION_RULE, failBuildOnUnusedSuppressionRule); if (Boolean.TRUE.equals(artifactoryAnalyzerEnabled)) { if (artifactoryAnalyzerServerId != null) { configureServerCredentials(artifactoryAnalyzerServerId, Settings.KEYS.ANALYZER_ARTIFACTORY_API_USERNAME, diff --git a/maven/src/site/markdown/configuration.md b/maven/src/site/markdown/configuration.md index fba95d8d463..751bac531c7 100644 --- a/maven/src/site/markdown/configuration.md +++ b/maven/src/site/markdown/configuration.md @@ -12,34 +12,35 @@ Configuration ==================== The following properties can be set on the dependency-check-maven plugin. -Property | Description | Default Value -----------------------------|------------------------------------|------------------ -autoUpdate | Sets whether auto-updating of the NVD CVE/CPE, retireJS and hosted suppressions data is enabled. It is not recommended that this be turned to false. | true -format | The report format to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, GITLAB, ALL). This configuration is ignored if `formats` is defined. This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML -formats | A list of report formats to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, GITLAB, ALL). This configuration overrides the value from `format`. This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. |   -junitFailOnCVSS | If using the JUNIT report format the junitFailOnCVSS sets the CVSS score threshold that is considered a failure. | 0 -prettyPrint | Whether the XML and JSON formatted reports should be pretty printed. | false -failBuildOnCVSS | Specifies if the build should be failed if a CVSS score equal to or 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. More information on CVSS scores can be found at the [NVD](https://nvd.nist.gov/vuln-metrics/cvss) | 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 -name | The name of the report in the site. | dependency-check or dependency-check:aggregate -outputDirectory | The location to write the report(s). This can be specified on the command line via `-Dodc.outputDirectory`. Note, this is not used if generating the report as part of a `mvn site` build. | 'target' -scanSet | An optional collection of file sets that specify additional files and/or directories to analyze as part of the scan. If not specified, defaults to standard Maven conventions. This cannot be configured via the command line parameters (e.g. `-DscanSet=./path`) - use the below `scanDirectory` instead. Note that the scan sets specified should be relative from the base directory - do not use Maven project variable substitution (e.g. `${project.basedir}/src/webpack`). Using Maven project variable substitution can cause directories to be missed especially when using an aggregate build. | ['src/main/resources', 'src/main/filters', 'src/main/webapp', './package.json', './package-lock.json', './npm-shrinkwrap.json', './Gopkg.lock', './go.mod'] -scanDirectory | An optional collection of directories to include in the scan. This configuration should only be used via the command line - if configuring the scan directories within the `pom.xml` please consider using the above `scanSet`. |   -scanDependencies | Sets whether the dependencies should be scanned. | true -scanPlugins | Sets whether the plugins and their dependencies should be scanned. | false -skip | Skips the dependency-check analysis. | false -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 -skipDependencyManagement | Skip analysis for dependencyManagement sections. | true -skipArtifactType | A regular expression used to filter/skip artifact types. This filters on the `type` of dependency as defined in the dependency section: jar, pom, test-jar, etc. |   -suppressionFiles | The file paths to the XML suppression files \- used to suppress [false positives](../general/suppression.html). The configuration value can be a local file path, a URL to a suppression file, or even a reference to a file on the class path (see https://github.com/jeremylong/DependencyCheck/issues/1878#issuecomment-487533799) |   -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 -enableRetired | Enable the [retired analyzers](../analyzers/index.html). If not enabled the retired analyzers (see below) will not be loaded or used. | false -versionCheckEnabled | Whether dependency-check should check if a new version of dependency-check-maven exists. | true +Property | Description | Default Value +---------------------------------|------------------------------------|------------------ +autoUpdate | Sets whether auto-updating of the NVD CVE/CPE, retireJS and hosted suppressions data is enabled. It is not recommended that this be turned to false. | true +format | The report format to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, GITLAB, ALL). This configuration is ignored if `formats` is defined. This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML +formats | A list of report formats to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, GITLAB, ALL). This configuration overrides the value from `format`. This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. |   +junitFailOnCVSS | If using the JUNIT report format the junitFailOnCVSS sets the CVSS score threshold that is considered a failure. | 0 +prettyPrint | Whether the XML and JSON formatted reports should be pretty printed. | false +failBuildOnCVSS | Specifies if the build should be failed if a CVSS score equal to or 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. More information on CVSS scores can be found at the [NVD](https://nvd.nist.gov/vuln-metrics/cvss) | 11 +failBuildOnAnyVulnerability | Specifies 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 +name | The name of the report in the site. | dependency-check or dependency-check:aggregate +outputDirectory | The location to write the report(s). This can be specified on the command line via `-Dodc.outputDirectory`. Note, this is not used if generating the report as part of a `mvn site` build. | 'target' +scanSet | An optional collection of file sets that specify additional files and/or directories to analyze as part of the scan. If not specified, defaults to standard Maven conventions. This cannot be configured via the command line parameters (e.g. `-DscanSet=./path`) - use the below `scanDirectory` instead. Note that the scan sets specified should be relative from the base directory - do not use Maven project variable substitution (e.g. `${project.basedir}/src/webpack`). Using Maven project variable substitution can cause directories to be missed especially when using an aggregate build. | ['src/main/resources', 'src/main/filters', 'src/main/webapp', './package.json', './package-lock.json', './npm-shrinkwrap.json', './Gopkg.lock', './go.mod'] +scanDirectory | An optional collection of directories to include in the scan. This configuration should only be used via the command line - if configuring the scan directories within the `pom.xml` please consider using the above `scanSet`. |   +scanDependencies | Sets whether the dependencies should be scanned. | true +scanPlugins | Sets whether the plugins and their dependencies should be scanned. | false +skip | Skips the dependency-check analysis. | false +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 +skipDependencyManagement | Skip analysis for dependencyManagement sections. | true +skipArtifactType | A regular expression used to filter/skip artifact types. This filters on the `type` of dependency as defined in the dependency section: jar, pom, test-jar, etc. |   +suppressionFiles | The file paths to the XML suppression files \- used to suppress [false positives](../general/suppression.html). The configuration value can be a local file path, a URL to a suppression file, or even a reference to a file on the class path (see https://github.com/jeremylong/DependencyCheck/issues/1878#issuecomment-487533799) |   +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 +enableRetired | Enable the [retired analyzers](../analyzers/index.html). If not enabled the retired analyzers (see below) will not be loaded or used. | false +versionCheckEnabled | Whether dependency-check should check if a new version of dependency-check-maven exists. | true +failBuildOnUnusedSuppressionRule | Specifies that if any unused suppression rule is found, the build will fail. | false Analyzer Configuration ==================== diff --git a/utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java b/utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java index d8c48eab53e..fa398a87411 100644 --- a/utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java +++ b/utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java @@ -861,6 +861,10 @@ public static final class KEYS { * query results; append the ecosystem to obtain the default query size. */ public static final String MAX_QUERY_SIZE_PREFIX = "odc.ecosystem.maxquerylimit."; + /** + * The properties key for whether the build should fail if there are unused suppression rules. + */ + public static final String FAIL_ON_UNUSED_SUPPRESSION_RULE = "analyzer.suppression.unused.fail"; /** * private constructor because this is a "utility" class containing From 3c3b0abfb8a60a61d8b8203a22292e52037e2c87 Mon Sep 17 00:00:00 2001 From: ftiercelin Date: Mon, 16 Dec 2024 15:07:33 +0000 Subject: [PATCH 5/7] add switch to ant client for unused suppression rules failure --- .../org/owasp/dependencycheck/taskdefs/Check.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java index 06dc486bbcf..56ccc740dbb 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java +++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java @@ -449,6 +449,11 @@ public class Check extends Update { */ private Reference refId = null; + /** + * whether an unsused suppression rule should get force the build to fail + */ + private boolean failBuildOnUnusedSuppressionRule = false; + /** * Returns whether the version check is enabled. * @@ -2092,6 +2097,13 @@ public String getArtifactoryAnalyzerBearerToken() { public void setArtifactoryAnalyzerBearerToken(String artifactoryAnalyzerBearerToken) { this.artifactoryAnalyzerBearerToken = artifactoryAnalyzerBearerToken; } + + /** + * @return whether an unsused suppression rule should get force the build to fail + */ + public boolean failBuildOnUnusedSuppressionRule() { + return failBuildOnUnusedSuppressionRule; + } //see note on `dealWithReferences()` for information on this suppression @SuppressWarnings("squid:RedundantThrowsDeclarationCheck") @@ -2280,6 +2292,7 @@ protected void populateSettings() throws BuildException { getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_OSSINDEX_USE_CACHE, ossindexAnalyzerUseCache); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS, ossIndexAnalyzerWarnOnlyOnRemoteErrors); getSettings().setFloat(Settings.KEYS.JUNIT_FAIL_ON_CVSS, junitFailOnCVSS); + getSettings().setBooleanIfNotNull(Settings.KEYS.FAIL_ON_UNUSED_SUPPRESSION_RULE, failBuildOnUnusedSuppressionRule); } /** From c0552303752ffdc389c0709b457bea32d8826849 Mon Sep 17 00:00:00 2001 From: ftiercelin Date: Mon, 16 Dec 2024 15:25:15 +0000 Subject: [PATCH 6/7] add setter --- .../org/owasp/dependencycheck/taskdefs/Check.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java index 56ccc740dbb..7d6043f065f 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java +++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java @@ -2099,12 +2099,23 @@ public void setArtifactoryAnalyzerBearerToken(String artifactoryAnalyzerBearerTo } /** + * Returns the value of failBuildOnUnusedSuppressionRule. * @return whether an unsused suppression rule should get force the build to fail */ public boolean failBuildOnUnusedSuppressionRule() { return failBuildOnUnusedSuppressionRule; } + /** + * Set the value of failBuildOnUnusedSuppressionRule. + * + * @param failBuildOnUnusedSuppressionRule new value of + * failBuildOnUnusedSuppressionRule + */ + public void setFailBuildOnUnusedSuppressionRule(boolean failBuildOnUnusedSuppressionRule) { + this.failBuildOnUnusedSuppressionRule = failBuildOnUnusedSuppressionRule; + } + //see note on `dealWithReferences()` for information on this suppression @SuppressWarnings("squid:RedundantThrowsDeclarationCheck") @Override From 1d68f83b3bcf1b7c4ec6f97d3e9596974a966cad Mon Sep 17 00:00:00 2001 From: ftiercelin Date: Mon, 16 Dec 2024 15:27:07 +0000 Subject: [PATCH 7/7] lint --- .../main/java/org/owasp/dependencycheck/taskdefs/Check.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java index 7d6043f065f..68760af6225 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java +++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java @@ -2102,9 +2102,9 @@ public void setArtifactoryAnalyzerBearerToken(String artifactoryAnalyzerBearerTo * Returns the value of failBuildOnUnusedSuppressionRule. * @return whether an unsused suppression rule should get force the build to fail */ - public boolean failBuildOnUnusedSuppressionRule() { - return failBuildOnUnusedSuppressionRule; - } + public boolean getFailBuildOnUnusedSuppressionRule() { + return failBuildOnUnusedSuppressionRule; + } /** * Set the value of failBuildOnUnusedSuppressionRule.