diff --git a/build.gradle b/build.gradle index 448c0f2..b73612a 100644 --- a/build.gradle +++ b/build.gradle @@ -17,8 +17,8 @@ */ ext { - odcVersion = '9.0.0' - openVulnClientVersion = '5.0.1' + odcVersion = '9.0.1' + openVulnClientVersion = '5.0.2' slackWebhookVersion = '1.4.0' spockCoreVersion = '2.3-groovy-3.0' } diff --git a/src/main/groovy/org/owasp/dependencycheck/gradle/extension/NvdExtension.groovy b/src/main/groovy/org/owasp/dependencycheck/gradle/extension/NvdExtension.groovy index dabc352..da819a8 100644 --- a/src/main/groovy/org/owasp/dependencycheck/gradle/extension/NvdExtension.groovy +++ b/src/main/groovy/org/owasp/dependencycheck/gradle/extension/NvdExtension.groovy @@ -28,6 +28,10 @@ class NvdExtension { * The number of milliseconds to wait between calls to the NVD API. */ Integer delay + /** + * The maximum number of retry requests for a single call to the NVD API. + */ + Integer maxRetryCount /** * The URL for the NVD API Data feed that can be generated using https://github.com/jeremylong/Open-Vulnerability-Project/tree/main/vulnz#caching-the-nvd-cve-data. */ 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 49b27da..51a2367 100644 --- a/src/main/groovy/org/owasp/dependencycheck/gradle/tasks/ConfiguredTask.groovy +++ b/src/main/groovy/org/owasp/dependencycheck/gradle/tasks/ConfiguredTask.groovy @@ -90,6 +90,7 @@ abstract class ConfiguredTask extends DefaultTask { settings.setStringIfNotEmpty(NVD_API_KEY, config.nvd.apiKey) settings.setIntIfNotNull(NVD_API_DELAY, config.nvd.delay) + settings.setIntIfNotNull(NVD_API_MAX_RETRY_COUNT, config.nvd.maxRetryCount) settings.setIntIfNotNull(NVD_API_VALID_FOR_HOURS, config.nvd.validForHours); settings.setStringIfNotEmpty(NVD_API_DATAFEED_URL, config.nvd.datafeedUrl) diff --git a/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckConfigurationSelectionIntegSpec.groovy b/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckConfigurationSelectionIntegSpec.groovy index 6c506f6..44bf4d6 100644 --- a/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckConfigurationSelectionIntegSpec.groovy +++ b/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckConfigurationSelectionIntegSpec.groovy @@ -14,113 +14,110 @@ class DependencyCheckConfigurationSelectionIntegSpec extends Specification { @TempDir File testProjectDir -///////////////////////////// -// Integration Specification Tests are failing since upgrading to 'com.h2database:h2:2.2.224' -///////////////////////////// -// def 'test dependencies are ignored by default'() { -// given: -// copyBuildFileIntoProjectDir('skipTestGroups.gradle') -// -// when: -// def result = executeTaskAndGetResult(ANALYZE_TASK, true) -// -// then: -// result.task(":$ANALYZE_TASK").outcome == SUCCESS -// } -// -// def "test dependencies are scanned if skipTestGroups flag is false"() { -// given: -// copyBuildFileIntoProjectDir('noSkipTestGroups.gradle') -// -// when: -// def result = executeTaskAndGetResult(ANALYZE_TASK, false) -// //println "-----------------" -// //println result.output -// //println "-----------------" -// //String fileContents = new File(new File(testProjectDir, 'build/reports'), 'dependency-check-report.html').text -// //println fileContents -// -// then: -// result.task(":$ANALYZE_TASK").outcome == FAILED -// result.output.contains('CVE-2015-6420') -// result.output.contains('CVE-2014-0114') -// result.output.contains('CVE-2016-3092') -// //the nvd CVE was updated and the version used is no longer considered vulnerable -// //result.output.contains('CVE-2015-5262') -// } -// -// def "custom configurations are scanned by default"() { -// given: -// copyBuildFileIntoProjectDir('scanCustomConfiguration.gradle') -// -// when: -// def result = executeTaskAndGetResult(ANALYZE_TASK, false) -// -// then: -// result.task(":$ANALYZE_TASK").outcome == FAILED -// result.output.contains('CVE-2015-6420') -// } -// -// def "custom configurations are skipped if blacklisted"() { -// given: -// copyBuildFileIntoProjectDir('blacklistCustomConfiguration.gradle') -// -// when: -// def result = executeTaskAndGetResult(ANALYZE_TASK, true) -// -// then: -// result.task(":$ANALYZE_TASK").outcome == SUCCESS -// } -// -// def "custom configurations are skipped when only scanning whitelisted configurations"() { -// given: -// copyBuildFileIntoProjectDir('skipCustomConfigurationViaWhitelist.gradle') -// -// when: -// def result = executeTaskAndGetResult(ANALYZE_TASK, true) -// -// then: -// result.task(":$ANALYZE_TASK").outcome == SUCCESS -// } -// -// def "groups are skipped if blacklisted"() { -// given: -// copyBuildFileIntoProjectDir('skipGroups.gradle') -// -// when: -// def result = executeTaskAndGetResult(ANALYZE_TASK, true) -// -// then: -// result.task(":$ANALYZE_TASK").outcome == SUCCESS -// } -// -// def "aggregate task aggregates"() { -// given: -// copyBuildFileIntoProjectDir('aggregateParent.gradle') -// copyResourceFileIntoProjectDir('aggregateSettings.gradle', 'settings.gradle') -// copyResourceFileIntoProjectDir('aggregateApp.gradle', 'app/build.gradle') -// copyResourceFileIntoProjectDir('aggregateCore.gradle', 'core/build.gradle') -// -// when: -// def result = executeTaskAndGetResult(AGGREGATE_TASK, true) -// -// then: -// result.task(":$AGGREGATE_TASK").outcome == SUCCESS -// result.output.contains('CVE-2016-7051') //jackson cve from core -// result.output.contains('CVE-2015-6420') //commons cve from app -// } -// -// def "suppressionFiles argument can be parsed and files are being respected"() { -// given: -// copyBuildFileIntoProjectDir('suppressionFiles.gradle') -// copyResourceFileIntoProjectDir('suppressions.xml', 'suppressions.xml') -// -// when: -// def result = executeTaskAndGetResult(ANALYZE_TASK, true) -// -// then: -// result.task(":$ANALYZE_TASK").outcome == SUCCESS -// } + def 'test dependencies are ignored by default'() { + given: + copyBuildFileIntoProjectDir('skipTestGroups.gradle') + + when: + def result = executeTaskAndGetResult(ANALYZE_TASK, true) + + then: + result.task(":$ANALYZE_TASK").outcome == SUCCESS + } + + def "test dependencies are scanned if skipTestGroups flag is false"() { + given: + copyBuildFileIntoProjectDir('noSkipTestGroups.gradle') + + when: + def result = executeTaskAndGetResult(ANALYZE_TASK, false) + //println "-----------------" + //println result.output + //println "-----------------" + //String fileContents = new File(new File(testProjectDir, 'build/reports'), 'dependency-check-report.html').text + //println fileContents + + then: + result.task(":$ANALYZE_TASK").outcome == FAILED + result.output.contains('CVE-2015-6420') + result.output.contains('CVE-2014-0114') + result.output.contains('CVE-2016-3092') + //the nvd CVE was updated and the version used is no longer considered vulnerable + //result.output.contains('CVE-2015-5262') + } + + def "custom configurations are scanned by default"() { + given: + copyBuildFileIntoProjectDir('scanCustomConfiguration.gradle') + + when: + def result = executeTaskAndGetResult(ANALYZE_TASK, false) + + then: + result.task(":$ANALYZE_TASK").outcome == FAILED + result.output.contains('CVE-2015-6420') + } + + def "custom configurations are skipped if blacklisted"() { + given: + copyBuildFileIntoProjectDir('blacklistCustomConfiguration.gradle') + + when: + def result = executeTaskAndGetResult(ANALYZE_TASK, true) + + then: + result.task(":$ANALYZE_TASK").outcome == SUCCESS + } + + def "custom configurations are skipped when only scanning whitelisted configurations"() { + given: + copyBuildFileIntoProjectDir('skipCustomConfigurationViaWhitelist.gradle') + + when: + def result = executeTaskAndGetResult(ANALYZE_TASK, true) + + then: + result.task(":$ANALYZE_TASK").outcome == SUCCESS + } + + def "groups are skipped if blacklisted"() { + given: + copyBuildFileIntoProjectDir('skipGroups.gradle') + + when: + def result = executeTaskAndGetResult(ANALYZE_TASK, true) + + then: + result.task(":$ANALYZE_TASK").outcome == SUCCESS + } + + def "aggregate task aggregates"() { + given: + copyBuildFileIntoProjectDir('aggregateParent.gradle') + copyResourceFileIntoProjectDir('aggregateSettings.gradle', 'settings.gradle') + copyResourceFileIntoProjectDir('aggregateApp.gradle', 'app/build.gradle') + copyResourceFileIntoProjectDir('aggregateCore.gradle', 'core/build.gradle') + + when: + def result = executeTaskAndGetResult(AGGREGATE_TASK, true) + + then: + result.task(":$AGGREGATE_TASK").outcome == SUCCESS + result.output.contains('CVE-2016-7051') //jackson cve from core + result.output.contains('CVE-2015-6420') //commons cve from app + } + + def "suppressionFiles argument can be parsed and files are being respected"() { + given: + copyBuildFileIntoProjectDir('suppressionFiles.gradle') + copyResourceFileIntoProjectDir('suppressions.xml', 'suppressions.xml') + + when: + def result = executeTaskAndGetResult(ANALYZE_TASK, true) + + then: + result.task(":$ANALYZE_TASK").outcome == SUCCESS + } private void copyBuildFileIntoProjectDir(String buildFileName) { diff --git a/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckGradlePluginSpec.groovy b/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckGradlePluginSpec.groovy index d942ac2..0fd8052 100644 --- a/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckGradlePluginSpec.groovy +++ b/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckGradlePluginSpec.groovy @@ -80,6 +80,7 @@ class DependencyCheckGradlePluginSpec extends Specification { project.dependencyCheck.proxy.password == null project.dependencyCheck.nvd.apiKey == null project.dependencyCheck.nvd.delay == null + project.dependencyCheck.nvd.maxRetryCount == null project.dependencyCheck.outputDirectory == "${project.buildDir}/reports" project.dependencyCheck.quickQueryTimestamp == null project.dependencyCheck.scanConfigurations == [] @@ -106,6 +107,7 @@ class DependencyCheckGradlePluginSpec extends Specification { nvd { apiKey = 'apiKey' delay = 5000 + maxRetryCount = 20 } hostedSuppressions { @@ -159,6 +161,7 @@ class DependencyCheckGradlePluginSpec extends Specification { project.dependencyCheck.nvd.apiKey == 'apiKey' project.dependencyCheck.nvd.delay == 5000 + project.dependencyCheck.nvd.maxRetryCount == 20 project.dependencyCheck.hostedSuppressions.url == 'suppressionsurl' project.dependencyCheck.hostedSuppressions.validForHours == 5 project.dependencyCheck.hostedSuppressions.forceupdate == true diff --git a/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckPluginIntegSpec.groovy b/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckPluginIntegSpec.groovy index 4e69d59..deae5e0 100644 --- a/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckPluginIntegSpec.groovy +++ b/src/test/groovy/org/owasp/dependencycheck/gradle/DependencyCheckPluginIntegSpec.groovy @@ -12,116 +12,112 @@ class DependencyCheckPluginIntegSpec extends Specification { @TempDir private FileSystemFixture fileSystemFixture -///////////////////////////// -// Integration Specification Tests are failing since upgrading to 'com.h2database:h2:2.2.224' -///////////////////////////// -// -// def "Plugin can be added"() { -// given: -// fileSystemFixture.create { -// dir("app") { -// file("build.gradle").text = """ -// plugins { -// id 'org.owasp.dependencycheck' -// } -// """.stripIndent() -// } -// } -// when: -// def result = GradleRunner.create() -// .withProjectDir(fileSystemFixture.resolve("app").toFile()) -// .withArguments('tasks') -// .withPluginClasspath() -// .forwardOutput() -// .build() -// -// then: -// result.output.contains("$DependencyCheckPlugin.ANALYZE_TASK") -// } -// -// def "custom configurations are skipped when only scanning whitelisted configurations"() { -// given: -// fileSystemFixture.create { -// dir("custom") { -// file("build.gradle").text = """ -// plugins { -// id 'org.owasp.dependencycheck' -// } -// apply plugin: 'java' -// -// sourceCompatibility = 1.5 -// version = '1.0' -// -// repositories { -// mavenLocal() -// mavenCentral() -// } -// -// dependencies { -// implementation group: 'commons-collections', name: 'commons-collections', version: '3.2' -// } -// dependencyCheck { -// nvd { -// datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' -// } -// } -// """.stripIndent() -// } -// } -// -// when: -// def result = GradleRunner.create() -// .withProjectDir(fileSystemFixture.resolve("custom").toFile()) -// .withArguments(DependencyCheckPlugin.ANALYZE_TASK) -// .withPluginClasspath() -// .withDebug(true) -// .forwardOutput() -// .build() -// -// then: -// result.task(":$DependencyCheckPlugin.ANALYZE_TASK").outcome == SUCCESS -// } -// -// def "task completes successfully when configuration cache is enabled in Gradle 7.4"() { -// given: -// fileSystemFixture.create { -// dir("configCache") { -// file("build.gradle").text = """ -// plugins { -// id 'org.owasp.dependencycheck' -// } -// apply plugin: 'java' -// -// sourceCompatibility = 1.5 -// version = '1.0' -// -// repositories { -// mavenLocal() -// mavenCentral() -// } -// -// dependencies { -// implementation group: 'commons-collections', name: 'commons-collections', version: '3.2' -// } -// dependencyCheck { -// nvd { -// datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' -// } -// } -// """.stripIndent() -// } -// } -// -// when: -// def result = GradleRunner.create() -// .withProjectDir(fileSystemFixture.resolve("configCache").toFile()) -// .withArguments(DependencyCheckPlugin.ANALYZE_TASK, "--configuration-cache") -// .withPluginClasspath() -// .withDebug(true) -// .forwardOutput() -// .build() -// -// then: -// result.task(":$DependencyCheckPlugin.ANALYZE_TASK").outcome == SUCCESS -// } + def "Plugin can be added"() { + given: + fileSystemFixture.create { + dir("app") { + file("build.gradle").text = """ + plugins { + id 'org.owasp.dependencycheck' + } + """.stripIndent() + } + } + when: + def result = GradleRunner.create() + .withProjectDir(fileSystemFixture.resolve("app").toFile()) + .withArguments('tasks') + .withPluginClasspath() + .forwardOutput() + .build() + + then: + result.output.contains("$DependencyCheckPlugin.ANALYZE_TASK") + } + + def "custom configurations are skipped when only scanning whitelisted configurations"() { + given: + fileSystemFixture.create { + dir("custom") { + file("build.gradle").text = """ + plugins { + id 'org.owasp.dependencycheck' + } + apply plugin: 'java' + + sourceCompatibility = 1.5 + version = '1.0' + + repositories { + mavenLocal() + mavenCentral() + } + + dependencies { + implementation group: 'commons-collections', name: 'commons-collections', version: '3.2' + } + dependencyCheck { + nvd { + datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' + } + } + """.stripIndent() + } + } + + when: + def result = GradleRunner.create() + .withProjectDir(fileSystemFixture.resolve("custom").toFile()) + .withArguments(DependencyCheckPlugin.ANALYZE_TASK) + .withPluginClasspath() + .withDebug(true) + .forwardOutput() + .build() + + then: + result.task(":$DependencyCheckPlugin.ANALYZE_TASK").outcome == SUCCESS + } + + def "task completes successfully when configuration cache is enabled in Gradle 7.4"() { + given: + fileSystemFixture.create { + dir("configCache") { + file("build.gradle").text = """ + plugins { + id 'org.owasp.dependencycheck' + } + apply plugin: 'java' + + sourceCompatibility = 1.5 + version = '1.0' + + repositories { + mavenLocal() + mavenCentral() + } + + dependencies { + implementation group: 'commons-collections', name: 'commons-collections', version: '3.2' + } + dependencyCheck { + nvd { + datafeedUrl = 'https://jeremylong.github.io/DependencyCheck/hb_nvd/' + } + } + """.stripIndent() + } + } + + when: + def result = GradleRunner.create() + .withProjectDir(fileSystemFixture.resolve("configCache").toFile()) + .withArguments(DependencyCheckPlugin.ANALYZE_TASK, "--configuration-cache") + .withPluginClasspath() + .withDebug(true) + .forwardOutput() + .build() + + then: + result.task(":$DependencyCheckPlugin.ANALYZE_TASK").outcome == SUCCESS + } }