Last active
March 2, 2023 16:53
-
-
Save milo-minderbinder/1e1ed911c5b2264dc659578f1baaef16 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* MIT License | |
* | |
* Copyright (c) 2018 Chris Passarello <www.insecurity.co> | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in all | |
* copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
* SOFTWARE. | |
* | |
* | |
* This init script modifies the Gradle project by applying the DependencyCheck plugin to all projects. | |
* | |
* The plugin adds the `dependencyCheckAnalyze` task, which will scan the project and its dependencies | |
* for known vulnerabilities (see: https://github.com/jeremylong/DependencyCheck). | |
* | |
* To add it dynamically with a Gradle build command, add the `-I` option with the path to this file, e.g.: | |
* > gradle -I /path/to/dependencyCheck.gradle dependencyCheckAnalyze | |
* | |
* Alternatively, to add the plugin automatically to all Gradle projects transparently, place this script | |
* in the `$GRADLE_HOME/init.d` or `$USER_HOME/.gradle/init.d` directory. | |
* | |
* Sane defaults are set for several dependencyCheck extension properties | |
* (https://jeremylong.github.io/DependencyCheck/dependency-check-gradle/configuration.html), which may be overridden in | |
* the build script or via project properties, the latter having higher precedence. This allows the user to overwrite | |
* any dependencyCheck options configured in the build.gradle or other scripts, by setting | |
* the option in the {@code $GRADLE_HOME/gradle.properties}, for example, or by passing the option via the command line | |
* with: | |
* <br/><pre>>gradle dependencyCheckAnalyze -PdependencyCheck.failBuildOnCVSS=5</pre> | |
* | |
* Below is the full list of dependencyCheck options configurable as project properties and their default values: | |
* dependencyCheck.analyzers.experimentalEnabled = true | |
* dependencyCheck.analyzers.nuspecEnabled = false | |
* dependencyCheck.analyzers.nugetconfEnabled = false | |
* dependencyCheck.analyzers.assemblyEnabled = false | |
* dependencyCheck.analyzers.pathToBundleAudit = '/usr/local/bin/bundle-audit' | |
* dependencyCheck.cve.urlModified = 'https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz' | |
* dependencyCheck.cve.urlBase = 'https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz' | |
* dependencyCheck.data.directory = null | |
* dependencyCheck.hintsFile = "${rootDir}/dependency-check-hints.xml" (if it exists) | |
* dependencyCheck.suppressionFiles = ["${rootDir}/dependency-check-hints.xml"] (if it exists) | |
* dependencyCheck.failBuildOnCVSS = 7.0 | |
* dependencyCheck.format = 'ALL' | |
* dependencyCheck.outputDirectory = "${buildDir}/reports" | |
* dependencyCheck.skip = false | |
* dependencyCheck.skipConfigurations = [] | |
* dependencyCheck.scanConfigurations = [] | |
* | |
*/ | |
import static org.owasp.dependencycheck.reporting.ReportGenerator.Format | |
void log(LogLevel level, String message, Object... objs) { | |
message = "(${level}) ${buildscript.sourceFile.name} - ${message}" | |
logger.log(level, message, *objs) | |
} | |
void log(String message, Object... objs) { | |
log(LogLevel.INFO, message, *objs) | |
} | |
log('applying') | |
/** | |
* Extract the named nested property from the given object. | |
* <p/> | |
* For example, if an object {@code foo} has a property {@code bar} which is also an object with its own property, | |
* {@code baz}, it can be accessed by calling <pre>extractProperty(foo, bar.baz)</pre>. | |
* | |
* @param obj the object to extract the property value from | |
* @param name the name of the (optionally) nested property to extract | |
* @return | |
*/ | |
def extractProperty(obj, String name) { | |
name.tokenize('.').inject(obj) { a, v -> a."$v" } | |
} | |
/** | |
* Check the project for the named dependencyCheck option, giving precedence to project properties over the standard | |
* dependencyCheck configuration closure where the option is specified in both places, and using fallback as the default. | |
* <p/> | |
* This allows us to overwrite any dependencyCheck options configured in the build.gradle or other scripts, by setting | |
* the option in the {@code $GRADLE_HOME/gradle.properties}, for example, or by passing the option via the command line | |
* with: | |
* <br/><pre>>./gradlew dependencyCheckAnalyze -Dorg.gradle.project.dependencyCheck.failBuildOnCVSS=5</pre> | |
* | |
* @param project the Gradle project | |
* @param name the name of the option to retrieve | |
* @param fallback fallback value to return if the named option is not set in either the properties or the plugin's | |
* configuration closure | |
* @param pluginDefault the default value set by the plugin | |
* @return the value of the named option, if set in build properties or using the standard plugin configuration closure | |
* (in that order of precedence), otherwise {@code fallback} | |
*/ | |
def getOption(Project project, String name, fallback, pluginDefault = null) { | |
def option = fallback | |
if (project.hasProperty("dependencyCheck.${name}")) { | |
option = project.property("dependencyCheck.${name}") | |
log("Set dependencyCheck.${name}=${option} via build properties") | |
} // Note: string coercion below is necessary since, for some reason, ReportGenerator.Format Enum comparison won't work | |
else if ("${extractProperty(project.dependencyCheck, name)}" != "${pluginDefault}") { | |
option = extractProperty(project.dependencyCheck, name) | |
log("Set dependencyCheck.${name}=${option} via config closure") | |
} else | |
log("Set dependencyCheck.${name}=${option} via init script fallback") | |
option | |
} | |
initscript { | |
ext { | |
dependencyCheckVersion = gradle.gradleVersion.startsWith('2.') ? '3.2.1' : '8.1.2' | |
} | |
// DepedencyCheck plugin is in Gradle Plugins Portal, but check if Gradle Plugins Portal is added already so we don't | |
// interfere with the number of repos added or their order. | |
boolean hasGradlePluginsPortal = repositories.withType(MavenArtifactRepository).find { MavenArtifactRepository r -> | |
r.url.toString().equals('https://plugins.gradle.org/m2/') | |
} | |
if (!hasGradlePluginsPortal) { | |
logger.log(LogLevel.INFO, "(INFO) ${buildscript.sourceFile.name} - Adding Gradle Plugin Portal to initscript repositories") | |
repositories { | |
gradlePluginPortal() | |
} | |
} | |
dependencies { | |
classpath "org.owasp:dependency-check-gradle:${dependencyCheckVersion}" | |
} | |
} | |
gradle.rootProject { | |
buildscript { | |
// DepedencyCheck plugin is in Gradle Plugins Portal, but check if Gradle Plugins Portal is added already so we don't | |
// interfere with the number of repos added or their order. | |
boolean hasGradlePluginsPortal = repositories.withType(MavenArtifactRepository).find { MavenArtifactRepository r -> | |
r.url.toString().equals('https://plugins.gradle.org/m2/') | |
} | |
if (!hasGradlePluginsPortal) { | |
log('Adding Gradle Plugin Portal to buildscript repositories') | |
repositories { | |
maven { url 'https://plugins.gradle.org/m2/' } | |
} | |
} | |
dependencies { | |
classpath "org.owasp:dependency-check-gradle:${dependencyCheckVersion}" | |
} | |
} | |
} | |
gradle.allprojects { | |
afterEvaluate { p -> | |
p.apply plugin: 'org.owasp.dependencycheck' | |
if (p.tasks.findByName('check')) { | |
p.check.dependsOn dependencyCheckAnalyze // Run DependencyCheck with other test/check tasks | |
} | |
p.dependencyCheckAnalyze { | |
doFirst { | |
dependencyCheck { | |
analyzers { | |
// required for NodeJS, PHP, Python, etc. (i.e. non-Java) | |
experimentalEnabled = getOption(p, 'analyzers.experimentalEnabled', true) | |
nuspecEnabled = getOption(p, 'analyzers.nuspecEnabled', false) | |
nugetconfEnabled = getOption(p, 'analyzers.nugetconfEnabled', false) | |
assemblyEnabled = getOption(p, 'analyzers.assemblyEnabled', false) | |
pathToBundleAudit = getOption(p, 'analyzers.pathToBundleAudit', '/usr/local/bin/bundle-audit') | |
//retiredEnabled = getOption(p, 'analyzers.retiredEnabled', true) | |
} | |
cve { | |
urlModified = getOption(p, 'cve.urlModified', 'https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz') | |
urlBase = getOption(p, 'cve.urlBase', 'https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz') | |
} | |
data { | |
directory = getOption(p, 'data.directory', null) | |
} | |
// See hints file info here: https://jeremylong.github.io/DependencyCheck/general/hints.html | |
File defaultHintsFile = file(new File(project.rootDir, 'dependency-check-hints.xml')) | |
defaultHintsFile = defaultHintsFile.isFile() ? defaultHintsFile : null | |
hintsFile = getOption(p, 'hintsFile', defaultHintsFile) | |
// See suppression file info here: https://jeremylong.github.io/DependencyCheck/general/suppression.html | |
File defaultSuppressionFile = file(new File(project.rootDir, 'dependency-check-suppressions.xml')) | |
defaultSuppressionFile = defaultSuppressionFile.isFile() ? defaultSuppressionFile : null | |
List<String> allSuppressionFiles = p.dependencyCheck.suppressionFiles ?: [] | |
def extractedVal = extractProperty(p.dependencyCheck, 'suppressionFile') | |
if (extractedVal) | |
allSuppressionFiles.add(extractedVal) | |
if (p.hasProperty('dependencyCheck.suppressionFiles')) { | |
allSuppressionFiles.addAll(p.property('dependencyCheck.suppressionFiles').split(',').collect { | |
it.trim() | |
}) | |
} | |
if (p.hasProperty('dependencyCheck.suppressionFile')) | |
allSuppressionFiles.add(p.property('dependencyCheck.suppressionFile')) | |
if (defaultSuppressionFile) | |
allSuppressionFiles.add(defaultSuppressionFile.toString()) | |
allSuppressionFiles = allSuppressionFiles.findAll { | |
file(it).isFile() | |
}.unique() | |
log("Set dependencyCheck.suppressionFiles=${allSuppressionFiles} via multiple sources") | |
suppressionFiles = allSuppressionFiles //as ArrayList<String> | |
suppressionFile = getOption(p, 'suppressionFile', defaultSuppressionFile) | |
// Non-zero exit code when high severity vulnerability is found | |
failBuildOnCVSS = getOption(p, 'failBuildOnCVSS', 7.0, 11.0) as Float | |
format = getOption(p, 'format', Format.ALL, Format.HTML) as String | |
outputDirectory = getOption(p, 'outputDirectory', "${p.buildDir}/reports", "${p.buildDir}/reports") | |
def coerceToList = { o -> | |
if (o instanceof String) | |
return o.split(',').collect { it.trim() } | |
return o | |
} | |
def coerceToBoolean = { o -> | |
if (o instanceof String) | |
return Boolean.parseBoolean(o) | |
return o | |
} | |
skip = coerceToBoolean(getOption(p, 'skip', false, false)) | |
skipConfigurations = coerceToList(getOption(p, 'skipConfigurations', [], [])) | |
scanConfigurations = coerceToList(getOption(p, 'scanConfigurations', [], [])) | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment