Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save risdenk/3e6609d1fd3743aea9e8362b7687497f to your computer and use it in GitHub Desktop.
Save risdenk/3e6609d1fd3743aea9e8362b7687497f to your computer and use it in GitHub Desktop.
/**
* 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.
*/
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 = '5.3.2'
}
repositories {
mavenCentral()
}
dependencies {
classpath "org.owasp:dependency-check-gradle:${dependencyCheckVersion}"
}
}
gradle.rootProject {
buildscript {
// DepedencyCheck plugin is in Maven Central, but check if Maven Central is added already so we don't
// interfere with the number of repos added or their order.
boolean hasMavenCentral = repositories.withType(MavenArtifactRepository).find { MavenArtifactRepository r ->
r.url.toString().equals('https://repo1.maven.org/maven2/')
}
if (!hasMavenCentral) {
log('Adding MavenCentral to buildscript repositories')
repositories {
mavenCentral()
}
}
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)
pathToBundleAudit = getOption(p, 'analyzers.pathToBundleAudit', '/usr/local/bin/bundle-audit')
//retiredEnabled = getOption(p, 'analyzers.retiredEnabled', true)
}
// 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
}
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