Skip to content

Commit

Permalink
Merge pull request #54 from calgaryscientific/people/davidgamba/rmd-2…
Browse files Browse the repository at this point in the history
…3648-Add-reports-to-workflow

People/davidgamba/rmd 23648 add reports to workflow

Reviewed by Tony Vo.
  • Loading branch information
DavidGamba authored Feb 22, 2018
2 parents d0eff3c + f5f0fe9 commit 5602934
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 8 deletions.
9 changes: 9 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ Set<String> moduleWhitelist
// Error Management
Boolean ignoreFailure = false
// Workflow reports
Boolean failWorkflowTasksOnNewFlaws = false
----

To pass these fields to the Plugin as properties, set the field on `veracodeSetup` to read the desired property, for example:
Expand All @@ -143,9 +146,11 @@ A single task will do the following:

* _Query the status_ of the latest build:
** If the latest build Scan is complete:
. Get latest build’s _Detailed Report_ and print flaw summary.
. _Creates a new build_.
. _Uploads the given files_ to the Veracode platform.
. _Begins a Pre-Scan_ of the uploaded files.
. Optionally fail the build if there were new flaws from the _Detailed Report_ on step 1.

** If the latest build has a completed Pre-scan:
*** _Begins the Scan_ of the application selecting the given white list modules.
Expand All @@ -164,12 +169,15 @@ task veracodeBuildWorkflow(type: com.calgaryscientific.gradle.VeracodeWorkflowTa
build_version = "build-name-if-creating-a-new-build"
ignoreFailure = true <1>
filesToUpload = fileTree(dir: "upload/", include: "*").getFiles() <2>
failWorkflowTasksOnNewFlaws = true <3>
}
}
}
----
<1> Optionally ignore failures to avoid stopping the build process if there is a problem with the Veracode calls.
<2> Setup `veracodeSetup` `filesToUpload` again to ensure it is evaluated after the `buildMyApplication` task.
<3> Optionally fail the task if there are new flaws introduced in the latest build.
The failure will be triggered after a new build creation, file upload and pre-scan submission.

This task can be triggered by every commit and will only create a new build, upload files, begin pre-scans or begin scans when the Veracode platform is ready for it.

Expand All @@ -184,6 +192,7 @@ task veracodeBuildWorkflow(type: com.calgaryscientific.gradle.VeracodeWorkflowSa
build_version = "build-name-if-creating-a-new-sandbox-build"
ignoreFailure = true
sandboxFilesToUpload = fileTree(dir: "upload/", include: "*").getFiles()
failWorkflowTasksOnNewFlaws = true
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,8 @@ class VeracodeBuildList {
XMLIO.getNodeAttributes(build, 'build_id', 'policy_updated_date', 'version')
}
}

static String getLatestBuildID(Node xml) {
XMLIO.getNodeList(xml, 'build').last().attribute('build_id')
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ class VeracodeDetailedReport {
return filterOpenFlaws(getAllFlawsFromDetailedReportXML(xml))
}

/**
* Extracts the New flaw Nodes from the detailed XML report
*
* @param xml
* @return flaws
*/
static List<Node> getNewFlawsFromDetailedReportXML(Node xml) {
return filterNewFlaws(getAllFlawsFromDetailedReportXML(xml))
}

/**
* Extract Open flaws from a list of flaws.
* @param flaws
Expand All @@ -146,6 +156,25 @@ class VeracodeDetailedReport {
}
}

/**
* Extract New flaws from a list of flaws.
* @param flaws
* @return flaws
*/
static List<Node> filterNewFlaws(List<Node> flaws) {
flaws.findAll { flaw ->
String status = flaw.attribute('remediation_status')
(status == "New")
}
}

static void printFlawSummary(List<Node> flaws) {
flaws.each { flaw ->
printf "issueid: %s, severity: %s, cweid: %s, categoryname: %s, module: %s, date_first_occurrence: %s\n",
XMLIO.getNodeAttributes(flaw, 'issueid', 'severity', 'cweid', 'categoryname', 'module', 'date_first_occurrence')
}
}

/**
* Extracts the flaws information of the detailed XML report and return a list of rows with it
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,7 @@ class VeracodeSetup {

// Error Management
Boolean ignoreFailure = false

// Workflow reports
Boolean failWorkflowTasksOnNewFlaws = false
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
package com.calgaryscientific.gradle

import groovy.transform.CompileStatic
import org.gradle.api.GradleException
import org.slf4j.Logger
import org.slf4j.LoggerFactory

Expand All @@ -42,14 +43,16 @@ class VeracodeWorkflow {
Set<String> moduleWhitelist,
Integer maxTries,
Integer waitTime,
Boolean delete
Boolean delete,
Boolean failOnNewFlaws
) {
// Work on the latest build
String build_id = null
// Save to variable to do the API call only once
Node buildInfo
String emptyAppRegex = "Could not find a build for application=\\S+"
String buildStatus
Boolean newFlaws = false

// This call to writeXmlWithErrorCheck might throw an error since Veracode errors out for empty Apps
try {
Expand All @@ -65,6 +68,18 @@ class VeracodeWorkflow {

log.info("buildStatus: " + buildStatus)

// Previous Scan is complete
if (buildStatus == "Results Ready") {
log.info("Retrieving build list to obtain latest build_id")
Node buildList = XMLIO.writeXmlWithErrorCheck(VeracodeBuildList.getFile(outputDir, app_id), veracodeAPI.getBuildList())
// Get the last build ID
build_id = VeracodeBuildList.getLatestBuildID(buildList)
log.info("Latest build_id: " + build_id)
newFlaws = printReportSummaryAndCheckForNewFlaws(veracodeAPI, outputDir, build_id)
// Reset to work on the latest build
build_id = null
}

// Previous Scan is complete (results are ready) or this is an newly created App that has no existing builds
if (buildStatus == "Results Ready" || buildStatus =~ emptyAppRegex) {
log.info("createBuild: " + build_version)
Expand Down Expand Up @@ -94,6 +109,10 @@ class VeracodeWorkflow {
buildStatus = VeracodeBuildInfo.getBuildStatus(buildInfo)
log.info("buildStatus: " + buildStatus)
}

if (failOnNewFlaws && newFlaws) {
throw new GradleException('New Veracode flaws introduced in latest build results')
}
}

static void sandboxWorkflow(VeracodeAPI veracodeAPI,
Expand All @@ -105,14 +124,16 @@ class VeracodeWorkflow {
Set<String> moduleWhitelist,
Integer maxTries,
Integer waitTime,
Boolean delete
Boolean delete,
Boolean failOnNewFlaws
) {
// Work on the latest build
String build_id = null
// Save to variable to do the API call only once
Node buildInfo
String emptySandboxRegex = "Could not find a build for application=\\S+ and sandbox=\\S+"
String buildStatus
Boolean newFlaws = false

// This call to writeXmlWithErrorCheck might throw an error since Veracode errors out for empty Sandboxes
try {
Expand All @@ -128,6 +149,18 @@ class VeracodeWorkflow {

log.info("buildStatus: " + buildStatus)

// Previous Scan is complete
if (buildStatus == "Results Ready") {
log.info("Retrieving build list to obtain latest build_id")
Node buildList = XMLIO.writeXmlWithErrorCheck(VeracodeBuildList.getSandboxFile(outputDir, app_id, sandbox_id), veracodeAPI.getBuildListSandbox())
// Get the last build ID
build_id = VeracodeBuildList.getLatestBuildID(buildList)
log.info("Latest build_id: " + build_id)
newFlaws = printReportSummaryAndCheckForNewFlaws(veracodeAPI, outputDir, build_id)
// Reset to work on the latest build
build_id = null
}

// Previous Scan is complete (results are ready) or this is an newly created Sandbox that has no existing builds
if (buildStatus == "Results Ready" || buildStatus =~ emptySandboxRegex) {
log.info("createBuild: " + build_version)
Expand Down Expand Up @@ -157,5 +190,31 @@ class VeracodeWorkflow {
buildStatus = VeracodeBuildInfo.getBuildStatus(buildInfo)
log.info("buildStatus: " + buildStatus)
}

if (failOnNewFlaws && newFlaws) {
throw new GradleException('New Veracode flaws introduced in latest build results')
}
}

/**
* Prints a report summary for the given build_id and returns true or false depending of if there are new flaws.
* @param veracodeAPI
* @param outputDir
* @param build_id
* @return
*/
private static Boolean printReportSummaryAndCheckForNewFlaws(VeracodeAPI veracodeAPI,
String outputDir,
String build_id) {
log.info("Get DetailedReport for build_id: " + build_id)
File detailedReportFile = VeracodeDetailedReport.getFile(outputDir, build_id)
Node detailedReport = XMLIO.writeXmlWithErrorCheck(detailedReportFile, veracodeAPI.detailedReport(build_id))
log.info("report file: " + detailedReportFile)
log.info("Overall flaw results:")
VeracodeDetailedReport.printFlawInformationByCWEID(detailedReport)
log.info("New flaw information:")
List<Node> newFlaws = VeracodeDetailedReport.getNewFlawsFromDetailedReportXML(detailedReport)
VeracodeDetailedReport.printFlawSummary(newFlaws)
return (newFlaws.size() > 0)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ class VeracodeWorkflowSandboxTask extends VeracodeTask {
getModuleWhitelist(),
veracodeSetup.maxUploadAttempts,
veracodeSetup.waitTimeBetweenAttempts,
veracodeSetup.deleteUploadedArtifacts)
veracodeSetup.deleteUploadedArtifacts,
veracodeSetup.failWorkflowTasksOnNewFlaws
)
} catch (Exception e) {
if (veracodeSetup.ignoreFailure) {
println e.getMessage()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ class VeracodeWorkflowTask extends VeracodeTask {
getModuleWhitelist(),
veracodeSetup.maxUploadAttempts,
veracodeSetup.waitTimeBetweenAttempts,
veracodeSetup.deleteUploadedArtifacts)
veracodeSetup.deleteUploadedArtifacts,
veracodeSetup.failWorkflowTasksOnNewFlaws
)
} catch (Exception e) {
if (veracodeSetup.ignoreFailure) {
println e.getMessage()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*******************************************************************************
* MIT License
*
* Copyright (c) 2017-2018 Calgary Scientific Incorporated
*
* Copyright (c) 2013-2014 kctang
*
* 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.
******************************************************************************/

package com.calgaryscientific.gradle

class VeracodeBuildListTest extends TestCommonSetup {
File buildlistFile = getResource('buildlist-1.3.xml')

def 'Test veracodeGetBuildList Task'() {
given:
Node xml = XMLIO.parse(buildlistFile)

when:
String buildID = VeracodeBuildList.getLatestBuildID(xml)

then:
assert buildID == '125'
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,32 @@ class VeracodeDetailedReportDOTest extends TestCommonSetup {
assert lines[0] == "issueid, remediation_status, mitigation_status, module, sourcefilepath, sourcefile, line, type"
assert lines[1] == "123, New, proposed, lib1.dll, path1, chunk.c, 305, vsprintf"
}

def 'Test getting new flaws'() {
given:
Node xml = XMLIO.parse(detailedReportFile)

when:
List<Node> newFlaws = VeracodeDetailedReport.getNewFlawsFromDetailedReportXML(xml)

then:
assert newFlaws.size() == 1
assert newFlaws[0].attribute('issueid') as String == '123'
}

def 'Test printing flaw summary'() {
given:
Node xml = XMLIO.parse(detailedReportFile)
def os = mockSystemOut()

when:
VeracodeDetailedReport.printFlawSummary(VeracodeDetailedReport.getNewFlawsFromDetailedReportXML(xml))
def is = getSystemOut(os)
restoreStdout()
List<String> lines = is.readLines()

then:
assert lines.size() == 1
assert lines[0] == "issueid: 123, severity: 5, cweid: 121, categoryname: Stack-based Buffer Overflow, module: lib1.dll, date_first_occurrence: 2017-06-18 16:22:39 UTC"
}
}
Loading

0 comments on commit 5602934

Please sign in to comment.