diff --git a/src/main/groovy/org/owasp/dependencycheck/gradle/extension/DependencyCheckExtension.groovy b/src/main/groovy/org/owasp/dependencycheck/gradle/extension/DependencyCheckExtension.groovy index 7017bb1..20499c6 100644 --- a/src/main/groovy/org/owasp/dependencycheck/gradle/extension/DependencyCheckExtension.groovy +++ b/src/main/groovy/org/owasp/dependencycheck/gradle/extension/DependencyCheckExtension.groovy @@ -166,6 +166,10 @@ class DependencyCheckExtension { * is 0.0 which means all identified vulnerabilities would be considered a failure. */ Float junitFailOnCVSS = 0.0f + /** + * Specifies that if any unused suppression rule is found, the build will fail. + */ + Boolean failBuildOnUnusedSuppressionRule = false /** * Displays a summary of the findings. Defaults to true. */ diff --git a/src/main/groovy/org/owasp/dependencycheck/gradle/tasks/ConfiguredTask.groovy b/src/main/groovy/org/owasp/dependencycheck/gradle/tasks/ConfiguredTask.groovy index 9b74807..90f8b5d 100644 --- a/src/main/groovy/org/owasp/dependencycheck/gradle/tasks/ConfiguredTask.groovy +++ b/src/main/groovy/org/owasp/dependencycheck/gradle/tasks/ConfiguredTask.groovy @@ -106,6 +106,7 @@ abstract class ConfiguredTask extends DefaultTask { settings.setBooleanIfNotNull(DOWNLOADER_QUICK_QUERY_TIMESTAMP, config.quickQueryTimestamp) settings.setFloat(JUNIT_FAIL_ON_CVSS, config.junitFailOnCVSS) + settings.setBooleanIfNotNull(FAIL_ON_UNUSED_SUPPRESSION_RULE, config.failBuildOnUnusedSuppressionRule) settings.setBooleanIfNotNull(HOSTED_SUPPRESSIONS_ENABLED, config.hostedSuppressions.enabled) settings.setBooleanIfNotNull(HOSTED_SUPPRESSIONS_FORCEUPDATE, config.hostedSuppressions.forceupdate) settings.setStringIfNotNull(HOSTED_SUPPRESSIONS_URL, config.hostedSuppressions.url) diff --git a/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckConfigurationSelectionIntegSpec.groovy b/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckConfigurationSelectionIntegSpec.groovy index 6b3f308..6fd8227 100644 --- a/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckConfigurationSelectionIntegSpec.groovy +++ b/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckConfigurationSelectionIntegSpec.groovy @@ -132,6 +132,20 @@ class DependencyCheckConfigurationSelectionIntegSpec extends Specification { result.task(":$ANALYZE_TASK").outcome == SUCCESS } + def "analysis fails when unused suppression rule is present"() { + given: + copyBuildFileIntoProjectDir('suppressionFilesFailOnUnusedRule.gradle') + copyResourceFileIntoProjectDir('suppressions.xml', 'suppressions.xml') + + when: + def result = executeTaskAndGetResult(ANALYZE_TASK, false) + + then: + result.task(":$ANALYZE_TASK").outcome == FAILED + result.output.contains('Suppression Rule had zero matches') + result.output.contains('commons-collections') + } + private void copyBuildFileIntoProjectDir(String buildFileName) { copyResourceFileIntoProjectDir(buildFileName, 'build.gradle') diff --git a/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckGradlePluginSpec.groovy b/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckGradlePluginSpec.groovy index 3d1c73f..9e6a966 100644 --- a/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckGradlePluginSpec.groovy +++ b/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckGradlePluginSpec.groovy @@ -97,46 +97,31 @@ class DependencyCheckGradlePluginSpec extends Specification { def slackWebhookUrl = 'https://slack.com/webhook' when: project.dependencyCheck { - proxy { - server = '127.0.0.1' - port = 3128 - username = 'proxyUsername' - password = 'proxyPassword' - nonProxyHosts = ['localhost'] - } - nvd { - apiKey = 'apiKey' - delay = 5000 - maxRetryCount = 20 - } - - hostedSuppressions { - url = 'suppressionsurl' - validForHours = 5 - forceupdate = true - } - - slack { - enabled = true - webhookUrl = slackWebhookUrl - } - - analyzers { - artifactory { - enabled = true - url = 'https://example.com/artifacgtory' - bearerToken = 'abc123==' - } - kev { - enabled = false - url = "https://example.com" - validForHours = 12 - } - retirejs { - filters = ['filter1', 'filter2'] - filterNonVulnerable = true - } - } + proxy.server = '127.0.0.1' + proxy.port = 3128 + proxy.username = 'proxyUsername' + proxy.password = 'proxyPassword' + proxy.nonProxyHosts = ['localhost'] + + nvd.apiKey = 'apiKey' + nvd.delay = 5000 + nvd.maxRetryCount = 20 + + hostedSuppressions.url = 'suppressionsurl' + hostedSuppressions.validForHours = 5 + hostedSuppressions.forceupdate = true + + slack.enabled = true + slack.webhookUrl = slackWebhookUrl + + analyzers.artifactory.enabled = true + analyzers.artifactory.url = 'https://example.com/artifacgtory' + analyzers.artifactory.bearerToken = 'abc123==' + analyzers.kev.enabled = false + analyzers.kev.url = "https://example.com" + analyzers.kev.validForHours = 12 + analyzers.retirejs.filters = ['filter1', 'filter2'] + analyzers.retirejs.filterNonVulnerable = true outputDirectory = 'outputDirectory' quickQueryTimestamp = false diff --git a/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckPluginIntegSpec.groovy b/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckPluginIntegSpec.groovy index deae5e0..d896d13 100644 --- a/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckPluginIntegSpec.groovy +++ b/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckPluginIntegSpec.groovy @@ -57,9 +57,7 @@ class DependencyCheckPluginIntegSpec extends Specification { implementation group: 'commons-collections', name: 'commons-collections', version: '3.2' } dependencyCheck { - nvd { - datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' - } + nvd.datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' } """.stripIndent() } @@ -100,9 +98,7 @@ class DependencyCheckPluginIntegSpec extends Specification { implementation group: 'commons-collections', name: 'commons-collections', version: '3.2' } dependencyCheck { - nvd { - datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' - } + nvd.datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' } """.stripIndent() } diff --git a/src/test/resources/aggregateParent.gradle b/src/test/resources/aggregateParent.gradle index 610de8e..88e0d58 100644 --- a/src/test/resources/aggregateParent.gradle +++ b/src/test/resources/aggregateParent.gradle @@ -6,9 +6,7 @@ plugins { dependencyCheck { failOnError=true format="HTML" - nvd { - datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' - } + nvd.datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' } subprojects { diff --git a/src/test/resources/blacklistCustomConfiguration.gradle b/src/test/resources/blacklistCustomConfiguration.gradle index 0afbaf2..ca26392 100644 --- a/src/test/resources/blacklistCustomConfiguration.gradle +++ b/src/test/resources/blacklistCustomConfiguration.gradle @@ -22,7 +22,5 @@ dependencies { dependencyCheck { failBuildOnCVSS = 0 skipConfigurations = ['foo'] - nvd { - datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' - } + nvd.datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' } diff --git a/src/test/resources/noSkipTestGroups.gradle b/src/test/resources/noSkipTestGroups.gradle index edf4104..3dbb4a4 100644 --- a/src/test/resources/noSkipTestGroups.gradle +++ b/src/test/resources/noSkipTestGroups.gradle @@ -30,7 +30,5 @@ dependencies { dependencyCheck { failBuildOnCVSS = 0 skipTestGroups = false - nvd { - datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' - } + nvd.datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' } diff --git a/src/test/resources/outputDir.gradle b/src/test/resources/outputDir.gradle index 75225aa..48ad243 100644 --- a/src/test/resources/outputDir.gradle +++ b/src/test/resources/outputDir.gradle @@ -20,7 +20,5 @@ dependencies { } dependencyCheck { - nvd { - datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' - } + nvd.datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' } diff --git a/src/test/resources/scanAdditionalCpesConfiguration.gradle b/src/test/resources/scanAdditionalCpesConfiguration.gradle index bd118c5..8c3077d 100644 --- a/src/test/resources/scanAdditionalCpesConfiguration.gradle +++ b/src/test/resources/scanAdditionalCpesConfiguration.gradle @@ -23,7 +23,5 @@ dependencyCheck { cpe = "cpe:2.3:a:apache:commons_fileupload:1.3.1:*:*:*:*:*:*:*" } } - nvd { - datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' - } + nvd.datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' } diff --git a/src/test/resources/scanCustomConfiguration.gradle b/src/test/resources/scanCustomConfiguration.gradle index 7795ff5..22228a7 100644 --- a/src/test/resources/scanCustomConfiguration.gradle +++ b/src/test/resources/scanCustomConfiguration.gradle @@ -21,7 +21,5 @@ dependencies { dependencyCheck { failBuildOnCVSS = 0 - nvd { - datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' - } + nvd.datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' } diff --git a/src/test/resources/skipCustomConfigurationViaWhitelist.gradle b/src/test/resources/skipCustomConfigurationViaWhitelist.gradle index 82e5210..3f3dc45 100644 --- a/src/test/resources/skipCustomConfigurationViaWhitelist.gradle +++ b/src/test/resources/skipCustomConfigurationViaWhitelist.gradle @@ -22,7 +22,5 @@ dependencies { dependencyCheck { failBuildOnCVSS = 0 scanConfigurations = ['runtime'] - nvd { - datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' - } + nvd.datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' } diff --git a/src/test/resources/skipGroups.gradle b/src/test/resources/skipGroups.gradle index f793bab..e163ebb 100644 --- a/src/test/resources/skipGroups.gradle +++ b/src/test/resources/skipGroups.gradle @@ -20,7 +20,5 @@ dependencies { dependencyCheck { skipGroups = ['commons-collections', 'commons-httpclient', 'commons-io', 'commons-file'] failBuildOnCVSS = 0 - nvd { - datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' - } + nvd.datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' } diff --git a/src/test/resources/skipTestGroups.gradle b/src/test/resources/skipTestGroups.gradle index 5c9c121..e82be12 100644 --- a/src/test/resources/skipTestGroups.gradle +++ b/src/test/resources/skipTestGroups.gradle @@ -17,7 +17,5 @@ dependencies { dependencyCheck { failBuildOnCVSS = 0 - nvd { - datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' - } + nvd.datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' } diff --git a/src/test/resources/suppressionFiles.gradle b/src/test/resources/suppressionFiles.gradle index 537721a..59977cb 100644 --- a/src/test/resources/suppressionFiles.gradle +++ b/src/test/resources/suppressionFiles.gradle @@ -13,12 +13,9 @@ dependencies { } dependencyCheck { - analyzers { - ossIndexEnabled = false - } + analyzers.ossIndexEnabled = false + failBuildOnCVSS = 0 suppressionFiles = ["${project.rootDir}/suppressions.xml"] - nvd { - datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' - } + nvd.datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' } diff --git a/src/test/resources/suppressionFilesFailOnUnusedRule.gradle b/src/test/resources/suppressionFilesFailOnUnusedRule.gradle new file mode 100644 index 0000000..c67e64e --- /dev/null +++ b/src/test/resources/suppressionFilesFailOnUnusedRule.gradle @@ -0,0 +1,22 @@ +plugins { + id 'org.owasp.dependencycheck' +} +apply plugin: 'java' + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + implementation 'commons-lang:commons-lang:2.6' // EOL dependency which has no vulnerabilities and unlikely to obtain any +} + +dependencyCheck { + analyzers.ossIndexEnabled = false + + failBuildOnCVSS = 0 + suppressionFiles = ["${project.rootDir}/suppressions.xml"] + failBuildOnUnusedSuppressionRule = true + nvd.datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' +}