1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00

Merge branch 'master' into xsa-docu-patch

This commit is contained in:
Thorsten Duda 2019-12-13 12:55:34 +01:00 committed by GitHub
commit cf2d570369
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 453 additions and 3 deletions

70
cmd/detectExecuteScan.go Normal file
View File

@ -0,0 +1,70 @@
package cmd
import (
"fmt"
"strings"
"github.com/SAP/jenkins-library/pkg/command"
"github.com/SAP/jenkins-library/pkg/log"
)
func detectExecuteScan(myDetectExecuteScanOptions detectExecuteScanOptions) error {
c := command.Command{}
// reroute command output to logging framework
c.Stdout(log.Entry().Writer())
c.Stderr(log.Entry().Writer())
runDetect(myDetectExecuteScanOptions, &c)
return nil
}
func runDetect(myDetectExecuteScanOptions detectExecuteScanOptions, command shellRunner) {
// detect execution details, see https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/88440888/Sample+Synopsys+Detect+Scan+Configuration+Scenarios+for+Black+Duck
args := []string{"bash <(curl -s https://detect.synopsys.com/detect.sh)"}
args = addDetectArgs(args, myDetectExecuteScanOptions)
script := strings.Join(args, " ")
command.Dir(".")
err := command.RunShell("/bin/bash", script)
if err != nil {
log.Entry().
WithError(err).
WithField("command", myKarmaExecuteTestsOptions.InstallCommand).
Fatal("failed to execute detect scan")
}
}
func addDetectArgs(args []string, myDetectExecuteScanOptions detectExecuteScanOptions) []string {
args = append(args, myDetectExecuteScanOptions.ScanProperties...)
args = append(args, fmt.Sprintf("--blackduck.url=%v", myDetectExecuteScanOptions.ServerURL))
args = append(args, fmt.Sprintf("--blackduck.api.token=%v", myDetectExecuteScanOptions.APIToken))
args = append(args, fmt.Sprintf("--detect.project.name=%v", myDetectExecuteScanOptions.ProjectName))
args = append(args, fmt.Sprintf("--detect.project.version.name=%v", myDetectExecuteScanOptions.ProjectVersion))
codeLocation := myDetectExecuteScanOptions.CodeLocation
if len(codeLocation) == 0 && len(myDetectExecuteScanOptions.ProjectName) > 0 {
codeLocation = fmt.Sprintf("%v/%v", myDetectExecuteScanOptions.ProjectName, myDetectExecuteScanOptions.ProjectVersion)
}
args = append(args, fmt.Sprintf("--detect.code.location.name=%v", codeLocation))
if sliceContains(myDetectExecuteScanOptions.Scanners, "signature") {
args = append(args, fmt.Sprintf("--detect.blackduck.signature.scanner.paths=%v", strings.Join(myDetectExecuteScanOptions.ScanPaths, ",")))
}
if sliceContains(myDetectExecuteScanOptions.Scanners, "source") {
args = append(args, fmt.Sprintf("--detect.source.path=%v", myDetectExecuteScanOptions.ScanPaths[0]))
}
return args
}
func sliceContains(slice []string, find string) bool {
for _, elem := range slice {
if elem == find {
return true
}
}
return false
}

View File

@ -0,0 +1,128 @@
package cmd
import (
"os"
"github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/spf13/cobra"
)
type detectExecuteScanOptions struct {
APIToken string `json:"apiToken,omitempty"`
CodeLocation string `json:"codeLocation,omitempty"`
ProjectName string `json:"projectName,omitempty"`
ProjectVersion string `json:"projectVersion,omitempty"`
Scanners []string `json:"scanners,omitempty"`
ScanPaths []string `json:"scanPaths,omitempty"`
ScanProperties []string `json:"scanProperties,omitempty"`
ServerURL string `json:"serverUrl,omitempty"`
}
var myDetectExecuteScanOptions detectExecuteScanOptions
var detectExecuteScanStepConfigJSON string
// DetectExecuteScanCommand Executes Synopsis Detect scan
func DetectExecuteScanCommand() *cobra.Command {
metadata := detectExecuteScanMetadata()
var createDetectExecuteScanCmd = &cobra.Command{
Use: "detectExecuteScan",
Short: "Executes Synopsis Detect scan",
Long: `This step executes [Synopsis Detect](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/62423113/Synopsys+Detect) scans.`,
PreRunE: func(cmd *cobra.Command, args []string) error {
log.SetStepName("detectExecuteScan")
log.SetVerbose(GeneralConfig.Verbose)
return PrepareConfig(cmd, &metadata, "detectExecuteScan", &myDetectExecuteScanOptions, config.OpenPiperFile)
},
RunE: func(cmd *cobra.Command, args []string) error {
return detectExecuteScan(myDetectExecuteScanOptions)
},
}
addDetectExecuteScanFlags(createDetectExecuteScanCmd)
return createDetectExecuteScanCmd
}
func addDetectExecuteScanFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(&myDetectExecuteScanOptions.APIToken, "apiToken", os.Getenv("PIPER_apiToken"), "Api token to be used for connectivity with Synopsis Detect server.")
cmd.Flags().StringVar(&myDetectExecuteScanOptions.CodeLocation, "codeLocation", os.Getenv("PIPER_codeLocation"), "An override for the name Detect will use for the scan file it creates.")
cmd.Flags().StringVar(&myDetectExecuteScanOptions.ProjectName, "projectName", os.Getenv("PIPER_projectName"), "Name of the Synopsis Detect (formerly BlackDuck) project.")
cmd.Flags().StringVar(&myDetectExecuteScanOptions.ProjectVersion, "projectVersion", os.Getenv("PIPER_projectVersion"), "Version of the Synopsis Detect (formerly BlackDuck) project.")
cmd.Flags().StringSliceVar(&myDetectExecuteScanOptions.Scanners, "scanners", []string{"signature"}, "List of scanners to be used for Synopsis Detect (formerly BlackDuck) scan.")
cmd.Flags().StringSliceVar(&myDetectExecuteScanOptions.ScanPaths, "scanPaths", []string{"."}, "List of paths which should be scanned by the Synopsis Detect (formerly BlackDuck) scan.")
cmd.Flags().StringSliceVar(&myDetectExecuteScanOptions.ScanProperties, "scanProperties", []string{"--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"}, "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)")
cmd.Flags().StringVar(&myDetectExecuteScanOptions.ServerURL, "serverUrl", os.Getenv("PIPER_serverUrl"), "Server url to the Synopsis Detect (formerly BlackDuck) Server.")
cmd.MarkFlagRequired("apiToken")
cmd.MarkFlagRequired("projectName")
cmd.MarkFlagRequired("projectVersion")
}
// retrieve step metadata
func detectExecuteScanMetadata() config.StepData {
var theMetaData = config.StepData{
Spec: config.StepSpec{
Inputs: config.StepInputs{
Parameters: []config.StepParameters{
{
Name: "apiToken",
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{{Name: "detect/apiToken"}},
},
{
Name: "codeLocation",
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
},
{
Name: "projectName",
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{{Name: "detect/projectName"}},
},
{
Name: "projectVersion",
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{{Name: "detect/projectVersion"}},
},
{
Name: "scanners",
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string",
Mandatory: false,
Aliases: []config.Alias{{Name: "detect/scanners"}},
},
{
Name: "scanPaths",
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string",
Mandatory: false,
Aliases: []config.Alias{{Name: "detect/scanPaths"}},
},
{
Name: "scanProperties",
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string",
Mandatory: false,
Aliases: []config.Alias{{Name: "detect/scanProperties"}},
},
{
Name: "serverUrl",
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{{Name: "detect/serverUrl"}},
},
},
},
},
}
return theMetaData
}

View File

@ -0,0 +1,16 @@
package cmd
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestDetectExecuteScanCommand(t *testing.T) {
testCmd := DetectExecuteScanCommand()
// only high level testing performed - details are tested in step generation procudure
assert.Equal(t, "detectExecuteScan", testCmd.Use, "command name incorrect")
}

View File

@ -0,0 +1,92 @@
package cmd
import (
"fmt"
"testing"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/stretchr/testify/assert"
)
func TestRunDetect(t *testing.T) {
t.Run("success case", func(t *testing.T) {
s := shellMockRunner{}
runDetect(detectExecuteScanOptions{}, &s)
assert.Equal(t, ".", s.dir, "Wrong execution directory used")
assert.Equal(t, "/bin/bash", s.shell[0], "Bash shell expected")
expectedScript := "bash <(curl -s https://detect.synopsys.com/detect.sh) --blackduck.url= --blackduck.api.token= --detect.project.name= --detect.project.version.name= --detect.code.location.name="
assert.Equal(t, expectedScript, s.calls[0])
})
t.Run("failure case", func(t *testing.T) {
var hasFailed bool
log.Entry().Logger.ExitFunc = func(int) { hasFailed = true }
s := shellMockRunner{shouldFailWith: fmt.Errorf("Test Error")}
runDetect(detectExecuteScanOptions{}, &s)
assert.True(t, hasFailed, "expected command to exit with fatal")
})
}
func TestAddDetectArgs(t *testing.T) {
testData := []struct {
args []string
options detectExecuteScanOptions
expected []string
}{
{
args: []string{"--testProp1=1"},
options: detectExecuteScanOptions{
ScanProperties: []string{"--scan1=1", "--scan2=2"},
ServerURL: "https://server.url",
APIToken: "apiToken",
ProjectName: "testName",
ProjectVersion: "1.0",
CodeLocation: "",
Scanners: []string{"signature"},
ScanPaths: []string{"path1", "path2"},
},
expected: []string{
"--testProp1=1",
"--scan1=1",
"--scan2=2",
"--blackduck.url=https://server.url",
"--blackduck.api.token=apiToken",
"--detect.project.name=testName",
"--detect.project.version.name=1.0",
"--detect.code.location.name=testName/1.0",
"--detect.blackduck.signature.scanner.paths=path1,path2",
},
},
{
args: []string{"--testProp1=1"},
options: detectExecuteScanOptions{
ServerURL: "https://server.url",
APIToken: "apiToken",
ProjectName: "testName",
ProjectVersion: "1.0",
CodeLocation: "testLocation",
Scanners: []string{"source"},
ScanPaths: []string{"path1", "path2"},
},
expected: []string{
"--testProp1=1",
"--blackduck.url=https://server.url",
"--blackduck.api.token=apiToken",
"--detect.project.name=testName",
"--detect.project.version.name=1.0",
"--detect.code.location.name=testLocation",
"--detect.source.path=path1",
},
},
}
for k, v := range testData {
t.Run(fmt.Sprintf("run %v", k), func(t *testing.T) {
got := addDetectArgs(v.args, v.options)
assert.Equal(t, v.expected, got)
})
}
}

View File

@ -43,6 +43,7 @@ func Execute() {
rootCmd.AddCommand(ConfigCommand())
rootCmd.AddCommand(VersionCommand())
rootCmd.AddCommand(DetectExecuteScanCommand())
rootCmd.AddCommand(KarmaExecuteTestsCommand())
rootCmd.AddCommand(XsDeployCommand())
rootCmd.AddCommand(GithubPublishReleaseCommand())

View File

@ -28,6 +28,7 @@ type execCall struct {
type shellMockRunner struct {
dir string
calls []string
shell []string
stdout io.Writer
stderr io.Writer
shouldFailWith error
@ -63,7 +64,7 @@ func (m *shellMockRunner) RunShell(s string, c string) error {
if m.shouldFailWith != nil {
return m.shouldFailWith
}
m.shell = append(m.shell, s)
m.calls = append(m.calls, c)
return nil
}

View File

@ -198,7 +198,7 @@ func setDefaultParameters(stepData *config.StepData) (bool, error) {
}
param.Default = boolVal
case "[]string":
param.Default = fmt.Sprintf("[]string{\"%v\"}", strings.Join(param.Default.([]string), "\", \""))
param.Default = fmt.Sprintf("[]string{\"%v\"}", strings.Join(getStringSliceFromInterface(param.Default), "\", \""))
default:
return false, fmt.Errorf("Meta data type not set or not known: '%v'", param.Type)
}
@ -308,3 +308,18 @@ func flagType(paramType string) string {
}
return theFlagType
}
func getStringSliceFromInterface(iSlice interface{}) []string {
s := []string{}
t, ok := iSlice.([]interface{})
if ok {
for _, v := range t {
s = append(s, fmt.Sprintf("%v", v))
}
} else {
s = append(s, fmt.Sprintf("%v", iSlice))
}
return s
}

View File

@ -89,6 +89,11 @@ func TestProcessMetaFiles(t *testing.T) {
func TestSetDefaultParameters(t *testing.T) {
t.Run("success case", func(t *testing.T) {
sliceVals := []string{"val4_1", "val4_2"}
stringSliceDefault := make([]interface{}, len(sliceVals))
for i, v := range sliceVals {
stringSliceDefault[i] = v
}
stepData := config.StepData{
Spec: config.StepSpec{
Inputs: config.StepInputs{
@ -97,7 +102,7 @@ func TestSetDefaultParameters(t *testing.T) {
{Name: "param1", Scope: []string{"STEPS"}, Type: "string"},
{Name: "param2", Scope: []string{"STAGES"}, Type: "bool", Default: true},
{Name: "param3", Scope: []string{"PARAMETERS"}, Type: "bool"},
{Name: "param4", Scope: []string{"ENV"}, Type: "[]string", Default: []string{"val4_1", "val4_2"}},
{Name: "param4", Scope: []string{"ENV"}, Type: "[]string", Default: stringSliceDefault},
{Name: "param5", Scope: []string{"ENV"}, Type: "[]string"},
},
},
@ -230,3 +235,17 @@ func TestFlagType(t *testing.T) {
assert.Equal(t, v.expected, flagType(v.input), fmt.Sprintf("wrong flag type for run %v", k))
}
}
func TestGetStringSliceFromInterface(t *testing.T) {
tt := []struct {
input interface{}
expected []string
}{
{input: []interface{}{"Test", 2}, expected: []string{"Test", "2"}},
{input: "Test", expected: []string{"Test"}},
}
for _, v := range tt {
assert.Equal(t, v.expected, getStringSliceFromInterface(v.input), "interface conversion failed")
}
}

View File

@ -0,0 +1,108 @@
metadata:
name: detectExecuteScan
description: Executes Synopsis Detect scan
longDescription: |
This step executes [Synopsis Detect](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/62423113/Synopsys+Detect) scans.
spec:
inputs:
resources:
- name: buildDescriptor
type: stash
- name: checkmarx
type: stash
secrets:
- name: apiTokenCredentialsId
description: Jenkins 'Secret text' credentials ID containing the API token used to authenticate with the Synopsis Detect (formerly BlackDuck) Server.
type: jenkins
params:
- name: apiToken
aliases:
- name: detect/apiToken
description: Api token to be used for connectivity with Synopsis Detect server.
type: string
mandatory: true
scope:
- PARAMETERS
- STAGES
- STEPS
- name: codeLocation
description: An override for the name Detect will use for the scan file it creates.
type: string
mandatory: false
scope:
- PARAMETERS
- STAGES
- STEPS
- name: projectName
description: Name of the Synopsis Detect (formerly BlackDuck) project.
aliases:
- name: detect/projectName
type: string
mandatory: true
scope:
- PARAMETERS
- STAGES
- STEPS
- name: projectVersion
description: Version of the Synopsis Detect (formerly BlackDuck) project.
aliases:
- name: detect/projectVersion
type: string
mandatory: true
scope:
- PARAMETERS
- STAGES
- STEPS
- name: scanners
description: List of scanners to be used for Synopsis Detect (formerly BlackDuck) scan.
aliases:
- name: detect/scanners
type: '[]string'
mandatory: false
default:
- signature
possibleValues:
- signature
scope:
- PARAMETERS
- STAGES
- STEPS
- name: scanPaths
description: List of paths which should be scanned by the Synopsis Detect (formerly BlackDuck) scan.
aliases:
- name: detect/scanPaths
type: '[]string'
mandatory: false
default:
- '.'
scope:
- PARAMETERS
- STAGES
- STEPS
- name: scanProperties
description: 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)
aliases:
- name: detect/scanProperties
type: '[]string'
mandatory: false
default:
- --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
scope:
- PARAMETERS
- STAGES
- STEPS
- name: serverUrl
description: Server url to the Synopsis Detect (formerly BlackDuck) Server.
aliases:
- name: detect/serverUrl
type: string
mandatory: false
scope:
- PARAMETERS
- STAGES
- STEPS