Last active
June 25, 2018 16:58
-
-
Save milo-minderbinder/92de1b93cd2b3e5b67a9cd761b22854f 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 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