From 39d52a2123380a4a1570c2882d401f25968e0e50 Mon Sep 17 00:00:00 2001 From: Anil Keshav Date: Wed, 14 Jun 2023 09:11:33 +0200 Subject: [PATCH] feat (protecodeExecuteScan) enhancing protecode step with registry credentials (#4378) * enhancing protecode with registry credentials * Use protecodeUtils instead of separate package * Add target path for docker config to be created * Fix tests * Fix build flags --------- Co-authored-by: Vyacheslav Starostin --- cmd/protecodeExecuteScan.go | 25 ++++++++--- cmd/protecodeExecuteScan_generated.go | 44 ++++++++++++++++++++ cmd/protecodeExecuteScan_test.go | 9 +++- resources/metadata/protecodeExecuteScan.yaml | 26 ++++++++++++ 4 files changed, 97 insertions(+), 7 deletions(-) diff --git a/cmd/protecodeExecuteScan.go b/cmd/protecodeExecuteScan.go index 52139c43a..13ad76def 100644 --- a/cmd/protecodeExecuteScan.go +++ b/cmd/protecodeExecuteScan.go @@ -15,6 +15,7 @@ import ( "github.com/pkg/errors" "github.com/SAP/jenkins-library/pkg/command" + "github.com/SAP/jenkins-library/pkg/docker" piperDocker "github.com/SAP/jenkins-library/pkg/docker" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperutils" @@ -25,9 +26,10 @@ import ( ) const ( - webReportPath = "%s/#/product/%v/" - scanResultFile = "protecodescan_vulns.json" - stepResultFile = "protecodeExecuteScan.json" + webReportPath = "%s/#/product/%v/" + scanResultFile = "protecodescan_vulns.json" + stepResultFile = "protecodeExecuteScan.json" + dockerConfigFile = ".pipeline/docker/config.json" ) type protecodeUtils interface { @@ -72,7 +74,9 @@ func runProtecodeScan(config *protecodeExecuteScanOptions, influx *protecodeExec return err } - correctDockerConfigEnvVar(config) + if err := correctDockerConfigEnvVar(config, utils); err != nil { + return err + } var fileName, filePath string var err error @@ -372,8 +376,18 @@ func uploadFile(utils protecodeUtils, config protecodeExecuteScanOptions, produc return productID } -func correctDockerConfigEnvVar(config *protecodeExecuteScanOptions) { +func correctDockerConfigEnvVar(config *protecodeExecuteScanOptions, utils protecodeUtils) error { + var err error path := config.DockerConfigJSON + + if len(config.DockerConfigJSON) > 0 && len(config.DockerRegistryURL) > 0 && len(config.ContainerRegistryPassword) > 0 && len(config.ContainerRegistryUser) > 0 { + path, err = docker.CreateDockerConfigJSON(config.DockerRegistryURL, config.ContainerRegistryUser, config.ContainerRegistryPassword, dockerConfigFile, config.DockerConfigJSON, utils) + } + + if err != nil { + return errors.Wrapf(err, "failed to create / update docker config json file") + } + if len(path) > 0 { log.Entry().Infof("Docker credentials configuration: %v", path) path, _ := filepath.Abs(path) @@ -383,6 +397,7 @@ func correctDockerConfigEnvVar(config *protecodeExecuteScanOptions) { } else { log.Entry().Info("Docker credentials configuration: NONE") } + return nil } // Calculate version based on versioning model and artifact version or return custom scan version provided by user diff --git a/cmd/protecodeExecuteScan_generated.go b/cmd/protecodeExecuteScan_generated.go index 90c343a87..d93672871 100644 --- a/cmd/protecodeExecuteScan_generated.go +++ b/cmd/protecodeExecuteScan_generated.go @@ -26,6 +26,8 @@ type protecodeExecuteScanOptions struct { FailOnSevereVulnerabilities bool `json:"failOnSevereVulnerabilities,omitempty"` ScanImage string `json:"scanImage,omitempty"` DockerRegistryURL string `json:"dockerRegistryUrl,omitempty"` + ContainerRegistryPassword string `json:"containerRegistryPassword,omitempty"` + ContainerRegistryUser string `json:"containerRegistryUser,omitempty"` DockerConfigJSON string `json:"dockerConfigJSON,omitempty"` CleanupMode string `json:"cleanupMode,omitempty" validate:"possible-values=none binary complete"` FilePath string `json:"filePath,omitempty"` @@ -173,6 +175,8 @@ BDBA (Protecode) uses a combination of static binary analysis techniques to X-ra log.SetErrorCategory(log.ErrorConfiguration) return err } + log.RegisterSecret(stepConfig.ContainerRegistryPassword) + log.RegisterSecret(stepConfig.ContainerRegistryUser) log.RegisterSecret(stepConfig.DockerConfigJSON) log.RegisterSecret(stepConfig.Username) log.RegisterSecret(stepConfig.Password) @@ -245,6 +249,8 @@ func addProtecodeExecuteScanFlags(cmd *cobra.Command, stepConfig *protecodeExecu cmd.Flags().BoolVar(&stepConfig.FailOnSevereVulnerabilities, "failOnSevereVulnerabilities", true, "Whether to fail the step on severe vulnerabilties or not") cmd.Flags().StringVar(&stepConfig.ScanImage, "scanImage", os.Getenv("PIPER_scanImage"), "The reference to the docker image to scan with Protecode. Note: If possible please also check [fetchUrl](https://www.project-piper.io/steps/protecodeExecuteScan/#fetchurl) parameter, which might help you to optimize upload time.") cmd.Flags().StringVar(&stepConfig.DockerRegistryURL, "dockerRegistryUrl", os.Getenv("PIPER_dockerRegistryUrl"), "The reference to the docker registry to scan with Protecode") + cmd.Flags().StringVar(&stepConfig.ContainerRegistryPassword, "containerRegistryPassword", os.Getenv("PIPER_containerRegistryPassword"), "For `buildTool: docker`: Password for container registry access - typically provided by the CI/CD environment.") + cmd.Flags().StringVar(&stepConfig.ContainerRegistryUser, "containerRegistryUser", os.Getenv("PIPER_containerRegistryUser"), "For `buildTool: docker`: Username for container registry access - typically provided by the CI/CD environment.") cmd.Flags().StringVar(&stepConfig.DockerConfigJSON, "dockerConfigJSON", os.Getenv("PIPER_dockerConfigJSON"), "Path to the file `.docker/config.json` - this is typically provided by your CI/CD system. You can find more details about the Docker credentials in the [Docker documentation](https://docs.docker.com/engine/reference/commandline/login/).") cmd.Flags().StringVar(&stepConfig.CleanupMode, "cleanupMode", `binary`, "Decides which parts are removed from the Protecode backend after the scan") cmd.Flags().StringVar(&stepConfig.FilePath, "filePath", os.Getenv("PIPER_filePath"), "The path to the file from local workspace to scan with Protecode") @@ -332,6 +338,44 @@ func protecodeExecuteScanMetadata() config.StepData { Aliases: []config.Alias{}, Default: os.Getenv("PIPER_dockerRegistryUrl"), }, + { + Name: "containerRegistryPassword", + ResourceRef: []config.ResourceReference{ + { + Name: "commonPipelineEnvironment", + Param: "container/repositoryPassword", + }, + + { + Name: "commonPipelineEnvironment", + Param: "custom/repositoryPassword", + }, + }, + Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_containerRegistryPassword"), + }, + { + Name: "containerRegistryUser", + ResourceRef: []config.ResourceReference{ + { + Name: "commonPipelineEnvironment", + Param: "container/repositoryUsername", + }, + + { + Name: "commonPipelineEnvironment", + Param: "custom/repositoryUsername", + }, + }, + Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_containerRegistryUser"), + }, { Name: "dockerConfigJSON", ResourceRef: []config.ResourceReference{ diff --git a/cmd/protecodeExecuteScan_test.go b/cmd/protecodeExecuteScan_test.go index 61570920a..a96031385 100644 --- a/cmd/protecodeExecuteScan_test.go +++ b/cmd/protecodeExecuteScan_test.go @@ -348,6 +348,11 @@ func TestExecuteProtecodeScan(t *testing.T) { } func TestCorrectDockerConfigEnvVar(t *testing.T) { + utils := protecodeTestUtilsBundle{ + FilesMock: &mock.FilesMock{}, + DownloadMock: &mock.DownloadMock{}, + } + t.Run("with credentials", func(t *testing.T) { // init testDirectory := t.TempDir() @@ -366,7 +371,7 @@ func TestCorrectDockerConfigEnvVar(t *testing.T) { resetValue := os.Getenv("DOCKER_CONFIG") defer os.Setenv("DOCKER_CONFIG", resetValue) // test - correctDockerConfigEnvVar(&protecodeExecuteScanOptions{DockerConfigJSON: dockerConfigFile}) + correctDockerConfigEnvVar(&protecodeExecuteScanOptions{DockerConfigJSON: dockerConfigFile}, utils) // assert absolutePath, _ := filepath.Abs(dockerConfigDir) assert.Equal(t, absolutePath, os.Getenv("DOCKER_CONFIG")) @@ -376,7 +381,7 @@ func TestCorrectDockerConfigEnvVar(t *testing.T) { resetValue := os.Getenv("DOCKER_CONFIG") defer os.Setenv("DOCKER_CONFIG", resetValue) // test - correctDockerConfigEnvVar(&protecodeExecuteScanOptions{}) + correctDockerConfigEnvVar(&protecodeExecuteScanOptions{}, utils) // assert assert.Equal(t, resetValue, os.Getenv("DOCKER_CONFIG")) }) diff --git a/resources/metadata/protecodeExecuteScan.yaml b/resources/metadata/protecodeExecuteScan.yaml index d3cbd5259..3c13c97ed 100644 --- a/resources/metadata/protecodeExecuteScan.yaml +++ b/resources/metadata/protecodeExecuteScan.yaml @@ -67,6 +67,32 @@ spec: - PARAMETERS - STAGES - STEPS + - name: containerRegistryPassword + description: "For `buildTool: docker`: Password for container registry access - typically provided by the CI/CD environment." + type: string + scope: + - PARAMETERS + - STAGES + - STEPS + secret: true + resourceRef: + - name: commonPipelineEnvironment + param: container/repositoryPassword + - name: commonPipelineEnvironment + param: custom/repositoryPassword + - name: containerRegistryUser + description: "For `buildTool: docker`: Username for container registry access - typically provided by the CI/CD environment." + type: string + scope: + - PARAMETERS + - STAGES + - STEPS + secret: true + resourceRef: + - name: commonPipelineEnvironment + param: container/repositoryUsername + - name: commonPipelineEnvironment + param: custom/repositoryUsername - name: dockerConfigJSON type: string description: Path to the file `.docker/config.json` - this is typically provided by your CI/CD system. You can find more details about the Docker credentials in the [Docker documentation](https://docs.docker.com/engine/reference/commandline/login/).