From 0fc131adec2e7ace9a7d76f0881d793d95b3fb72 Mon Sep 17 00:00:00 2001 From: Giridhar Shenoy Date: Tue, 28 Jul 2020 10:48:19 +0200 Subject: [PATCH] detectExecuteScan : Changes to include user group and handle build fails (#1775) * changes to detectExec before master merge * changes for detectExecuteScan * self generated code added * fix syntax errors and update docu * added unit tests for fail and Group * fix failOn bug * add Groups as string array * add Groups as string array * tests and validation for groups, failOn * Updated docs and added more tests * documentation md files should not be changed * Handle merge conflicts from PR 1845 * fix merge errors Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com> --- cmd/detectExecuteScan.go | 18 ++++++++++-- cmd/detectExecuteScan_generated.go | 30 ++++++++++++++++--- cmd/detectExecuteScan_test.go | 46 ++++++++++++++++++++++++------ resources/metadata/detect.yaml | 41 +++++++++++++++++++++++--- 4 files changed, 116 insertions(+), 19 deletions(-) diff --git a/cmd/detectExecuteScan.go b/cmd/detectExecuteScan.go index 65eb8f380a..27beeb405c 100644 --- a/cmd/detectExecuteScan.go +++ b/cmd/detectExecuteScan.go @@ -52,14 +52,26 @@ func addDetectArgs(args []string, config detectExecuteScanOptions) []string { args = append(args, fmt.Sprintf("--blackduck.url=%v", config.ServerURL)) args = append(args, fmt.Sprintf("--blackduck.api.token=%v", config.APIToken)) + // ProjectNames, VersionName, GroupName etc can contain spaces and need to be escaped using double quotes in CLI + // Hence the string need to be surrounded by \" + args = append(args, fmt.Sprintf("--detect.project.name=\\\"%v\\\"", config.ProjectName)) + args = append(args, fmt.Sprintf("--detect.project.version.name=\\\"%v\\\"", detectVersionName)) + + // Groups parameter is added only when there is atleast one non-empty groupname provided + if len(config.Groups) > 0 && len(config.Groups[0]) > 0 { + args = append(args, fmt.Sprintf("--detect.project.user.groups=\\\"%v\\\"", strings.Join(config.Groups, "\\\",\\\""))) + } + + // Atleast 1, non-empty category to fail on must be provided + if len(config.FailOn) > 0 && len(config.FailOn[0]) > 0 { + args = append(args, fmt.Sprintf("--detect.policy.check.fail.on.severities=%v", strings.Join(config.FailOn, ","))) + } - args = append(args, fmt.Sprintf("--detect.project.name=%v", config.ProjectName)) - args = append(args, fmt.Sprintf("--detect.project.version.name=%v", detectVersionName)) codeLocation := config.CodeLocation if len(codeLocation) == 0 && len(config.ProjectName) > 0 { codeLocation = fmt.Sprintf("%v/%v", config.ProjectName, detectVersionName) } - args = append(args, fmt.Sprintf("--detect.code.location.name=%v", codeLocation)) + args = append(args, fmt.Sprintf("--detect.code.location.name=\\\"%v\\\"", codeLocation)) if sliceUtils.ContainsString(config.Scanners, "signature") { args = append(args, fmt.Sprintf("--detect.blackduck.signature.scanner.paths=%v", strings.Join(config.ScanPaths, ","))) diff --git a/cmd/detectExecuteScan_generated.go b/cmd/detectExecuteScan_generated.go index e151a614df..30e30e7d45 100644 --- a/cmd/detectExecuteScan_generated.go +++ b/cmd/detectExecuteScan_generated.go @@ -21,11 +21,13 @@ type detectExecuteScanOptions struct { ScanPaths []string `json:"scanPaths,omitempty"` ScanProperties []string `json:"scanProperties,omitempty"` ServerURL string `json:"serverUrl,omitempty"` + Groups []string `json:"groups,omitempty"` + FailOn []string `json:"failOn,omitempty"` Version string `json:"version,omitempty"` VersioningModel string `json:"versioningModel,omitempty"` } -// DetectExecuteScanCommand Executes Synopsis Detect scan +// DetectExecuteScanCommand Executes Synopsys Detect scan func DetectExecuteScanCommand() *cobra.Command { const STEP_NAME = "detectExecuteScan" @@ -35,8 +37,10 @@ func DetectExecuteScanCommand() *cobra.Command { var createDetectExecuteScanCmd = &cobra.Command{ Use: STEP_NAME, - Short: "Executes Synopsis Detect scan", - Long: `This step executes [Synopsis Detect](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/62423113/Synopsys+Detect) scans.`, + Short: "Executes Synopsys Detect scan", + Long: `This step executes [Synopsys Detect](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/62423113/Synopsys+Detect) scans. +Synopsys Detect command line utlity can be used to run various scans including BlackDuck and Polaris scans. This step allows users to run BlackDuck scans by default. +Please configure your BlackDuck server Url using the serverUrl parameter and the API token of your user using the apiToken parameter for this step.`, PreRunE: func(cmd *cobra.Command, _ []string) error { startTime = time.Now() log.SetStepName(STEP_NAME) @@ -86,8 +90,10 @@ func addDetectExecuteScanFlags(cmd *cobra.Command, stepConfig *detectExecuteScan cmd.Flags().StringVar(&stepConfig.ProjectName, "projectName", os.Getenv("PIPER_projectName"), "Name of the Synopsis Detect (formerly BlackDuck) project.") cmd.Flags().StringSliceVar(&stepConfig.Scanners, "scanners", []string{`signature`}, "List of scanners to be used for Synopsis Detect (formerly BlackDuck) scan.") cmd.Flags().StringSliceVar(&stepConfig.ScanPaths, "scanPaths", []string{`.`}, "List of paths which should be scanned by the Synopsis Detect (formerly BlackDuck) scan.") - cmd.Flags().StringSliceVar(&stepConfig.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().StringSliceVar(&stepConfig.ScanProperties, "scanProperties", []string{`--blackduck.signature.scanner.memory=4096`, `--blackduck.timeout=6000`, `--blackduck.trust.cert=true`, `--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(&stepConfig.ServerURL, "serverUrl", os.Getenv("PIPER_serverUrl"), "Server url to the Synopsis Detect (formerly BlackDuck) Server.") + cmd.Flags().StringSliceVar(&stepConfig.Groups, "groups", []string{}, "Users groups to be assigned for the Project") + cmd.Flags().StringSliceVar(&stepConfig.FailOn, "failOn", []string{`BLOCKER`}, "Mark the current build as fail based on the policy categories applied.") cmd.Flags().StringVar(&stepConfig.Version, "version", os.Getenv("PIPER_version"), "Defines the version number of the artifact being build in the pipeline. It is used as source for the Detect version.") cmd.Flags().StringVar(&stepConfig.VersioningModel, "versioningModel", `major`, "The versioning model used for result reporting (based on the artifact version). Example 1.2.3 using `major` will result in version 1") @@ -161,6 +167,22 @@ func detectExecuteScanMetadata() config.StepData { Mandatory: false, Aliases: []config.Alias{{Name: "detect/serverUrl"}}, }, + { + Name: "groups", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, + Type: "[]string", + Mandatory: false, + Aliases: []config.Alias{{Name: "detect/groups"}}, + }, + { + Name: "failOn", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, + Type: "[]string", + Mandatory: false, + Aliases: []config.Alias{{Name: "detect/failOn"}}, + }, { Name: "version", ResourceRef: []config.ResourceReference{{Name: "commonPipelineEnvironment", Param: "artifactVersion"}}, diff --git a/cmd/detectExecuteScan_test.go b/cmd/detectExecuteScan_test.go index fbae46fccc..f73ff0b5b6 100644 --- a/cmd/detectExecuteScan_test.go +++ b/cmd/detectExecuteScan_test.go @@ -18,7 +18,7 @@ func TestRunDetect(t *testing.T) { 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=" + 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]) }) @@ -26,7 +26,7 @@ func TestRunDetect(t *testing.T) { var hasFailed bool log.Entry().Logger.ExitFunc = func(int) { hasFailed = true } - s := mock.ShellMockRunner{ShouldFailOnCommand: map[string]error{"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=": fmt.Errorf("Test Error")}} + s := mock.ShellMockRunner{ShouldFailOnCommand: map[string]error{"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=\\\"\\\"": fmt.Errorf("Test Error")}} runDetect(detectExecuteScanOptions{}, &s) assert.True(t, hasFailed, "expected command to exit with fatal") }) @@ -57,9 +57,9 @@ func TestAddDetectArgs(t *testing.T) { "--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.project.name=\\\"testName\\\"", + "--detect.project.version.name=\\\"1.0\\\"", + "--detect.code.location.name=\\\"testName/1.0\\\"", "--detect.blackduck.signature.scanner.paths=path1,path2", }, }, @@ -72,16 +72,46 @@ func TestAddDetectArgs(t *testing.T) { Version: "1.0", VersioningModel: "major-minor", CodeLocation: "testLocation", + FailOn: []string{"BLOCKER", "MAJOR"}, Scanners: []string{"source"}, ScanPaths: []string{"path1", "path2"}, + Groups: []string{"testGroup"}, }, 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.project.name=\\\"testName\\\"", + "--detect.project.version.name=\\\"1.0\\\"", + "--detect.project.user.groups=\\\"testGroup\\\"", + "--detect.policy.check.fail.on.severities=BLOCKER,MAJOR", + "--detect.code.location.name=\\\"testLocation\\\"", + "--detect.source.path=path1", + }, + }, + { + args: []string{"--testProp1=1"}, + options: detectExecuteScanOptions{ + ServerURL: "https://server.url", + APIToken: "apiToken", + ProjectName: "testName", + CodeLocation: "testLocation", + FailOn: []string{"BLOCKER", "MAJOR"}, + Scanners: []string{"source"}, + ScanPaths: []string{"path1", "path2"}, + Groups: []string{"testGroup", "testGroup2"}, + Version: "1.0", + VersioningModel: "major-minor", + }, + expected: []string{ + "--testProp1=1", + "--blackduck.url=https://server.url", + "--blackduck.api.token=apiToken", + "--detect.project.name=\\\"testName\\\"", + "--detect.project.version.name=\\\"1.0\\\"", + "--detect.project.user.groups=\\\"testGroup\\\",\\\"testGroup2\\\"", + "--detect.policy.check.fail.on.severities=BLOCKER,MAJOR", + "--detect.code.location.name=\\\"testLocation\\\"", "--detect.source.path=path1", }, }, diff --git a/resources/metadata/detect.yaml b/resources/metadata/detect.yaml index a4d2ef52e3..4ab19d89ec 100644 --- a/resources/metadata/detect.yaml +++ b/resources/metadata/detect.yaml @@ -1,8 +1,10 @@ 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. + description: Executes Synopsys Detect scan + longDescription: | + This step executes [Synopsys Detect](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/62423113/Synopsys+Detect) scans. + Synopsys Detect command line utlity can be used to run various scans including BlackDuck and Polaris scans. This step allows users to run BlackDuck scans by default. + Please configure your BlackDuck server Url using the serverUrl parameter and the API token of your user using the apiToken parameter for this step. spec: inputs: resources: @@ -86,7 +88,6 @@ spec: - --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: @@ -103,6 +104,38 @@ spec: - PARAMETERS - STAGES - STEPS + - name: groups + description: Users groups to be assigned for the Project + aliases: + - name: detect/groups + type: '[]string' + mandatory: false + scope: + - PARAMETERS + - STAGES + - STEPS + - name: failOn + description: Mark the current build as fail based on the policy categories applied. + longDescription: | + A list of policies can be provided which will be applied after the scan is completed. These policies if violated will mark the build/scan result as failed. + The list of accepted valed can be found at https://blackducksoftware.github.io/synopsys-detect/latest/properties/configuration/project/#fail-on-policy-violation-severities + aliases: + - name: detect/failOn + type: '[]string' + mandatory: false + default: + - BLOCKER + possibleValues: + - ALL + - BLOCKER + - CRITICAL + - MAJOR + - MINOR + - NONE + scope: + - PARAMETERS + - STAGES + - STEPS - name: version aliases: - name: projectVersion