Skip to content

Instantly share code, notes, and snippets.

@milo-minderbinder
Last active June 25, 2018 16:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save milo-minderbinder/92de1b93cd2b3e5b67a9cd761b22854f to your computer and use it in GitHub Desktop.
Save milo-minderbinder/92de1b93cd2b3e5b67a9cd761b22854f 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 and subprojects by enforcing that they are compiled with debug symbols,
* and, for Spring Boot projects, that they are set to non-executable, so that the build artifacts can be scanned
* successfully with the Veracode Static Analysis engine.
*
* It also adds the `com.calgaryscientific.gradle.VeracodePlugin` to all projects and defines tasks to automatically
* configure and run static analysis scans with Veracode. At a minimum, the following Gradle project properties must be
* defined to run the scan tasks successfully:
* * veracodeID - the API ID to authenticate to Veracode with
* * veracodeKey - the API key to authenticate to Veracode with
* * veracodeAppName - the Application name (as it appears in the Veracode portal)
*
* Once the required options are set, either through the `gradle.properties` or via `-P` command-line arguments, then
* simply execute the `veracodeGetAppID` and `veracodeBuildWorkflow` tasks to build the project and upload the artifacts
* for a policy scan, or execute the `veracodeGetAppID`, `veracodeGetSandboxID` and `veracodeBuildWorkflowSandbox` tasks
* to build the project and upload the artifacts for a sandbox scan.
*
* 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/veracode.gradle :veracodeBuildWorkflow
*
* 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.
*/
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')
initscript {
ext {
veracodePluginVersion = '0.6.0'
}
repositories {
maven { url 'https://plugins.gradle.org/m2/' }
}
dependencies {
classpath "gradle.plugin.com.calgaryscientific.gradle:veracodePlugin:${veracodePluginVersion}"
}
}
def logVeracodeSetup(Project project, LogLevel logLevel = LogLevel.DEBUG) {
def ignoredProperties = [
'asDynamicObject',
'class',
'convention',
'conventionMapping',
'extensions',
'id',
'key',
'username',
'password'
]
log(logLevel, "${project} veracodeSetup:\n\t" +
project.veracodeSetup.properties.findAll { name, val ->
val != null && !(name in ignoredProperties)
}.collect { name, val ->
if (val instanceof Collection)
val = val.join('\n\t\t')
"${name} = ${val}"
}.sort().join('\n\t'))
}
Set<String> veracodeArchiveExtensions = [
'.tar',
'.tar.gz',
'.tgz',
'.zip'
]
Set<String> veracodeASPExtensions = [
'.asp',
'.bas',
'.cls',
'.ctl',
'.frm',
'.frx',
'.grp',
'.htm',
'.html',
'.inc',
'.js',
'.ocx',
'.vbscript',
'.vpb',
'.vbw'
]
Set<String> veracodeJavaExtensions = [
'.aar',
'.ear',
'.jar',
'.mar',
'.war'
]
Set<String> veracodeJSExtensions = [
'.asp',
'.css',
'.ehtml',
'.es',
'.es6',
'.handlebars',
'.hbs',
'.hjs',
'.htm',
'.html',
'.js',
'.jsx',
'.json',
'.jsp',
'.mustache',
'.php',
'.ts',
'.tsx',
'.xhtml'
]
Set<String> veracodePHPExtensions = [
'.php',
'.module',
'.inc',
'.html',
'.htm',
'.profile',
'.install',
'.engine',
'.theme',
'.php4',
'.php5',
'.php7',
'.phtml'
]
Set<String> veracodePerlExtensions = [
'.pl',
'.pm',
'.plx',
'.pl5',
'.cgi'
]
Set<String> veracodePythonExtensions = [
'.py',
'.html',
'.htm'
]
Set<String> veracodeUploadExtensions = (veracodeArchiveExtensions + veracodeJavaExtensions)
Set<String> veracodeExtensions = (veracodeArchiveExtensions +
veracodeASPExtensions +
veracodeJavaExtensions +
veracodeJSExtensions +
veracodePHPExtensions +
veracodePerlExtensions +
veracodePythonExtensions)
allprojects {
apply plugin: com.calgaryscientific.gradle.VeracodePlugin
veracodeSetup {
id = project.veracodeSetup.id ?: project.findProperty('veracodeID')?.trim()
key = project.veracodeSetup.key ?: project.findProperty('veracodeKey')?.trim()
outputDir = project.veracodeSetup.outputDir ?: project.findProperty('veracodeOutputDir')?.trim()
app_id = project.veracodeSetup.app_id ?: project.findProperty('veracodeAppID')?.trim()
sandbox_id = project.veracodeSetup.sandbox_id ?: project.findProperty('veracodeSandboxID')?.trim()
sandbox_name = project.veracodeSetup.sandbox_name ?: project.findProperty('veracodeSandboxName')?.trim()
build_version = project.veracodeSetup.build_version ?: project.findProperty('veracodeBuildVersion')?.trim()
}
task gitCommitHash(type: Exec) {
workingDir "${project.rootDir}"
executable 'git'
args 'rev-parse', '--short', 'HEAD'
standardOutput = new ByteArrayOutputStream()
ext.output = {
return standardOutput.toString().trim()
}
}
task gitBranchName(type: Exec) {
workingDir "${project.rootDir}"
executable 'git'
args 'rev-parse', '--abbrev-ref', 'HEAD'
standardOutput = new ByteArrayOutputStream()
ext.output = {
return standardOutput.toString().trim()
}
}
task veracodeGetAppID {
dependsOn veracodeGetAppList
ext {
applistFile = null
appName = project.findProperty('veracodeAppName')
}
doLast {
def outputDir = project.veracodeSetup.outputDir ?: new File("${project.buildDir}", 'veracode')
applistFile = applistFile ?: new File(outputDir, 'applist.xml')
def applist = new XmlSlurper().parse(file(applistFile))
def appID = applist.app.find { app ->
app.@app_name == appName
}.collect { app ->
app.@app_id
}.first()
log("Setting veracodeSetup.app_id = '${appID}'")
project.veracodeSetup.app_id = appID
}
}
task veracodeGetOrCreateSandboxID(type: com.calgaryscientific.gradle.VeracodeCreateSandboxTask) {
dependsOn gitBranchName, veracodeGetSandboxList
mustRunAfter veracodeGetAppID
ext {
sandboxlistFile = null
}
doFirst {
if (!project.veracodeSetup.sandbox_name) {
log("Setting veracodeSetup.sandbox_name = '${gitBranchName.output()}'")
project.veracodeSetup.sandbox_name = gitBranchName.output()
}
def outputDir = project.veracodeSetup.outputDir ?: new File("${project.buildDir}", 'veracode')
sandboxlistFile = sandboxlistFile ?: new File(outputDir, "sandboxlist-${project.veracodeSetup.app_id}.xml")
def sandboxlist = new XmlSlurper().parse(file(sandboxlistFile))
def sandboxID = sandboxlist.sandbox.find { sandbox ->
sandbox.@sandbox_name == project.veracodeSetup.sandbox_name
}.collect { sandbox ->
sandbox.@sandbox_id
}.find()
if (sandboxID) {
log("Setting veracodeSetup.sandbox_id = '${sandboxID}'")
project.veracodeSetup.sandbox_id = sandboxID
def msg = "Sandbox '${project.veracodeSetup.sandbox_name}' with ID '${sandboxID}' exists"
log(msg)
throw new StopExecutionException(msg)
}
log("Sandbox '${project.veracodeSetup.sandbox_name}' does NOT exist yet")
}
doLast {
def sandboxinfoFile = new File(project.veracodeSetup.outputDir,
"sandboxinfo-${project.veracodeSetup.app_id}-latest.xml")
def sandboxinfo = new XmlSlurper().parse(file(sandboxinfoFile))
def sandboxID = sandboxinfo.sandbox.find { sandbox ->
sandbox.@sandbox_name == project.veracodeSetup.sandbox_name
}.collect { sandbox ->
sandbox.@sandbox_id
}.first()
log("Setting veracodeSetup.sandbox_id '${sandboxID}'")
project.veracodeSetup.sandbox_id = sandboxID
}
}
task veracodeGetSandboxID {
dependsOn gitBranchName, veracodeGetSandboxList
mustRunAfter veracodeGetAppID, veracodeCreateSandbox
ext {
sandboxlistFile = null
}
doLast {
if (!project.veracodeSetup.sandbox_name) {
log("Setting veracodeSetup.sandbox_name = '${gitBranchName.output()}'")
project.veracodeSetup.sandbox_name = gitBranchName.output()
}
def outputDir = project.veracodeSetup.outputDir ?: new File("${project.buildDir}", 'veracode')
sandboxlistFile = sandboxlistFile ?: new File(outputDir, "sandboxlist-${project.veracodeSetup.app_id}.xml")
def sandboxlist = new XmlSlurper().parse(file(sandboxlistFile))
def sandboxID = sandboxlist.sandbox.find { sandbox ->
sandbox.@sandbox_name == project.veracodeSetup.sandbox_name
}.collect { sandbox ->
sandbox.@sandbox_id
}.first()
log("Setting veracodeSetup.sandbox_id '${sandboxID}'")
project.veracodeSetup.sandbox_id = sandboxID
}
}
task veracodeGetBuildDependencies() {
outputs.files inputs.files
}
task veracodeGetBuildArtifacts {
outputs.files inputs.files
}
task veracodeBuildWorkflowBase {
dependsOn veracodeGetBuildArtifacts, veracodeGetBuildDependencies, gitCommitHash
mustRunAfter veracodeGetAppID, veracodeGetSandboxID, veracodeGetOrCreateSandboxID
doLast {
FileCollection scanFiles = veracodeGetBuildArtifacts.outputs.files
FileCollection dependencyFiles = veracodeGetBuildDependencies.outputs.files
String timestamp = new Date().format('YMMdd-HHmmss', TimeZone.getTimeZone('UTC'))
def buildVersion = project.veracodeSetup.build_version ?: "${gitCommitHash.output()}|${timestamp}"
project.veracodeSetup {
build_version = buildVersion
filesToUpload = scanFiles.asFileTree.getFiles() + dependencyFiles.asFileTree.getFiles()
sandboxFilesToUpload = scanFiles.asFileTree.getFiles() + dependencyFiles.asFileTree.getFiles()
moduleWhitelist = scanFiles.asFileTree.getFiles().collect { File f ->
f.name
} + scanFiles.asFileTree.matching {
include veracodeUploadExtensions.collect { extn -> "**/*${extn}" }
}.getFiles().collectMany { File f ->
['ASP' : veracodeASPExtensions,
'JS' : veracodeJSExtensions,
'PHP' : veracodePHPExtensions,
'Perl' : veracodePerlExtensions,
'Python': veracodePythonExtensions
].collect { fileType, extensions ->
def matchedFiles = project.zipTree(f).matching {
include extensions.collect { extn -> "**/*${extn}" }
}
if (!matchedFiles.empty) {
log("Found ${fileType} files within ${f}")
"${fileType} files within ${f.name}".toString()
}
}.findAll()
}
}
logVeracodeSetup(project, LogLevel.INFO)
}
}
task veracodeBuildWorkflow(type: com.calgaryscientific.gradle.VeracodeWorkflowTask) {
dependsOn veracodeBuildWorkflowBase
doFirst {
log("Executing veracodeBuildWorkflow for ${project}")
logVeracodeSetup(project, LogLevel.INFO)
}
}
task veracodeBuildWorkflowSandbox(type: com.calgaryscientific.gradle.VeracodeWorkflowSandboxTask) {
dependsOn veracodeBuildWorkflowBase
doFirst {
log("Executing veracodeBuildWorkflowSandbox for ${project}")
logVeracodeSetup(project, LogLevel.INFO)
}
}
project.getTasksByName('copyDependencies', true).each { Task t ->
veracodeGetBuildDependencies.inputs.files t.outputs.files.asFileTree.matching {
include veracodeUploadExtensions.collect { extn -> "**/*${extn}" }
}
}
project.allprojects.collectMany { p ->
['ear', 'war', 'jar', 'assembleDebug', 'assemble'].findResult { String n ->
p.getTasksByName(n, false) ?: null
} ?: []
}.each { Task t ->
veracodeGetBuildArtifacts.inputs.files t.outputs.files.asFileTree.matching {
include veracodeUploadExtensions.collect { extn -> "**/*${extn}" }
}
log("Adding ${t.outputs.files} to ${veracodeGetBuildArtifacts.inputs.files}")
}
tasks.withType(AbstractCompile).matching { task ->
task.respondsTo('getOptions').find { MetaMethod method ->
CompileOptions.isAssignableFrom(method.returnType)
}
}.all {
doFirst {
log("Forcing debug options for task ${it}")
options.with {
debug = true
debugOptions.debugLevel = 'source,lines,vars'
}
}
}
Action<? super Plugin> reconfigureSpringBoot = {
log("Found Spring Boot plugin in ${project}")
gradle.taskGraph.whenReady {
if (gradle.taskGraph.hasTask(veracodeBuildWorkflowBase)) {
log("Attempting to reconfigure spring-boot plugin for ${project}")
def ext = project.extensions.findByName('springBoot')
if (ext && ext.hasProperty('executable')) {
log("Setting springBoot.executable = false for ${project}")
ext.executable = false
} else
log("Unable to set ${project}.${ext}.executable = false")
}
}
}
plugins.withId('spring-boot', reconfigureSpringBoot)
plugins.withId('org.springframework.boot', reconfigureSpringBoot)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment