You've already forked sap-jenkins-library
mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-06-27 00:41:29 +02:00
add step for Synopsis Detect Scans (#690)
* add step for Synopsis Detect Scans tool was formerly calles Blackduck Hub Detect. Details about the tool can be found here: https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/62423113/Synopsys+Detect
This commit is contained in:
@ -88,7 +88,7 @@ class Helper {
|
|||||||
static getConfigHelper(classLoader, roots, script) {
|
static getConfigHelper(classLoader, roots, script) {
|
||||||
|
|
||||||
def compilerConfig = new CompilerConfiguration()
|
def compilerConfig = new CompilerConfiguration()
|
||||||
compilerConfig.setClasspathList( roots )
|
compilerConfig.setClasspathList( roots )
|
||||||
|
|
||||||
new GroovyClassLoader(classLoader, compilerConfig, true)
|
new GroovyClassLoader(classLoader, compilerConfig, true)
|
||||||
.parseClass(new File(projectRoot, 'src/com/sap/piper/ConfigurationHelper.groovy'))
|
.parseClass(new File(projectRoot, 'src/com/sap/piper/ConfigurationHelper.groovy'))
|
||||||
@ -210,114 +210,114 @@ class Helper {
|
|||||||
f.eachLine {
|
f.eachLine {
|
||||||
line ->
|
line ->
|
||||||
|
|
||||||
if(line ==~ /.*dependingOn.*/) {
|
if(line ==~ /.*dependingOn.*/) {
|
||||||
def dependentConfigKey = (line =~ /.*dependingOn\('(.*)'\).mixin\('(.*)'/)[0][1]
|
def dependentConfigKey = (line =~ /.*dependingOn\('(.*)'\).mixin\('(.*)'/)[0][1]
|
||||||
def configKey = (line =~ /.*dependingOn\('(.*)'\).mixin\('(.*)'/)[0][2]
|
def configKey = (line =~ /.*dependingOn\('(.*)'\).mixin\('(.*)'/)[0][2]
|
||||||
if(! step.dependentConfig[configKey]) {
|
if(! step.dependentConfig[configKey]) {
|
||||||
step.dependentConfig[configKey] = []
|
step.dependentConfig[configKey] = []
|
||||||
|
}
|
||||||
|
step.dependentConfig[configKey] << dependentConfigKey
|
||||||
}
|
}
|
||||||
step.dependentConfig[configKey] << dependentConfigKey
|
|
||||||
}
|
|
||||||
|
|
||||||
if(docuEnd) {
|
if(docuEnd) {
|
||||||
docuEnd = false
|
docuEnd = false
|
||||||
|
|
||||||
if(isHeader(line)) {
|
if(isHeader(line)) {
|
||||||
def _docu = []
|
def _docu = []
|
||||||
docuLines.each { _docu << it }
|
docuLines.each { _docu << it }
|
||||||
_docu = Helper.trim(_docu)
|
_docu = Helper.trim(_docu)
|
||||||
step.description = _docu.join('\n')
|
step.description = _docu.join('\n')
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
def param = retrieveParameterName(line)
|
def param = retrieveParameterName(line)
|
||||||
|
|
||||||
if(!param) {
|
if(!param) {
|
||||||
throw new RuntimeException('Cannot retrieve parameter for a comment')
|
throw new RuntimeException('Cannot retrieve parameter for a comment')
|
||||||
|
}
|
||||||
|
|
||||||
|
def _docu = [], _value = [], _mandatory = [], _parentObject = []
|
||||||
|
docuLines.each { _docu << it }
|
||||||
|
valueLines.each { _value << it }
|
||||||
|
mandatoryLines.each { _mandatory << it }
|
||||||
|
parentObjectLines.each { _parentObject << it }
|
||||||
|
_parentObject << param
|
||||||
|
param = _parentObject*.trim().join('/').trim()
|
||||||
|
|
||||||
|
if(step.parameters[param].docu || step.parameters[param].value)
|
||||||
|
System.err << "[WARNING] There is already some documentation for parameter '${param}. Is this parameter documented twice?'\n"
|
||||||
|
|
||||||
|
step.parameters[param].docu = _docu*.trim().join(' ').trim()
|
||||||
|
step.parameters[param].value = _value*.trim().join(' ').trim()
|
||||||
|
step.parameters[param].mandatory = _mandatory*.trim().join(' ').trim()
|
||||||
|
}
|
||||||
|
docuLines.clear()
|
||||||
|
valueLines.clear()
|
||||||
|
mandatoryLines.clear()
|
||||||
|
parentObjectLines.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
if( line.trim() ==~ /^\/\*\*.*/ ) {
|
||||||
|
docu = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if(docu) {
|
||||||
|
def _line = line
|
||||||
|
_line = _line.replaceAll('^\\s*', '') // leading white spaces
|
||||||
|
if(_line.startsWith('/**')) _line = _line.replaceAll('^\\/\\*\\*', '') // start comment
|
||||||
|
if(_line.startsWith('*/') || _line.trim().endsWith('*/')) _line = _line.replaceAll('^\\*/', '').replaceAll('\\*/\\s*$', '') // end comment
|
||||||
|
if(_line.startsWith('*')) _line = _line.replaceAll('^\\*', '') // continue comment
|
||||||
|
if(_line.startsWith(' ')) _line = _line.replaceAll('^\\s', '')
|
||||||
|
if(_line ==~ /.*@possibleValues.*/) {
|
||||||
|
mandatory = false // should be something like reset attributes
|
||||||
|
value = true
|
||||||
|
parentObject = false
|
||||||
|
}
|
||||||
|
// some remark for mandatory e.g. some parameters are only mandatory under certain conditions
|
||||||
|
if(_line ==~ /.*@mandatory.*/) {
|
||||||
|
value = false // should be something like reset attributes ...
|
||||||
|
mandatory = true
|
||||||
|
parentObject = false
|
||||||
|
}
|
||||||
|
// grouping config properties within a parent object for easier readability
|
||||||
|
if(_line ==~ /.*@parentConfigKey.*/) {
|
||||||
|
value = false // should be something like reset attributes ...
|
||||||
|
mandatory = false
|
||||||
|
parentObject = true
|
||||||
}
|
}
|
||||||
|
|
||||||
def _docu = [], _value = [], _mandatory = [], _parentObject = []
|
if(value) {
|
||||||
docuLines.each { _docu << it }
|
if(_line) {
|
||||||
valueLines.each { _value << it }
|
_line = (_line =~ /.*@possibleValues\s*?(.*)/)[0][1]
|
||||||
mandatoryLines.each { _mandatory << it }
|
valueLines << _line
|
||||||
parentObjectLines.each { _parentObject << it }
|
}
|
||||||
_parentObject << param
|
}
|
||||||
param = _parentObject*.trim().join('/').trim()
|
|
||||||
|
|
||||||
if(step.parameters[param].docu || step.parameters[param].value)
|
if(mandatory) {
|
||||||
System.err << "[WARNING] There is already some documentation for parameter '${param}. Is this parameter documented twice?'\n"
|
if(_line) {
|
||||||
|
_line = (_line =~ /.*@mandatory\s*?(.*)/)[0][1]
|
||||||
|
mandatoryLines << _line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
step.parameters[param].docu = _docu*.trim().join(' ').trim()
|
if(parentObject) {
|
||||||
step.parameters[param].value = _value*.trim().join(' ').trim()
|
if(_line) {
|
||||||
step.parameters[param].mandatory = _mandatory*.trim().join(' ').trim()
|
_line = (_line =~ /.*@parentConfigKey\s*?(.*)/)[0][1]
|
||||||
|
parentObjectLines << _line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!value && !mandatory && !parentObject) {
|
||||||
|
docuLines << _line
|
||||||
|
}
|
||||||
}
|
}
|
||||||
docuLines.clear()
|
|
||||||
valueLines.clear()
|
|
||||||
mandatoryLines.clear()
|
|
||||||
parentObjectLines.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
if( line.trim() ==~ /^\/\*\*.*/ ) {
|
if(docu && line.trim() ==~ /^.*\*\//) {
|
||||||
docu = true
|
docu = false
|
||||||
}
|
value = false
|
||||||
|
|
||||||
if(docu) {
|
|
||||||
def _line = line
|
|
||||||
_line = _line.replaceAll('^\\s*', '') // leading white spaces
|
|
||||||
if(_line.startsWith('/**')) _line = _line.replaceAll('^\\/\\*\\*', '') // start comment
|
|
||||||
if(_line.startsWith('*/') || _line.trim().endsWith('*/')) _line = _line.replaceAll('^\\*/', '').replaceAll('\\*/\\s*$', '') // end comment
|
|
||||||
if(_line.startsWith('*')) _line = _line.replaceAll('^\\*', '') // continue comment
|
|
||||||
if(_line.startsWith(' ')) _line = _line.replaceAll('^\\s', '')
|
|
||||||
if(_line ==~ /.*@possibleValues.*/) {
|
|
||||||
mandatory = false // should be something like reset attributes
|
|
||||||
value = true
|
|
||||||
parentObject = false
|
|
||||||
}
|
|
||||||
// some remark for mandatory e.g. some parameters are only mandatory under certain conditions
|
|
||||||
if(_line ==~ /.*@mandatory.*/) {
|
|
||||||
value = false // should be something like reset attributes ...
|
|
||||||
mandatory = true
|
|
||||||
parentObject = false
|
|
||||||
}
|
|
||||||
// grouping config properties within a parent object for easier readability
|
|
||||||
if(_line ==~ /.*@parentConfigKey.*/) {
|
|
||||||
value = false // should be something like reset attributes ...
|
|
||||||
mandatory = false
|
mandatory = false
|
||||||
parentObject = true
|
parentObject = false
|
||||||
|
docuEnd = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if(value) {
|
|
||||||
if(_line) {
|
|
||||||
_line = (_line =~ /.*@possibleValues\s*?(.*)/)[0][1]
|
|
||||||
valueLines << _line
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mandatory) {
|
|
||||||
if(_line) {
|
|
||||||
_line = (_line =~ /.*@mandatory\s*?(.*)/)[0][1]
|
|
||||||
mandatoryLines << _line
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(parentObject) {
|
|
||||||
if(_line) {
|
|
||||||
_line = (_line =~ /.*@parentConfigKey\s*?(.*)/)[0][1]
|
|
||||||
parentObjectLines << _line
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!value && !mandatory && !parentObject) {
|
|
||||||
docuLines << _line
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(docu && line.trim() ==~ /^.*\*\//) {
|
|
||||||
docu = false
|
|
||||||
value = false
|
|
||||||
mandatory = false
|
|
||||||
parentObject = false
|
|
||||||
docuEnd = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,7 +405,7 @@ class Helper {
|
|||||||
roots = [
|
roots = [
|
||||||
new File(Helper.projectRoot, "vars").getAbsolutePath(),
|
new File(Helper.projectRoot, "vars").getAbsolutePath(),
|
||||||
new File(Helper.projectRoot, "src").getAbsolutePath()
|
new File(Helper.projectRoot, "src").getAbsolutePath()
|
||||||
]
|
]
|
||||||
|
|
||||||
stepsDir = null
|
stepsDir = null
|
||||||
stepsDocuDir = null
|
stepsDocuDir = null
|
||||||
@ -434,7 +434,7 @@ if(args.length >= 3 && args[2].contains('.yml')) {
|
|||||||
|
|
||||||
if(args.length >= 3)
|
if(args.length >= 3)
|
||||||
steps = (args as List).drop(argsDrop) // the first two entries are stepsDir and docuDir
|
steps = (args as List).drop(argsDrop) // the first two entries are stepsDir and docuDir
|
||||||
// the other parts are considered as step names
|
// the other parts are considered as step names
|
||||||
|
|
||||||
|
|
||||||
// assign parameters
|
// assign parameters
|
||||||
@ -558,7 +558,7 @@ def fetchMandatoryFrom(def step, def parameterName, def steps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def fetchPossibleValuesFrom(def step, def parameterName, def steps) {
|
def fetchPossibleValuesFrom(def step, def parameterName, def steps) {
|
||||||
return steps[step]?.parameters[parameterName]?.value ?: ''
|
return steps[step]?.parameters[parameterName]?.value ?: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
def handleStep(stepName, prepareDefaultValuesStep, gse, customDefaults) {
|
def handleStep(stepName, prepareDefaultValuesStep, gse, customDefaults) {
|
||||||
@ -578,8 +578,8 @@ def handleStep(stepName, prepareDefaultValuesStep, gse, customDefaults) {
|
|||||||
prepareDefaultValuesStepParams.customDefaults = customDefaults
|
prepareDefaultValuesStepParams.customDefaults = customDefaults
|
||||||
|
|
||||||
def defaultConfig = Helper.getConfigHelper(getClass().getClassLoader(),
|
def defaultConfig = Helper.getConfigHelper(getClass().getClassLoader(),
|
||||||
roots,
|
roots,
|
||||||
Helper.getDummyScript(prepareDefaultValuesStep, stepName, prepareDefaultValuesStepParams)).use()
|
Helper.getDummyScript(prepareDefaultValuesStep, stepName, prepareDefaultValuesStepParams)).use()
|
||||||
|
|
||||||
def params = [] as Set
|
def params = [] as Set
|
||||||
|
|
||||||
@ -605,10 +605,10 @@ def handleStep(stepName, prepareDefaultValuesStep, gse, customDefaults) {
|
|||||||
def compatibleParams = [] as Set
|
def compatibleParams = [] as Set
|
||||||
if(parentObjectMappings) {
|
if(parentObjectMappings) {
|
||||||
params.each {
|
params.each {
|
||||||
if (parentObjectMappings[it])
|
if (parentObjectMappings[it])
|
||||||
compatibleParams.add(parentObjectMappings[it] + '/' + it)
|
compatibleParams.add(parentObjectMappings[it] + '/' + it)
|
||||||
else
|
else
|
||||||
compatibleParams.add(it)
|
compatibleParams.add(it)
|
||||||
}
|
}
|
||||||
if (compatibleParams)
|
if (compatibleParams)
|
||||||
params = compatibleParams
|
params = compatibleParams
|
||||||
@ -623,16 +623,16 @@ def handleStep(stepName, prepareDefaultValuesStep, gse, customDefaults) {
|
|||||||
// ... would be better if there is no special handling required ...
|
// ... would be better if there is no special handling required ...
|
||||||
|
|
||||||
step.parameters['script'] = [
|
step.parameters['script'] = [
|
||||||
docu: 'The common script environment of the Jenkinsfile running. ' +
|
docu: 'The common script environment of the Jenkinsfile running. ' +
|
||||||
'Typically the reference to the script calling the pipeline ' +
|
'Typically the reference to the script calling the pipeline ' +
|
||||||
'step is provided with the this parameter, as in `script: this`. ' +
|
'step is provided with the this parameter, as in `script: this`. ' +
|
||||||
'This allows the function to access the ' +
|
'This allows the function to access the ' +
|
||||||
'commonPipelineEnvironment for retrieving, for example, configuration parameters.',
|
'commonPipelineEnvironment for retrieving, for example, configuration parameters.',
|
||||||
required: true,
|
required: true,
|
||||||
|
|
||||||
GENERAL_CONFIG: false,
|
GENERAL_CONFIG: false,
|
||||||
STEP_CONFIG: false
|
STEP_CONFIG: false
|
||||||
]
|
]
|
||||||
|
|
||||||
// END special handling for 'script' parameter
|
// END special handling for 'script' parameter
|
||||||
|
|
||||||
@ -643,9 +643,9 @@ def handleStep(stepName, prepareDefaultValuesStep, gse, customDefaults) {
|
|||||||
def defaultValue = Helper.getValue(defaultConfig, it.split('/'))
|
def defaultValue = Helper.getValue(defaultConfig, it.split('/'))
|
||||||
|
|
||||||
def parameterProperties = [
|
def parameterProperties = [
|
||||||
defaultValue: defaultValue,
|
defaultValue: defaultValue,
|
||||||
required: requiredParameters.contains((it as String)) && defaultValue == null
|
required: requiredParameters.contains((it as String)) && defaultValue == null
|
||||||
]
|
]
|
||||||
|
|
||||||
step.parameters.put(it, parameterProperties)
|
step.parameters.put(it, parameterProperties)
|
||||||
|
|
||||||
|
20
documentation/docs/steps/detectExecuteScan.md
Normal file
20
documentation/docs/steps/detectExecuteScan.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# ${docGenStepName}
|
||||||
|
|
||||||
|
## ${docGenDescription}
|
||||||
|
|
||||||
|
## Prerequsites
|
||||||
|
|
||||||
|
You need to store the API token for the Detect service as _'Secret text'_ credential in your Jenkins system.
|
||||||
|
|
||||||
|
!!! note "minimum plugin requirement"
|
||||||
|
This step requires [synopsys-detect-plugin](https://github.com/jenkinsci/synopsys-detect-plugin) with at least version `2.0.0`.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
detectExecuteScan script: this, scanProperties: ['--logging.level.com.synopsys.integration=TRACE']
|
||||||
|
```
|
||||||
|
|
||||||
|
## ${docGenParameters}
|
||||||
|
|
||||||
|
## ${docGenConfiguration}
|
@ -177,6 +177,27 @@ steps:
|
|||||||
stashContent:
|
stashContent:
|
||||||
- 'tests'
|
- 'tests'
|
||||||
testReportFilePath: 'cst-report.json'
|
testReportFilePath: 'cst-report.json'
|
||||||
|
detectExecuteScan:
|
||||||
|
detect:
|
||||||
|
projectVersion: '1'
|
||||||
|
scanners:
|
||||||
|
- signature
|
||||||
|
scanPaths:
|
||||||
|
- '.'
|
||||||
|
scanProperties:
|
||||||
|
- '--blackduck.signature.scanner.memory=4096'
|
||||||
|
- '--blackduck.timeout=6000'
|
||||||
|
- '--blackduck.trust.cert=true'
|
||||||
|
- '--detect.policy.check.fail.on.severities=BLOCKER,CRITICAL,MAJOR'
|
||||||
|
- '--detect.report.timeout=4800'
|
||||||
|
- '--logging.level.com.synopsys.integration=DEBUG'
|
||||||
|
stashContent:
|
||||||
|
- 'buildDescriptor'
|
||||||
|
- 'checkmarx'
|
||||||
|
# buildTool specific settings
|
||||||
|
golang:
|
||||||
|
dockerImage: 'golang:1.12-stretch'
|
||||||
|
dockerWorkspace: ''
|
||||||
dockerExecute:
|
dockerExecute:
|
||||||
dockerPullImage: true
|
dockerPullImage: true
|
||||||
sidecarPullImage: true
|
sidecarPullImage: true
|
||||||
|
143
test/groovy/DetectExecuteScanTest.groovy
Normal file
143
test/groovy/DetectExecuteScanTest.groovy
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#!groovy
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.rules.RuleChain
|
||||||
|
import util.BasePiperTest
|
||||||
|
import util.JenkinsCredentialsRule
|
||||||
|
import util.JenkinsDockerExecuteRule
|
||||||
|
import util.JenkinsReadYamlRule
|
||||||
|
import util.JenkinsShellCallRule
|
||||||
|
import util.JenkinsStepRule
|
||||||
|
import util.Rules
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.containsString
|
||||||
|
import static org.hamcrest.CoreMatchers.is
|
||||||
|
import static org.hamcrest.Matchers.allOf
|
||||||
|
import static org.hamcrest.Matchers.hasItem
|
||||||
|
import static org.hamcrest.Matchers.not
|
||||||
|
import static org.junit.Assert.assertThat
|
||||||
|
|
||||||
|
class DetectExecuteScanTest extends BasePiperTest {
|
||||||
|
|
||||||
|
private JenkinsDockerExecuteRule dockerRule = new JenkinsDockerExecuteRule(this)
|
||||||
|
private JenkinsShellCallRule shellRule = new JenkinsShellCallRule(this)
|
||||||
|
private JenkinsStepRule stepRule = new JenkinsStepRule(this)
|
||||||
|
|
||||||
|
private String detectProperties = ''
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public RuleChain rules = Rules
|
||||||
|
.getCommonRules(this)
|
||||||
|
.around(new JenkinsReadYamlRule(this))
|
||||||
|
.around(shellRule)
|
||||||
|
.around(dockerRule)
|
||||||
|
.around(stepRule)
|
||||||
|
.around(new JenkinsCredentialsRule(this)
|
||||||
|
.withCredentials('testCredentials', 'testToken')
|
||||||
|
)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
void init() {
|
||||||
|
|
||||||
|
detectProperties = ''
|
||||||
|
helper.registerAllowedMethod('synopsys_detect', [String.class], {s ->
|
||||||
|
detectProperties = s
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDetectDefault() {
|
||||||
|
stepRule.step.detectExecuteScan([
|
||||||
|
apiTokenCredentialsId: 'testCredentials',
|
||||||
|
projectName: 'testProject',
|
||||||
|
serverUrl: 'https://test.blackducksoftware.com',
|
||||||
|
juStabUtils: utils,
|
||||||
|
script: nullScript
|
||||||
|
])
|
||||||
|
|
||||||
|
//ToDo: assert unstashing
|
||||||
|
|
||||||
|
assertThat(detectProperties, containsString("--detect.project.name='testProject'"))
|
||||||
|
assertThat(detectProperties, containsString("--detect.project.version.name='1'"))
|
||||||
|
assertThat(detectProperties, containsString("--blackduck.url=https://test.blackducksoftware.com"))
|
||||||
|
assertThat(detectProperties, containsString("--blackduck.api.token=testToken"))
|
||||||
|
assertThat(detectProperties, containsString("--detect.blackduck.signature.scanner.paths=."))
|
||||||
|
assertThat(detectProperties, containsString("--blackduck.signature.scanner.memory=4096"))
|
||||||
|
assertThat(detectProperties, containsString("--blackduck.timeout=6000"))
|
||||||
|
assertThat(detectProperties, containsString("--blackduck.trust.cert=true"))
|
||||||
|
assertThat(detectProperties, containsString("--detect.report.timeout=4800"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDetectCustomPaths() {
|
||||||
|
stepRule.step.detectExecuteScan([
|
||||||
|
apiTokenCredentialsId: 'testCredentials',
|
||||||
|
projectName: 'testProject',
|
||||||
|
scanPaths: ['test1/', 'test2/'],
|
||||||
|
serverUrl: 'https://test.blackducksoftware.com',
|
||||||
|
juStabUtils: utils,
|
||||||
|
script: nullScript
|
||||||
|
])
|
||||||
|
|
||||||
|
assertThat(detectProperties, containsString("--detect.blackduck.signature.scanner.paths=test1/,test2/"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDetectSourceScanOnly() {
|
||||||
|
stepRule.step.detectExecuteScan([
|
||||||
|
apiTokenCredentialsId: 'testCredentials',
|
||||||
|
projectName: 'testProject',
|
||||||
|
scanners: ['source'],
|
||||||
|
serverUrl: 'https://test.blackducksoftware.com',
|
||||||
|
juStabUtils: utils,
|
||||||
|
script: nullScript
|
||||||
|
])
|
||||||
|
|
||||||
|
assertThat(detectProperties, not(containsString("--detect.blackduck.signature.scanner.paths=.")))
|
||||||
|
assertThat(detectProperties, containsString("--detect.source.path=."))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDetectGolang() {
|
||||||
|
stepRule.step.detectExecuteScan([
|
||||||
|
buildTool: 'golang',
|
||||||
|
apiTokenCredentialsId: 'testCredentials',
|
||||||
|
projectName: 'testProject',
|
||||||
|
serverUrl: 'https://test.blackducksoftware.com',
|
||||||
|
juStabUtils: utils,
|
||||||
|
script: nullScript
|
||||||
|
])
|
||||||
|
|
||||||
|
assertThat(dockerRule.dockerParams.dockerImage, is('golang:1.12-stretch'))
|
||||||
|
assertThat(dockerRule.dockerParams.dockerWorkspace, is(''))
|
||||||
|
assertThat(dockerRule.dockerParams.stashContent, allOf(hasItem('buildDescriptor'),hasItem('checkmarx')))
|
||||||
|
|
||||||
|
assertThat(shellRule.shell, hasItem('curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh'))
|
||||||
|
assertThat(shellRule.shell, hasItem('ln --symbolic $(pwd) $GOPATH/src/hub'))
|
||||||
|
assertThat(shellRule.shell, hasItem('cd $GOPATH/src/hub && dep ensure'))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCustomScanProperties() {
|
||||||
|
def detectProps = [
|
||||||
|
'--blackduck.signature.scanner.memory=1024'
|
||||||
|
]
|
||||||
|
stepRule.step.detectExecuteScan([
|
||||||
|
//scanProperties: detectProps,
|
||||||
|
scanProperties: ['--blackduck.signature.scanner.memory=1024', '--myNewOne'],
|
||||||
|
apiTokenCredentialsId: 'testCredentials',
|
||||||
|
projectName: 'testProject',
|
||||||
|
serverUrl: 'https://test.blackducksoftware.com',
|
||||||
|
juStabUtils: utils,
|
||||||
|
script: nullScript
|
||||||
|
])
|
||||||
|
|
||||||
|
assertThat(detectProperties, containsString("--detect.project.name='testProject'"))
|
||||||
|
assertThat(detectProperties, containsString("--detect.project.version.name='1'"))
|
||||||
|
assertThat(detectProperties, containsString("--blackduck.signature.scanner.memory=1024"))
|
||||||
|
assertThat(detectProperties, not(containsString("--blackduck.signature.scanner.memory=4096")))
|
||||||
|
assertThat(detectProperties, not(containsString("--detect.report.timeout=4800")))
|
||||||
|
assertThat(detectProperties, containsString("--myNewOne"))
|
||||||
|
}
|
||||||
|
}
|
154
vars/detectExecuteScan.groovy
Normal file
154
vars/detectExecuteScan.groovy
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
import com.sap.piper.GenerateDocumentation
|
||||||
|
import com.sap.piper.Utils
|
||||||
|
import com.sap.piper.ConfigurationHelper
|
||||||
|
|
||||||
|
import groovy.transform.Field
|
||||||
|
|
||||||
|
import static com.sap.piper.Prerequisites.checkScript
|
||||||
|
|
||||||
|
@Field String STEP_NAME = getClass().getName()
|
||||||
|
@Field Set GENERAL_CONFIG_KEYS = [
|
||||||
|
'detect',
|
||||||
|
/**
|
||||||
|
* Jenkins 'Secret text' credentials ID containing the API token used to authenticate with the Synopsis Detect (formerly BlackDuck) Server.
|
||||||
|
* @parentConfigKey detect
|
||||||
|
*/
|
||||||
|
'apiTokenCredentialsId',
|
||||||
|
/**
|
||||||
|
* Defines the tool which is used for building the artifact.<br />
|
||||||
|
* Currently, it is possible to select two behaviors of the step:
|
||||||
|
* <br />
|
||||||
|
* 1. Golang-specific behavior (`buildTool: golang`). Assumption here is that project uses the dependency management tool _dep_<br />
|
||||||
|
* 2. Custom-specific behavior for all other values of `buildTool`
|
||||||
|
*
|
||||||
|
* @possibleValues `golang`, any other build tool
|
||||||
|
*/
|
||||||
|
'buildTool',
|
||||||
|
/**
|
||||||
|
* Name of the Synopsis Detect (formerly BlackDuck) project.
|
||||||
|
* @parentConfigKey detect
|
||||||
|
*/
|
||||||
|
'projectName',
|
||||||
|
/**
|
||||||
|
* Version of the Synopsis Detect (formerly BlackDuck) project.
|
||||||
|
* @parentConfigKey detect
|
||||||
|
*/
|
||||||
|
'projectVersion',
|
||||||
|
/**
|
||||||
|
* List of paths which should be scanned by the Synopsis Detect (formerly BlackDuck) scan.
|
||||||
|
* @parentConfigKey detect
|
||||||
|
*/
|
||||||
|
'scanPaths',
|
||||||
|
/**
|
||||||
|
* Properties passed to the Synopsis Detect (formerly BlackDuck) scan. You can find details in the [Synopsis Detect documentation](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/622846/Using+Synopsys+Detect+Properties)
|
||||||
|
* @parentConfigKey detect
|
||||||
|
*/
|
||||||
|
'scanProperties',
|
||||||
|
/**
|
||||||
|
* List of scanners to be used for Synopsis Detect (formerly BlackDuck) scan.
|
||||||
|
* @possibleValues `['signature']`
|
||||||
|
* @parentConfigKey detect
|
||||||
|
*/
|
||||||
|
'scanners',
|
||||||
|
/**
|
||||||
|
* Server url to the Synopsis Detect (formerly BlackDuck) Server.
|
||||||
|
* @parentConfigKey detect
|
||||||
|
*/
|
||||||
|
'serverUrl'
|
||||||
|
]
|
||||||
|
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([
|
||||||
|
/** @see dockerExecute */
|
||||||
|
'dockerImage',
|
||||||
|
/** @see dockerExecute */
|
||||||
|
'dockerWorkspace',
|
||||||
|
/** If specific stashes should be considered for the scan, their names need to be passed via the parameter `stashContent`. */
|
||||||
|
'stashContent'
|
||||||
|
])
|
||||||
|
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||||
|
|
||||||
|
@Field Map CONFIG_KEY_COMPATIBILITY = [
|
||||||
|
detect: [
|
||||||
|
apiTokenCredentialsId: 'apiTokenCredentialsId',
|
||||||
|
projectName: 'projectName',
|
||||||
|
projectVersion: 'projectVersion',
|
||||||
|
scanners: 'scanners',
|
||||||
|
scanPaths: 'scanPaths',
|
||||||
|
scanProperties: 'scanProperties',
|
||||||
|
serverUrl: 'serverUrl'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This step executes [Synopsis Detect](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/62423113/Synopsys+Detect) scans.
|
||||||
|
*/
|
||||||
|
@GenerateDocumentation
|
||||||
|
void call(Map parameters = [:]) {
|
||||||
|
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||||
|
def script = checkScript(this, parameters) ?: this
|
||||||
|
def utils = parameters.juStabUtils ?: new Utils()
|
||||||
|
// load default & individual configuration
|
||||||
|
Map config = ConfigurationHelper.newInstance(this)
|
||||||
|
.loadStepDefaults()
|
||||||
|
.mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS, CONFIG_KEY_COMPATIBILITY)
|
||||||
|
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS,CONFIG_KEY_COMPATIBILITY)
|
||||||
|
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS, CONFIG_KEY_COMPATIBILITY)
|
||||||
|
.mixin(parameters, PARAMETER_KEYS, CONFIG_KEY_COMPATIBILITY)
|
||||||
|
.dependingOn('buildTool').mixin('dockerImage')
|
||||||
|
.dependingOn('buildTool').mixin('dockerWorkspace')
|
||||||
|
.withMandatoryProperty('detect/apiTokenCredentialsId')
|
||||||
|
.withMandatoryProperty('detect/projectName')
|
||||||
|
.withMandatoryProperty('detect/projectVersion')
|
||||||
|
.use()
|
||||||
|
|
||||||
|
config.stashContent = utils.unstashAll(config.stashContent)
|
||||||
|
|
||||||
|
script.commonPipelineEnvironment.setInfluxStepData('detect', false)
|
||||||
|
|
||||||
|
utils.pushToSWA([
|
||||||
|
step: STEP_NAME,
|
||||||
|
stepParamKey1: 'buildTool',
|
||||||
|
stepParam1: config.buildTool ?: 'default'
|
||||||
|
], config)
|
||||||
|
|
||||||
|
//prepare Hub Detect execution using package manager
|
||||||
|
switch (config.buildTool) {
|
||||||
|
case 'golang':
|
||||||
|
dockerExecute(script: script, dockerImage: config.dockerImage, dockerWorkspace: config.dockerWorkspace, stashContent: config.stashContent) {
|
||||||
|
sh 'curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh'
|
||||||
|
sh 'ln --symbolic $(pwd) $GOPATH/src/hub'
|
||||||
|
sh 'cd $GOPATH/src/hub && dep ensure'
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
//no additional tasks are performed
|
||||||
|
echo "[${STEP_NAME}] No preparation steps performed for scan. Please make sure to properly set configuration for `detect.scanProperties`"
|
||||||
|
}
|
||||||
|
|
||||||
|
withCredentials ([string(
|
||||||
|
credentialsId: config.detect.apiTokenCredentialsId,
|
||||||
|
variable: 'detectApiToken'
|
||||||
|
)]) {
|
||||||
|
def authentication = "--blackduck.api.token=${detectApiToken}"
|
||||||
|
config.detect.scanProperties += [
|
||||||
|
"--detect.project.name='${config.detect.projectName}'",
|
||||||
|
"--detect.project.version.name='${config.detect.projectVersion}'",
|
||||||
|
"--detect.code.location.name='${config.detect.projectName}/${config.detect.projectVersion}'",
|
||||||
|
"--blackduck.url=${config.detect.serverUrl}",
|
||||||
|
]
|
||||||
|
|
||||||
|
if ('signature' in config.detect.scanners) [
|
||||||
|
config.detect.scanProperties.add("--detect.blackduck.signature.scanner.paths=${config.detect.scanPaths.join(',')}")
|
||||||
|
]
|
||||||
|
|
||||||
|
if ('source' in config.detect.scanners) [
|
||||||
|
config.detect.scanProperties.add("--detect.source.path=${config.detect.scanPaths[0]}")
|
||||||
|
]
|
||||||
|
|
||||||
|
def detectProperties = config.detect.scanProperties.join(' ') + " ${authentication}"
|
||||||
|
|
||||||
|
echo "[${STEP_NAME}] Running with following Detect configuration: ${detectProperties}"
|
||||||
|
synopsys_detect detectProperties
|
||||||
|
script.commonPipelineEnvironment.setInfluxStepData('detect', true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user