diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index a9e37aaaca..1f511785b9 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -53,14 +53,12 @@ jobs: - name: Generate Golang Docs run: go run pkg/documentation/generator.go --docuDir=documentation/docs/steps/ --customDefaultFile resources/default_pipeline_environment.yml - - run: docker pull squidfunk/mkdocs-material:8.3.6 - - name: Build run: | docker run \ -u $(id -u):$(id -g) \ -v ${GITHUB_WORKSPACE}/documentation:/docs \ - squidfunk/mkdocs-material:latest build --clean --strict + squidfunk/mkdocs-material:8.5.11 build --clean --strict - name: Provide Docs Metadata run: | diff --git a/.github/workflows/integration-tests-pr.yml b/.github/workflows/integration-tests-pr.yml index 220bbe6b5b..d9b241296d 100644 --- a/.github/workflows/integration-tests-pr.yml +++ b/.github/workflows/integration-tests-pr.yml @@ -120,6 +120,7 @@ jobs: needs: - build_piper - build_integration_tests + - start strategy: fail-fast: true matrix: ${{ fromJson(needs.build_integration_tests.outputs.matrix) }} diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index bc83350876..88c65eabaa 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -92,6 +92,7 @@ jobs: needs: - build_piper - build_integration_tests + - start strategy: fail-fast: true matrix: ${{ fromJson(needs.build_integration_tests.outputs.matrix) }} diff --git a/cmd/abapEnvironmentAssembleConfirm_generated.go b/cmd/abapEnvironmentAssembleConfirm_generated.go index aa4c7499fb..ac3b4b80f4 100644 --- a/cmd/abapEnvironmentAssembleConfirm_generated.go +++ b/cmd/abapEnvironmentAssembleConfirm_generated.go @@ -59,7 +59,7 @@ func (p *abapEnvironmentAssembleConfirmCommonPipelineEnvironment) persist(path, } } -// AbapEnvironmentAssembleConfirmCommand Confirm the Delivery of Assembly for installation, support package or patch in SAP Cloud Platform ABAP Environment system +// AbapEnvironmentAssembleConfirmCommand Confirm the Delivery of Assembly for installation, support package or patch in SAP BTP ABAP Environment system func AbapEnvironmentAssembleConfirmCommand() *cobra.Command { const STEP_NAME = "abapEnvironmentAssembleConfirm" @@ -73,8 +73,8 @@ func AbapEnvironmentAssembleConfirmCommand() *cobra.Command { var createAbapEnvironmentAssembleConfirmCmd = &cobra.Command{ Use: STEP_NAME, - Short: "Confirm the Delivery of Assembly for installation, support package or patch in SAP Cloud Platform ABAP Environment system", - Long: `This step confirms the assemblies of provided [installations, support packages or patches] in SAP Cloud Platform ABAP Environment system`, + Short: "Confirm the Delivery of Assembly for installation, support package or patch in SAP BTP ABAP Environment system", + Long: `This step confirms the assemblies of provided [installations, support packages or patches] in SAP BTP ABAP Environment system`, PreRunE: func(cmd *cobra.Command, _ []string) error { startTime = time.Now() log.SetStepName(STEP_NAME) @@ -161,7 +161,7 @@ func addAbapEnvironmentAssembleConfirmFlags(cmd *cobra.Command, stepConfig *abap cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "Cloud Foundry target space") cmd.Flags().StringVar(&stepConfig.CfServiceInstance, "cfServiceInstance", os.Getenv("PIPER_cfServiceInstance"), "Cloud Foundry Service Instance") cmd.Flags().StringVar(&stepConfig.CfServiceKeyName, "cfServiceKeyName", os.Getenv("PIPER_cfServiceKeyName"), "Cloud Foundry Service Key") - cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP Cloud Platform ABAP Environment system") + cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP BTP ABAP Environment system") cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "User for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0582") cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0582") cmd.Flags().StringVar(&stepConfig.AddonDescriptor, "addonDescriptor", os.Getenv("PIPER_addonDescriptor"), "Structure in the commonPipelineEnvironment containing information about the Product Version and corresponding Software Component Versions") @@ -180,7 +180,7 @@ func abapEnvironmentAssembleConfirmMetadata() config.StepData { Metadata: config.StepMetadata{ Name: "abapEnvironmentAssembleConfirm", Aliases: []config.Alias{}, - Description: "Confirm the Delivery of Assembly for installation, support package or patch in SAP Cloud Platform ABAP Environment system", + Description: "Confirm the Delivery of Assembly for installation, support package or patch in SAP BTP ABAP Environment system", }, Spec: config.StepSpec{ Inputs: config.StepInputs{ diff --git a/cmd/abapEnvironmentAssemblePackages_generated.go b/cmd/abapEnvironmentAssemblePackages_generated.go index 297de6aa28..0e5bd5365f 100644 --- a/cmd/abapEnvironmentAssemblePackages_generated.go +++ b/cmd/abapEnvironmentAssemblePackages_generated.go @@ -60,7 +60,7 @@ func (p *abapEnvironmentAssemblePackagesCommonPipelineEnvironment) persist(path, } } -// AbapEnvironmentAssemblePackagesCommand Assembly of installation, support package or patch in SAP Cloud Platform ABAP Environment system +// AbapEnvironmentAssemblePackagesCommand Assembly of installation, support package or patch in SAP BTP ABAP Environment system func AbapEnvironmentAssemblePackagesCommand() *cobra.Command { const STEP_NAME = "abapEnvironmentAssemblePackages" @@ -74,7 +74,7 @@ func AbapEnvironmentAssemblePackagesCommand() *cobra.Command { var createAbapEnvironmentAssemblePackagesCmd = &cobra.Command{ Use: STEP_NAME, - Short: "Assembly of installation, support package or patch in SAP Cloud Platform ABAP Environment system", + Short: "Assembly of installation, support package or patch in SAP BTP ABAP Environment system", Long: `This step runs the assembly of a list of provided [installations, support packages or patches](https://help.sap.com/viewer/9043aa5d2f834ad385e1cdfdadc06b6f/LATEST/en-US/9a81f55473568c77e10000000a174cb4.html) in SAP Cloud Platform ABAP Environment system and saves the corresponding [SAR archive](https://launchpad.support.sap.com/#/notes/212876) to the filesystem.`, PreRunE: func(cmd *cobra.Command, _ []string) error { @@ -163,7 +163,7 @@ func addAbapEnvironmentAssemblePackagesFlags(cmd *cobra.Command, stepConfig *aba cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "Cloud Foundry target space") cmd.Flags().StringVar(&stepConfig.CfServiceInstance, "cfServiceInstance", os.Getenv("PIPER_cfServiceInstance"), "Cloud Foundry Service Instance") cmd.Flags().StringVar(&stepConfig.CfServiceKeyName, "cfServiceKeyName", os.Getenv("PIPER_cfServiceKeyName"), "Cloud Foundry Service Key") - cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP Cloud Platform ABAP Environment system") + cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP BTP ABAP Environment system") cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "User for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0582") cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0582") cmd.Flags().StringVar(&stepConfig.AddonDescriptor, "addonDescriptor", os.Getenv("PIPER_addonDescriptor"), "Structure in the commonPipelineEnvironment containing information about the Product Version and corresponding Software Component Versions") @@ -184,7 +184,7 @@ func abapEnvironmentAssemblePackagesMetadata() config.StepData { Metadata: config.StepMetadata{ Name: "abapEnvironmentAssemblePackages", Aliases: []config.Alias{}, - Description: "Assembly of installation, support package or patch in SAP Cloud Platform ABAP Environment system", + Description: "Assembly of installation, support package or patch in SAP BTP ABAP Environment system", }, Spec: config.StepSpec{ Inputs: config.StepInputs{ diff --git a/cmd/abapEnvironmentBuild_generated.go b/cmd/abapEnvironmentBuild_generated.go index ea1883b89c..59ebd57562 100644 --- a/cmd/abapEnvironmentBuild_generated.go +++ b/cmd/abapEnvironmentBuild_generated.go @@ -176,8 +176,8 @@ func addAbapEnvironmentBuildFlags(cmd *cobra.Command, stepConfig *abapEnvironmen cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "Cloud Foundry target space") cmd.Flags().StringVar(&stepConfig.CfServiceInstance, "cfServiceInstance", os.Getenv("PIPER_cfServiceInstance"), "Cloud Foundry Service Instance") cmd.Flags().StringVar(&stepConfig.CfServiceKeyName, "cfServiceKeyName", os.Getenv("PIPER_cfServiceKeyName"), "Cloud Foundry Service Key") - cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP Cloud Platform ABAP Environment system") - cmd.Flags().StringVar(&stepConfig.AbapSourceClient, "abapSourceClient", os.Getenv("PIPER_abapSourceClient"), "Specifies the client of the SAP Cloud Platform ABAP Environment system, use only in combination with host") + cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP BTP ABAP Environment system") + cmd.Flags().StringVar(&stepConfig.AbapSourceClient, "abapSourceClient", os.Getenv("PIPER_abapSourceClient"), "Specifies the client of the SAP BTP ABAP Environment system, use only in combination with host") cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "User") cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password") cmd.Flags().StringVar(&stepConfig.Phase, "phase", os.Getenv("PIPER_phase"), "Phase as specified in the build script in the backend system") diff --git a/cmd/abapEnvironmentPushATCSystemConfig.go b/cmd/abapEnvironmentPushATCSystemConfig.go index ec3bfa0eef..4dd5cbf2c0 100644 --- a/cmd/abapEnvironmentPushATCSystemConfig.go +++ b/cmd/abapEnvironmentPushATCSystemConfig.go @@ -47,12 +47,12 @@ func runAbapEnvironmentPushATCSystemConfig(config *abapEnvironmentPushATCSystemC // Determine the host, user and password, either via the input parameters or via a cloud foundry service key. connectionDetails, err := autils.GetAbapCommunicationArrangementInfo(subOptions, "/sap/opu/odata4/sap/satc_ci_cf_api/srvd_a2x/sap/satc_ci_cf_sv_api/0001") if err != nil { - return errors.Wrap(err, "Parameters for the ABAP Connection not available") + return errors.Errorf("Parameters for the ABAP Connection not available: %v", err) } cookieJar, err := cookiejar.New(nil) if err != nil { - return errors.Wrap(err, "could not create a Cookie Jar") + return errors.Errorf("could not create a Cookie Jar: %v", err) } clientOptions := piperhttp.ClientOptions{ MaxRequestDuration: 180 * time.Second, @@ -62,6 +62,10 @@ func runAbapEnvironmentPushATCSystemConfig(config *abapEnvironmentPushATCSystemC } client.SetOptions(clientOptions) + if connectionDetails.XCsrfToken, err = fetchXcsrfTokenFromHead(connectionDetails, client); err != nil { + return err + } + return pushATCSystemConfig(config, connectionDetails, client) } @@ -122,7 +126,7 @@ func checkATCSystemConfigurationFile(config *abapEnvironmentPushATCSystemConfigO //check if parsedConfigurationJson is not initial or Configuration Name not supplied if reflect.DeepEqual(parsedConfigurationJson, emptyConfigurationJson) || parsedConfigurationJson.ConfName == "" { - return parsedConfigurationJson, atcSystemConfiguartionJsonFile, fmt.Errorf("pushing ATC System Configuration failed. Reason: Configured File does not contain required ATC System Configuration attributes (File: " + config.AtcSystemConfigFilePath + ")") + return parsedConfigurationJson, atcSystemConfiguartionJsonFile, errors.Errorf("pushing ATC System Configuration failed. Reason: Configured File does not contain required ATC System Configuration attributes (File: " + config.AtcSystemConfigFilePath + ")") } return parsedConfigurationJson, atcSystemConfiguartionJsonFile, nil @@ -140,7 +144,7 @@ func readATCSystemConfigurationFile(config *abapEnvironmentPushATCSystemConfigOp } if len(filelocation) == 0 { - return parsedConfigurationJson, atcSystemConfiguartionJsonFile, fmt.Errorf("pushing ATC System Configuration failed. Reason: Configured Filelocation is empty (File: " + config.AtcSystemConfigFilePath + ")") + return parsedConfigurationJson, atcSystemConfiguartionJsonFile, errors.Errorf("pushing ATC System Configuration failed. Reason: Configured Filelocation is empty (File: " + config.AtcSystemConfigFilePath + ")") } filename, err = filepath.Abs(filelocation[0]) @@ -152,12 +156,12 @@ func readATCSystemConfigurationFile(config *abapEnvironmentPushATCSystemConfigOp return parsedConfigurationJson, atcSystemConfiguartionJsonFile, err } if len(atcSystemConfiguartionJsonFile) == 0 { - return parsedConfigurationJson, atcSystemConfiguartionJsonFile, fmt.Errorf("pushing ATC System Configuration failed. Reason: Configured File is empty (File: " + config.AtcSystemConfigFilePath + ")") + return parsedConfigurationJson, atcSystemConfiguartionJsonFile, errors.Errorf("pushing ATC System Configuration failed. Reason: Configured File is empty (File: " + config.AtcSystemConfigFilePath + ")") } err = json.Unmarshal(atcSystemConfiguartionJsonFile, &parsedConfigurationJson) if err != nil { - return emptyConfigurationJson, atcSystemConfiguartionJsonFile, err + return emptyConfigurationJson, atcSystemConfiguartionJsonFile, errors.Errorf("pushing ATC System Configuration failed. Unmarshal Error of ATC Configuration File ("+config.AtcSystemConfigFilePath+"): %v", err) } return parsedConfigurationJson, atcSystemConfiguartionJsonFile, err @@ -165,10 +169,6 @@ func readATCSystemConfigurationFile(config *abapEnvironmentPushATCSystemConfigOp func handlePushConfiguration(config *abapEnvironmentPushATCSystemConfigOptions, confUUID string, configDoesExist bool, atcSystemConfiguartionJsonFile []byte, connectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) error { var err error - connectionDetails.XCsrfToken, err = fetchXcsrfTokenFromHead(connectionDetails, client) - if err != nil { - return err - } if configDoesExist { err = doPatchATCSystemConfig(config, confUUID, atcSystemConfiguartionJsonFile, connectionDetails, client) if err != nil { @@ -199,7 +199,7 @@ func fetchXcsrfTokenFromHead(connectionDetails abaputils.ConnectionDetailsHTTP, resp, err := abaputils.GetHTTPResponse("HEAD", connectionDetails, nil, client) if err != nil { err = abaputils.HandleHTTPError(resp, err, "authentication on the ABAP system failed", connectionDetails) - return connectionDetails.XCsrfToken, err + return connectionDetails.XCsrfToken, errors.Errorf("X-Csrf-Token fetch failed for Service ATC System Configuration: %v", err) } defer resp.Body.Close() @@ -285,25 +285,24 @@ func buildParsedATCSystemConfigBaseJsonBody(confUUID string, atcSystemConfiguart var outputString string = `` if err := json.Unmarshal([]byte(atcSystemConfiguartionJsonFile), &i); err != nil { - log.Entry().Errorf("problem with unmarshall input "+atcSystemConfiguartionJsonFile, err) - return outputString, err + return outputString, errors.Errorf("problem with unmarshall input "+atcSystemConfiguartionJsonFile+": %v", err) } if m, ok := i.(map[string]interface{}); ok { delete(m, "_priorities") } - output, err := json.Marshal(i) - if err != nil { - log.Entry().Errorf("problem with marshall output "+atcSystemConfiguartionJsonFile, err) + if output, err := json.Marshal(i); err != nil { + return outputString, errors.Errorf("problem with marshall output "+atcSystemConfiguartionJsonFile+": %v", err) + } else { + output = output[1:] // remove leading '{' + outputString = string(output) + //injecting the configuration ID + confIDString := `{"conf_id":"` + confUUID + `",` + outputString = confIDString + outputString + return outputString, err } - //injecting the configuration ID - output = output[1:] // remove leading '{' - outputString = string(output) - confIDString := `{"conf_id":"` + confUUID + `",` - outputString = confIDString + outputString - return outputString, err } func addPatchConfigBaseChangeset(inputString string, confUUID string, configBaseJsonBody string) string { @@ -419,9 +418,8 @@ func checkConfigExistsInBackend(config *abapEnvironmentPushATCSystemConfigOption } var parsedoDataResponse parsedOdataResp - err = json.Unmarshal(body, &parsedoDataResponse) - if err != nil { - return false, configName, configUUID, configLastChangedAt, err + if err = json.Unmarshal(body, &parsedoDataResponse); err != nil { + return false, configName, configUUID, configLastChangedAt, errors.New("GET Request for check existence of ATC System Configuration - Unexpected Response - Problem with Unmarshal body: " + string(body)) } if len(parsedoDataResponse.Value) > 0 { configUUID = parsedoDataResponse.Value[0].ConfUUID @@ -502,7 +500,7 @@ func getErrorDetailsFromBody(resp *http.Response, bodyText []byte) (errorString } } - return errorString, errors.New("Could not parse the JSON error response") + return errorString, errors.New("Could not parse the JSON error response. stringified body " + string(bodyText)) } diff --git a/cmd/abapEnvironmentRunATCCheck.go b/cmd/abapEnvironmentRunATCCheck.go index f094ab2c47..650a4edc4b 100644 --- a/cmd/abapEnvironmentRunATCCheck.go +++ b/cmd/abapEnvironmentRunATCCheck.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "encoding/xml" - "fmt" "io/ioutil" "net/http" "net/http/cookiejar" @@ -73,6 +72,7 @@ func abapEnvironmentRunATCCheck(options abapEnvironmentRunATCCheckOptions, telem func fetchAndPersistATCResults(resp *http.Response, details abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, utils piperutils.FileUtils, atcResultFileName string, generateHTML bool, failOnSeverityLevel string) error { var err error + var failStep bool abapEndpoint := details.URL location := resp.Header.Get("Location") details.URL = abapEndpoint + location @@ -88,10 +88,13 @@ func fetchAndPersistATCResults(resp *http.Response, details abaputils.Connection } if err == nil { defer resp.Body.Close() - err = logAndPersistATCResult(utils, body, atcResultFileName, generateHTML, failOnSeverityLevel) + err, failStep = logAndPersistAndEvaluateATCResults(utils, body, atcResultFileName, generateHTML, failOnSeverityLevel) } if err != nil { - return fmt.Errorf("Handling ATC result failed: %w", err) + return errors.Errorf("Handling ATC result failed: %v", err) + } + if failStep { + return errors.Errorf("Step execution failed due to at least one ATC finding with severity equal to or higher than the failOnSeverity parameter of this step (see config.yml)") } return nil } @@ -139,7 +142,7 @@ func buildATCRequestBody(config abapEnvironmentRunATCCheckOptions) (bodyString s } if objectSetString == "" { - return objectSetString, fmt.Errorf("Error while parsing ATC test run object set config. No object set has been provided. Please configure the objects you want to be checked for the respective test run") + return objectSetString, errors.Errorf("Error while parsing ATC test run object set config. No object set has been provided. Please configure the objects you want to be checked for the respective test run") } bodyString = `` + objectSetString + `` @@ -202,15 +205,16 @@ func getATCObjectSet(ATCConfig ATCConfiguration) (objectSet string, err error) { return objectSet, nil } -func logAndPersistATCResult(utils piperutils.FileUtils, body []byte, atcResultFileName string, generateHTML bool, failOnSeverityLevel string) error { +func logAndPersistAndEvaluateATCResults(utils piperutils.FileUtils, body []byte, atcResultFileName string, generateHTML bool, failOnSeverityLevel string) (error, bool) { + var failStep bool if len(body) == 0 { - return fmt.Errorf("Parsing ATC result failed: %w", errors.New("Body is empty, can't parse empty body")) + return errors.Errorf("Parsing ATC result failed: %v", errors.New("Body is empty, can't parse empty body")), failStep } responseBody := string(body) log.Entry().Debugf("Response body: %s", responseBody) if strings.HasPrefix(responseBody, "") { - return errors.New("The Software Component could not be checked. Please make sure the respective Software Component has been cloned successfully on the system") + return errors.New("The Software Component could not be checked. Please make sure the respective Software Component has been cloned successfully on the system"), failStep } parsedXML := new(Result) @@ -225,7 +229,6 @@ func logAndPersistATCResult(utils piperutils.FileUtils, body []byte, atcResultFi if err == nil { log.Entry().Infof("Writing %s file was successful", atcResultFileName) var reports []piperutils.Path - var failStep bool reports = append(reports, piperutils.Path{Target: atcResultFileName, Name: "ATC Results", Mandatory: true}) for _, s := range parsedXML.Files { for _, t := range s.ATCErrors { @@ -246,14 +249,11 @@ func logAndPersistATCResult(utils piperutils.FileUtils, body []byte, atcResultFi } } piperutils.PersistReportsAndLinks("abapEnvironmentRunATCCheck", "", utils, reports, nil) - if failStep { - return errors.New("Step Execution failed due to at least one ATC Finding with severity equal (or higher) to configured failOnSeverity Option - '" + failOnSeverityLevel + "'") - } } if err != nil { - return fmt.Errorf("Writing results failed: %w", err) + return errors.Errorf("Writing results failed: %v", err), failStep } - return nil + return nil, failStep } func checkStepFailing(severity string, failOnSeverityLevel string) bool { switch failOnSeverityLevel { @@ -307,7 +307,7 @@ func runATC(requestType string, details abaputils.ConnectionDetailsHTTP, body [] if err != nil || (resp != nil && resp.StatusCode == 400) { // send request does not seem to produce error with StatusCode 400!!! err = abaputils.HandleHTTPError(resp, err, "triggering ATC run failed with Status: "+resp.Status, details) log.SetErrorCategory(log.ErrorService) - return resp, fmt.Errorf("triggering ATC run failed: %w", err) + return resp, errors.Errorf("triggering ATC run failed: %v", err) } defer resp.Body.Close() return resp, err @@ -337,7 +337,7 @@ func fetchXcsrfToken(requestType string, details abaputils.ConnectionDetailsHTTP req, err := client.SendRequest(requestType, details.URL, bytes.NewBuffer(body), header, nil) if err != nil { log.SetErrorCategory(log.ErrorInfrastructure) - return "", fmt.Errorf("Fetching Xcsrf-Token failed: %w", err) + return "", errors.Errorf("Fetching Xcsrf-Token failed: %v", err) } defer req.Body.Close() @@ -351,11 +351,11 @@ func pollATCRun(details abaputils.ConnectionDetailsHTTP, body []byte, client pip for { resp, err := getHTTPResponseATCRun("GET", details, nil, client) if err != nil { - return "", fmt.Errorf("Getting HTTP response failed: %w", err) + return "", errors.Errorf("Getting HTTP response failed: %v", err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { - return "", fmt.Errorf("Reading response body failed: %w", err) + return "", errors.Errorf("Reading response body failed: %v", err) } x := new(Run) @@ -371,7 +371,7 @@ func pollATCRun(details abaputils.ConnectionDetailsHTTP, body []byte, client pip return x.Link[0].Key, err } if x.Status == "" { - return "", fmt.Errorf("Could not get any response from ATC poll: %w", errors.New("Status from ATC run is empty. Either it's not an ABAP system or ATC run hasn't started")) + return "", errors.Errorf("Could not get any response from ATC poll: %v", errors.New("Status from ATC run is empty. Either it's not an ABAP system or ATC run hasn't started")) } time.Sleep(5 * time.Second) } @@ -383,7 +383,7 @@ func getHTTPResponseATCRun(requestType string, details abaputils.ConnectionDetai resp, err := client.SendRequest(requestType, details.URL, bytes.NewBuffer(body), header, nil) if err != nil { - return resp, fmt.Errorf("Getting ATC run status failed: %w", err) + return resp, errors.Errorf("Getting ATC run status failed: %v", err) } return resp, err } @@ -397,7 +397,7 @@ func getResultATCRun(requestType string, details abaputils.ConnectionDetailsHTTP resp, err := client.SendRequest(requestType, details.URL, bytes.NewBuffer(body), header, nil) if err != nil { - return resp, fmt.Errorf("Getting ATC run results failed: %w", err) + return resp, errors.Errorf("Getting ATC run results failed: %v", err) } return resp, err } diff --git a/cmd/abapEnvironmentRunATCCheck_generated.go b/cmd/abapEnvironmentRunATCCheck_generated.go index 31b54d7db8..7ca48d4e4f 100644 --- a/cmd/abapEnvironmentRunATCCheck_generated.go +++ b/cmd/abapEnvironmentRunATCCheck_generated.go @@ -45,7 +45,7 @@ func AbapEnvironmentRunATCCheckCommand() *cobra.Command { var createAbapEnvironmentRunATCCheckCmd = &cobra.Command{ Use: STEP_NAME, Short: "Runs an ATC Check", - Long: `This step is for triggering an [ATC](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/d8cec788fc104ff9ad9c3757b4dd13d4.html) test run on an SAP Cloud Platform ABAP Environment system. + Long: `This step is for triggering an [ATC](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/d8cec788fc104ff9ad9c3757b4dd13d4.html) test run on an SAP BTP ABAP Environment system. Please provide either of the following options: * The host and credentials the Cloud Platform ABAP Environment system itself. The credentials must be configured for the Communication Scenario [SAP_COM_0901](https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/d8cec788fc104ff9ad9c3757b4dd13d4.html). @@ -142,7 +142,7 @@ func addAbapEnvironmentRunATCCheckFlags(cmd *cobra.Command, stepConfig *abapEnvi cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "CF Space") cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "User for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0901") cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0901") - cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP Cloud Platform ABAP Environment system") + cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP BTP ABAP Environment system") cmd.Flags().StringVar(&stepConfig.AtcResultsFileName, "atcResultsFileName", `ATCResults.xml`, "Specifies output file name for the results from the ATC run. This file name will also be used for generating the HTML file") cmd.Flags().BoolVar(&stepConfig.GenerateHTML, "generateHTML", false, "Specifies whether the ATC results should also be generated as an HTML document") cmd.Flags().StringVar(&stepConfig.FailOnSeverity, "failOnSeverity", os.Getenv("PIPER_failOnSeverity"), "Specifies the severity level, for which the ATC step should fail if at least one message with this severity (or \"higher\") level is returned by the ATC Check Run (possible values - error, warning, info). Initial value is default behavior and ATC findings of any severity do not fail the step") diff --git a/cmd/abapEnvironmentRunATCCheck_test.go b/cmd/abapEnvironmentRunATCCheck_test.go index c5b1447050..3ddee24c33 100644 --- a/cmd/abapEnvironmentRunATCCheck_test.go +++ b/cmd/abapEnvironmentRunATCCheck_test.go @@ -8,7 +8,6 @@ import ( "github.com/SAP/jenkins-library/pkg/abaputils" "github.com/SAP/jenkins-library/pkg/mock" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -243,7 +242,8 @@ func TestParseATCResult(t *testing.T) { ` body := []byte(bodyString) - err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.xml", false, "") + err, failStep := logAndPersistAndEvaluateATCResults(&mock.FilesMock{}, body, "ATCResults.xml", false, "") + assert.Equal(t, false, failStep) assert.Equal(t, nil, err) }) t.Run("succes case: test parsing example XML result - Fail on Severity error", func(t *testing.T) { @@ -269,9 +269,11 @@ func TestParseATCResult(t *testing.T) { ` body := []byte(bodyString) doFailOnSeverityLevel := "error" - err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) - expErr := errors.New("Step Execution failed due to at least one ATC Finding with severity equal (or higher) to configured failOnSeverity Option - '" + doFailOnSeverityLevel + "'") - assert.Equal(t, expErr.Error(), err.Error()) + err, failStep := logAndPersistAndEvaluateATCResults(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) + //fail true + assert.Equal(t, true, failStep) + //but no error here + assert.Equal(t, nil, err) }) t.Run("succes case: test parsing example XML result - Fail on Severity warning", func(t *testing.T) { dir := t.TempDir() @@ -296,9 +298,11 @@ func TestParseATCResult(t *testing.T) { ` body := []byte(bodyString) doFailOnSeverityLevel := "warning" - err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) - expErr := errors.New("Step Execution failed due to at least one ATC Finding with severity equal (or higher) to configured failOnSeverity Option - '" + doFailOnSeverityLevel + "'") - assert.Equal(t, expErr.Error(), err.Error()) + err, failStep := logAndPersistAndEvaluateATCResults(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) + //fail true + assert.Equal(t, true, failStep) + //but no error here + assert.Equal(t, nil, err) }) t.Run("succes case: test parsing example XML result - Fail on Severity info", func(t *testing.T) { dir := t.TempDir() @@ -323,9 +327,11 @@ func TestParseATCResult(t *testing.T) { ` body := []byte(bodyString) doFailOnSeverityLevel := "info" - err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) - expErr := errors.New("Step Execution failed due to at least one ATC Finding with severity equal (or higher) to configured failOnSeverity Option - '" + doFailOnSeverityLevel + "'") - assert.Equal(t, expErr.Error(), err.Error()) + err, failStep := logAndPersistAndEvaluateATCResults(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) + //fail true + assert.Equal(t, true, failStep) + //but no error here + assert.Equal(t, nil, err) }) t.Run("succes case: test parsing example XML result - Fail on Severity warning - only errors", func(t *testing.T) { dir := t.TempDir() @@ -350,9 +356,11 @@ func TestParseATCResult(t *testing.T) { ` body := []byte(bodyString) doFailOnSeverityLevel := "warning" - err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) - expErr := errors.New("Step Execution failed due to at least one ATC Finding with severity equal (or higher) to configured failOnSeverity Option - '" + doFailOnSeverityLevel + "'") - assert.Equal(t, expErr.Error(), err.Error()) + err, failStep := logAndPersistAndEvaluateATCResults(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) + //fail true + assert.Equal(t, true, failStep) + //but no error here + assert.Equal(t, nil, err) }) t.Run("succes case: test parsing example XML result - Fail on Severity info - only errors", func(t *testing.T) { dir := t.TempDir() @@ -377,11 +385,13 @@ func TestParseATCResult(t *testing.T) { ` body := []byte(bodyString) doFailOnSeverityLevel := "info" - err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) - expErr := errors.New("Step Execution failed due to at least one ATC Finding with severity equal (or higher) to configured failOnSeverity Option - '" + doFailOnSeverityLevel + "'") - assert.Equal(t, expErr.Error(), err.Error()) + err, failStep := logAndPersistAndEvaluateATCResults(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) + //fail true + assert.Equal(t, true, failStep) + //but no error here + assert.Equal(t, nil, err) }) - t.Run("succes case: test parsing example XML result - Fail on Severity warning - only warnings", func(t *testing.T) { + t.Run("succes case: test parsing example XML result - Fail on Severity info - only warnings", func(t *testing.T) { dir := t.TempDir() oldCWD, _ := os.Getwd() _ = os.Chdir(dir) @@ -404,9 +414,69 @@ func TestParseATCResult(t *testing.T) { ` body := []byte(bodyString) doFailOnSeverityLevel := "info" - err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) - expErr := errors.New("Step Execution failed due to at least one ATC Finding with severity equal (or higher) to configured failOnSeverity Option - '" + doFailOnSeverityLevel + "'") - assert.Equal(t, expErr.Error(), err.Error()) + err, failStep := logAndPersistAndEvaluateATCResults(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) + //fail true + assert.Equal(t, true, failStep) + //but no error here + assert.Equal(t, nil, err) + }) + t.Run("succes case: test parsing example XML result - NOT Fail on Severity warning - only infos", func(t *testing.T) { + dir := t.TempDir() + oldCWD, _ := os.Getwd() + _ = os.Chdir(dir) + // clean up tmp dir + defer func() { + _ = os.Chdir(oldCWD) + }() + bodyString := ` + + + + + + + + + + + + ` + body := []byte(bodyString) + doFailOnSeverityLevel := "warning" + err, failStep := logAndPersistAndEvaluateATCResults(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) + //fail false + assert.Equal(t, false, failStep) + //no error here + assert.Equal(t, nil, err) + }) + t.Run("succes case: test parsing example XML result - NOT Fail on Severity error - only warnings", func(t *testing.T) { + dir := t.TempDir() + oldCWD, _ := os.Getwd() + _ = os.Chdir(dir) + // clean up tmp dir + defer func() { + _ = os.Chdir(oldCWD) + }() + bodyString := ` + + + + + + + + + + + + ` + body := []byte(bodyString) + doFailOnSeverityLevel := "error" + err, failStep := logAndPersistAndEvaluateATCResults(&mock.FilesMock{}, body, "ATCResults.xml", false, doFailOnSeverityLevel) + //fail false + assert.Equal(t, false, failStep) + //no error here + assert.Equal(t, nil, err) }) t.Run("succes case: test parsing empty XML result", func(t *testing.T) { dir := t.TempDir() @@ -420,14 +490,16 @@ func TestParseATCResult(t *testing.T) { ` body := []byte(bodyString) - err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.xml", false, "") + err, failStep := logAndPersistAndEvaluateATCResults(&mock.FilesMock{}, body, "ATCResults.xml", false, "") + assert.Equal(t, false, failStep) assert.Equal(t, nil, err) }) t.Run("failure case: parsing empty xml", func(t *testing.T) { var bodyString string body := []byte(bodyString) - err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.xml", false, "") + err, failStep := logAndPersistAndEvaluateATCResults(&mock.FilesMock{}, body, "ATCResults.xml", false, "") + assert.Equal(t, false, failStep) assert.EqualError(t, err, "Parsing ATC result failed: Body is empty, can't parse empty body") }) t.Run("failure case: html response", func(t *testing.T) { @@ -440,7 +512,8 @@ func TestParseATCResult(t *testing.T) { }() bodyString := `HTMLTestResponse</title</head></html>` body := []byte(bodyString) - err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.xml", false, "") + err, failStep := logAndPersistAndEvaluateATCResults(&mock.FilesMock{}, body, "ATCResults.xml", false, "") + assert.Equal(t, false, failStep) assert.EqualError(t, err, "The Software Component could not be checked. Please make sure the respective Software Component has been cloned successfully on the system") }) } diff --git a/cmd/checkmarxExecuteScan.go b/cmd/checkmarxExecuteScan.go index 298e2d786c..a04ee23582 100644 --- a/cmd/checkmarxExecuteScan.go +++ b/cmd/checkmarxExecuteScan.go @@ -133,7 +133,7 @@ func runScan(ctx context.Context, config checkmarxExecuteScanOptions, sys checkm if err != nil { return errors.Wrap(err, "error when trying to load project") } - if project.Name == projectName { + if strings.EqualFold(project.Name, projectName) { // case insensitive string comparison err = presetExistingProject(config, sys, projectName, project) if err != nil { return err @@ -176,7 +176,7 @@ func loadTeamIDByTeamName(config checkmarxExecuteScanOptions, sys checkmarx.Syst func createNewProject(config checkmarxExecuteScanOptions, sys checkmarx.System, projectName string, teamID string) (checkmarx.Project, error) { log.Entry().Infof("Project %v does not exist, starting to create it...", projectName) presetID, _ := strconv.Atoi(config.Preset) - project, err := createAndConfigureNewProject(sys, projectName, teamID, presetID, config.Preset, config.SourceEncoding) + project, err := createAndConfigureNewProject(sys, projectName, teamID, presetID, config.Preset, config.EngineConfigurationID) if err != nil { return checkmarx.Project{}, errors.Wrapf(err, "failed to create and configure new project %v", projectName) } @@ -187,7 +187,7 @@ func presetExistingProject(config checkmarxExecuteScanOptions, sys checkmarx.Sys log.Entry().Infof("Project %v exists...", projectName) if len(config.Preset) > 0 { presetID, _ := strconv.Atoi(config.Preset) - err := setPresetForProject(sys, project.ID, presetID, projectName, config.Preset, config.SourceEncoding) + err := setPresetForProject(sys, project.ID, presetID, projectName, config.Preset, config.EngineConfigurationID) if err != nil { return errors.Wrapf(err, "failed to set preset %v for project %v", config.Preset, projectName) } @@ -212,6 +212,9 @@ func loadTeam(sys checkmarx.System, teamName string) (checkmarx.Team, error) { func loadExistingProject(sys checkmarx.System, initialProjectName, pullRequestName, teamID string) (checkmarx.Project, string, error) { var project checkmarx.Project projectName := initialProjectName + if len(initialProjectName) == 0 { + return project, projectName, errors.New("You need to provide the Checkmarx project name, projectName parameter is mandatory") + } if len(pullRequestName) > 0 { projectName = fmt.Sprintf("%v_%v", initialProjectName, pullRequestName) projects, err := sys.GetProjectsByNameAndTeam(projectName, teamID) diff --git a/cmd/checkmarxExecuteScan_generated.go b/cmd/checkmarxExecuteScan_generated.go index d57fd38941..a92c56e35c 100644 --- a/cmd/checkmarxExecuteScan_generated.go +++ b/cmd/checkmarxExecuteScan_generated.go @@ -39,7 +39,7 @@ type checkmarxExecuteScanOptions struct { PullRequestName string `json:"pullRequestName,omitempty"` Repository string `json:"repository,omitempty"` ServerURL string `json:"serverUrl,omitempty"` - SourceEncoding string `json:"sourceEncoding,omitempty"` + EngineConfigurationID string `json:"engineConfigurationID,omitempty"` TeamID string `json:"teamId,omitempty"` TeamName string `json:"teamName,omitempty"` Username string `json:"username,omitempty"` @@ -334,7 +334,7 @@ thresholds instead of ` + "`" + `percentage` + "`" + ` whereas we strongly recom func addCheckmarxExecuteScanFlags(cmd *cobra.Command, stepConfig *checkmarxExecuteScanOptions) { cmd.Flags().StringSliceVar(&stepConfig.Assignees, "assignees", []string{``}, "Defines the assignees for the Github Issue created/updated with the results of the scan as a list of login names.") - cmd.Flags().BoolVar(&stepConfig.AvoidDuplicateProjectScans, "avoidDuplicateProjectScans", true, "Whether duplicate scans of the same project state shall be avoided or not") + cmd.Flags().BoolVar(&stepConfig.AvoidDuplicateProjectScans, "avoidDuplicateProjectScans", true, "Tell Checkmarx to skip the scan if no code change is detected") cmd.Flags().StringVar(&stepConfig.FilterPattern, "filterPattern", `!**/node_modules/**, !**/.xmake/**, !**/*_test.go, !**/vendor/**/*.go, **/*.html, **/*.xml, **/*.go, **/*.py, **/*.js, **/*.scala, **/*.ts`, "The filter pattern used to zip the files relevant for scanning, patterns can be negated by setting an exclamation mark in front i.e. `!test/*.js` would avoid adding any javascript files located in the test directory") cmd.Flags().StringVar(&stepConfig.FullScanCycle, "fullScanCycle", `5`, "Indicates how often a full scan should happen between the incremental scans when activated") cmd.Flags().BoolVar(&stepConfig.FullScansScheduled, "fullScansScheduled", true, "Whether full scans are to be scheduled or not. Should be used in relation with `incremental` and `fullScanCycle`") @@ -350,7 +350,7 @@ func addCheckmarxExecuteScanFlags(cmd *cobra.Command, stepConfig *checkmarxExecu cmd.Flags().StringVar(&stepConfig.PullRequestName, "pullRequestName", os.Getenv("PIPER_pullRequestName"), "Used to supply the name for the newly created PR project branch when being used in pull request scenarios") cmd.Flags().StringVar(&stepConfig.Repository, "repository", os.Getenv("PIPER_repository"), "Set the GitHub repository.") cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", os.Getenv("PIPER_serverUrl"), "The URL pointing to the root of the Checkmarx server to be used") - cmd.Flags().StringVar(&stepConfig.SourceEncoding, "sourceEncoding", `1`, "The source encoding to be used, if not set explicitly the project's default will be used") + cmd.Flags().StringVar(&stepConfig.EngineConfigurationID, "engineConfigurationID", os.Getenv("PIPER_engineConfigurationID"), "The engine configuration ID to be used, if not set explicitly the project's default will be used") cmd.Flags().StringVar(&stepConfig.TeamID, "teamId", os.Getenv("PIPER_teamId"), "The group ID related to your team which can be obtained via the Pipeline Syntax plugin as described in the `Details` section") cmd.Flags().StringVar(&stepConfig.TeamName, "teamName", os.Getenv("PIPER_teamName"), "The full name of the team to assign newly created projects to which is preferred to teamId") cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "The username to authenticate") @@ -406,7 +406,7 @@ func checkmarxExecuteScanMetadata() config.StepData { Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Type: "bool", Mandatory: false, - Aliases: []config.Alias{}, + Aliases: []config.Alias{{Name: "notForceScan"}}, Default: true, }, { @@ -578,13 +578,13 @@ func checkmarxExecuteScanMetadata() config.StepData { Default: os.Getenv("PIPER_serverUrl"), }, { - Name: "sourceEncoding", + Name: "engineConfigurationID", ResourceRef: []config.ResourceReference{}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Type: "string", Mandatory: false, - Aliases: []config.Alias{}, - Default: `1`, + Aliases: []config.Alias{{Name: "sourceEncoding"}}, + Default: os.Getenv("PIPER_engineConfigurationID"), }, { Name: "teamId", diff --git a/cmd/checkmarxExecuteScan_test.go b/cmd/checkmarxExecuteScan_test.go index e8d95a3349..127dd0ebe4 100644 --- a/cmd/checkmarxExecuteScan_test.go +++ b/cmd/checkmarxExecuteScan_test.go @@ -95,7 +95,7 @@ func (sys *systemMock) GetProjectsByNameAndTeam(projectName, teamID string) ([]c } return []checkmarx.Project{{ID: 19, Name: projectName, TeamID: teamID, IsPublic: true}}, nil } - if projectName == "Test" { + if strings.EqualFold(projectName, "Test") { return []checkmarx.Project{{ID: 1, Name: projectName, TeamID: teamID, IsPublic: true}}, nil } sys.previousPName = projectName @@ -708,7 +708,7 @@ func TestRunScanWOtherCycle(t *testing.T) { ctx := context.Background() sys := &systemMock{response: []byte(`<?xml version="1.0" encoding="utf-8"?><CxXMLResults />`), createProject: true} - options := checkmarxExecuteScanOptions{VulnerabilityThresholdUnit: "percentage", FullScanCycle: "3", Incremental: true, FullScansScheduled: true, Preset: "123", TeamID: "16", VulnerabilityThresholdEnabled: true, GeneratePdfReport: true} + options := checkmarxExecuteScanOptions{ProjectName: "test", VulnerabilityThresholdUnit: "percentage", FullScanCycle: "3", Incremental: true, FullScansScheduled: true, Preset: "123", TeamID: "16", VulnerabilityThresholdEnabled: true, GeneratePdfReport: true} workspace := t.TempDir() err := ioutil.WriteFile(filepath.Join(workspace, "abcd.go"), []byte("abcd.go"), 0o700) assert.NoError(t, err) @@ -731,7 +731,7 @@ func TestRunScanErrorInZip(t *testing.T) { ctx := context.Background() sys := &systemMock{response: []byte(`<?xml version="1.0" encoding="utf-8"?><CxXMLResults />`), createProject: true} - options := checkmarxExecuteScanOptions{VulnerabilityThresholdUnit: "percentage", FullScanCycle: "3", Incremental: true, FullScansScheduled: true, Preset: "123", TeamID: "16", VulnerabilityThresholdEnabled: true, GeneratePdfReport: true} + options := checkmarxExecuteScanOptions{ProjectName: "test", VulnerabilityThresholdUnit: "percentage", FullScanCycle: "3", Incremental: true, FullScansScheduled: true, Preset: "123", TeamID: "16", VulnerabilityThresholdEnabled: true, GeneratePdfReport: true} workspace := t.TempDir() influx := checkmarxExecuteScanInflux{} @@ -833,7 +833,7 @@ func TestRunScanHighViolationPercentage(t *testing.T) { </Result> </Query> </CxXMLResults>`)} - options := checkmarxExecuteScanOptions{VulnerabilityThresholdUnit: "percentage", VulnerabilityThresholdResult: "FAILURE", VulnerabilityThresholdHigh: 100, FullScanCycle: "10", FullScansScheduled: true, Preset: "10048", TeamID: "16", VulnerabilityThresholdEnabled: true, GeneratePdfReport: true} + options := checkmarxExecuteScanOptions{ProjectName: "test", VulnerabilityThresholdUnit: "percentage", VulnerabilityThresholdResult: "FAILURE", VulnerabilityThresholdHigh: 100, FullScanCycle: "10", FullScansScheduled: true, Preset: "10048", TeamID: "16", VulnerabilityThresholdEnabled: true, GeneratePdfReport: true} workspace := t.TempDir() err := ioutil.WriteFile(filepath.Join(workspace, "abcd.go"), []byte("abcd.go"), 0o700) assert.NoError(t, err) @@ -872,7 +872,7 @@ func TestRunScanHighViolationAbsolute(t *testing.T) { </Result> </Query> </CxXMLResults>`)} - options := checkmarxExecuteScanOptions{VulnerabilityThresholdUnit: "absolute", VulnerabilityThresholdResult: "FAILURE", VulnerabilityThresholdLow: 1, FullScanCycle: "10", FullScansScheduled: true, Preset: "10048", TeamID: "16", VulnerabilityThresholdEnabled: true, GeneratePdfReport: true} + options := checkmarxExecuteScanOptions{ProjectName: "test", VulnerabilityThresholdUnit: "absolute", VulnerabilityThresholdResult: "FAILURE", VulnerabilityThresholdLow: 1, FullScanCycle: "10", FullScansScheduled: true, Preset: "10048", TeamID: "16", VulnerabilityThresholdEnabled: true, GeneratePdfReport: true} workspace := t.TempDir() err := ioutil.WriteFile(filepath.Join(workspace, "abcd.go"), []byte("abcd.go"), 0o700) assert.NoError(t, err) diff --git a/cmd/cloudFoundryDeploy_generated.go b/cmd/cloudFoundryDeploy_generated.go index da9f3e29e4..d1c8db3ac3 100644 --- a/cmd/cloudFoundryDeploy_generated.go +++ b/cmd/cloudFoundryDeploy_generated.go @@ -208,7 +208,7 @@ func addCloudFoundryDeployFlags(cmd *cobra.Command, stepConfig *cloudFoundryDepl cmd.Flags().StringVar(&stepConfig.DeployDockerImage, "deployDockerImage", os.Getenv("PIPER_deployDockerImage"), "Docker image deployments are supported (via manifest file in general)[https://docs.cloudfoundry.org/devguide/deploy-apps/manifest-attributes.html#docker]. If no manifest is used, this parameter defines the image to be deployed. The specified name of the image is passed to the `--docker-image` parameter of the cf CLI and must adhere it's naming pattern (e.g. REPO/IMAGE:TAG). See (cf CLI documentation)[https://docs.cloudfoundry.org/devguide/deploy-apps/push-docker.html] for details. Note: The used Docker registry must be visible for the targeted Cloud Foundry instance.") cmd.Flags().StringVar(&stepConfig.DeployTool, "deployTool", os.Getenv("PIPER_deployTool"), "Defines the tool which should be used for deployment.") cmd.Flags().StringVar(&stepConfig.BuildTool, "buildTool", os.Getenv("PIPER_buildTool"), "Defines the tool which is used for building the artifact. If provided, `deployTool` is automatically derived from it. For MTA projects, `deployTool` defaults to `mtaDeployPlugin`. For other projects `cf_native` will be used.") - cmd.Flags().StringVar(&stepConfig.DeployType, "deployType", `standard`, "Defines the type of deployment, either `standard` deployment which results in a system downtime or a zero-downtime `blue-green` deployment.If 'cf_native' as deployType and 'blue-green' as deployTool is used in combination, your manifest.yaml may only contain one application. If this application has the option 'no-route' active the deployType will be changed to 'standard'.") + cmd.Flags().StringVar(&stepConfig.DeployType, "deployType", `standard`, "Defines the type of deployment, either `standard` deployment which results in a system downtime or a zero-downtime `blue-green` deployment. If 'cf_native' as deployTool and 'blue-green' as deployType is used in combination, your manifest.yaml may only contain one application. If this application has the option 'no-route' active the deployType will be changed to 'standard'.") cmd.Flags().StringVar(&stepConfig.DockerPassword, "dockerPassword", os.Getenv("PIPER_dockerPassword"), "If the specified image in `deployDockerImage` is contained in a Docker registry, which requires authorization, this defines the password to be used.") cmd.Flags().StringVar(&stepConfig.DockerUsername, "dockerUsername", os.Getenv("PIPER_dockerUsername"), "If the specified image in `deployDockerImage` is contained in a Docker registry, which requires authorization, this defines the username to be used.") cmd.Flags().BoolVar(&stepConfig.KeepOldInstance, "keepOldInstance", false, "In case of a `blue-green` deployment the old instance will be deleted by default. If this option is set to true the old instance will remain stopped in the Cloud Foundry space.") diff --git a/cmd/cnbBuild.go b/cmd/cnbBuild.go index a65948e3ec..74bb30301b 100644 --- a/cmd/cnbBuild.go +++ b/cmd/cnbBuild.go @@ -7,7 +7,6 @@ import ( "os" "path" "path/filepath" - "strings" "github.com/SAP/jenkins-library/pkg/buildsettings" "github.com/SAP/jenkins-library/pkg/certutils" @@ -21,6 +20,7 @@ import ( piperhttp "github.com/SAP/jenkins-library/pkg/http" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperutils" + "github.com/SAP/jenkins-library/pkg/syft" "github.com/SAP/jenkins-library/pkg/telemetry" "github.com/imdario/mergo" @@ -211,28 +211,29 @@ func extractZip(source, target string) error { return nil } -func prepareDockerConfig(source string, utils cnbutils.BuildUtils) (string, error) { - if filepath.Base(source) != "config.json" { - log.Entry().Debugf("Renaming docker config file from '%s' to 'config.json'", filepath.Base(source)) +func renameDockerConfig(config *cnbBuildOptions, utils cnbutils.BuildUtils) error { + if filepath.Base(config.DockerConfigJSON) != "config.json" { + log.Entry().Debugf("Renaming docker config file from '%s' to 'config.json'", filepath.Base(config.DockerConfigJSON)) - newPath := filepath.Join(filepath.Dir(source), "config.json") + newPath := filepath.Join(filepath.Dir(config.DockerConfigJSON), "config.json") alreadyExists, err := utils.FileExists(newPath) if err != nil { - return "", err + return err } + if alreadyExists { - return newPath, nil + return nil } - err = utils.FileRename(source, newPath) + err = utils.FileRename(config.DockerConfigJSON, newPath) if err != nil { - return "", err + return err } - return newPath, nil + config.DockerConfigJSON = newPath } - return source, nil + return nil } func linkTargetFolder(utils cnbutils.BuildUtils, source, target string) error { @@ -380,10 +381,19 @@ func callCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, } commonPipelineEnvironment.custom.buildSettingsInfo = buildSettingsInfo + if len(config.DockerConfigJSON) > 0 { + err = renameDockerConfig(config, utils) + if err != nil { + log.SetErrorCategory(log.ErrorConfiguration) + return errors.Wrapf(err, "failed to rename DockerConfigJSON file '%v'", config.DockerConfigJSON) + } + } + mergedConfigs, err := processConfigs(*config, config.MultipleImages) if err != nil { return errors.Wrap(err, "failed to process config") } + for _, c := range mergedConfigs { err = runCnbBuild(&c, cnbTelemetry, utils, commonPipelineEnvironment, httpClient) if err != nil { @@ -391,6 +401,14 @@ func callCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, } } + if config.CreateBOM { + err = syft.GenerateSBOM(config.SyftDownloadURL, filepath.Dir(config.DockerConfigJSON), utils, utils, httpClient, commonPipelineEnvironment.container.registryURL, commonPipelineEnvironment.container.imageNameTags) + if err != nil { + log.SetErrorCategory(log.ErrorCompliance) + return errors.Wrap(err, "failed to create BOM file") + } + } + telemetryData.Custom1Label = "cnbBuildStepData" customData, err := json.Marshal(cnbTelemetry) if err != nil { @@ -502,15 +520,6 @@ func runCnbBuild(config *cnbBuildOptions, cnbTelemetry *cnbBuildTelemetry, utils return errors.Wrap(err, "failed process bindings") } - dockerConfigFile := "" - if len(config.DockerConfigJSON) > 0 { - dockerConfigFile, err = prepareDockerConfig(config.DockerConfigJSON, utils) - if err != nil { - log.SetErrorCategory(log.ErrorConfiguration) - return errors.Wrapf(err, "failed to rename DockerConfigJSON file '%v'", config.DockerConfigJSON) - } - } - pathType, source, err := config.resolvePath(utils) if err != nil { log.SetErrorCategory(log.ErrorBuild) @@ -553,7 +562,7 @@ func runCnbBuild(config *cnbBuildOptions, cnbTelemetry *cnbBuildTelemetry, utils if config.Buildpacks != nil && len(config.Buildpacks) > 0 { log.Entry().Infof("Setting custom buildpacks: '%v'", config.Buildpacks) - buildpacksPath, orderPath, err = setCustomBuildpacks(config.Buildpacks, dockerConfigFile, utils) + buildpacksPath, orderPath, err = setCustomBuildpacks(config.Buildpacks, config.DockerConfigJSON, utils) defer func() { _ = utils.RemoveAll(buildpacksPath) }() defer func() { _ = utils.RemoveAll(orderPath) }() if err != nil { @@ -562,7 +571,7 @@ func runCnbBuild(config *cnbBuildOptions, cnbTelemetry *cnbBuildTelemetry, utils } } - cnbRegistryAuth, err := cnbutils.GenerateCnbAuth(dockerConfigFile, utils) + cnbRegistryAuth, err := cnbutils.GenerateCnbAuth(config.DockerConfigJSON, utils) if err != nil { log.SetErrorCategory(log.ErrorConfiguration) return errors.Wrap(err, "failed to generate CNB_REGISTRY_AUTH") @@ -602,6 +611,10 @@ func runCnbBuild(config *cnbBuildOptions, cnbTelemetry *cnbBuildTelemetry, utils creatorArgs = append(creatorArgs, "-run-image", config.RunImage) } + if config.DefaultProcess != "" { + creatorArgs = append(creatorArgs, "-process-type", config.DefaultProcess) + } + containerImage := path.Join(targetImage.ContainerRegistry.Host, targetImage.ContainerImageName) for _, tag := range config.AdditionalTags { target := fmt.Sprintf("%s:%s", containerImage, tag) @@ -625,16 +638,6 @@ func runCnbBuild(config *cnbBuildOptions, cnbTelemetry *cnbBuildTelemetry, utils commonPipelineEnvironment.container.imageDigest = digest commonPipelineEnvironment.container.imageDigests = append(commonPipelineEnvironment.container.imageDigests, digest) - if config.CreateBOM { - bomFilename := fmt.Sprintf("bom-%s-%s.xml", targetImage.ContainerImageName, strings.TrimLeft(digest, "sha256:")) - imageName := fmt.Sprintf("%s:%s", containerImage, targetImage.ContainerImageTag) - err = cnbutils.MergeSBOMFiles("/layers/sbom/launch/**/sbom.syft.json", bomFilename, imageName, dockerConfigFile, utils) - if err != nil { - log.SetErrorCategory(log.ErrorBuild) - return errors.Wrap(err, "failed to create SBoM file") - } - } - if len(config.PreserveFiles) > 0 { if pathType != pathEnumArchive { err = cnbutils.CopyProject(target, source, ignore.CompileIgnoreLines(config.PreserveFiles...), nil, utils) diff --git a/cmd/cnbBuild_generated.go b/cmd/cnbBuild_generated.go index 348a07c87f..300c43d733 100644 --- a/cmd/cnbBuild_generated.go +++ b/cmd/cnbBuild_generated.go @@ -38,7 +38,9 @@ type cnbBuildOptions struct { PreserveFiles []string `json:"preserveFiles,omitempty"` BuildSettingsInfo string `json:"buildSettingsInfo,omitempty"` CreateBOM bool `json:"createBOM,omitempty"` + SyftDownloadURL string `json:"syftDownloadUrl,omitempty"` RunImage string `json:"runImage,omitempty"` + DefaultProcess string `json:"defaultProcess,omitempty"` } type cnbBuildCommonPipelineEnvironment struct { @@ -232,8 +234,10 @@ func addCnbBuildFlags(cmd *cobra.Command, stepConfig *cnbBuildOptions) { cmd.Flags().StringSliceVar(&stepConfig.PreserveFiles, "preserveFiles", []string{}, "List of globs, for keeping build results in the Jenkins workspace.\n\n*Note*: globs will be calculated relative to the [path](#path) property.\n") cmd.Flags().StringVar(&stepConfig.BuildSettingsInfo, "buildSettingsInfo", os.Getenv("PIPER_buildSettingsInfo"), "Build settings info is typically filled by the step automatically to create information about the build settings that were used during the mta build. This information is typically used for compliance related processes.") - cmd.Flags().BoolVar(&stepConfig.CreateBOM, "createBOM", false, "**EXPERIMENTAL:** Creates the bill of materials (BOM) using CycloneDX plugin.") + cmd.Flags().BoolVar(&stepConfig.CreateBOM, "createBOM", false, "Creates the bill of materials (BOM) using Syft and stores it in a file in CycloneDX 1.4 format.") + cmd.Flags().StringVar(&stepConfig.SyftDownloadURL, "syftDownloadUrl", `https://github.com/anchore/syft/releases/download/v0.62.3/syft_0.62.3_linux_amd64.tar.gz`, "Specifies the download url of the Syft Linux amd64 tar binary file. This can be found at https://github.com/anchore/syft/releases/.") cmd.Flags().StringVar(&stepConfig.RunImage, "runImage", os.Getenv("PIPER_runImage"), "Base image from which application images are built. Will be defaulted to the image provided by the builder.") + cmd.Flags().StringVar(&stepConfig.DefaultProcess, "defaultProcess", os.Getenv("PIPER_defaultProcess"), "Process that should be started by default. See https://buildpacks.io/docs/app-developer-guide/run-an-app/") cmd.MarkFlagRequired("containerImageTag") cmd.MarkFlagRequired("containerRegistryUrl") @@ -435,6 +439,15 @@ func cnbBuildMetadata() config.StepData { Aliases: []config.Alias{}, Default: false, }, + { + Name: "syftDownloadUrl", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STEPS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: `https://github.com/anchore/syft/releases/download/v0.62.3/syft_0.62.3_linux_amd64.tar.gz`, + }, { Name: "runImage", ResourceRef: []config.ResourceReference{}, @@ -444,6 +457,15 @@ func cnbBuildMetadata() config.StepData { Aliases: []config.Alias{}, Default: os.Getenv("PIPER_runImage"), }, + { + Name: "defaultProcess", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"GENERAL", "STEPS", "STAGES", "PARAMETERS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_defaultProcess"), + }, }, }, Containers: []config.Container{ diff --git a/cmd/cnbBuild_test.go b/cmd/cnbBuild_test.go index 08609a7c54..cff1195784 100644 --- a/cmd/cnbBuild_test.go +++ b/cmd/cnbBuild_test.go @@ -79,6 +79,7 @@ func TestRunCnbBuild(t *testing.T) { ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), DockerConfigJSON: "/path/to/config.json", RunImage: "my-run-image", + DefaultProcess: "my-process", } projectToml := `[project] @@ -99,6 +100,8 @@ func TestRunCnbBuild(t *testing.T) { assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, config.ContainerImageName, config.ContainerImageTag)) assert.Contains(t, runner.Calls[0].Params, "-run-image") assert.Contains(t, runner.Calls[0].Params, "my-run-image") + assert.Contains(t, runner.Calls[0].Params, "-process-type") + assert.Contains(t, runner.Calls[0].Params, "my-process") assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL) assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag) assert.Equal(t, `{"cnbBuild":[{"dockerImage":"paketobuildpacks/builder:base"}]}`, commonPipelineEnvironment.custom.buildSettingsInfo) diff --git a/cmd/detectExecuteScan.go b/cmd/detectExecuteScan.go index f644d747ab..2a008b4ab9 100644 --- a/cmd/detectExecuteScan.go +++ b/cmd/detectExecuteScan.go @@ -499,7 +499,7 @@ func isMajorVulnerability(v bd.Vulnerability) bool { func postScanChecksAndReporting(ctx context.Context, config detectExecuteScanOptions, influx *detectExecuteScanInflux, utils detectUtils, sys *blackduckSystem) error { errorsOccured := []string{} - vulns, components, err := getVulnsAndComponents(config, influx, sys) + vulns, err := getVulnerabilitiesWithComponents(config, influx, sys) if err != nil { return errors.Wrap(err, "failed to fetch vulnerabilities") } @@ -520,7 +520,14 @@ func postScanChecksAndReporting(ctx context.Context, config detectExecuteScanOpt } } - sarif := bd.CreateSarifResultFile(vulns, components) + projectVersion, err := sys.Client.GetProjectVersion(config.ProjectName, config.Version) + + var projectLink string + if projectVersion != nil { + projectLink = projectVersion.Href + } + + sarif := bd.CreateSarifResultFile(vulns, config.ProjectName, config.Version, projectLink) paths, err := bd.WriteSarifFile(sarif, utils) if err != nil { errorsOccured = append(errorsOccured, fmt.Sprint(err)) @@ -566,22 +573,22 @@ func postScanChecksAndReporting(ctx context.Context, config detectExecuteScanOpt return nil } -func getVulnsAndComponents(config detectExecuteScanOptions, influx *detectExecuteScanInflux, sys *blackduckSystem) (*bd.Vulnerabilities, *bd.Components, error) { +func getVulnerabilitiesWithComponents(config detectExecuteScanOptions, influx *detectExecuteScanInflux, sys *blackduckSystem) (*bd.Vulnerabilities, error) { detectVersionName := getVersionName(config) components, err := sys.Client.GetComponents(config.ProjectName, detectVersionName) if err != nil { - return nil, nil, err + return nil, err } // create component lookup map to interconnect vulnerability and component keyFormat := "%v/%v" componentLookup := map[string]*bd.Component{} - for _, comp := range components.Items { - componentLookup[fmt.Sprintf(keyFormat, comp.Name, comp.Version)] = &comp + for i := 0; i < len(components.Items); i++ { + componentLookup[fmt.Sprintf(keyFormat, components.Items[i].Name, components.Items[i].Version)] = &components.Items[i] } vulns, err := sys.Client.GetVulnerabilities(config.ProjectName, detectVersionName) if err != nil { - return nil, components, err + return nil, err } majorVulns := 0 @@ -605,7 +612,7 @@ func getVulnsAndComponents(config detectExecuteScanOptions, influx *detectExecut influx.detect_data.fields.minor_vulnerabilities = activeVulns - majorVulns influx.detect_data.fields.components = components.TotalCount - return vulns, components, nil + return vulns, nil } func getPolicyStatus(config detectExecuteScanOptions, influx *detectExecuteScanInflux, sys *blackduckSystem) (*bd.PolicyStatus, error) { diff --git a/cmd/detectExecuteScan_generated.go b/cmd/detectExecuteScan_generated.go index c5cd4114a8..83e214e9a7 100644 --- a/cmd/detectExecuteScan_generated.go +++ b/cmd/detectExecuteScan_generated.go @@ -117,12 +117,15 @@ func (p *detectExecuteScanReports) persist(stepConfig detectExecuteScanOptions, log.Entry().Info("Uploading reports to Google Cloud Storage...") content := []gcs.ReportOutputParam{ {FilePattern: "**/*BlackDuck_RiskReport.pdf", ParamRef: "", StepResultType: "blackduck-ip"}, - {FilePattern: "blackduck-ip.json", ParamRef: "", StepResultType: "blackduck-ip"}, + {FilePattern: "**/blackduck-ip.json", ParamRef: "", StepResultType: "blackduck-ip"}, {FilePattern: "**/toolrun_detectExecute_*.json", ParamRef: "", StepResultType: "blackduck-ip"}, - {FilePattern: "**/piper_detect_vulnerability_report.html", ParamRef: "", StepResultType: "blackduck-ip"}, - {FilePattern: "**/detectExecuteScan_oss_*.json", ParamRef: "", StepResultType: "blackduck-ip"}, {FilePattern: "**/piper_detect_policy_violation_report.html", ParamRef: "", StepResultType: "blackduck-ip"}, - {FilePattern: "**/detectExecuteScan_policy_*.json", ParamRef: "", StepResultType: "blackduck-ip"}, + {FilePattern: "**/*BlackDuck_RiskReport.pdf", ParamRef: "", StepResultType: "blackduck-security"}, + {FilePattern: "**/detectExecuteScan_policy_*.json", ParamRef: "", StepResultType: "blackduck-security"}, + {FilePattern: "**/piper_detect_vulnerability_report.html", ParamRef: "", StepResultType: "blackduck-security"}, + {FilePattern: "**/toolrun_detectExecute_*.json", ParamRef: "", StepResultType: "blackduck-security"}, + {FilePattern: "**/piper_detect_vulnerability.sarif", ParamRef: "", StepResultType: "blackduck-security"}, + {FilePattern: "**/piper_hub_detect_sbom.xml", ParamRef: "", StepResultType: "blackduck-security"}, } envVars := []gcs.EnvVar{ {Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: gcpJsonKeyFilePath, Modified: false}, @@ -164,7 +167,7 @@ func DetectExecuteScanCommand() *cobra.Command { var createDetectExecuteScanCmd = &cobra.Command{ Use: STEP_NAME, Short: "Executes Synopsys Detect scan", - Long: `This step executes [Synopsys Detect](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/62423113/Synopsys+Detect) scans. + Long: `This step executes [Synopsys Detect](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=introduction.html&_LANG=enus) 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 { @@ -256,7 +259,7 @@ func addDetectExecuteScanFlags(cmd *cobra.Command, stepConfig *detectExecuteScan cmd.Flags().StringSliceVar(&stepConfig.ScanPaths, "scanPaths", []string{`.`}, "List of paths which should be scanned by the Synopsis Detect (formerly BlackDuck) scan.") cmd.Flags().StringVar(&stepConfig.DependencyPath, "dependencyPath", `.`, "Absolute Path of the dependency management file of the project. This path represents the folder which contains the pom file, package.json etc. If the project contains multiple pom files, provide the path to the parent pom file or the base folder of the project") cmd.Flags().BoolVar(&stepConfig.Unmap, "unmap", false, "Unmap flag will unmap all previous code locations and keep only the current scan results in the specified project version. Set this parameter to true, when the project version needs to store only the latest scan results.") - cmd.Flags().StringSliceVar(&stepConfig.ScanProperties, "scanProperties", []string{`--blackduck.signature.scanner.memory=4096`, `--detect.timeout=6000`, `--blackduck.trust.cert=true`, `--logging.level.com.synopsys.integration=DEBUG`, `--detect.maven.excluded.scopes=test`}, "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`, `--detect.timeout=6000`, `--blackduck.trust.cert=true`, `--logging.level.com.synopsys.integration=DEBUG`, `--detect.maven.excluded.scopes=test`}, "Properties passed to the Synopsis Detect (formerly BlackDuck) scan. You can find details in the [Synopsis Detect documentation](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=properties%2Fall-properties.html&_LANG=enus)") 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.") @@ -267,12 +270,12 @@ func addDetectExecuteScanFlags(cmd *cobra.Command, stepConfig *detectExecuteScan cmd.Flags().StringVar(&stepConfig.GlobalSettingsFile, "globalSettingsFile", os.Getenv("PIPER_globalSettingsFile"), "Path or url to the mvn settings file that should be used as global settings file") cmd.Flags().StringVar(&stepConfig.M2Path, "m2Path", os.Getenv("PIPER_m2Path"), "Path to the location of the local repository that should be used.") cmd.Flags().BoolVar(&stepConfig.InstallArtifacts, "installArtifacts", false, "If enabled, it will install all artifacts to the local maven repository to make them available before running detect. This is required if any maven module has dependencies to other modules in the repository and they were not installed before.") - cmd.Flags().StringSliceVar(&stepConfig.IncludedPackageManagers, "includedPackageManagers", []string{}, "The package managers that need to be included for this scan. Providing the package manager names with this parameter will ensure that the build descriptor file of that package manager will be searched in the scan folder For the complete list of possible values for this parameter, please refer [Synopsys detect documentation](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/631407160/Configuring+Detect+General+Properties#Detector-types-included-(Advanced))") - cmd.Flags().StringSliceVar(&stepConfig.ExcludedPackageManagers, "excludedPackageManagers", []string{}, "The package managers that need to be excluded for this scan. Providing the package manager names with this parameter will ensure that the build descriptor file of that package manager will be ignored in the scan folder For the complete list of possible values for this parameter, please refer [Synopsys detect documentation](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/631407160/Configuring+Detect+General+Properties#%5BhardBreak%5DDetector-types-excluded-(Advanced))") + cmd.Flags().StringSliceVar(&stepConfig.IncludedPackageManagers, "includedPackageManagers", []string{}, "The package managers that need to be included for this scan. Providing the package manager names with this parameter will ensure that the build descriptor file of that package manager will be searched in the scan folder For the complete list of possible values for this parameter, please refer [Synopsys detect documentation](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=properties%2Fconfiguration%2Fdetector.html&_LANG=enus&anchor=detector-types-included-advanced)") + cmd.Flags().StringSliceVar(&stepConfig.ExcludedPackageManagers, "excludedPackageManagers", []string{}, "The package managers that need to be excluded for this scan. Providing the package manager names with this parameter will ensure that the build descriptor file of that package manager will be ignored in the scan folder For the complete list of possible values for this parameter, please refer [Synopsys detect documentation](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=properties%2Fconfiguration%2Fdetector.html&_LANG=enus&anchor=detector-types-excluded-advanced)") cmd.Flags().StringSliceVar(&stepConfig.MavenExcludedScopes, "mavenExcludedScopes", []string{}, "The maven scopes that need to be excluded from the scan. For example, setting the value 'test' will exclude all components which are defined with a test scope in maven") - cmd.Flags().StringSliceVar(&stepConfig.DetectTools, "detectTools", []string{}, "The type of BlackDuck scanners to include while running the BlackDuck scan. By default All scanners are included. For the complete list of possible values, Please refer [Synopsys detect documentation](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/631407160/Configuring+Detect+General+Properties#Detect-tools-included)") + cmd.Flags().StringSliceVar(&stepConfig.DetectTools, "detectTools", []string{}, "The type of BlackDuck scanners to include while running the BlackDuck scan. By default All scanners are included. For the complete list of possible values, Please refer [Synopsys detect documentation](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=properties%2Fconfiguration%2Fpaths.html&_LANG=enus&anchor=detect-tools-included)") cmd.Flags().BoolVar(&stepConfig.ScanOnChanges, "scanOnChanges", false, "This flag determines if the scan is submitted to the server. If set to true, then the scan request is submitted to the server only when changes are detected in the Open Source Bill of Materials If the flag is set to false, then the scan request is submitted to server regardless of any changes. For more details please refer to the [documentation](https://github.com/blackducksoftware/detect_rescan/blob/master/README.md)") - cmd.Flags().StringSliceVar(&stepConfig.CustomEnvironmentVariables, "customEnvironmentVariables", []string{}, "A list of environment variables which can be set to prepare the environment to run a BlackDuck scan. This includes a list of environment variables defined by Synopsys. The full list can be found [here](https://synopsys.atlassian.net/wiki/spaces/IA/pages/1562214619/Shell+Script+Reference+6.9.0) This list affects the detect script downloaded while running the scan. By default detect7.sh will be used. To continue using different versions of detect, please use DETECT_LATEST_RELEASE_VERSION and set it to a valid value defined [here](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=releasenotes.html&_LANG=enus) Additionally, please note, depending on the Project certain versions of detect will be required. For example: For Swift version 5.5 and lower, Detect 7.13.0 is the minimum required version. For Swift version 5.6 and higher, Detect 7.14.0 is required ") + cmd.Flags().StringSliceVar(&stepConfig.CustomEnvironmentVariables, "customEnvironmentVariables", []string{}, "A list of environment variables which can be set to prepare the environment to run a BlackDuck scan. This includes a list of environment variables defined by Synopsys. The full list can be found [here](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=configuring%2Fenvvars.html&_LANG=enus) This list affects the detect script downloaded while running the scan. By default detect7.sh will be used. To continue using different versions of detect, please use DETECT_LATEST_RELEASE_VERSION and set it to a valid value defined [here](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=releasenotes.html&_LANG=enus) Additionally, please note, depending on the Project certain versions of detect will be required. For example: For Swift version 5.5 and lower, Detect 7.13.0 is the minimum required version. For Swift version 5.6 and higher, Detect 7.14.0 is required ") cmd.Flags().IntVar(&stepConfig.MinScanInterval, "minScanInterval", 0, "This parameter controls the frequency (in number of hours) at which the signature scan is re-submitted for scan. When set to a value greater than 0, the signature scans are skipped until the specified number of hours has elapsed since the last signature scan.") cmd.Flags().StringVar(&stepConfig.GithubToken, "githubToken", os.Getenv("PIPER_githubToken"), "GitHub personal access token as per https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line") cmd.Flags().BoolVar(&stepConfig.CreateResultIssue, "createResultIssue", false, "Activate creation of a result issue in GitHub.") @@ -666,12 +669,15 @@ func detectExecuteScanMetadata() config.StepData { Type: "reports", Parameters: []map[string]interface{}{ {"filePattern": "**/*BlackDuck_RiskReport.pdf", "type": "blackduck-ip"}, - {"filePattern": "blackduck-ip.json", "type": "blackduck-ip"}, + {"filePattern": "**/blackduck-ip.json", "type": "blackduck-ip"}, {"filePattern": "**/toolrun_detectExecute_*.json", "type": "blackduck-ip"}, - {"filePattern": "**/piper_detect_vulnerability_report.html", "type": "blackduck-ip"}, - {"filePattern": "**/detectExecuteScan_oss_*.json", "type": "blackduck-ip"}, {"filePattern": "**/piper_detect_policy_violation_report.html", "type": "blackduck-ip"}, - {"filePattern": "**/detectExecuteScan_policy_*.json", "type": "blackduck-ip"}, + {"filePattern": "**/*BlackDuck_RiskReport.pdf", "type": "blackduck-security"}, + {"filePattern": "**/detectExecuteScan_policy_*.json", "type": "blackduck-security"}, + {"filePattern": "**/piper_detect_vulnerability_report.html", "type": "blackduck-security"}, + {"filePattern": "**/toolrun_detectExecute_*.json", "type": "blackduck-security"}, + {"filePattern": "**/piper_detect_vulnerability.sarif", "type": "blackduck-security"}, + {"filePattern": "**/piper_hub_detect_sbom.xml", "type": "blackduck-security"}, }, }, }, diff --git a/cmd/detectExecuteScan_test.go b/cmd/detectExecuteScan_test.go index 95b48000f7..9d9b2c84a1 100644 --- a/cmd/detectExecuteScan_test.go +++ b/cmd/detectExecuteScan_test.go @@ -782,16 +782,14 @@ func TestGetActivePolicyViolations(t *testing.T) { }) } -func TestGetVulnsAndComponents(t *testing.T) { +func TestGetVulnerabilitiesWithComponents(t *testing.T) { t.Parallel() t.Run("Case true", func(t *testing.T) { config := detectExecuteScanOptions{Token: "token", ServerURL: "https://my.blackduck.system", ProjectName: "SHC-PiperTest", Version: "", CustomScanVersion: "1.0"} sys := newBlackduckMockSystem(config) - vulns, components, err := getVulnsAndComponents(config, &detectExecuteScanInflux{}, &sys) + vulns, err := getVulnerabilitiesWithComponents(config, &detectExecuteScanInflux{}, &sys) assert.NoError(t, err) - assert.Equal(t, 3, len(vulns.Items)) - assert.Equal(t, 3, len(components.Items)) vulnerabilitySpring := bd.Vulnerability{} vulnerabilityLog4j1 := bd.Vulnerability{} vulnerabilityLog4j2 := bd.Vulnerability{} @@ -808,12 +806,12 @@ func TestGetVulnsAndComponents(t *testing.T) { } vulnerableComponentSpring := &bd.Component{} vulnerableComponentLog4j := &bd.Component{} - for _, c := range components.Items { - if c.Name == "Spring Framework" { - vulnerableComponentSpring = &c + for i := 0; i < len(vulns.Items); i++ { + if vulns.Items[i].Component != nil && vulns.Items[i].Component.Name == "Spring Framework" { + vulnerableComponentSpring = vulns.Items[i].Component } - if c.Name == "Apache Log4j" { - vulnerableComponentLog4j = &c + if vulns.Items[i].Component != nil && vulns.Items[i].Component.Name == "Apache Log4j" { + vulnerableComponentLog4j = vulns.Items[i].Component } } assert.Equal(t, vulnerableComponentSpring, vulnerabilitySpring.Component) diff --git a/cmd/golangBuild.go b/cmd/golangBuild.go index 75d561c0f3..d3760e0e38 100644 --- a/cmd/golangBuild.go +++ b/cmd/golangBuild.go @@ -35,8 +35,6 @@ const ( golangTestsumPackage = "gotest.tools/gotestsum@latest" golangCycloneDXPackage = "github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latest" sbomFilename = "bom-golang.xml" - golangciLintURL = "https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh" - golangciLintVersion = "latest" ) type golangBuildUtils interface { @@ -49,6 +47,7 @@ type golangBuildUtils interface { getDockerImageValue(stepName string) (string, error) GetExitCode() int DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error + Untar(src string, dest string, stripComponentLevel int) error // Add more methods here, or embed additional interfaces, or remove/replace as required. // The golangBuildUtils interface should be descriptive of your runtime dependencies, @@ -78,6 +77,10 @@ func (g *golangBuildUtilsBundle) getDockerImageValue(stepName string) (string, e return GetDockerImageValue(stepName) } +func (g *golangBuildUtilsBundle) Untar(src string, dest string, stripComponentLevel int) error { + return piperutils.Untar(src, dest, stripComponentLevel) +} + func newGolangBuildUtils(config golangBuildOptions) golangBuildUtils { httpClientOptions := piperhttp.ClientOptions{} @@ -175,7 +178,7 @@ func runGolangBuild(config *golangBuildOptions, telemetryData *telemetry.CustomD goPath := os.Getenv("GOPATH") golangciLintDir := filepath.Join(goPath, "bin") - if err := retrieveGolangciLint(utils, golangciLintDir); err != nil { + if err := retrieveGolangciLint(utils, golangciLintDir, config.GolangciLintURL); err != nil { return err } @@ -433,19 +436,14 @@ func reportGolangTestCoverage(config *golangBuildOptions, utils golangBuildUtils return nil } -func retrieveGolangciLint(utils golangBuildUtils, golangciLintDir string) error { - installationScript := "./install.sh" - err := utils.DownloadFile(golangciLintURL, installationScript, nil, nil) +func retrieveGolangciLint(utils golangBuildUtils, golangciLintDir, golangciLintURL string) error { + archiveName := "golangci-lint.tar.gz" + err := utils.DownloadFile(golangciLintURL, archiveName, nil, nil) if err != nil { return fmt.Errorf("failed to download golangci-lint: %w", err) } - err = utils.Chmod(installationScript, 0777) - if err != nil { - return err - } - - err = utils.RunExecutable(installationScript, "-b", golangciLintDir, golangciLintVersion) + err = utils.Untar(archiveName, golangciLintDir, 1) if err != nil { return fmt.Errorf("failed to install golangci-lint: %w", err) } @@ -455,6 +453,7 @@ func retrieveGolangciLint(utils golangBuildUtils, golangciLintDir string) error func runGolangciLint(utils golangBuildUtils, golangciLintDir string, lintSettings map[string]string) error { binaryPath := filepath.Join(golangciLintDir, "golangci-lint") + var outputBuffer bytes.Buffer utils.Stdout(&outputBuffer) err := utils.RunExecutable(binaryPath, "run", "--out-format", lintSettings["reportStyle"]) diff --git a/cmd/golangBuild_generated.go b/cmd/golangBuild_generated.go index 17817dce03..474ad74968 100644 --- a/cmd/golangBuild_generated.go +++ b/cmd/golangBuild_generated.go @@ -46,6 +46,7 @@ type golangBuildOptions struct { PrivateModules string `json:"privateModules,omitempty"` PrivateModulesGitToken string `json:"privateModulesGitToken,omitempty"` ArtifactVersion string `json:"artifactVersion,omitempty"` + GolangciLintURL string `json:"golangciLintUrl,omitempty"` } type golangBuildCommonPipelineEnvironment struct { @@ -245,6 +246,7 @@ func addGolangBuildFlags(cmd *cobra.Command, stepConfig *golangBuildOptions) { cmd.Flags().StringVar(&stepConfig.PrivateModules, "privateModules", os.Getenv("PIPER_privateModules"), "Tells go which modules shall be considered to be private (by setting [GOPRIVATE](https://pkg.go.dev/cmd/go#hdr-Configuration_for_downloading_non_public_code)).") cmd.Flags().StringVar(&stepConfig.PrivateModulesGitToken, "privateModulesGitToken", os.Getenv("PIPER_privateModulesGitToken"), "GitHub personal access token as per https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line.") cmd.Flags().StringVar(&stepConfig.ArtifactVersion, "artifactVersion", os.Getenv("PIPER_artifactVersion"), "Version of the artifact to be built.") + cmd.Flags().StringVar(&stepConfig.GolangciLintURL, "golangciLintUrl", `https://github.com/golangci/golangci-lint/releases/download/v1.50.1/golangci-lint-1.50.1-linux-amd64.tar.gz`, "Specifies the download url of the Golangci-Lint Linux amd64 tar binary file. This can be found at https://github.com/golangci/golangci-lint/releases.") cmd.MarkFlagRequired("targetArchitectures") } @@ -531,6 +533,15 @@ func golangBuildMetadata() config.StepData { Aliases: []config.Alias{}, Default: os.Getenv("PIPER_artifactVersion"), }, + { + Name: "golangciLintUrl", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STEPS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: `https://github.com/golangci/golangci-lint/releases/download/v1.50.1/golangci-lint-1.50.1-linux-amd64.tar.gz`, + }, }, }, Containers: []config.Container{ diff --git a/cmd/golangBuild_test.go b/cmd/golangBuild_test.go index daff4bff71..45eac1593d 100644 --- a/cmd/golangBuild_test.go +++ b/cmd/golangBuild_test.go @@ -27,9 +27,11 @@ type golangBuildMockUtils struct { returnFileUploadStatus int // expected to be set upfront returnFileUploadError error // expected to be set upfront returnFileDownloadError error // expected to be set upfront + returnFileUntarError error // expected to be set upfront - clientOptions []piperhttp.ClientOptions // set by mock - fileUploads map[string]string // set by mock + clientOptions []piperhttp.ClientOptions // set by mock + fileUploads map[string]string // set by mock + untarFileNames []string } func (g *golangBuildMockUtils) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { @@ -74,6 +76,16 @@ func (g *golangBuildMockUtils) getDockerImageValue(stepName string) (string, err return "golang:latest", nil } +func (g *golangBuildMockUtils) Untar(src string, dest string, stripComponentLevel int) error { + if g.returnFileUntarError != nil { + return g.returnFileUntarError + } + for _, file := range g.untarFileNames { + g.AddFile(filepath.Join(dest, file), []byte("test content")) + } + return nil +} + func newGolangBuildTestsUtils() *golangBuildMockUtils { utils := golangBuildMockUtils{ ExecMockRunner: &mock.ExecMockRunner{}, @@ -290,15 +302,12 @@ go 1.17` err := runGolangBuild(&config, &telemetry, utils, &cpe) assert.NoError(t, err) - b, err := utils.FileRead("install.sh") + b, err := utils.FileRead("golangci-lint.tar.gz") assert.NoError(t, err) assert.Equal(t, []byte("content"), b) - assert.Equal(t, "./install.sh", utils.Calls[0].Exec) - assert.Equal(t, []string{"-b", golangciLintDir, golangciLintVersion}, utils.Calls[0].Params) - assert.Equal(t, binaryPath, utils.Calls[1].Exec) - assert.Equal(t, []string{"run", "--out-format", "checkstyle"}, utils.Calls[1].Params) - + assert.Equal(t, binaryPath, utils.Calls[0].Exec) + assert.Equal(t, []string{"run", "--out-format", "checkstyle"}, utils.Calls[0].Params) }) t.Run("failure - install pre-requisites for testing", func(t *testing.T) { @@ -476,20 +485,16 @@ go 1.17` }) t.Run("failure - RunLint: retrieveGolangciLint failed", func(t *testing.T) { - goPath := os.Getenv("GOPATH") - golangciLintDir := filepath.Join(goPath, "bin") - config := golangBuildOptions{ RunLint: true, } + utils := newGolangBuildTestsUtils() utils.AddFile("go.mod", []byte(modTestFile)) - utils.ShouldFailOnCommand = map[string]error{ - fmt.Sprintf("./install.sh -b %s %s", golangciLintDir, golangciLintVersion): fmt.Errorf("installation err"), - } + utils.returnFileDownloadError = fmt.Errorf("downloading error") telemetry := telemetry.CustomData{} err := runGolangBuild(&config, &telemetry, utils, &cpe) - assert.EqualError(t, err, "failed to install golangci-lint: installation err") + assert.EqualError(t, err, "failed to download golangci-lint: downloading error") }) t.Run("failure - RunLint: runGolangciLint failed", func(t *testing.T) { @@ -1023,6 +1028,7 @@ func TestRunGolangciLint(t *testing.T) { goPath := os.Getenv("GOPATH") golangciLintDir := filepath.Join(goPath, "bin") binaryPath := filepath.Join(golangciLintDir, "golangci-lint") + lintSettings := map[string]string{ "reportStyle": "checkstyle", "reportOutputPath": "golangci-lint-report.xml", @@ -1070,8 +1076,8 @@ func TestRunGolangciLint(t *testing.T) { }, } - for i, test := range tt { - i, test := i, test + for _, test := range tt { + test := test t.Run(test.name, func(t *testing.T) { t.Parallel() utils := newGolangBuildTestsUtils() @@ -1081,8 +1087,8 @@ func TestRunGolangciLint(t *testing.T) { err := runGolangciLint(utils, golangciLintDir, lintSettings) if test.expectedErr == nil { - assert.Equal(t, test.expectedCommand[0], utils.Calls[i].Exec) - assert.Equal(t, test.expectedCommand[1:], utils.Calls[i].Params) + assert.Equal(t, test.expectedCommand[0], utils.Calls[0].Exec) + assert.Equal(t, test.expectedCommand[1:], utils.Calls[0].Params) } else { assert.EqualError(t, err, test.expectedErr.Error()) } @@ -1097,48 +1103,48 @@ func TestRetrieveGolangciLint(t *testing.T) { golangciLintDir := filepath.Join(goPath, "bin") tt := []struct { - name string - shouldFailOnCommand map[string]error - downloadErr error - expectedCommand []string - expectedErr error + name string + downloadErr error + untarErr error + expectedErr error }{ { - name: "success", - shouldFailOnCommand: map[string]error{}, - downloadErr: nil, - expectedCommand: []string{"./install.sh", "-b", golangciLintDir, golangciLintVersion}, - expectedErr: nil, + name: "success", }, { - name: "failure - failed to download golangci-lint", - shouldFailOnCommand: map[string]error{}, - downloadErr: fmt.Errorf("download err"), - expectedCommand: []string{}, - expectedErr: fmt.Errorf("failed to download golangci-lint: download err"), + name: "failure - failed to download golangci-lint", + downloadErr: fmt.Errorf("download err"), + expectedErr: fmt.Errorf("failed to download golangci-lint: download err"), }, { - name: "failure - failed to install golangci-lint with sh error", - shouldFailOnCommand: map[string]error{fmt.Sprintf("./install.sh -b %s %s", golangciLintDir, golangciLintVersion): fmt.Errorf("installation err")}, - expectedCommand: []string{}, - expectedErr: fmt.Errorf("failed to install golangci-lint: installation err"), + name: "failure - failed to install golangci-lint", + untarErr: fmt.Errorf("retrieve archive err"), + expectedErr: fmt.Errorf("failed to install golangci-lint: retrieve archive err"), }, } - for i, test := range tt { - i, test := i, test + for _, test := range tt { + test := test t.Run(test.name, func(t *testing.T) { t.Parallel() utils := newGolangBuildTestsUtils() - utils.ShouldFailOnCommand = test.shouldFailOnCommand utils.returnFileDownloadError = test.downloadErr - err := retrieveGolangciLint(utils, golangciLintDir) + utils.returnFileUntarError = test.untarErr + utils.untarFileNames = []string{"golangci-lint"} + config := golangBuildOptions{ + GolangciLintURL: "https://github.com/golangci/golangci-lint/releases/download/v1.50.1/golangci-lint-1.50.0-darwin-amd64.tar.gz", + } + err := retrieveGolangciLint(utils, golangciLintDir, config.GolangciLintURL) - if test.expectedErr == nil { - assert.Equal(t, test.expectedCommand[0], utils.Calls[i].Exec) - assert.Equal(t, test.expectedCommand[1:], utils.Calls[i].Params) - } else { + if test.expectedErr != nil { assert.EqualError(t, err, test.expectedErr.Error()) + } else { + b, err := utils.ReadFile("golangci-lint.tar.gz") + assert.NoError(t, err) + assert.Equal(t, []byte("content"), b) + b, err = utils.ReadFile(filepath.Join(golangciLintDir, "golangci-lint")) + assert.NoError(t, err) + assert.Equal(t, []byte("test content"), b) } }) } diff --git a/cmd/gradleExecuteBuild.go b/cmd/gradleExecuteBuild.go index 13ee6bd4ec..3daf77bb01 100644 --- a/cmd/gradleExecuteBuild.go +++ b/cmd/gradleExecuteBuild.go @@ -4,6 +4,9 @@ import ( "bytes" "encoding/json" "fmt" + "io/fs" + "path/filepath" + "strings" "text/template" "github.com/SAP/jenkins-library/pkg/command" @@ -21,51 +24,55 @@ const ( var ( bomGradleTaskName = "cyclonedxBom" publishTaskName = "publish" - pathToModuleFile = "./build/publications/maven/module.json" + pathToModuleFile = filepath.Join("build", "publications", "maven", "module.json") + rootPath = "." ) const publishInitScriptContentTemplate = ` -rootProject { - apply plugin: 'maven-publish' - apply plugin: 'java' - - publishing { - publications { - maven(MavenPublication) { - versionMapping { - usage('java-api') { - fromResolutionOf('runtimeClasspath') - } - usage('java-runtime') { - fromResolutionResult() +{{ if .ApplyPublishingForAllProjects}}allprojects{{else}}rootProject{{ end }} { + def gradleExecuteBuild_skipPublishingProjects = [{{ if .ApplyPublishingForAllProjects}}{{range .ExcludePublishingForProjects}} "{{.}}",{{end}}{{end}} ]; + if (!gradleExecuteBuild_skipPublishingProjects.contains(project.name)) { + apply plugin: 'maven-publish' + apply plugin: 'java' + publishing { + publications { + maven(MavenPublication) { + versionMapping { + usage('java-api') { + fromResolutionOf('runtimeClasspath') + } + usage('java-runtime') { + fromResolutionResult() + } } + {{- if .ArtifactGroupID}} + groupId = '{{.ArtifactGroupID}}' + {{- end }} + {{- if .ApplyPublishingForAllProjects }} + {{else if .ArtifactID}} + artifactId = '{{.ArtifactID}}' + {{- end }} + {{- if .ArtifactVersion}} + version = '{{.ArtifactVersion}}' + {{- end }} + from components.java } - {{- if .ArtifactGroupID}} - groupId = '{{.ArtifactGroupID}}' - {{- end }} - {{- if .ArtifactID}} - artifactId = '{{.ArtifactID}}' - {{- end }} - {{- if .ArtifactVersion}} - version = '{{.ArtifactVersion}}' - {{- end }} - from components.java } - } - repositories { - maven { - credentials { - username = "{{.RepositoryUsername}}" - password = "{{.RepositoryPassword}}" + repositories { + maven { + credentials { + username = "{{.RepositoryUsername}}" + password = "{{.RepositoryPassword}}" + } + url = "{{.RepositoryURL}}" } - url = "{{.RepositoryURL}}" } } } } ` -const bomInitScriptContent = ` +const bomInitScriptContentTemplate = ` initscript { repositories { mavenCentral() @@ -78,24 +85,33 @@ initscript { } } -rootProject { - apply plugin: 'java' - apply plugin: 'maven' - apply plugin: org.cyclonedx.gradle.CycloneDxPlugin +allprojects { + def gradleExecuteBuild_skipBOMProjects = [{{range .ExcludeCreateBOMForProjects}} "{{.}}",{{end}} ]; + if (!gradleExecuteBuild_skipBOMProjects.contains(project.name)) { + apply plugin: 'java' + apply plugin: org.cyclonedx.gradle.CycloneDxPlugin - cyclonedxBom { - outputName = "` + gradleBomFilename + `" - outputFormat = "xml" - schemaVersion = "1.2" + cyclonedxBom { + outputName = "` + gradleBomFilename + `" + outputFormat = "xml" + schemaVersion = "1.2" + includeConfigs = ["runtimeClasspath"] + skipConfigs = ["compileClasspath", "testCompileClasspath"] + } } } ` // PublishedArtifacts contains information about published artifacts type PublishedArtifacts struct { + Info Component `json:"component,omitempty"` Elements []Element `json:"variants,omitempty"` } +type Component struct { + Module string `json:"module,omitempty"` +} + type Element struct { Name string `json:"name,omitempty"` Artifacts []Artifact `json:"files,omitempty"` @@ -105,22 +121,38 @@ type Artifact struct { Name string `json:"name,omitempty"` } +type WalkDir func(root string, fn fs.WalkDirFunc) error + +type Filepath interface { + WalkDir(root string, fn fs.WalkDirFunc) error +} + +type WalkDirFunc func(root string, fn fs.WalkDirFunc) error + +func (f WalkDirFunc) WalkDir(root string, fn fs.WalkDirFunc) error { + return f(root, fn) +} + type gradleExecuteBuildUtils interface { command.ExecRunner piperutils.FileUtils + Filepath } type gradleExecuteBuildUtilsBundle struct { *command.Command *piperutils.Files + Filepath } func newGradleExecuteBuildUtils() gradleExecuteBuildUtils { + var walkDirFunc WalkDirFunc = filepath.WalkDir utils := gradleExecuteBuildUtilsBundle{ Command: &command.Command{ StepName: "gradleExecuteBuild", }, - Files: &piperutils.Files{}, + Files: &piperutils.Files{}, + Filepath: walkDirFunc, } utils.Stdout(log.Writer()) utils.Stderr(log.Writer()) @@ -137,6 +169,7 @@ func gradleExecuteBuild(config gradleExecuteBuildOptions, telemetryData *telemet func runGradleExecuteBuild(config *gradleExecuteBuildOptions, telemetryData *telemetry.CustomData, utils gradleExecuteBuildUtils, pipelineEnv *gradleExecuteBuildCommonPipelineEnvironment) error { log.Entry().Info("BOM file creation...") + if config.CreateBOM { if err := createBOM(config, utils); err != nil { return err @@ -165,11 +198,15 @@ func runGradleExecuteBuild(config *gradleExecuteBuildOptions, telemetryData *tel } func createBOM(config *gradleExecuteBuildOptions, utils gradleExecuteBuildUtils) error { + createBOMInitScriptContent, err := getInitScriptContent(config, bomInitScriptContentTemplate) + if err != nil { + return fmt.Errorf("failed to get BOM init script content: %v", err) + } gradleOptions := &gradle.ExecuteOptions{ BuildGradlePath: config.Path, Task: bomGradleTaskName, UseWrapper: config.UseWrapper, - InitScriptContent: bomInitScriptContent, + InitScriptContent: createBOMInitScriptContent, } if _, err := gradle.Execute(gradleOptions, utils); err != nil { log.Entry().WithError(err).Errorf("failed to create BOM: %v", err) @@ -179,7 +216,7 @@ func createBOM(config *gradleExecuteBuildOptions, utils gradleExecuteBuildUtils) } func publishArtifacts(config *gradleExecuteBuildOptions, utils gradleExecuteBuildUtils, pipelineEnv *gradleExecuteBuildCommonPipelineEnvironment) error { - publishInitScriptContent, err := getPublishInitScriptContent(config) + publishInitScriptContent, err := getInitScriptContent(config, publishInitScriptContentTemplate) if err != nil { return fmt.Errorf("failed to get publish init script content: %v", err) } @@ -193,16 +230,29 @@ func publishArtifacts(config *gradleExecuteBuildOptions, utils gradleExecuteBuil log.Entry().WithError(err).Errorf("failed to publish artifacts: %v", err) return err } - artifacts, err := getPublishedArtifactsNames(pathToModuleFile, utils) + var artifacts piperenv.Artifacts + err = utils.WalkDir(rootPath, func(path string, d fs.DirEntry, err error) error { + if d.IsDir() { + return nil + } + if strings.HasSuffix(path, pathToModuleFile) { + pathArtifacts, artifactsErr := getPublishedArtifactsNames(path, utils) + if artifactsErr != nil { + return fmt.Errorf("failed to get published artifacts in path %s: %v", path, artifactsErr) + } + artifacts = append(artifacts, pathArtifacts...) + } + return nil + }) if err != nil { - return fmt.Errorf("failed to get published artifacts: %v", err) + return err } pipelineEnv.custom.artifacts = artifacts return nil } -func getPublishInitScriptContent(options *gradleExecuteBuildOptions) (string, error) { - tmpl, err := template.New("resources").Parse(publishInitScriptContentTemplate) +func getInitScriptContent(options *gradleExecuteBuildOptions, templateContent string) (string, error) { + tmpl, err := template.New("resources").Parse(templateContent) if err != nil { return "", err } @@ -239,7 +289,7 @@ func getPublishedArtifactsNames(file string, utils gradleExecuteBuildUtils) (pip continue } for _, artifact := range element.Artifacts { - artifacts = append(artifacts, piperenv.Artifact{Name: artifact.Name}) + artifacts = append(artifacts, piperenv.Artifact{Id: publishedArtifacts.Info.Module, Name: artifact.Name}) } } return artifacts, nil diff --git a/cmd/gradleExecuteBuild_generated.go b/cmd/gradleExecuteBuild_generated.go index c95ed53826..dc90111206 100644 --- a/cmd/gradleExecuteBuild_generated.go +++ b/cmd/gradleExecuteBuild_generated.go @@ -22,17 +22,20 @@ import ( ) type gradleExecuteBuildOptions struct { - Path string `json:"path,omitempty"` - Task string `json:"task,omitempty"` - Publish bool `json:"publish,omitempty"` - RepositoryURL string `json:"repositoryUrl,omitempty"` - RepositoryPassword string `json:"repositoryPassword,omitempty"` - RepositoryUsername string `json:"repositoryUsername,omitempty"` - CreateBOM bool `json:"createBOM,omitempty"` - ArtifactVersion string `json:"artifactVersion,omitempty"` - ArtifactGroupID string `json:"artifactGroupId,omitempty"` - ArtifactID string `json:"artifactId,omitempty"` - UseWrapper bool `json:"useWrapper,omitempty"` + Path string `json:"path,omitempty"` + Task string `json:"task,omitempty"` + Publish bool `json:"publish,omitempty"` + RepositoryURL string `json:"repositoryUrl,omitempty"` + RepositoryPassword string `json:"repositoryPassword,omitempty"` + RepositoryUsername string `json:"repositoryUsername,omitempty"` + CreateBOM bool `json:"createBOM,omitempty"` + ArtifactVersion string `json:"artifactVersion,omitempty"` + ArtifactGroupID string `json:"artifactGroupId,omitempty"` + ArtifactID string `json:"artifactId,omitempty"` + UseWrapper bool `json:"useWrapper,omitempty"` + ApplyPublishingForAllProjects bool `json:"applyPublishingForAllProjects,omitempty"` + ExcludeCreateBOMForProjects []string `json:"excludeCreateBOMForProjects,omitempty"` + ExcludePublishingForProjects []string `json:"excludePublishingForProjects,omitempty"` } type gradleExecuteBuildReports struct { @@ -209,6 +212,9 @@ func addGradleExecuteBuildFlags(cmd *cobra.Command, stepConfig *gradleExecuteBui cmd.Flags().StringVar(&stepConfig.ArtifactGroupID, "artifactGroupId", os.Getenv("PIPER_artifactGroupId"), "The group of the artifact.") cmd.Flags().StringVar(&stepConfig.ArtifactID, "artifactId", os.Getenv("PIPER_artifactId"), "The name of the artifact.") cmd.Flags().BoolVar(&stepConfig.UseWrapper, "useWrapper", false, "If set to false all commands are executed using 'gradle', otherwise 'gradlew' is executed.") + cmd.Flags().BoolVar(&stepConfig.ApplyPublishingForAllProjects, "applyPublishingForAllProjects", false, "If set to false publishing logic will be applied in 'rootProject' directive, otherwise 'allprojects' will be directive used") + cmd.Flags().StringSliceVar(&stepConfig.ExcludeCreateBOMForProjects, "excludeCreateBOMForProjects", []string{}, "Defines which projects/subprojects will be ignored during bom creation. Only if applyCreateBOMForAllProjects is set to true") + cmd.Flags().StringSliceVar(&stepConfig.ExcludePublishingForProjects, "excludePublishingForProjects", []string{}, "Defines which projects/subprojects will be ignored during publishing. Only if applyCreateBOMForAllProjects is set to true") } @@ -352,6 +358,33 @@ func gradleExecuteBuildMetadata() config.StepData { Aliases: []config.Alias{}, Default: false, }, + { + Name: "applyPublishingForAllProjects", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"STEPS", "STAGES", "PARAMETERS"}, + Type: "bool", + Mandatory: false, + Aliases: []config.Alias{}, + Default: false, + }, + { + Name: "excludeCreateBOMForProjects", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, + Type: "[]string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: []string{}, + }, + { + Name: "excludePublishingForProjects", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, + Type: "[]string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: []string{}, + }, }, }, Containers: []config.Container{ diff --git a/cmd/gradleExecuteBuild_test.go b/cmd/gradleExecuteBuild_test.go index 6dddacf964..3b53699f2a 100644 --- a/cmd/gradleExecuteBuild_test.go +++ b/cmd/gradleExecuteBuild_test.go @@ -2,6 +2,8 @@ package cmd import ( "fmt" + "io/fs" + "path/filepath" "testing" "github.com/pkg/errors" @@ -16,6 +18,24 @@ const moduleFileContent = `{"variants": [{"name": "apiElements","files": [{"name type gradleExecuteBuildMockUtils struct { *mock.ExecMockRunner *mock.FilesMock + Filepath +} + +type isDirEntryMock func() bool + +func (d isDirEntryMock) Name() string { + panic("not implemented") +} + +func (d isDirEntryMock) IsDir() bool { + return d() +} + +func (d isDirEntryMock) Type() fs.FileMode { + panic("not implemented") +} +func (d isDirEntryMock) Info() (fs.FileInfo, error) { + panic("not implemented") } func TestRunGradleExecuteBuild(t *testing.T) { @@ -79,12 +99,19 @@ func TestRunGradleExecuteBuild(t *testing.T) { }) t.Run("success case - publishing of artifacts", func(t *testing.T) { + var walkDir WalkDirFunc = func(root string, fn fs.WalkDirFunc) error { + var dirMock isDirEntryMock = func() bool { + return false + } + return fn(filepath.Join("test_subproject_path", "build", "publications", "maven", "module.json"), dirMock, nil) + } utils := gradleExecuteBuildMockUtils{ ExecMockRunner: &mock.ExecMockRunner{}, FilesMock: &mock.FilesMock{}, + Filepath: walkDir, } utils.FilesMock.AddFile("path/to/build.gradle", []byte{}) - utils.FilesMock.AddFile("/build/publications/maven/module.json", []byte(moduleFileContent)) + utils.FilesMock.AddFile(filepath.Join("test_subproject_path", "build", "publications", "maven", "module.json"), []byte(moduleFileContent)) options := &gradleExecuteBuildOptions{ Path: "path/to", Task: "build", diff --git a/cmd/integrationArtifactDeploy_generated.go b/cmd/integrationArtifactDeploy_generated.go index e062995856..c507916207 100644 --- a/cmd/integrationArtifactDeploy_generated.go +++ b/cmd/integrationArtifactDeploy_generated.go @@ -34,7 +34,7 @@ func IntegrationArtifactDeployCommand() *cobra.Command { var createIntegrationArtifactDeployCmd = &cobra.Command{ Use: STEP_NAME, Short: "Deploy a CPI integration flow", - Long: `With this step you can deploy a integration flow artifact in to SAP Cloud Platform integration runtime using OData API. Learn more about the SAP Cloud Integration remote API for deploying an integration artifact [here](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/d1679a80543f46509a7329243b595bdb.html)`, + Long: `With this step you can deploy a integration flow artifact in to SAP BTP integration runtime using OData API. Learn more about the SAP Cloud Integration remote API for deploying an integration artifact [here](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/d1679a80543f46509a7329243b595bdb.html)`, PreRunE: func(cmd *cobra.Command, _ []string) error { startTime = time.Now() log.SetStepName(STEP_NAME) diff --git a/cmd/integrationArtifactGetServiceEndpoint_generated.go b/cmd/integrationArtifactGetServiceEndpoint_generated.go index f1802da734..6a2c559fcb 100644 --- a/cmd/integrationArtifactGetServiceEndpoint_generated.go +++ b/cmd/integrationArtifactGetServiceEndpoint_generated.go @@ -65,7 +65,7 @@ func IntegrationArtifactGetServiceEndpointCommand() *cobra.Command { var createIntegrationArtifactGetServiceEndpointCmd = &cobra.Command{ Use: STEP_NAME, Short: "Get an deployed CPI intgeration flow service endpoint", - Long: `With this step you can obtain information about the service endpoints exposed by SAP Cloud Platform Integration on a tenant using OData API. Learn more about the SAP Cloud Integration remote API for getting service endpoint of deployed integration artifact [here](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/d1679a80543f46509a7329243b595bdb.html).`, + Long: `With this step you can obtain information about the service endpoints exposed by SAP BTP Integration on a tenant using OData API. Learn more about the SAP Cloud Integration remote API for getting service endpoint of deployed integration artifact [here](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/d1679a80543f46509a7329243b595bdb.html).`, PreRunE: func(cmd *cobra.Command, _ []string) error { startTime = time.Now() log.SetStepName(STEP_NAME) diff --git a/cmd/integrationArtifactTriggerIntegrationTest_generated.go b/cmd/integrationArtifactTriggerIntegrationTest_generated.go index b09c514bc8..c5ca0f5dec 100644 --- a/cmd/integrationArtifactTriggerIntegrationTest_generated.go +++ b/cmd/integrationArtifactTriggerIntegrationTest_generated.go @@ -37,7 +37,7 @@ func IntegrationArtifactTriggerIntegrationTestCommand() *cobra.Command { var createIntegrationArtifactTriggerIntegrationTestCmd = &cobra.Command{ Use: STEP_NAME, Short: "Test the service endpoint of your iFlow", - Long: `With this step you can test your intergration flow exposed by SAP Cloud Platform Integration on a tenant using OData API.Learn more about the SAP Cloud Integration remote API for getting service endpoint of deployed integration artifact [here](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/d1679a80543f46509a7329243b595bdb.html).`, + Long: `With this step you can test your intergration flow exposed by SAP BTP Integration on a tenant using OData API.Learn more about the SAP Cloud Integration remote API for getting service endpoint of deployed integration artifact [here](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/d1679a80543f46509a7329243b595bdb.html).`, PreRunE: func(cmd *cobra.Command, _ []string) error { startTime = time.Now() log.SetStepName(STEP_NAME) diff --git a/cmd/kanikoExecute.go b/cmd/kanikoExecute.go index e4631d95ff..26bf039e5b 100644 --- a/cmd/kanikoExecute.go +++ b/cmd/kanikoExecute.go @@ -2,12 +2,12 @@ package cmd import ( "fmt" - "net/http" "strings" "github.com/SAP/jenkins-library/pkg/buildsettings" "github.com/SAP/jenkins-library/pkg/certutils" piperhttp "github.com/SAP/jenkins-library/pkg/http" + "github.com/SAP/jenkins-library/pkg/syft" "github.com/pkg/errors" "github.com/SAP/jenkins-library/pkg/command" @@ -17,50 +17,6 @@ import ( "github.com/SAP/jenkins-library/pkg/telemetry" ) -const syftURL = "https://raw.githubusercontent.com/anchore/syft/main/install.sh" - -type kanikoHttpClient interface { - piperhttp.Sender - DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error -} - -func installSyft(shellRunner command.ShellRunner, fileUtils piperutils.FileUtils, httpClient kanikoHttpClient) error { - installationScript := "./install.sh" - err := httpClient.DownloadFile(syftURL, installationScript, nil, nil) - if err != nil { - return fmt.Errorf("failed to download syft: %w", err) - } - - err = fileUtils.Chmod(installationScript, 0777) - if err != nil { - return err - } - - err = shellRunner.RunShell("/busybox/sh", "cat ./install.sh | sh -s -- -b .") - if err != nil { - return fmt.Errorf("failed to install syft: %w", err) - } - - return nil -} - -func generateSBOM(shellRunner command.ShellRunner, fileUtils piperutils.FileUtils, httpClient kanikoHttpClient, commonPipelineEnvironment *kanikoExecuteCommonPipelineEnvironment) error { - shellRunner.AppendEnv([]string{"DOCKER_CONFIG", "/kaniko/.docker"}) - syftInstallErr := installSyft(shellRunner, fileUtils, httpClient) - if syftInstallErr != nil { - return syftInstallErr - } - for index, eachImageTag := range commonPipelineEnvironment.container.imageNameTags { - // TrimPrefix needed as syft needs containerRegistry name only - syftRunErr := shellRunner.RunShell("/busybox/sh", fmt.Sprintf("./syft %s/%s -o cyclonedx-xml=bom-docker-%v.xml", strings.TrimPrefix(commonPipelineEnvironment.container.registryURL, "https://"), eachImageTag, index)) - if syftRunErr != nil { - return fmt.Errorf("failed to generate SBOM: %w", syftRunErr) - } - } - return nil - -} - func kanikoExecute(config kanikoExecuteOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *kanikoExecuteCommonPipelineEnvironment) { // for command execution use Command c := command.Command{ @@ -79,13 +35,13 @@ func kanikoExecute(config kanikoExecuteOptions, telemetryData *telemetry.CustomD fileUtils := &piperutils.Files{} - err := runKanikoExecute(&config, telemetryData, commonPipelineEnvironment, &c, &c, client, fileUtils) + err := runKanikoExecute(&config, telemetryData, commonPipelineEnvironment, &c, client, fileUtils) if err != nil { log.Entry().WithError(err).Fatal("Kaniko execution failed") } } -func runKanikoExecute(config *kanikoExecuteOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *kanikoExecuteCommonPipelineEnvironment, execRunner command.ExecRunner, shellRunner command.ShellRunner, httpClient kanikoHttpClient, fileUtils piperutils.FileUtils) error { +func runKanikoExecute(config *kanikoExecuteOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *kanikoExecuteCommonPipelineEnvironment, execRunner command.ExecRunner, httpClient piperhttp.Sender, fileUtils piperutils.FileUtils) error { binfmtSupported, _ := docker.IsBinfmtMiscSupportedByHost(fileUtils) if !binfmtSupported && len(config.TargetArchitectures) > 0 { @@ -222,7 +178,7 @@ func runKanikoExecute(config *kanikoExecuteOptions, telemetryData *telemetry.Cus } if config.CreateBOM { //Syft for multi image, generates bom-docker-(1/2/3).xml - return generateSBOM(shellRunner, fileUtils, httpClient, commonPipelineEnvironment) + return syft.GenerateSBOM(config.SyftDownloadURL, "/kaniko/.docker", execRunner, fileUtils, httpClient, commonPipelineEnvironment.container.registryURL, commonPipelineEnvironment.container.imageNameTags) } return nil } else { @@ -286,7 +242,7 @@ func runKanikoExecute(config *kanikoExecuteOptions, telemetryData *telemetry.Cus } if config.CreateBOM { // Syft for single image, generates bom-docker-0.xml - return generateSBOM(shellRunner, fileUtils, httpClient, commonPipelineEnvironment) + return syft.GenerateSBOM(config.SyftDownloadURL, "/kaniko/.docker", execRunner, fileUtils, httpClient, commonPipelineEnvironment.container.registryURL, commonPipelineEnvironment.container.imageNameTags) } return nil } diff --git a/cmd/kanikoExecute_generated.go b/cmd/kanikoExecute_generated.go index 991b1d27bd..db10dbd8be 100644 --- a/cmd/kanikoExecute_generated.go +++ b/cmd/kanikoExecute_generated.go @@ -6,14 +6,18 @@ import ( "fmt" "os" "path/filepath" + "reflect" + "strings" "time" "github.com/SAP/jenkins-library/pkg/config" + "github.com/SAP/jenkins-library/pkg/gcs" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperenv" "github.com/SAP/jenkins-library/pkg/splunk" "github.com/SAP/jenkins-library/pkg/telemetry" "github.com/SAP/jenkins-library/pkg/validation" + "github.com/bmatcuk/doublestar" "github.com/spf13/cobra" ) @@ -37,6 +41,7 @@ type kanikoExecuteOptions struct { TargetArchitectures []string `json:"targetArchitectures,omitempty"` ReadImageDigest bool `json:"readImageDigest,omitempty"` CreateBOM bool `json:"createBOM,omitempty"` + SyftDownloadURL string `json:"syftDownloadUrl,omitempty"` } type kanikoExecuteCommonPipelineEnvironment struct { @@ -81,6 +86,42 @@ func (p *kanikoExecuteCommonPipelineEnvironment) persist(path, resourceName stri } } +type kanikoExecuteReports struct { +} + +func (p *kanikoExecuteReports) persist(stepConfig kanikoExecuteOptions, gcpJsonKeyFilePath string, gcsBucketId string, gcsFolderPath string, gcsSubFolder string) { + if gcsBucketId == "" { + log.Entry().Info("persisting reports to GCS is disabled, because gcsBucketId is empty") + return + } + log.Entry().Info("Uploading reports to Google Cloud Storage...") + content := []gcs.ReportOutputParam{ + {FilePattern: "**/bom-*.xml", ParamRef: "", StepResultType: "sbom"}, + } + envVars := []gcs.EnvVar{ + {Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: gcpJsonKeyFilePath, Modified: false}, + } + gcsClient, err := gcs.NewClient(gcs.WithEnvVars(envVars)) + if err != nil { + log.Entry().Errorf("creation of GCS client failed: %v", err) + return + } + defer gcsClient.Close() + structVal := reflect.ValueOf(&stepConfig).Elem() + inputParameters := map[string]string{} + for i := 0; i < structVal.NumField(); i++ { + field := structVal.Type().Field(i) + if field.Type.String() == "string" { + paramName := strings.Split(field.Tag.Get("json"), ",") + paramValue, _ := structVal.Field(i).Interface().(string) + inputParameters[paramName[0]] = paramValue + } + } + if err := gcs.PersistReportsToGCS(gcsClient, content, inputParameters, gcsFolderPath, gcsBucketId, gcsSubFolder, doublestar.Glob, os.Stat); err != nil { + log.Entry().Errorf("failed to persist reports: %v", err) + } +} + // KanikoExecuteCommand Executes a [Kaniko](https://github.com/GoogleContainerTools/kaniko) build for creating a Docker container. func KanikoExecuteCommand() *cobra.Command { const STEP_NAME = "kanikoExecute" @@ -89,6 +130,7 @@ func KanikoExecuteCommand() *cobra.Command { var stepConfig kanikoExecuteOptions var startTime time.Time var commonPipelineEnvironment kanikoExecuteCommonPipelineEnvironment + var reports kanikoExecuteReports var logCollector *log.CollectorHook var splunkClient *splunk.Splunk telemetryClient := &telemetry.Telemetry{} @@ -209,6 +251,7 @@ Following final image names will be built: stepTelemetryData.ErrorCode = "1" handler := func() { commonPipelineEnvironment.persist(GeneralConfig.EnvRootPath, "commonPipelineEnvironment") + reports.persist(stepConfig, GeneralConfig.GCPJsonKeyFilePath, GeneralConfig.GCSBucketId, GeneralConfig.GCSFolderPath, GeneralConfig.GCSSubFolder) config.RemoveVaultSecretFiles() stepTelemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds()) stepTelemetryData.ErrorCategory = log.GetErrorCategory().String() @@ -258,7 +301,8 @@ func addKanikoExecuteFlags(cmd *cobra.Command, stepConfig *kanikoExecuteOptions) cmd.Flags().StringVar(&stepConfig.DockerfilePath, "dockerfilePath", `Dockerfile`, "Defines the location of the Dockerfile relative to the Jenkins workspace.") cmd.Flags().StringSliceVar(&stepConfig.TargetArchitectures, "targetArchitectures", []string{``}, "Defines the target architectures for which the build should run using OS and architecture separated by a comma. (EXPERIMENTAL)") cmd.Flags().BoolVar(&stepConfig.ReadImageDigest, "readImageDigest", false, "") - cmd.Flags().BoolVar(&stepConfig.CreateBOM, "createBOM", false, "Creates the bill of materials (BOM) using Syft and stored in a file of CycloneDX 1.4 format.") + cmd.Flags().BoolVar(&stepConfig.CreateBOM, "createBOM", false, "Creates the bill of materials (BOM) using Syft and stores it in a file in CycloneDX 1.4 format.") + cmd.Flags().StringVar(&stepConfig.SyftDownloadURL, "syftDownloadUrl", `https://github.com/anchore/syft/releases/download/v0.62.3/syft_0.62.3_linux_amd64.tar.gz`, "Specifies the download url of the Syft Linux amd64 tar binary file. This can be found at https://github.com/anchore/syft/releases/.") } @@ -483,6 +527,15 @@ func kanikoExecuteMetadata() config.StepData { Aliases: []config.Alias{}, Default: false, }, + { + Name: "syftDownloadUrl", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STEPS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: `https://github.com/anchore/syft/releases/download/v0.62.3/syft_0.62.3_linux_amd64.tar.gz`, + }, }, }, Containers: []config.Container{ @@ -503,6 +556,13 @@ func kanikoExecuteMetadata() config.StepData { {"name": "custom/buildSettingsInfo"}, }, }, + { + Name: "reports", + Type: "reports", + Parameters: []map[string]interface{}{ + {"filePattern": "**/bom-*.xml", "type": "sbom"}, + }, + }, }, }, }, diff --git a/cmd/kanikoExecute_test.go b/cmd/kanikoExecute_test.go index 352d767687..fd330d6d2a 100644 --- a/cmd/kanikoExecute_test.go +++ b/cmd/kanikoExecute_test.go @@ -13,6 +13,7 @@ import ( piperhttp "github.com/SAP/jenkins-library/pkg/http" "github.com/SAP/jenkins-library/pkg/mock" "github.com/SAP/jenkins-library/pkg/telemetry" + "github.com/jarcoal/httpmock" "github.com/stretchr/testify/assert" ) @@ -66,7 +67,6 @@ func TestRunKanikoExecute(t *testing.T) { } execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} certClient := &kanikoMockClient{ @@ -76,7 +76,7 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils.AddFile("path/to/docker/config.json", []byte(`{"auths":{"custom":"test"}}`)) fileUtils.AddFile("/kaniko/ssl/certs/ca-certificates.crt", []byte(``)) - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.NoError(t, err) @@ -117,7 +117,6 @@ func TestRunKanikoExecute(t *testing.T) { } execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} certClient := &kanikoMockClient{ @@ -128,7 +127,7 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils.AddFile("/kaniko/ssl/certs/ca-certificates.crt", []byte(``)) fileUtils.AddFile("/tmp/*-kanikoExecutetest/digest.txt", []byte(`sha256:468dd1253cc9f498fc600454bb8af96d880fec3f9f737e7057692adfe9f7d5b0`)) - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.NoError(t, err) @@ -169,7 +168,6 @@ func TestRunKanikoExecute(t *testing.T) { } execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} certClient := &kanikoMockClient{ @@ -179,7 +177,7 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils.AddFile("path/to/docker/config.json", []byte(`{"auths":{"custom":"test"}}`)) fileUtils.AddFile("/kaniko/ssl/certs/ca-certificates.crt", []byte(``)) - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.NoError(t, err) @@ -214,7 +212,6 @@ func TestRunKanikoExecute(t *testing.T) { } execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} certClient := &kanikoMockClient{ @@ -224,7 +221,7 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils.AddFile("path/to/docker/config.json", []byte(`{"auths":{"custom":"test"}}`)) fileUtils.AddFile("/kaniko/ssl/certs/ca-certificates.crt", []byte(``)) - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.NoError(t, err) @@ -262,7 +259,6 @@ func TestRunKanikoExecute(t *testing.T) { } execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} certClient := &kanikoMockClient{} @@ -270,7 +266,7 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils.AddFile("path/to/docker/config.json", []byte(``)) fileUtils.FileReadErrors = map[string]error{"/kaniko/ssl/certs/ca-certificates.crt": fmt.Errorf("read error")} - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.NoErrorf(t, err, "failed to update certificates: failed to load file '/kaniko/ssl/certs/ca-certificates.crt': read error") }) @@ -284,7 +280,6 @@ func TestRunKanikoExecute(t *testing.T) { } execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} certClient := &kanikoMockClient{ @@ -293,7 +288,7 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils := &mock.FilesMock{} fileUtils.AddFile("/kaniko/ssl/certs/ca-certificates.crt", []byte(``)) - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.NoError(t, err) @@ -316,7 +311,6 @@ func TestRunKanikoExecute(t *testing.T) { } execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} certClient := &kanikoMockClient{ @@ -326,12 +320,13 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils.AddFile("path/to/docker/config.json", []byte(`{"auths":{"custom":"test"}}`)) fileUtils.AddFile("/kaniko/ssl/certs/ca-certificates.crt", []byte(``)) - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.NoError(t, err) cwd, _ := fileUtils.Getwd() assert.Equal(t, []string{"--dockerfile", "Dockerfile", "--context", cwd, "--skip-tls-verify-pull", "--destination", "myImage:tag"}, execRunner.Calls[1].Params) }) + t.Run("success case - createBOM", func(t *testing.T) { config := &kanikoExecuteOptions{ ContainerImage: "myImage:tag", @@ -339,31 +334,31 @@ func TestRunKanikoExecute(t *testing.T) { DockerfilePath: "Dockerfile", DockerConfigJSON: "path/to/docker/config.json", CreateBOM: true, + SyftDownloadURL: "http://test-syft-url.io", } execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} - - certClient := &kanikoMockClient{ - responseBody: "testCert", - } fileUtils := &mock.FilesMock{} fileUtils.AddFile("path/to/docker/config.json", []byte(`{"auths":{"custom":"test"}}`)) - fileUtils.AddFile("install.sh", []byte(`echo syft`)) - - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + httpmock.Activate() + defer httpmock.DeactivateAndReset() + fakeArchive, err := fileUtils.CreateArchive(map[string][]byte{"syft": []byte("test")}) assert.NoError(t, err) - assert.Equal(t, "/kaniko/executor", execRunner.Calls[1].Exec) + httpmock.RegisterResponder(http.MethodGet, "http://test-syft-url.io", httpmock.NewBytesResponder(http.StatusOK, fakeArchive)) + client := &piperhttp.Client{} + client.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true}) + err = runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, client, fileUtils) + assert.NoError(t, err) + assert.Equal(t, "/kaniko/executor", execRunner.Calls[1].Exec) assert.Equal(t, "myImage:tag", commonPipelineEnvironment.container.imageNameTag) assert.Equal(t, "https://index.docker.io", commonPipelineEnvironment.container.registryURL) - //Syft install and call - assert.Contains(t, shellRunner.Calls[0], "cat ./install.sh | sh -s -- -b .") - assert.Contains(t, shellRunner.Calls[1], "./syft index.docker.io/myImage:tag -o cyclonedx-xml=bom-docker-0.xml") + assert.Equal(t, "/tmp/syfttest/syft", execRunner.Calls[2].Exec) + assert.Equal(t, []string{"packages", "registry:index.docker.io/myImage:tag", "-o", "cyclonedx-xml", "--file", "bom-docker-0.xml", "-q"}, execRunner.Calls[2].Params) }) t.Run("success case - multi image build with root image", func(t *testing.T) { @@ -375,7 +370,6 @@ func TestRunKanikoExecute(t *testing.T) { } execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} fileUtils := &mock.FilesMock{} @@ -383,7 +377,7 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils.AddFile("sub1/Dockerfile", []byte("some content")) fileUtils.AddFile("sub2/Dockerfile", []byte("some content")) - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, nil, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, nil, fileUtils) assert.NoError(t, err) @@ -433,7 +427,6 @@ func TestRunKanikoExecute(t *testing.T) { } execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} fileUtils := &mock.FilesMock{} @@ -441,7 +434,7 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils.AddFile("sub1/Dockerfile", []byte("some content")) fileUtils.AddFile("sub2/Dockerfile", []byte("some content")) - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, nil, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, nil, fileUtils) assert.NoError(t, err) @@ -482,26 +475,29 @@ func TestRunKanikoExecute(t *testing.T) { ContainerMultiImageBuild: true, DockerConfigJSON: "path/to/docker/config.json", CreateBOM: true, + SyftDownloadURL: "http://test-syft-url.io", } - certClient := &kanikoMockClient{ - responseBody: "testCert", - } - execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} - fileUtils := &mock.FilesMock{} fileUtils.AddFile("path/to/docker/config.json", []byte(`{"auths":{"custom":"test"}}`)) fileUtils.AddFile("Dockerfile", []byte("some content")) fileUtils.AddFile("sub1/Dockerfile", []byte("some content")) fileUtils.AddFile("sub2/Dockerfile", []byte("some content")) - fileUtils.AddFile("install.sh", []byte(`echo syft`)) - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + httpmock.Activate() + defer httpmock.DeactivateAndReset() + fakeArchive, err := fileUtils.CreateArchive(map[string][]byte{"syft": []byte("test")}) assert.NoError(t, err) - assert.Equal(t, 3, len(execRunner.Calls)) + httpmock.RegisterResponder(http.MethodGet, "http://test-syft-url.io", httpmock.NewBytesResponder(http.StatusOK, fakeArchive)) + client := &piperhttp.Client{} + client.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true}) + + err = runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, client, fileUtils) + assert.NoError(t, err) + + assert.Equal(t, 6, len(execRunner.Calls)) assert.Equal(t, "/kaniko/executor", execRunner.Calls[0].Exec) assert.Equal(t, "/kaniko/executor", execRunner.Calls[1].Exec) assert.Equal(t, "/kaniko/executor", execRunner.Calls[2].Exec) @@ -511,6 +507,9 @@ func TestRunKanikoExecute(t *testing.T) { {"--dockerfile", "Dockerfile", "--context", cwd, "--destination", "my.registry.com:50000/myImage:myTag"}, {"--dockerfile", filepath.Join("sub1", "Dockerfile"), "--context", cwd, "--destination", "my.registry.com:50000/myImage-sub1:myTag"}, {"--dockerfile", filepath.Join("sub2", "Dockerfile"), "--context", cwd, "--destination", "my.registry.com:50000/myImage-sub2:myTag"}, + {"packages", "registry:my.registry.com:50000/myImage:myTag", "-o", "cyclonedx-xml", "--file", "bom-docker-0.xml", "-q"}, + {"packages", "registry:my.registry.com:50000/myImage-sub1:myTag", "-o", "cyclonedx-xml", "--file", "bom-docker-1.xml", "-q"}, + {"packages", "registry:my.registry.com:50000/myImage-sub2:myTag", "-o", "cyclonedx-xml", "--file", "bom-docker-2.xml", "-q"}, } // need to go this way since we cannot count on the correct order for _, call := range execRunner.Calls { @@ -535,25 +534,6 @@ func TestRunKanikoExecute(t *testing.T) { assert.Equal(t, "", commonPipelineEnvironment.container.imageDigest) assert.Empty(t, commonPipelineEnvironment.container.imageDigests) - - //Syft install and call, can we do it better without 2 for loops - expectedShellCalls := []string{ - "cat ./install.sh | sh -s -- -b .", - "./syft my.registry.com:50000/myImage:myTag -o cyclonedx-xml=bom-docker-0.xml", - "./syft my.registry.com:50000/myImage-sub1:myTag -o cyclonedx-xml=bom-docker-1.xml", - "./syft my.registry.com:50000/myImage-sub2:myTag -o cyclonedx-xml=bom-docker-2.xml", - } - for _, call := range shellRunner.Calls { - found := false - for _, expected := range expectedShellCalls { - if strings.Contains(call, expected) { - found = true - break - } - } - assert.True(t, found) - } - }) t.Run("success case - updating an existing docker config json with addtional credentials", func(t *testing.T) { @@ -571,7 +551,6 @@ func TestRunKanikoExecute(t *testing.T) { } execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} certClient := &kanikoMockClient{ @@ -581,7 +560,7 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils.AddFile("path/to/docker/config.json", []byte(`{"auths": {"dummyUrl": {"auth": "XXXXXXX"}}}`)) fileUtils.AddFile("/kaniko/ssl/certs/ca-certificates.crt", []byte(``)) - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.NoError(t, err) @@ -608,7 +587,6 @@ func TestRunKanikoExecute(t *testing.T) { } execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} certClient := &kanikoMockClient{ @@ -617,7 +595,7 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils := &mock.FilesMock{} fileUtils.AddFile("/kaniko/ssl/certs/ca-certificates.crt", []byte(``)) - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.NoError(t, err) @@ -640,11 +618,9 @@ func TestRunKanikoExecute(t *testing.T) { cpe := kanikoExecuteCommonPipelineEnvironment{} execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} - fileUtils := &mock.FilesMock{} - err := runKanikoExecute(config, &telemetry.CustomData{}, &cpe, execRunner, shellRunner, nil, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &cpe, execRunner, nil, fileUtils) assert.Error(t, err) assert.Contains(t, fmt.Sprint(err), "failed to identify image list for multi image build") @@ -661,12 +637,11 @@ func TestRunKanikoExecute(t *testing.T) { cpe := kanikoExecuteCommonPipelineEnvironment{} execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} fileUtils := &mock.FilesMock{} fileUtils.AddFile("Dockerfile", []byte("some content")) - err := runKanikoExecute(config, &telemetry.CustomData{}, &cpe, execRunner, shellRunner, nil, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &cpe, execRunner, nil, fileUtils) assert.Error(t, err) assert.Contains(t, fmt.Sprint(err), "no docker files to process, please check exclude list") @@ -682,14 +657,13 @@ func TestRunKanikoExecute(t *testing.T) { cpe := kanikoExecuteCommonPipelineEnvironment{} execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} execRunner.ShouldFailOnCommand = map[string]error{"/kaniko/executor": fmt.Errorf("execution failed")} fileUtils := &mock.FilesMock{} fileUtils.AddFile("Dockerfile", []byte("some content")) - err := runKanikoExecute(config, &telemetry.CustomData{}, &cpe, execRunner, shellRunner, nil, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &cpe, execRunner, nil, fileUtils) assert.Error(t, err) assert.Contains(t, fmt.Sprint(err), "failed to build image") @@ -699,7 +673,6 @@ func TestRunKanikoExecute(t *testing.T) { config := &kanikoExecuteOptions{ ContainerPreparationCommand: "rm -f /kaniko/.docker/config.json", } - shellRunner := &mock.ShellMockRunner{} execRunner := &mock.ExecMockRunner{ ShouldFailOnCommand: map[string]error{"rm": fmt.Errorf("rm failed")}, } @@ -708,14 +681,13 @@ func TestRunKanikoExecute(t *testing.T) { certClient := &kanikoMockClient{} fileUtils := &mock.FilesMock{} - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.EqualError(t, err, "failed to initialize Kaniko container: rm failed") }) t.Run("error case - Kaniko execution failed", func(t *testing.T) { config := &kanikoExecuteOptions{} - shellRunner := &mock.ShellMockRunner{} execRunner := &mock.ExecMockRunner{ ShouldFailOnCommand: map[string]error{"/kaniko/executor": fmt.Errorf("kaniko run failed")}, } @@ -724,7 +696,7 @@ func TestRunKanikoExecute(t *testing.T) { certClient := &kanikoMockClient{} fileUtils := &mock.FilesMock{} - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.EqualError(t, err, "execution of '/kaniko/executor' failed: kaniko run failed") }) @@ -740,7 +712,6 @@ func TestRunKanikoExecute(t *testing.T) { DockerfilePath: "Dockerfile", DockerConfigJSON: "path/to/docker/config.json", } - shellRunner := &mock.ShellMockRunner{} execRunner := &mock.ExecMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} @@ -748,7 +719,7 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils := &mock.FilesMock{} fileUtils.FileReadErrors = map[string]error{"/kaniko/ssl/certs/ca-certificates.crt": fmt.Errorf("read error")} - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.EqualError(t, err, "failed to update certificates: failed to load file '/kaniko/ssl/certs/ca-certificates.crt': read error") }) @@ -757,7 +728,6 @@ func TestRunKanikoExecute(t *testing.T) { config := &kanikoExecuteOptions{ DockerConfigJSON: "path/to/docker/config.json", } - shellRunner := &mock.ShellMockRunner{} execRunner := &mock.ExecMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} @@ -765,7 +735,7 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils := &mock.FilesMock{} fileUtils.FileReadErrors = map[string]error{"path/to/docker/config.json": fmt.Errorf("read error")} - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.EqualError(t, err, "failed to read existing docker config json at 'path/to/docker/config.json': read error") }) @@ -774,7 +744,6 @@ func TestRunKanikoExecute(t *testing.T) { config := &kanikoExecuteOptions{ DockerConfigJSON: "path/to/docker/config.json", } - shellRunner := &mock.ShellMockRunner{} execRunner := &mock.ExecMockRunner{} commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} @@ -783,48 +752,8 @@ func TestRunKanikoExecute(t *testing.T) { fileUtils.AddFile("path/to/docker/config.json", []byte(`{"auths":{"custom":"test"}}`)) fileUtils.FileWriteErrors = map[string]error{"/kaniko/.docker/config.json": fmt.Errorf("write error")} - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) + err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, certClient, fileUtils) assert.EqualError(t, err, "failed to write file '/kaniko/.docker/config.json': write error") }) - - t.Run("error cases - createBOM", func(t *testing.T) { - config := &kanikoExecuteOptions{ - ContainerImage: "myImage:tag", - DockerfilePath: "Dockerfile", - DockerConfigJSON: "path/to/docker/config.json", - ContainerPreparationCommand: "rm -f /kaniko/.docker/config.json", - CreateBOM: true, - } - - execRunner := &mock.ExecMockRunner{} - shellRunner := &mock.ShellMockRunner{} - commonPipelineEnvironment := kanikoExecuteCommonPipelineEnvironment{} - certClient := &kanikoMockClient{ - responseBody: "testCert", - } - fileUtils := &mock.FilesMock{} - fileUtils.AddFile("path/to/docker/config.json", []byte(`{"auths":{"custom":"test"}}`)) - fileUtils.AddFile("install.sh", []byte(`echo syft`)) - - // Case 1 - Download of syft installation file failed - certClient.errorMessage = "Download failed" - err := runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient, fileUtils) - assert.Error(t, err) - assert.Contains(t, fmt.Sprint(err), certClient.errorMessage) - - // Case 2 - Installation of syft failed, using new kanikoMockClient here - certClient1 := &kanikoMockClient{} - shellRunner.ShouldFailOnCommand = map[string]error{"cat ./install.sh | sh -s -- -b .": fmt.Errorf("install failed")} - err = runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner, certClient1, fileUtils) - assert.Error(t, err) - assert.Contains(t, fmt.Sprint(err), "failed to install syft") - - // Case 3 syft run failed, using new ShellMockRunner here - shellRunner1 := &mock.ShellMockRunner{} - shellRunner1.ShouldFailOnCommand = map[string]error{"./syft index.docker.io/myImage:tag -o cyclonedx-xml=bom-docker-0.xml": fmt.Errorf("run failed")} - err = runKanikoExecute(config, &telemetry.CustomData{}, &commonPipelineEnvironment, execRunner, shellRunner1, certClient1, fileUtils) - assert.Error(t, err) - assert.Contains(t, fmt.Sprint(err), "failed to generate SBOM") - }) } diff --git a/cmd/whitesourceExecuteScan_generated.go b/cmd/whitesourceExecuteScan_generated.go index 2f5a5e2f2b..467c801865 100644 --- a/cmd/whitesourceExecuteScan_generated.go +++ b/cmd/whitesourceExecuteScan_generated.go @@ -162,12 +162,13 @@ func (p *whitesourceExecuteScanReports) persist(stepConfig whitesourceExecuteSca log.Entry().Info("Uploading reports to Google Cloud Storage...") content := []gcs.ReportOutputParam{ {FilePattern: "**/whitesource-ip.json", ParamRef: "", StepResultType: "whitesource-ip"}, - {FilePattern: "whitesource-riskReport.pdf", ParamRef: "", StepResultType: "whitesource-ip"}, + {FilePattern: "**/whitesource-riskReport.pdf", ParamRef: "", StepResultType: "whitesource-ip"}, {FilePattern: "**/toolrun_whitesource_*.json", ParamRef: "", StepResultType: "whitesource-ip"}, {FilePattern: "**/piper_whitesource_vulnerability_report.html", ParamRef: "", StepResultType: "whitesource-security"}, - {FilePattern: "whitesource-riskReport.pdf", ParamRef: "", StepResultType: "whitesource-security"}, + {FilePattern: "**/whitesource-riskReport.pdf", ParamRef: "", StepResultType: "whitesource-security"}, {FilePattern: "**/toolrun_whitesource_*.json", ParamRef: "", StepResultType: "whitesource-security"}, {FilePattern: "**/piper_whitesource_vulnerability.sarif", ParamRef: "", StepResultType: "whitesource-security"}, + {FilePattern: "**/piper_whitesource_sbom.xml", ParamRef: "", StepResultType: "whitesource-security"}, } envVars := []gcs.EnvVar{ {Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: gcpJsonKeyFilePath, Modified: false}, @@ -994,12 +995,13 @@ func whitesourceExecuteScanMetadata() config.StepData { Type: "reports", Parameters: []map[string]interface{}{ {"filePattern": "**/whitesource-ip.json", "type": "whitesource-ip"}, - {"filePattern": "whitesource-riskReport.pdf", "type": "whitesource-ip"}, + {"filePattern": "**/whitesource-riskReport.pdf", "type": "whitesource-ip"}, {"filePattern": "**/toolrun_whitesource_*.json", "type": "whitesource-ip"}, {"filePattern": "**/piper_whitesource_vulnerability_report.html", "type": "whitesource-security"}, - {"filePattern": "whitesource-riskReport.pdf", "type": "whitesource-security"}, + {"filePattern": "**/whitesource-riskReport.pdf", "type": "whitesource-security"}, {"filePattern": "**/toolrun_whitesource_*.json", "type": "whitesource-security"}, {"filePattern": "**/piper_whitesource_vulnerability.sarif", "type": "whitesource-security"}, + {"filePattern": "**/piper_whitesource_sbom.xml", "type": "whitesource-security"}, }, }, }, diff --git a/documentation/docs/configuration.md b/documentation/docs/configuration.md index e412013dea..0c2d30e01e 100644 --- a/documentation/docs/configuration.md +++ b/documentation/docs/configuration.md @@ -141,8 +141,8 @@ service-key. The environment variable used is: `PIPER_ansHookServiceKey`. If Jenkins is used to run "Piper", you can use the Jenkins credential store to store the alert notification service service-key as a "Secret Text" -credential. Provide the credential id in the configuration file in the `hooks` -section as follows: +credential. Provide the credential ID in a custom defaults file +([described below](#custom-default-configuration)) as follows: ```yaml hooks: @@ -150,6 +150,8 @@ hooks: serviceKeyCredentialsId: 'my_ANS_Service_Key' ``` +!!! warning It is **not** possible to configure the above in the project configuration file, i.e. in `.pipeline/config.yaml` + #### Event template You can also create an event template in JSON format to overwrite diff --git a/documentation/docs/images/CICD_Piper.png b/documentation/docs/images/CICD_Piper.png new file mode 100644 index 0000000000..f1c9f25a90 Binary files /dev/null and b/documentation/docs/images/CICD_Piper.png differ diff --git a/documentation/docs/index.md b/documentation/docs/index.md index 13c3f81c17..6df52fad65 100644 --- a/documentation/docs/index.md +++ b/documentation/docs/index.md @@ -1,46 +1,51 @@ # Project "Piper" User Documentation -Continuous delivery is a method to develop software with short feedback cycles. -It is applicable to projects both for SAP BTP and SAP on-premise platforms. +Easily set up continuous delivery in your software development using SAP technologies. +Continuous delivery is a method to develop software with short feedback cycles. It is applicable to projects both on the SAP Business Technology Platform (BTP) and on SAP on-premise platforms. SAP implements tooling for continuous delivery in project "Piper". -The goal of project "Piper" is to substantially ease setting up continuous delivery in your project using SAP technologies. ## What you get -To get you started quickly, project "Piper" offers you the following artifacts: +To get started with project "Piper", you can choose from the following offerings: -* A set of ready-made Continuous Delivery pipelines for direct use in your project +* A set of predefined pipelines that build, test, and deploy your code changes + + You can choose between the following use cases: + * [ABAP Environment Pipeline](pipelines/abapEnvironment/introduction/) * [General Purpose Pipeline](stages/introduction/) -* [A shared library][piper-library] that contains reusable step implementations, which enable you to customize our preconfigured pipelines, or to even build your own customized ones -* A standalone [command line utility](cli) for Linux and a [GitHub Action](https://github.com/SAP/project-piper-action) - * Note: This version is still in early development. Feel free to use it and [provide feedback](https://github.com/SAP/jenkins-library/issues), but don't expect all the features of the Jenkins library -* A set of [Docker images][devops-docker-images] to setup a CI/CD environment in minutes using sophisticated life-cycle management + * [A shared library][piper-library] that contains reusable step implementations, which enable you to customize the preconfigured pipelines or to build your own ones, if necessary + * A standalone [command line utility](cli) for Linux and a [GitHub Action](https://github.com/SAP/project-piper-action) + **Note:** This version is still in early development and might not contain all features of the Jenkins library, yet. Feel free to use it and [provide feedback](https://github.com/SAP/jenkins-library/issues). + +* A set of [Docker images][devops-docker-images] to easily set up a CI/CD environment using sophisticated life-cycle management + +To find out which offering is right for you, we recommend you to look at the preconfigured pipelines first. In most cases, you don't need to build your own pipelines - you can use the ready-made ones and adapt them according to your needs, if necessary. + +If you don't need to care about the underlying infrastructure of your pipelines, you can use the [SAP Continuous Integration and Delivery](https://help.sap.com/docs/CONTINUOUS_DELIVERY) service on SAP BTP. It offers an easy, UI-guided way to set up continuous integration and delivery without hosting your own Jenkins instance. + + ![SAP CI/CD vs Project "Piper"](images/CICD_Piper.png "Solution Comparison") + +The support infrastructure for SAP Continuous Integration and Delivery is provided by SAP according to the Service Level Agreements (SLAs). Project "Piper" offers community support using GitHub issues and pull requests. Users are free to contribute to the repository independently. See [Contributing](https://github.com/SAP/jenkins-library/blob/master/.github/CONTRIBUTING.md). -To find out which offering is right for you, we recommend to look at the ready-made pipelines first. -In many cases, they should satisfy your requirements, and if this is the case, you don't need to build your own pipeline. +For more information about the CI/CD solutions offered by SAP, see [SAP Solutions for Continuous Integration and Delivery](https://help.sap.com/docs/CICD_OVERVIEW/8cacec64ed854b2a88e9a0973e0f97a2/e9fa320181124fa9808d4446a1bf69dd.html). -### The best-practice way: Ready-made pipelines +To learn more about the continuous integration and delivery offerings by SAP, see [Continuous Integration and Delivery by SAP](https://help.sap.com/docs/CICD_OVERVIEW) and [Continuous Integration and Delivery by SAP Learning Journey](https://help.sap.com/learning-journeys/b76f0b2e5d534c449c1f3b0fa84ab697). -**Are you building a standalone SAP BTP application, an application with the SAP Cloud SDK, or using the SAP Cloud Application Programming Model?<br>** -Then continue reading about our [general purpose pipeline](stages/introduction/), which supports various technologies and programming languages. +### The Best-Practice Way: Ready-Made Pipelines -Previously, project "Piper" included also the SAP Cloud SDK Pipeline designed specifically for SAP Cloud SDK and SAP Cloud Application Model (CAP) projects. -SAP Cloud SDK pipeline and its features are merged into the General Purpose Pipeline as of November 2020. -The reasoning as well as further information how to adopt the General Purpose Pipeline are described in our [guide](https://github.com/SAP/cloud-s4-sdk-pipeline/blob/master/gpp-guide.md). +Use the [general purpose pipeline](stages/introduction/) to build a standalone SAP BTP application or an SAP Cloud Application Programming Model application project. It supports various technologies and programming languages. -### The do-it-yourself way: Build with Library +### The Do-It-Yourself Way: Customized Pipelines -The shared library contains building blocks for your own pipeline, following our best practice Jenkins pipelines described in the Scenarios section. +The shared library contains building blocks for your own pipelines using Jenkins pipelines to implement best practice processes. For more information, see the **Scenarios** section from the navigation pane. The best practice pipelines are based on the general concepts of [Pipelines as Code, as introduced in Jenkins 2][jenkins-doc-pipelines]. -With that you have the power of the Jenkins community at hand to optimize your pipelines. +This way, you can optimize your pipelines with the help of the Jenkins community. -You can run the best practice Jenkins pipelines out of the box, take them as a -starting point for project-specific adaptations or implement your own pipelines -from scratch using the shared library. +You can run the best practice Jenkins pipelines out-of-the-box, use them for project-specific adaptations, or create your own pipelines from scratch using the shared library. -For an example, you might want to check out our ["Build and Deploy SAPUI5 or SAP Fiori Applications on SAP Business Technology Platform (SAP BTP) with Jenkins" scenario][piper-library-scenario]. +For an example, see the [Build and Deploy SAPUI5 or SAP Fiori Applications on SAP Business Technology Platform (SAP BTP) with Jenkins][piper-library-scenario] scenario. #### Extensibility diff --git a/documentation/docs/steps/ansSendEvent.md b/documentation/docs/steps/ansSendEvent.md new file mode 100644 index 0000000000..99532c1e8d --- /dev/null +++ b/documentation/docs/steps/ansSendEvent.md @@ -0,0 +1,67 @@ +# ${docGenStepName} + +## ${docGenDescription} + +The SAP Alert Notification service for SAP BTP allows users to define +certain delivery channels, for example, e-mail or triggering of HTTP +requests, to receive notifications from pipeline events. + +## Prerequisites + +A service-key credential from the alert notification service. + +## ${docGenParameters} + +## ${docGenConfiguration} + +## ${docJenkinsPluginDependencies} + +## Example + +Example configuration for the use in a `Jenkinsfile`. + +```groovy +ansSendEvent( + script: this, + ansServiceKeyCredentialsId: "myANSCredential", + eventType: "errorEvent", + severity: "ERROR", + category: "EXCEPTION", + subject: "Something went wrong", + body: "The details of what went wrong", + priority: 3, + tags: [ + myTag: "myValue", + yourTag: "yourValue" + ], + resourceName: "Test Pipeline", + resourceType: "My Pipeline", + resourceInstance: "myPipeline", + resourceTags: [ + myResourceTag: "a value" + ] +) +``` + +Example for the use in a YAML configuration file (such as `.pipeline/config.yaml`). + +```yaml +steps: + <...> + ansSendEvent: + ansServiceKeyCredentialsId: "myANSCredential", + eventType: "errorEvent", + severity: "ERROR", + category: "EXCEPTION", + subject: "Something went wrong", + body: "The details of what went wrong", + priority: 3, + tags: + myTag: "myValue", + yourTag: "yourValue", + resourceName: "Test Pipeline", + resourceType: "My Pipeline", + resourceInstance: "myPipeline", + resourceTags: + myResourceTag: "a value" +``` diff --git a/documentation/docs/steps/cnbBuild.md b/documentation/docs/steps/cnbBuild.md index c09362fd7f..90b610aa3d 100644 --- a/documentation/docs/steps/cnbBuild.md +++ b/documentation/docs/steps/cnbBuild.md @@ -45,7 +45,7 @@ This behavior can be overwritten by using the respective sections in [`project.t ```groovy cnbBuild( - script: script, + script: this, dockerConfigJsonCredentialsId: 'DOCKER_REGISTRY_CREDS', containerImageName: 'images/example', containerImageTag: 'v0.0.1', @@ -57,7 +57,7 @@ cnbBuild( ```groovy cnbBuild( - script: script, + script: this, dockerConfigJsonCredentialsId: 'DOCKER_REGISTRY_CREDS', dockerImage: 'paketobuildpacks/builder:base', containerImageName: 'images/example', @@ -70,7 +70,7 @@ cnbBuild( ```groovy cnbBuild( - script: script, + script: this, dockerConfigJsonCredentialsId: 'DOCKER_REGISTRY_CREDS', containerImageName: 'images/example', containerImageTag: 'v0.0.1', @@ -83,7 +83,7 @@ cnbBuild( ```groovy cnbBuild( - script: script, + script: this, dockerConfigJsonCredentialsId: 'DOCKER_REGISTRY_CREDS', containerImageName: 'images/example', containerImageTag: 'v0.0.1', diff --git a/documentation/docs/steps/neoDeploy.md b/documentation/docs/steps/neoDeploy.md index 2ff7ecf979..940a147af6 100644 --- a/documentation/docs/steps/neoDeploy.md +++ b/documentation/docs/steps/neoDeploy.md @@ -95,5 +95,5 @@ steps: invalidateCache: true portalLandscape: "cloudnwcportal" oauthCredentialId: <OAUTH_CREDENTIAL_ID> - siteId: <PORTAL_SITE_ID> # not required, if the default site is already set in the portal service (SAP Cloud Platform) + siteId: <PORTAL_SITE_ID> # not required, if the default site is already set in the portal service (SAP BTP) ``` diff --git a/documentation/mkdocs.yml b/documentation/mkdocs.yml index d2555ecfd7..47e8478a95 100644 --- a/documentation/mkdocs.yml +++ b/documentation/mkdocs.yml @@ -41,7 +41,7 @@ nav: - 'Release Stage': stages/release.md - 'Scenarios': - 'Build and Deploy Hybrid Applications with SAP Solution Manager': scenarios/changeManagement.md - - 'Build and Deploy SAPUI5/SAP Fiori Applications on SAP Cloud Platform': scenarios/ui5-sap-cp/Readme.md + - 'Build and Deploy SAPUI5/SAP Fiori Applications on SAP BTP': scenarios/ui5-sap-cp/Readme.md - 'Build and Deploy SAP Cloud Application Programming Model Applications': scenarios/CAP_Scenario.md - 'Integrate SAP Cloud Transport Management Into Your CI/CD Pipeline': scenarios/TMS_Extension.md - 'Build and Deploy SAP Fiori Applications on SAP HANA Extended Application Services, Advanced Model': scenarios/xsa-deploy/Readme.md diff --git a/go.mod b/go.mod index 8f90f69ae1..d53661c45e 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.0 github.com/Jeffail/gabs/v2 v2.6.1 github.com/Masterminds/sprig v2.22.0+incompatible - github.com/anchore/syft v0.53.4 github.com/antchfx/htmlquery v1.2.4 github.com/aws/aws-sdk-go-v2/config v1.15.10 github.com/aws/aws-sdk-go-v2/service/s3 v1.26.3 @@ -66,14 +65,6 @@ require ( mvdan.cc/xurls/v2 v2.4.0 ) -require ( - github.com/dnaeon/go-vcr v1.2.0 // indirect - github.com/emicklei/go-restful/v3 v3.8.0 // indirect - github.com/google/gnostic v0.5.7-v3refs // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect -) - require ( cloud.google.com/go v0.102.0 // indirect cloud.google.com/go/compute v1.7.0 // indirect @@ -101,19 +92,13 @@ require ( github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/semver/v3 v3.1.1 // indirect - github.com/Masterminds/sprig/v3 v3.2.2 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect github.com/Microsoft/hcsshim v0.9.3 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5 // indirect github.com/StackExchange/wmi v1.2.1 // indirect - github.com/acobaugh/osrelease v0.1.0 // indirect github.com/acomagu/bufpipe v1.0.3 // indirect github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190620160927-9418d7b0cd0f // indirect - github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb // indirect - github.com/anchore/packageurl-go v0.1.1-0.20220428202044-a072fa3cb6d7 // indirect - github.com/anchore/stereoscope v0.0.0-20220803153229-c55b13fee7e4 // indirect - github.com/andybalholm/brotli v1.0.4 // indirect github.com/antchfx/xpath v1.2.0 // indirect github.com/armon/go-metrics v0.3.10 // indirect github.com/armon/go-proxyproto v0.0.0-20210323213023-7e956b284f0a // indirect @@ -136,33 +121,35 @@ require ( github.com/aws/smithy-go v1.11.3 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect - github.com/bmatcuk/doublestar/v4 v4.0.2 // indirect github.com/buildpacks/imgutil v0.0.0-20211001201950-cf7ae41c3771 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible // indirect github.com/circonus-labs/circonusllhist v0.1.3 // indirect github.com/containerd/cgroups v1.0.3 // indirect github.com/containerd/containerd v1.6.6 // indirect github.com/containerd/stargz-snapshotter/estargz v0.11.4 // indirect + github.com/coreos/go-oidc/v3 v3.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba // indirect github.com/digitalocean/godo v1.7.5 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/dnaeon/go-vcr v1.2.0 // indirect github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/docker v20.10.17+incompatible // indirect github.com/docker/docker-credential-helpers v0.6.4 // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.4.0 // indirect - github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect - github.com/dustin/go-humanize v1.0.0 // indirect + github.com/emicklei/go-restful/v3 v3.8.0 // indirect github.com/emirpasic/gods v1.12.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/facebookincubator/nvdtools v0.1.4 // indirect github.com/fatih/color v1.13.0 // indirect + github.com/frankban/quicktest v1.14.3 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/gabriel-vasile/mimetype v1.4.0 // indirect github.com/go-errors/errors v1.4.1 // indirect github.com/go-git/gcfg v1.5.0 // indirect @@ -176,15 +163,16 @@ require ( github.com/go-openapi/spec v0.20.6 // indirect github.com/go-openapi/swag v0.21.1 // indirect github.com/go-openapi/validate v0.22.0 // indirect - github.com/go-restruct/restruct v1.2.0-alpha // indirect github.com/go-sql-driver/mysql v1.5.0 // indirect github.com/go-test/deep v1.0.8 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang-jwt/jwt/v4 v4.3.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.0.1 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-metrics-stackdriver v0.2.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -234,17 +222,14 @@ require ( github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f // indirect github.com/jefferai/jsonx v1.0.0 // indirect - github.com/jinzhu/copier v0.3.2 // indirect + github.com/jhump/protoreflect v1.10.3 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect github.com/keybase/go-crypto v0.0.0-20190403132359-d65b6b94177f // indirect github.com/klauspost/compress v1.15.4 // indirect - github.com/klauspost/pgzip v1.2.5 // indirect - github.com/knqyf263/go-rpmdb v0.0.0-20220629110411-9a3bd2ebb923 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/lib/pq v1.10.6 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect @@ -253,16 +238,12 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect - github.com/mattn/go-runewidth v0.0.13 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect - github.com/mholt/archiver/v3 v3.5.1 // indirect - github.com/microsoft/go-rustaudit v0.0.0-20220730194248-4b17361d90a5 // indirect github.com/miekg/dns v1.1.41 // indirect github.com/mitchellh/cli v1.1.2 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.0 // indirect - github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/locker v1.0.1 // indirect github.com/moby/sys/mount v0.2.0 // indirect @@ -273,11 +254,11 @@ require ( github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 // indirect - github.com/nwaples/rardecode v1.1.2 // indirect github.com/oklog/run v1.1.0 // indirect github.com/oklog/ulid v1.3.1 // indirect - github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/onsi/ginkgo v1.16.5 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 // indirect github.com/opencontainers/runc v1.1.2 // indirect @@ -289,7 +270,6 @@ require ( github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect - github.com/pierrec/lz4/v4 v4.1.8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/posener/complete v1.2.3 // indirect github.com/prometheus/client_golang v1.12.2 // indirect @@ -297,39 +277,23 @@ require ( github.com/prometheus/common v0.34.0 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/rboyer/safeio v0.2.1 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 // indirect github.com/richardlehane/mscfb v1.0.3 // indirect github.com/richardlehane/msoleps v1.0.1 // indirect - github.com/rivo/uniseg v0.2.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/sasha-s/go-deadlock v0.2.0 // indirect - github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e // indirect github.com/sergi/go-diff v1.2.0 // indirect github.com/sethvargo/go-limiter v0.7.1 // indirect github.com/shirou/gopsutil v3.21.5+incompatible // indirect - github.com/shopspring/decimal v1.2.0 // indirect github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d // indirect - github.com/spdx/tools-golang v0.2.0 // indirect - github.com/spf13/afero v1.8.2 // indirect - github.com/spf13/cast v1.5.0 // indirect github.com/stretchr/objx v0.4.0 // indirect - github.com/sylabs/sif/v2 v2.7.0 // indirect - github.com/sylabs/squashfs v0.5.5-0.20220803150326-9393a0b4cef5 // indirect github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible // indirect - github.com/therootcompany/xz v1.0.1 // indirect github.com/tklauser/go-sysconf v0.3.9 // indirect github.com/tklauser/numcpus v0.3.0 // indirect github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c // indirect - github.com/ulikunitz/xz v0.5.10 // indirect - github.com/vbatts/go-mtree v0.5.0 // indirect github.com/vbatts/tar-split v0.11.2 // indirect - github.com/vifraa/gopom v0.1.0 // indirect github.com/vmware/govmomi v0.18.0 // indirect - github.com/wagoodman/go-partybus v0.0.0-20210627031916-db1f5573bbc5 // indirect - github.com/wagoodman/go-progress v0.0.0-20200731105512-1020f39e6240 // indirect github.com/xanzy/ssh-agent v0.3.0 // indirect - github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 // indirect go.etcd.io/bbolt v1.3.6 // indirect @@ -343,7 +307,6 @@ require ( golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect - golang.org/x/tools v0.1.10 // indirect golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f // indirect @@ -361,16 +324,6 @@ require ( k8s.io/klog/v2 v2.60.1 // indirect k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 // indirect k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect - lukechampine.com/uint128 v1.1.1 // indirect - modernc.org/cc/v3 v3.36.0 // indirect - modernc.org/ccgo/v3 v3.16.6 // indirect - modernc.org/libc v1.16.7 // indirect - modernc.org/mathutil v1.4.1 // indirect - modernc.org/memory v1.1.1 // indirect - modernc.org/opt v0.1.1 // indirect - modernc.org/sqlite v1.17.3 // indirect - modernc.org/strutil v1.1.1 // indirect - modernc.org/token v1.0.0 // indirect oras.land/oras-go v1.2.0 // indirect sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect sigs.k8s.io/kustomize/api v0.11.4 // indirect diff --git a/go.sum b/go.sum index 95baccaf87..5831014cb1 100644 --- a/go.sum +++ b/go.sum @@ -7,7 +7,6 @@ cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSR cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -21,7 +20,6 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= @@ -72,7 +70,6 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cloud.google.com/go/storage v1.22.1 h1:F6IlQJZrZM++apn9V5/VfS3gbTUYg98PS3EMQAzqtfg= cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f h1:UrKzEwTgeiff9vxdrfdqxibzpWjxLnuXDI5m6z3GJAk= @@ -160,8 +157,6 @@ github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CalebQ42/GoAppImage v0.5.0 h1:znoKNXtliH754tS9sYwyOIg/0wFDjFN5Twc7PAh1rSM= -github.com/CalebQ42/GoAppImage v0.5.0/go.mod h1:qHudJKAn/dlkNWNnH4h1YKXp29EZ7Bppsn7sNP2HuvU= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/CycloneDX/cyclonedx-go v0.6.0 h1:SizWGbZzFTC/O/1yh072XQBMxfvsoWqd//oKCIyzFyE= @@ -170,7 +165,6 @@ github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3 github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= -github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible/go.mod h1:BB1eHdMLYEFuFdBlRMb0N7YGVdM5s6Pt0njxgvfbGGs= github.com/Jeffail/gabs v1.1.1 h1:V0uzR08Hj22EX8+8QMhyI9sX2hwRu+/RJhJUmnwda/E= github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/Jeffail/gabs/v2 v2.6.1 h1:wwbE6nTQTwIMsMxzi6XFQQYRZ6wDc1mSdxoAN+9U4Gk= @@ -187,8 +181,6 @@ github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0 github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= -github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= @@ -198,7 +190,6 @@ github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JP github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= @@ -209,7 +200,6 @@ github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2 github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= -github.com/Microsoft/hcsshim v0.8.24/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= github.com/Microsoft/hcsshim v0.9.3 h1:k371PzBuRrz2b+ebGuI2nVgVhgsVX60jMfSw80NECxo= github.com/Microsoft/hcsshim v0.9.3/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= @@ -236,13 +226,8 @@ github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDO github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af h1:DBNMBMuMiWYu0b+8KMJuWmfCkcxl09JwdlqwDZZ6U14= github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= -github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE= -github.com/acobaugh/osrelease v0.1.0/go.mod h1:4bFEs0MtgHNHBrmHCt67gNisnabCRAlzdVasCEGHTWY= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= -github.com/adrg/xdg v0.2.2/go.mod h1:7I2hH/IT30IsupOpKZ5ue7/qNi3CoKzD6tL3HwpaRMQ= -github.com/adrg/xdg v0.3.3 h1:s/tV7MdqQnzB1nKY8aqHvAMD+uCiuEDzVB5HLRY849U= -github.com/adrg/xdg v0.3.3/go.mod h1:61xAR2VZcggl2St4O9ohF5qCKe08+JDmE4VNzPFQvOQ= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -255,22 +240,9 @@ github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cv github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190620160927-9418d7b0cd0f h1:oRD16bhpKNAanfcDDVU+J0NXqsgHIvGbbe/sy+r6Rs0= github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190620160927-9418d7b0cd0f/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ= github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= -github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb h1:iDMnx6LIjtjZ46C0akqveX83WFzhpTD3eqOthawb5vU= -github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb/go.mod h1:DmTY2Mfcv38hsHbG78xMiTDdxFtkHpgYNVDPsF2TgHk= -github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0vW0nnNKJfJieyH/TZ9UYAnTZs5/gHTdAe8= -github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ= -github.com/anchore/packageurl-go v0.1.1-0.20220428202044-a072fa3cb6d7 h1:kDrYkTSM9uIxaX/P9s0F4nKYNM+hnSgLJdLpqvsaQ/g= -github.com/anchore/packageurl-go v0.1.1-0.20220428202044-a072fa3cb6d7/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4= -github.com/anchore/stereoscope v0.0.0-20220803153229-c55b13fee7e4 h1:OMc0B7MxfjfqagdgboPFVJzsDJbFk7J7NXhgTTnhvuo= -github.com/anchore/stereoscope v0.0.0-20220803153229-c55b13fee7e4/go.mod h1:90tB0wMdDe2V8fB52tPf1xjg/ieLoWayRu8YJNd9c7w= -github.com/anchore/syft v0.53.4 h1:tRiKa8ZL2FpDzzrcBHms4E6lgsmOkVbITrlcM35aKc0= -github.com/anchore/syft v0.53.4/go.mod h1:Ms14EskPVOazbPO1j38sxR8kki0uL13xzV5fcuoQDBY= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antchfx/htmlquery v1.2.4 h1:qLteofCMe/KGovBI6SQgmou2QNyedFUW+pE+BpeZ494= @@ -318,19 +290,15 @@ github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZve github.com/aws/aws-sdk-go v1.36.30/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.37.19 h1:/xKHoSsYfH9qe16pJAHIjqTVpMM2DRSsEt8Ok1bzYiw= github.com/aws/aws-sdk-go v1.37.19/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go-v2 v1.7.1/go.mod h1:L5LuPC1ZgDr2xQS7AmIec/Jlc7O/Y1u2KxJyNVab250= github.com/aws/aws-sdk-go-v2 v1.16.2/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU= github.com/aws/aws-sdk-go-v2 v1.16.5 h1:Ah9h1TZD9E2S1LzHpViBO3Jz9FPL5+rmflmb8hXirtI= github.com/aws/aws-sdk-go-v2 v1.16.5/go.mod h1:Wh7MEsmEApyL5hrWzpDkba4gwAPc5/piwLVLFnCxp48= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1 h1:SdK4Ppk5IzLs64ZMvr6MrSficMtjY2oS0WOORXTlxwU= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1/go.mod h1:n8Bs1ElDD2wJ9kCRTczA83gYbBmjSwZp3umc6zF4EeM= -github.com/aws/aws-sdk-go-v2/config v1.5.0/go.mod h1:RWlPOAW3E3tbtNAqTwvSW54Of/yP3oiZXMI0xfUdjyA= github.com/aws/aws-sdk-go-v2/config v1.15.10 h1:0HSMRNGlR0/WlGbeKC9DbBphBwRIK5H4cKUbgqNTKcA= github.com/aws/aws-sdk-go-v2/config v1.15.10/go.mod h1:XL4DzwzWdwXBzKdwMdpLkMIaGEQCYRQyzA4UnJaUnNk= -github.com/aws/aws-sdk-go-v2/credentials v1.3.1/go.mod h1:r0n73xwsIVagq8RsxmZbGSRQFj9As3je72C2WzUIToc= github.com/aws/aws-sdk-go-v2/credentials v1.12.5 h1:WNNCUTWA0vyMy5t8LfS4iB7QshsW0DsHS/VdhyCGZWM= github.com/aws/aws-sdk-go-v2/credentials v1.12.5/go.mod h1:DOcdLlkqUiNGyXnjWgspC3eIAdXhj8q0pO1LiSvrTI4= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.3.0/go.mod h1:2LAuqPx1I6jNfaGDucWfA2zqQCYCOMCDHiCOciALyNw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.6 h1:+NZzDh/RpcQTpo9xMFUgkseIam6PC+YJbdhbQp1NOXI= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.6/go.mod h1:ClLMcuQA/wcHPmOIfNzNI4Y1Q0oDbmEkbYhMFOzHDh8= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.4.0 h1:Iqp2aHeRF3kaaNuDS82bHBzER285NM6lLPAgsxHCR2A= @@ -340,16 +308,12 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12/go.mod h1:Afj/U8svX6 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3/go.mod h1:ssOhaLpRlh88H3UmEcsBoVKq309quMvm3Ds8e9d4eJM= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6 h1:eeXdGVtXEe+2Jc49+/vAzna3FAQnUD4AagAw8tzbmfc= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6/go.mod h1:FwpAKI+FBPIELJIdmQzlLtRe8LQSOreMcM2wBsPMvvc= -github.com/aws/aws-sdk-go-v2/internal/ini v1.1.1/go.mod h1:Zy8smImhTdOETZqfyn01iNOe0CNggVbPjCajyaz6Gvg= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.13 h1:L/l0WbIpIadRO7i44jZh1/XeXpNDX0sokFppb4ZnXUI= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.13/go.mod h1:hiM/y1XPp3DoEPhoVEYc/CZcS58dP6RKJRDFp99wdX0= -github.com/aws/aws-sdk-go-v2/service/ecr v1.4.1/go.mod h1:FglZcyeiBqcbvyinl+n14aT/EWC7S1MIH+Gan2iizt0= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.4.1/go.mod h1:eD5Eo4drVP2FLTw0G+SMIPWNWvQRGGTtIZR2XeAagoA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1 h1:T4pFel53bkHjL2mMo+4DKE6r6AuoZnM0fg7k1/ratr4= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1/go.mod h1:GeUru+8VzrTXV/83XyMJ80KpH8xO89VPoUileyNQ+tc= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.3 h1:I0dcwWitE752hVSMrsLCxqNQ+UdEp3nACx2bYNMQq+k= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.3/go.mod h1:Seb8KNmD6kVTjwRjVEgOT5hPin6sq+v4C2ycJQDwuH8= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.2.1/go.mod h1:zceowr5Z1Nh2WVP8bf/3ikB41IZW59E4yIYbg+pC6mw= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.3/go.mod h1:wlY6SVjuwvh3TVRpTqdy4I1JpBFLX4UGeKZdWntaocw= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.6 h1:0ZxYAZ1cn7Swi/US55VKciCE6RhRHIwCKIWaMLdT6pg= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.6/go.mod h1:DxAPjquoEHf3rUHh1b9+47RAaXB8/7cB6jkzCt/GOEI= @@ -357,17 +321,13 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.3 h1:BKjwCJPnANbkwQ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.3/go.mod h1:Bm/v2IaN6rZ+Op7zX+bOUMdL4fsrYZiD0dsjLhNKwZc= github.com/aws/aws-sdk-go-v2/service/s3 v1.26.3 h1:rMPtwA7zzkSQZhhz9U3/SoIDz/NZ7Q+iRn4EIO8rSyU= github.com/aws/aws-sdk-go-v2/service/s3 v1.26.3/go.mod h1:g1qvDuRsJY+XghsV6zg00Z4KJ7DtFFCx8fJD2a491Ak= -github.com/aws/aws-sdk-go-v2/service/sso v1.3.1/go.mod h1:J3A3RGUvuCZjvSuZEcOpHDnzZP/sKbhDWV2T1EOzFIM= github.com/aws/aws-sdk-go-v2/service/sso v1.11.8 h1:GNIdO14AHW5CgnzMml3Tg5Fy/+NqPQvnh1HsC1zpcPo= github.com/aws/aws-sdk-go-v2/service/sso v1.11.8/go.mod h1:UqRD9bBt15P0ofRyDZX6CfsIqPpzeHOhZKWzgSuAzpo= -github.com/aws/aws-sdk-go-v2/service/sts v1.6.0/go.mod h1:q7o0j7d7HrJk/vr9uUt3BVRASvcU7gYZB9PUgPiByXg= github.com/aws/aws-sdk-go-v2/service/sts v1.16.7 h1:HLzjwQM9975FQWSF3uENDGHT1gFQm/q3QXu2BYIcI08= github.com/aws/aws-sdk-go-v2/service/sts v1.16.7/go.mod h1:lVxTdiiSHY3jb1aeg+BBFtDzZGSUCv6qaNOyEGCJ1AY= -github.com/aws/smithy-go v1.6.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= github.com/aws/smithy-go v1.11.3 h1:DQixirEFM9IaKxX1olZ3ke3nvxRS2xMDteKIDWxozW8= github.com/aws/smithy-go v1.11.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220517224237-e6f29200ae04/go.mod h1:Z+bXnIbhKJYSvxNwsNnwde7pDKxuqlEZCbUBoTwAqf0= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= @@ -388,8 +348,6 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/blizzy78/varnamelen v0.3.0/go.mod h1:hbwRdBvoBqxk34XyQ6HA0UH3G0/1TKuv5AC4eaBT0Ec= github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0= github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= -github.com/bmatcuk/doublestar/v4 v4.0.2 h1:X0krlUVAVmtr2cRoTqR8aDMrDqnB36ht8wpWTiQ3jsA= -github.com/bmatcuk/doublestar/v4 v4.0.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bndr/gojenkins v1.1.1-0.20210520222939-90ed82bfdff6 h1:yHK3nXjSRklq0SWhK6KW6kJtTebTUvVxN3gPmUtoVJ4= github.com/bndr/gojenkins v1.1.1-0.20210520222939-90ed82bfdff6/go.mod h1:QeskxN9F/Csz0XV/01IC8y37CapKKWvOHa0UHLLX1fM= @@ -422,6 +380,7 @@ github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTx github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/centrify/cloud-golang-sdk v0.0.0-20210923165758-a8c48d049166 h1:jQ93fKqb/wRmK/KiHpa7Tk9rmHeKXhp4j+5Sg/tENiY= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -492,7 +451,6 @@ github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMX github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= @@ -500,7 +458,6 @@ github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoT github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= github.com/containerd/containerd v1.5.2/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= -github.com/containerd/containerd v1.5.13/go.mod h1:3AlCrzKROjIuP3JALsY14n8YtntaUDBu7vek+rPN5Vc= github.com/containerd/containerd v1.6.6 h1:xJNPhbrmz8xAMDNoVjHy9YHtWwEQNS+CDkcIRh7t8Y0= github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= @@ -534,7 +491,6 @@ github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oM github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM= github.com/containerd/stargz-snapshotter/estargz v0.6.4/go.mod h1:83VWDqHnurTKliEB0YvWMiCfLDwv4Cjj1X9Vk98GJZw= -github.com/containerd/stargz-snapshotter/estargz v0.10.0/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0= github.com/containerd/stargz-snapshotter/estargz v0.11.4 h1:LjrYUZpyOhiSaU7hHrdR82/RBoxfGWSaC0VeSSMXqnk= github.com/containerd/stargz-snapshotter/estargz v0.11.4/go.mod h1:7vRJIcImfY8bpifnMjt+HTJoQxASq7T28MYbP15/Nf0= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= @@ -569,6 +525,7 @@ github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmeka github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc/v3 v3.2.0 h1:2eR2MGR7thBXSQ2YbODlF0fcmgtliLCfr9iX6RW11fc= +github.com/coreos/go-oidc/v3 v3.2.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -628,14 +585,11 @@ github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v20.10.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/cli v20.10.10+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/cli v20.10.12+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M= github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.8.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= @@ -644,7 +598,6 @@ github.com/docker/docker v20.10.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05b github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.8+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.10+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE= github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= @@ -665,12 +618,8 @@ github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arX github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= -github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= -github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74 h1:2MIhn2R6oXQbgW5yHfS+d6YqyMfXiu2L55rFZC4UD/M= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= @@ -704,16 +653,12 @@ github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQL github.com/evanphx/json-patch/v5 v5.5.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/facebookincubator/nvdtools v0.1.4 h1:x1Ucw9+bSkMd8DJJN4jNQ1Lk4PSFlJarGOxp9D6WUMo= -github.com/facebookincubator/nvdtools v0.1.4/go.mod h1:0/FIVnSEl9YHXLq3tKBPpKaI0iUceDhdSHPlIwIX44Y= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA= -github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= @@ -726,10 +671,12 @@ github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E= @@ -888,8 +835,6 @@ github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4 github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSrdV7Nv3/gkvc= -github.com/go-restruct/restruct v1.2.0-alpha/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= @@ -959,6 +904,7 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= @@ -1004,7 +950,6 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -1047,7 +992,6 @@ github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/go-containerregistry v0.5.2-0.20210604130445-3bfab55f3bd9/go.mod h1:R5WRYyTdQqTchlBhX4q+WICGh8HQIL5wDFoFZv7Jq6Q= -github.com/google/go-containerregistry v0.7.0/go.mod h1:2zaoelrL0d08gGbpdP3LqyUuBmhWbpD6IOe2s9nLS2k= github.com/google/go-containerregistry v0.10.0 h1:qd/fv2nQajGZJenaNcdaghlwSPjQ0NphN9hzArr2WWg= github.com/google/go-containerregistry v0.10.0/go.mod h1:C7uwbB1QUAtvnknyd3ethxJRd4gtEjU/9WLXzckfI1Y= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= @@ -1079,7 +1023,6 @@ github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -1114,14 +1057,10 @@ github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3i github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gookit/color v1.2.5/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg= -github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20210420193930-a4630ec28c79/go.mod h1:Opf9rtYVq0eTyX+aRVmRO9hE8ERAozcdrBxWG9Q6mkQ= github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gordonklaus/ineffassign v0.0.0-20210225214923-2e10b2664254/go.mod h1:M9mZEtGIsR1oDaZagNPNG9iq9n2HrhZ17dsXk73V3Lw= github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= @@ -1338,7 +1277,6 @@ github.com/heroku/color v0.0.6/go.mod h1:ZBvOcx7cTF2QKOv4LbmoBtNl5uB17qWxGuzZrsi github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huaweicloud/golangsdk v0.0.0-20200304081349-45ec0797f2a4/go.mod h1:WQBcHRNX9shz3928lWEvstQJtAtYI7ks6XlgtRT9Tcw= @@ -1390,9 +1328,8 @@ github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7H github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= github.com/jhump/protoreflect v1.10.3 h1:8ogeubpKh2TiulA0apmGlW5YAH4U1Vi4TINIP+gpNfQ= +github.com/jhump/protoreflect v1.10.3/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= -github.com/jinzhu/copier v0.3.2 h1:QdBOCbaouLDYaIPFfi1bKv5F5tPpeTwXe4sD0jqtz5w= -github.com/jinzhu/copier v0.3.2/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -1439,8 +1376,6 @@ github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYb github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= @@ -1451,13 +1386,10 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.6.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.0/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= @@ -1466,12 +1398,7 @@ github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.4 h1:1kn4/7MepF/CHmYub99/nNX8az0IJjfSOU/jbnTVfqQ= github.com/klauspost/compress v1.15.4/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= -github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/knqyf263/go-rpmdb v0.0.0-20220629110411-9a3bd2ebb923 h1:lANQvsfy2FOuURL6vKO3T4gNpez/3xZt+dx6uWMD42I= -github.com/knqyf263/go-rpmdb v0.0.0-20220629110411-9a3bd2ebb923/go.mod h1:zp6SMcRd0GB+uwNJjr+DkrNZdQZ4er2HMO6KyD0vIGU= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -1513,8 +1440,6 @@ github.com/linode/linodego v0.7.1 h1:4WZmMpSA2NRwlPZcc0+4Gyn7rr99Evk9bnr0B3gXRKE github.com/linode/linodego v0.7.1/go.mod h1:ga11n3ivecUrPCHN0rANxKmfWBJVkOXfLMZinAbj2sY= github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs= -github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -1572,13 +1497,9 @@ github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0= -github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= @@ -1589,14 +1510,10 @@ github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= github.com/mgechev/revive v1.1.2/go.mod h1:bnXsMr+ZTH09V5rssEI+jHAZ4z+ZdyhgO/zsy3EhK+0= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= -github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= github.com/michaelklishin/rabbit-hole/v2 v2.12.0 h1:946p6jOYFcVJdtBBX8MwXvuBkpPjwm1Nm2Qg8oX+uFk= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5 h1:YH424zrwLTlyHSH/GzLMJeu5zhYVZSx5RQxGKm1h96s= github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5/go.mod h1:PoGiBqKSQK1vIfQ+yVaFcGjDySHvym6FM1cNYnwzbrY= -github.com/microsoft/go-rustaudit v0.0.0-20220730194248-4b17361d90a5 h1:tQRHcLQwnwrPq2j2Qra/NnyjyESBGwdeBeVdAE9kXYg= -github.com/microsoft/go-rustaudit v0.0.0-20220730194248-4b17361d90a5/go.mod h1:vYT9HE7WCvL64iVeZylKmCsWKfE+JZ8105iuh2Trk8g= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= @@ -1622,8 +1539,6 @@ github.com/mitchellh/go-testing-interface v1.14.0 h1:/x0XQ6h+3U3nAyk1yx+bHPURrKa github.com/mitchellh/go-testing-interface v1.14.0/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= -github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -1695,17 +1610,13 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= -github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= -github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 h1:BQ1HW7hr4IVovMwWg0E0PYcyW8CzqDcVmaew9cujU4s= github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nishanths/exhaustive v0.2.3/go.mod h1:bhIX678Nx8inLM9PbpvK1yv6oGtoP8BfaIeMzgBNKvc= github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ= +github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= github.com/nishanths/predeclared v0.2.1/go.mod h1:HvkGJcA3naj4lOwnFXFDkFxVtSqQMB9sbB1usJ+xjQE= -github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= -github.com/nwaples/rardecode v1.1.2 h1:Cj0yZY6T1Zx1R7AhTbyGSALm44/Mmq+BAPc4B/p/d3M= -github.com/nwaples/rardecode v1.1.2/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -1719,7 +1630,6 @@ github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:v github.com/olekukonko/tablewriter v0.0.0-20180130162743-b8a9be070da4/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -1753,8 +1663,6 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.2-0.20210730191737-8e42a01fb1b7/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 h1:+czc/J8SlhPKLOtVLMQc+xDCFBT73ZStMsRhSsUhsSg= github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198/go.mod h1:j4h1pJW6ZcJTgMZWP3+7RlG3zTaP02aDZ/Qw0sppK7Q= github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= @@ -1818,10 +1726,7 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pierrec/lz4/v4 v4.1.6/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.8 h1:ieHkV+i2BRzngO4Wd/3HGowuZStgq6QkPsD1eolNAO4= -github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/piper-validation/fortify-client-go v0.0.0-20220126145513-7b3e9a72af01 h1:eGWtA25A6ryV+I2wHt0iE+i6euveKwbCi9d87RZu0fA= @@ -1834,7 +1739,6 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -1902,16 +1806,12 @@ github.com/quasilyte/go-ruleguard/rules v0.0.0-20210428214800-545e0d2e0bf7/go.mo github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/rboyer/safeio v0.2.1 h1:05xhhdRNAdS3apYm7JRjOqngf4xruaW959jmRxGDuSU= github.com/rboyer/safeio v0.2.1/go.mod h1:Cq/cEPK+YXFn622lsQ0K4KsPZSPtaptHHEldsy7Fmig= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 h1:Wdi9nwnhFNAlseAOekn6B5G/+GMtks9UKbvRU/CMM/o= github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU= github.com/richardlehane/mscfb v1.0.3 h1:rD8TBkYWkObWO0oLDFCbwMeZ4KoalxQy+QgniCj3nKI= github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk= github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o= github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -1948,14 +1848,10 @@ github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtm github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8= github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM= -github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ= -github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs= github.com/sean-/conswriter v0.0.0-20180208195008-f5ae3917a627/go.mod h1:7zjs06qF79/FKAJpBvFx3P8Ww4UTIMAe+lpNXDHziac= github.com/sean-/pager v0.0.0-20180208200047-666be9bf53b5/go.mod h1:BeybITEsBEg6qbIiqJ6/Bqeq25bCLbL7YFmpaFfJDuM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y= -github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/securego/gosec/v2 v2.9.1/go.mod h1:oDcDLcatOJxkCGaCaq8lua1jTnYf6Sou4wdiJ1n4iHc= @@ -1970,17 +1866,12 @@ github.com/shirou/gopsutil v3.21.5+incompatible h1:OloQyEerMi7JUrXiNzy8wQ5XN+bae github.com/shirou/gopsutil v3.21.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v3 v3.21.10/go.mod h1:t75NhzCZ/dYyPQjyQmrAYP6c8+LCdFANeBMdLPCNnew= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= -github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -1991,7 +1882,6 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic github.com/sivchari/tenv v1.4.7/go.mod h1:5nF+bITvkebQVanjU6IuMbvIot/7ReNsUV7I5NbprB0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= -github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -2003,20 +1893,13 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM= -github.com/spdx/tools-golang v0.2.0 h1:KBNcw7xvVycRWeCWZK/5xQJA+plymW1+rTCs8ekJDro= -github.com/spdx/tools-golang v0.2.0/go.mod h1:RO4Y3IFROJnz+43JKm1YOrbtgQNljW4gAPpA/sY2eqo= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= -github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= @@ -2061,10 +1944,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/sylabs/sif/v2 v2.7.0 h1:VFzN8alnJ/3n1JA0K9DyUtfSzezWgWrzLDcYGhgBskk= -github.com/sylabs/sif/v2 v2.7.0/go.mod h1:TiyBWsgWeh5yBeQFNuQnvROwswqK7YJT8JA1L53bsXQ= -github.com/sylabs/squashfs v0.5.5-0.20220803150326-9393a0b4cef5 h1:OfmBgc/n/FAKrtK5TEkX2sqQo5zMBb/4EFEQQAKKrro= -github.com/sylabs/squashfs v0.5.5-0.20220803150326-9393a0b4cef5/go.mod h1:lGupCIjaVP476d0G7UppFr3h123OsNLGRCtm6rgwPwA= github.com/sylvia7788/contextcheck v1.0.4/go.mod h1:vuPKJMQ7MQ91ZTqfdyreNKwZjyUg6KO+IebVyQDedZQ= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -2079,8 +1958,6 @@ github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1: github.com/testcontainers/testcontainers-go v0.10.0 h1:ASWe0nwTNg5z8K3WSQ8aBNB6j5vrNJocFPEZF4NS0qI= github.com/testcontainers/testcontainers-go v0.10.0/go.mod h1:zFYk0JndthnMHEwtVRHCpLwIP/Ik1G7mvIAQ2MdZ+Ig= github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= -github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= -github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= @@ -2107,10 +1984,6 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= -github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -2128,13 +2001,9 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/vbatts/go-mtree v0.5.0 h1:dM+5XZdqH0j9CSZeerhoN/tAySdwnmevaZHO1XGW2Vc= -github.com/vbatts/go-mtree v0.5.0/go.mod h1:7JbaNHyBMng+RP8C3Q4E+4Ca8JnGQA2R/MB+jb4tSOk= github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME= github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -github.com/vifraa/gopom v0.1.0 h1:v897eVxf6lflkEXzPmKbo4YhX2oS/LGjz7cqjWnSmCU= -github.com/vifraa/gopom v0.1.0/go.mod h1:oPa1dcrGrtlO37WPDBm5SqHAT+wTgF8An1Q71Z6Vv4o= github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= @@ -2144,12 +2013,6 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17 github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vmware/govmomi v0.18.0 h1:f7QxSmP7meCtoAmiKZogvVbLInT+CZx6Px6K5rYsJZo= github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= -github.com/wagoodman/go-partybus v0.0.0-20200526224238-eb215533f07d/go.mod h1:JPirS5jde/CF5qIjcK4WX+eQmKXdPc6vcZkJ/P0hfPw= -github.com/wagoodman/go-partybus v0.0.0-20210627031916-db1f5573bbc5 h1:phTLPgMRDYTizrBSKsNSOa2zthoC2KsJsaY/8sg3rD8= -github.com/wagoodman/go-partybus v0.0.0-20210627031916-db1f5573bbc5/go.mod h1:JPirS5jde/CF5qIjcK4WX+eQmKXdPc6vcZkJ/P0hfPw= -github.com/wagoodman/go-progress v0.0.0-20200621122631-1a2120f0695a/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA= -github.com/wagoodman/go-progress v0.0.0-20200731105512-1020f39e6240 h1:r6BlIP7CVZtMlxUQhT40h1IE1TzEgKVqwmsVGuscvdk= -github.com/wagoodman/go-progress v0.0.0-20200731105512-1020f39e6240/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= @@ -2169,12 +2032,9 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= -github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= -github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 h1:EpI0bqf/eX9SdZDwlMmahKM+CDBgNbsXMhsN28XrM8o= @@ -2213,8 +2073,6 @@ go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3C go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.lsp.dev/uri v0.3.0 h1:KcZJmh6nFIBeJzTugn5JTU6OOyG0lDOo3R9KwTxTYbo= -go.lsp.dev/uri v0.3.0/go.mod h1:P5sbO1IQR+qySTWOCnhnK7phBx+W3zbLqSMDJNTw88I= go.mongodb.org/atlas v0.13.0 h1:JkJOWsKm9k2mcFaivaaMNDpKDsxJJj1O0eUsDtnNvuE= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= @@ -2280,7 +2138,6 @@ golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -2294,7 +2151,6 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220314234716-a5774263c1e0 h1:VX5DDcOISmzJbt7ej5lyL1TxQc9dHTtNcTABzu1UsTw= @@ -2381,6 +2237,7 @@ golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -2412,7 +2269,6 @@ golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211111160137-58aab5ef257a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -2555,7 +2411,6 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2565,7 +2420,6 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2585,10 +2439,8 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2705,6 +2557,7 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -2714,6 +2567,7 @@ golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -2730,7 +2584,6 @@ golang.org/x/tools v0.0.0-20201028025901-8cd080b735b3/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201114224030-61ea331ec02b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201118003311-bd56c0adb394/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -2739,7 +2592,6 @@ golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= @@ -2750,8 +2602,6 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2863,9 +2713,7 @@ google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -2889,7 +2737,6 @@ google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEc google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211111162719-482062a4217b/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= @@ -2948,7 +2795,6 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= @@ -2967,6 +2813,7 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= @@ -2979,7 +2826,6 @@ gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= @@ -3105,41 +2951,6 @@ k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= layeh.com/radius v0.0.0-20190322222518-890bc1058917 h1:BDXFaFzUt5EIqe/4wrTc4AcYZWP6iC6Ult+jQWLh5eU= -lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU= -lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc/v3 v3.36.0 h1:0kmRkTmqNidmu3c7BNDSdVHCxXCkWLmWmCIVX4LUboo= -modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= -modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= -modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.6 h1:3l18poV+iUemQ98O3X5OMr97LOqlzis+ytivU4NqGhA= -modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= -modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= -modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= -modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= -modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= -modernc.org/libc v1.16.7 h1:qzQtHhsZNpVPpeCu+aMIQldXeV1P0vRhSqCL0nOIJOA= -modernc.org/libc v1.16.7/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= -modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8= -modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.1.1 h1:bDOL0DIDLQv7bWhP3gMvIrnoFw+Eo6F7a2QK9HPDiFU= -modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A= -modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.17.3 h1:iE+coC5g17LtByDYDWKpR6m2Z9022YrSh3bumwOnIrI= -modernc.org/sqlite v1.17.3/go.mod h1:10hPVYar9C0kfXuTWGz8s0XtB8uAGymUy51ZzStYe3k= -modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs= -modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= -modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao= -modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= -modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= -modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM= -modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= diff --git a/integration/docker_test_executor.go b/integration/docker_test_executor.go index fdde4e1731..87f944434f 100644 --- a/integration/docker_test_executor.go +++ b/integration/docker_test_executor.go @@ -188,7 +188,10 @@ func (d *IntegrationTestDockerExecRunner) whenRunningPiperCommand(command string args = append(args, "/piper-wrapper", "/piper", command) err := d.Runner.RunExecutable("docker", append(args, parameters...)...) if err != nil { - stdOut, err := d.getPiperOutput() + stdOut, outputErr := d.getPiperOutput() + if outputErr != nil { + return errors.Wrap(outputErr, "unable to get output after Piper command failure") + } return errors.Wrapf(err, "piper output: \n%s", stdOut.String()) } return err diff --git a/integration/integration_cnb_test.go b/integration/integration_cnb_test.go index 80b62f9bb5..cec16cbd6e 100644 --- a/integration/integration_cnb_test.go +++ b/integration/integration_cnb_test.go @@ -57,12 +57,13 @@ func TestCNBIntegrationNPMProject(t *testing.T) { }) defer container2.terminate(t) - err := container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--path", "TestCnbIntegration/project", "--customConfig", "TestCnbIntegration/config.yml", "--containerImageName", "node", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL) + err := container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--path", "TestCnbIntegration/project", "--customConfig", "TestCnbIntegration/config.yml", "--containerImageName", "node", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL, "--defaultProcess", "greeter") assert.NoError(t, err) container.assertHasOutput(t, "running command: /cnb/lifecycle/creator") container.assertHasOutput(t, "Selected Node Engine version (using BP_NODE_VERSION): 16") container.assertHasOutput(t, "Paketo NPM Start Buildpack") container.assertHasOutput(t, fmt.Sprintf("Saving %s/node:0.0.1", registryURL)) + container.assertHasOutput(t, "Setting default process type 'greeter'") container.assertHasOutput(t, "*** Images (sha256:") container.assertHasOutput(t, "SUCCESS") container.terminate(t) @@ -92,7 +93,8 @@ func TestCNBIntegrationProjectDescriptor(t *testing.T) { }) defer container.terminate(t) - container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL) + err := container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL) + assert.NoError(t, err) container.assertHasOutput(t, "running command: /cnb/lifecycle/creator", "Dockerfile doesn't match include pattern, ignoring", @@ -122,7 +124,8 @@ func TestCNBIntegrationZipPath(t *testing.T) { }) defer container.terminate(t) - container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL, "--path", "go.zip") + err := container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL, "--path", "go.zip", "--createBOM") + assert.NoError(t, err) container.assertHasOutput(t, "running command: /cnb/lifecycle/creator", @@ -131,7 +134,9 @@ func TestCNBIntegrationZipPath(t *testing.T) { fmt.Sprintf("Saving %s/not-found:0.0.1", registryURL), "*** Images (sha256:", "SUCCESS", + "syft packages registry:localhost:5000/not-found:0.0.1 -o cyclonedx-xml --file bom-docker-0.xml -q", ) + container.assertHasFiles(t, "/project/bom-docker-0.xml") } func TestCNBIntegrationNonZipPath(t *testing.T) { @@ -148,7 +153,8 @@ func TestCNBIntegrationNonZipPath(t *testing.T) { }) defer container.terminate(t) - container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL, "--path", "mta.yaml") + err := container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL, "--path", "mta.yaml") + assert.Error(t, err) container.assertHasOutput(t, "Copying '/project/mta.yaml' into '/workspace' failed: application path must be a directory or zip") } @@ -167,7 +173,8 @@ func TestCNBIntegrationNPMCustomBuildpacksFullProject(t *testing.T) { }) defer container.terminate(t) - container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--buildpacks", "gcr.io/paketo-buildpacks/nodejs:0.19.0", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL) + err := container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--buildpacks", "gcr.io/paketo-buildpacks/nodejs:0.19.0", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL) + assert.NoError(t, err) container.assertHasOutput(t, "Setting custom buildpacks: '[gcr.io/paketo-buildpacks/nodejs:0.19.0]'", @@ -194,7 +201,8 @@ func TestCNBIntegrationNPMCustomBuildpacksBuildpacklessProject(t *testing.T) { }) defer container.terminate(t) - container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--buildpacks", "gcr.io/paketo-buildpacks/nodejs:0.19.0", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL) + err := container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--buildpacks", "gcr.io/paketo-buildpacks/nodejs:0.19.0", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL) + assert.NoError(t, err) container.assertHasOutput(t, "Setting custom buildpacks: '[gcr.io/paketo-buildpacks/nodejs:0.19.0]'", "Downloading buildpack 'gcr.io/paketo-buildpacks/nodejs:0.19.0' to /tmp/buildpacks_cache/sha256:", @@ -214,7 +222,8 @@ func TestCNBIntegrationWrongBuilderProject(t *testing.T) { }) defer container.terminate(t) - container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", "test") + err := container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", "test") + assert.Error(t, err) container.assertHasOutput(t, "the provided dockerImage is not a valid builder") } @@ -233,7 +242,8 @@ func TestCNBIntegrationBindings(t *testing.T) { }) defer container.terminate(t) - container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--customConfig", "TestCnbIntegration/config.yml", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL, "--path", "TestMtaIntegration/maven") + err := container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--customConfig", "TestCnbIntegration/config.yml", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL, "--path", "TestMtaIntegration/maven") + assert.Error(t, err) container.assertHasOutput(t, "bindings/maven-settings/settings.xml: only whitespace content allowed before start tag") container.assertHasFiles(t, @@ -256,7 +266,8 @@ func TestCNBIntegrationMultiImage(t *testing.T) { }) defer container.terminate(t) - container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--customConfig", "config_multi_image.yml") + err := container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--customConfig", "config_multi_image.yml", "--createBOM") + assert.NoError(t, err) container.assertHasOutput(t, "Previous image with name \"localhost:5000/io-buildpacks-my-app:latest\" not found", @@ -265,7 +276,14 @@ func TestCNBIntegrationMultiImage(t *testing.T) { "Saving localhost:5000/go-app:v1.0.0...", "Using cached buildpack", "Saving localhost:5000/my-app2:latest...", + "syft packages registry:localhost:5000/io-buildpacks-my-app:latest -o cyclonedx-xml --file bom-docker-0.xml -q", + "syft packages registry:localhost:5000/go-app:v1.0.0 -o cyclonedx-xml --file bom-docker-1.xml -q", + "syft packages registry:localhost:5000/my-app2:latest -o cyclonedx-xml --file bom-docker-2.xml -q", ) + + container.assertHasFiles(t, "/project/bom-docker-0.xml") + container.assertHasFiles(t, "/project/bom-docker-1.xml") + container.assertHasFiles(t, "/project/bom-docker-2.xml") } func TestCNBIntegrationPreserveFiles(t *testing.T) { @@ -282,7 +300,9 @@ func TestCNBIntegrationPreserveFiles(t *testing.T) { }) defer container.terminate(t) - container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--customConfig", "config_preserve_files.yml") + err := container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--customConfig", "config_preserve_files.yml") + assert.NoError(t, err) + container.assertHasFiles(t, "/project/project/node_modules/base/README.md", "/project/project/package-lock.json") } @@ -300,6 +320,7 @@ func TestCNBIntegrationPreserveFilesIgnored(t *testing.T) { }) defer container.terminate(t) - container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--customConfig", "config_preserve_files.yml", "--path", "zip/go.zip", "--containerImageName", "go-zip") + err := container.whenRunningPiperCommand("cnbBuild", "--noTelemetry", "--verbose", "--customConfig", "config_preserve_files.yml", "--path", "zip/go.zip", "--containerImageName", "go-zip") + assert.NoError(t, err) container.assertHasOutput(t, "skipping preserving files because the source") } diff --git a/integration/testdata/TestCnbIntegration/project/Procfile b/integration/testdata/TestCnbIntegration/project/Procfile new file mode 100644 index 0000000000..348c6ba03c --- /dev/null +++ b/integration/testdata/TestCnbIntegration/project/Procfile @@ -0,0 +1,2 @@ +greeter: echo 'Hello World' + diff --git a/integration/testdata/TestCnbIntegration/project/project.toml b/integration/testdata/TestCnbIntegration/project/project.toml index 9115e4821d..aca4a89a06 100644 --- a/integration/testdata/TestCnbIntegration/project/project.toml +++ b/integration/testdata/TestCnbIntegration/project/project.toml @@ -5,7 +5,8 @@ version = "0.1" [build] include = [ "*.js", - "/package.json" + "/package.json", + "Procfile" ] [[build.env]] @@ -26,3 +27,6 @@ uri = "gcr.io/paketo-buildpacks/node-module-bom:0.4.0" [[build.buildpacks]] uri = "gcr.io/paketo-buildpacks/npm-start:0.9.2" + +[[build.buildpacks]] +uri = "gcr.io/paketo-buildpacks/procfile:5.4.0" diff --git a/integration/testdata/TestMavenIntegration/cloud-sdk-spring-archetype/application/src/main/resources/static/index.html b/integration/testdata/TestMavenIntegration/cloud-sdk-spring-archetype/application/src/main/resources/static/index.html index 845c90acea..46b7d4bf71 100644 --- a/integration/testdata/TestMavenIntegration/cloud-sdk-spring-archetype/application/src/main/resources/static/index.html +++ b/integration/testdata/TestMavenIntegration/cloud-sdk-spring-archetype/application/src/main/resources/static/index.html @@ -31,7 +31,7 @@ <h1>Welcome to Your Application!</h1> </a> <p> - This is your <strong>SAP Cloud Platform Cloud Foundry Spring</strong> application + This is your <strong>SAP BTP Cloud Foundry Spring</strong> application powered by the <strong>SAP Cloud SDK</strong>. </p> <ul> diff --git a/integration/testdata/TestMavenIntegration/cloud-sdk-tomee-archetype/application/src/main/webapp/index.html b/integration/testdata/TestMavenIntegration/cloud-sdk-tomee-archetype/application/src/main/webapp/index.html index c622bc1b85..e99e41f4dc 100644 --- a/integration/testdata/TestMavenIntegration/cloud-sdk-tomee-archetype/application/src/main/webapp/index.html +++ b/integration/testdata/TestMavenIntegration/cloud-sdk-tomee-archetype/application/src/main/webapp/index.html @@ -31,7 +31,7 @@ <h1>Welcome to Your Application!</h1> </a> <p> - This is your <strong>SAP Cloud Platform Cloud Foundry TomEE</strong> application + This is your <strong>SAP BTP Cloud Foundry TomEE</strong> application powered by the <strong>SAP Cloud SDK</strong>. </p> <ul> diff --git a/pkg/blackduck/blackduck.go b/pkg/blackduck/blackduck.go index 3796c20c22..aa9071dcca 100644 --- a/pkg/blackduck/blackduck.go +++ b/pkg/blackduck/blackduck.go @@ -8,6 +8,7 @@ import ( "net/http" "net/url" "path" + "strings" "time" piperhttp "github.com/SAP/jenkins-library/pkg/http" @@ -67,16 +68,50 @@ type Components struct { } type Component struct { - Name string `json:"componentName,omitempty"` - Version string `json:"componentVersionName,omitempty"` - ComponentOriginName string `json:"componentVersionOriginName,omitempty"` - PrimaryLanguage string `json:"primaryLanguage,omitempty"` - PolicyStatus string `json:"policyStatus,omitempty"` + Name string `json:"componentName,omitempty"` + Version string `json:"componentVersionName,omitempty"` + ComponentOriginName string `json:"componentVersionOriginName,omitempty"` + PrimaryLanguage string `json:"primaryLanguage,omitempty"` + PolicyStatus string `json:"policyStatus,omitempty"` + MatchTypes []string `json:"matchTypes,omitempty"` + Origins []ComponentOrigin `json:"origins,omitempty"` Metadata `json:"_meta,omitempty"` } -func (c Component) ToPackageUrl() *packageurl.PackageURL { - return packageurl.NewPackageURL(transformComponentToPurlType(c.PrimaryLanguage), "", c.Name, c.Version, nil, "") +type ComponentOrigin struct { + ExternalNamespace string `json:"externalNamespace,omitempty"` + ExternalID string `json:"externalId,omitempty"` +} + +// ToPackageUrl creates the package URL for the component +func (c *Component) ToPackageUrl() *packageurl.PackageURL { + purlParts := transformComponentOriginToPurlParts(c) + + // Namespace could not be in purlParts + var purlType, namespace, name, version string + if len(purlParts) >= 3 { + version = purlParts[len(purlParts)-1] + name = purlParts[len(purlParts)-2] + purlType = purlParts[0] + } + if len(purlParts) == 4 { + namespace = purlParts[1] + } + + return packageurl.NewPackageURL(purlType, namespace, name, version, nil, "") +} + +// MatchedType returns matched type of component: direct/transitive +func (c *Component) MatchedType() string { + for _, matchedType := range c.MatchTypes { + if matchedType == "FILE_DEPENDENCY_DIRECT" { + return "direct" + } else if matchedType == "FILE_DEPENDENCY_TRANSITIVE" { + return "transitive" + } + } + + return "" } type Vulnerabilities struct { @@ -87,9 +122,14 @@ type Vulnerabilities struct { type Vulnerability struct { Name string `json:"componentName,omitempty"` Version string `json:"componentVersionName,omitempty"` + ComponentVersionOriginID string `json:"componentVersionOriginId,omitempty"` + ComponentVersionOriginName string `json:"componentVersionOriginName,omitempty"` Ignored bool `json:"ignored,omitempty"` VulnerabilityWithRemediation `json:"vulnerabilityWithRemediation,omitempty"` Component *Component + projectName string + projectVersion string + projectVersionLink string } type VulnerabilityWithRemediation struct { @@ -102,6 +142,7 @@ type VulnerabilityWithRemediation struct { CweID string `json:"cweId,omitempty"` ExploitabilitySubscore float32 `json:"exploitabilitySubscore,omitempty"` ImpactSubscore float32 `json:"impactSubscore,omitempty"` + RelatedVulnerability string `json:"relatedVulnerability,omitempty"` } // Title returns the issue title representation of the contents @@ -112,16 +153,13 @@ func (v Vulnerability) Title() string { // ToMarkdown returns the markdown representation of the contents func (v Vulnerability) ToMarkdown() ([]byte, error) { vul := reporting.VulnerabilityReport{ - ArtifactID: v.Component.Name, - - // no information available about branch and commit, yet - Branch: "", - CommitID: "", - - Description: v.Description, - - // no information available about direct/indirect dependency, yet - //DirectDependency: ... , + ProjectName: v.projectName, + ProjectVersion: v.projectVersion, + BlackDuckProjectLink: v.projectVersionLink, + ArtifactID: v.Component.Name, + Description: v.Description, + DependencyType: v.Component.MatchedType(), + Origin: v.ComponentVersionOriginID, // no information available about footer, yet Footer: "", @@ -129,19 +167,15 @@ func (v Vulnerability) ToMarkdown() ([]byte, error) { // no information available about group, yet Group: "", - // no information available about pipeline name and link, publish date and resolution yet - PipelineName: "", - PipelineLink: "", - PublishDate: "", - Resolution: "", + // no information available about publish date and resolution yet + PublishDate: "", + Resolution: "", - Score: float64(v.VulnerabilityWithRemediation.BaseScore), - Severity: v.VulnerabilityWithRemediation.Severity, - Version: v.Version, - PackageURL: v.Component.ToPackageUrl().ToString(), - - // no vulnerability link available, yet - VulnerabilityLink: "", + Score: float64(v.VulnerabilityWithRemediation.BaseScore), + Severity: v.VulnerabilityWithRemediation.Severity, + Version: v.Version, + PackageURL: v.Component.ToPackageUrl().ToString(), + VulnerabilityLink: v.RelatedVulnerability, VulnerabilityName: v.VulnerabilityName, } @@ -197,6 +231,7 @@ type Client struct { token string httpClient piperhttp.Sender serverURL string + projectVersion *ProjectVersion } // NewClient creates a new BlackDuck client @@ -242,6 +277,10 @@ func (b *Client) GetProject(projectName string) (*Project, error) { // GetProjectVersion returns a project version with a given name func (b *Client) GetProjectVersion(projectName, projectVersion string) (*ProjectVersion, error) { + // get version from cache if it is there + if b.projectVersion != nil { + return b.projectVersion, nil + } project, err := b.GetProject(projectName) if err != nil { return nil, err @@ -276,6 +315,8 @@ func (b *Client) GetProjectVersion(projectName, projectVersion string) (*Project // even if more than one projects found, let's return the first one with exact project name match for _, version := range projectVersions.Items { if version.Name == projectVersion { + // save version to cache in order not to do several same requests + b.projectVersion = &version return &version, nil } } @@ -503,17 +544,32 @@ func urlPath(fullUrl string) string { return theUrl.Path } -func transformComponentToPurlType(primaryLanguage string) string { - // TODO verify possible relevant values - switch primaryLanguage { - case "Java": - return packageurl.TypeMaven - case "Javascript": - return packageurl.TypeNPM - case "Golang": - return packageurl.TypeGolang - case "Docker": - return packageurl.TypeDocker +func transformComponentOriginToPurlParts(component *Component) []string { + result := []string{} + purlType := packageurl.TypeGeneric + gav := []string{"", component.Name, component.Version} + origins := component.Origins + if origins != nil && len(origins) > 0 { + // parts of npm origin are separated by "/" + if origins[0].ExternalNamespace == "npmjs" { + gav = strings.Split(origins[0].ExternalID, "/") + } else { + gav = strings.Split(origins[0].ExternalID, ":") + } + switch strings.ToLower(origins[0].ExternalNamespace) { + case "maven": + purlType = packageurl.TypeMaven + case "node": + purlType = packageurl.TypeNPM + case "npmjs": + purlType = packageurl.TypeNPM + case "golang": + purlType = packageurl.TypeGolang + case "docker": + purlType = packageurl.TypeDocker + } } - return packageurl.TypeGeneric + result = append(result, purlType) + result = append(result, gav...) + return result } diff --git a/pkg/blackduck/blackduck_test.go b/pkg/blackduck/blackduck_test.go index b3688cdce9..e2e8676f03 100644 --- a/pkg/blackduck/blackduck_test.go +++ b/pkg/blackduck/blackduck_test.go @@ -630,3 +630,106 @@ func TestAuthenticationValid(t *testing.T) { func TestUrlPath(t *testing.T) { assert.Equal(t, "/this/is/the/path", urlPath("https://the.server.domain:8080/this/is/the/path")) } + +func TestTransformComponentOriginToPurlParts(t *testing.T) { + tt := []struct { + description string + component *Component + expected []string + }{ + { + // pkg:maven/org.apache.cxf/cxf-rt-rs-client@3.1.2 + description: "Origin with Url type, namespace, name, version", + component: &Component{ + Name: "Apache CXF", + Version: "3.1.2", + Origins: []ComponentOrigin{{ + ExternalNamespace: "maven", + ExternalID: "org.apache.cxf:cxf-rt-rs-client:3.1.2", + }}, + }, + expected: []string{"maven", "org.apache.cxf", "cxf-rt-rs-client", "3.1.2"}, + }, + { + // pkg:npm/minimist@0.0.8 + description: "Origin with Url type, name, version", + component: &Component{ + Name: "Minimist", + Version: "0.0.8", + Origins: []ComponentOrigin{{ + ExternalNamespace: "npmjs", + ExternalID: "minimist/0.0.8", + }}, + }, + expected: []string{"npm", "minimist", "0.0.8"}, + }, + { + // pkg:maven/org.springframework/spring-expression@4.1.6.RELEASE + description: "Empty origin", + component: &Component{ + Name: "spring-expression", + Version: "4.1.6.RELEASE", + Origins: []ComponentOrigin{}, + }, + expected: []string{"generic", "", "spring-expression", "4.1.6.RELEASE"}, + }, + } + + for _, test := range tt { + t.Run(test.description, func(t *testing.T) { + got := transformComponentOriginToPurlParts(test.component) + + assert.Equal(t, test.expected, got) + }) + } +} + +func TestComponentToPackageUrl(t *testing.T) { + tt := []struct { + description string + component *Component + expected string + }{ + { + description: "Origin with Url type, namespace, name, version", + component: &Component{ + Name: "Apache CXF", + Version: "3.1.2", + Origins: []ComponentOrigin{{ + ExternalNamespace: "maven", + ExternalID: "org.apache.cxf:cxf-rt-rs-client:3.1.2", + }}, + }, + expected: "pkg:maven/org.apache.cxf/cxf-rt-rs-client@3.1.2", + }, + { + description: "Origin with Url type, name, version", + component: &Component{ + Name: "Minimist", + Version: "0.0.8", + Origins: []ComponentOrigin{{ + ExternalNamespace: "npmjs", + ExternalID: "minimist/0.0.8", + }}, + }, + expected: "pkg:npm/minimist@0.0.8", + }, + { + description: "Empty origin", + component: &Component{ + Name: "spring-expression", + Version: "4.1.6.RELEASE", + Origins: []ComponentOrigin{}, + }, + expected: "pkg:generic/spring-expression@4.1.6.RELEASE", + }, + } + + for _, test := range tt { + t.Run(test.description, func(t *testing.T) { + got := test.component.ToPackageUrl().ToString() + + assert.Equal(t, test.expected, got) + }) + } +} diff --git a/pkg/blackduck/reporting.go b/pkg/blackduck/reporting.go index 9a1ae9c4b8..a2efe3b132 100644 --- a/pkg/blackduck/reporting.go +++ b/pkg/blackduck/reporting.go @@ -15,7 +15,7 @@ import ( ) // CreateSarifResultFile creates a SARIF result from the Vulnerabilities that were brought up by the scan -func CreateSarifResultFile(vulns *Vulnerabilities, components *Components) *format.SARIF { +func CreateSarifResultFile(vulns *Vulnerabilities, projectName, projectVersion, projectLink string) *format.SARIF { log.Entry().Debug("Creating SARIF file for data transfer") // Handle results/vulnerabilities @@ -51,11 +51,17 @@ func CreateSarifResultFile(vulns *Vulnerabilities, components *Components) *form if !piperutils.ContainsString(collectedRules, result.RuleID) { collectedRules = append(collectedRules, result.RuleID) + // set information about BlackDuck project + v.projectVersionLink = projectLink + v.projectName = projectName + v.projectVersion = projectVersion + markdown, _ := v.ToMarkdown() tags := []string{ "SECURITY_VULNERABILITY", v.Component.ToPackageUrl().ToString(), v.VulnerabilityWithRemediation.CweID, + v.Component.MatchedType(), } ruleProp := format.SarifRuleProperties{ Tags: tags, @@ -95,7 +101,7 @@ func CreateSarifResultFile(vulns *Vulnerabilities, components *Components) *form //handle the tool object tool := format.Tool{ Driver: format.Driver{ - Name: "Blackduck Hub Detect", + Name: "Black Duck", Version: "unknown", InformationUri: "https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=introduction.html&_LANG=enus", Rules: rules, diff --git a/pkg/blackduck/reporting_test.go b/pkg/blackduck/reporting_test.go index 41f006c647..5b25ad07e3 100644 --- a/pkg/blackduck/reporting_test.go +++ b/pkg/blackduck/reporting_test.go @@ -26,19 +26,16 @@ func TestCreateSarifResultFile(t *testing.T) { vulns := Vulnerabilities{ Items: alerts, } - components := []Component{ - affectedComponent, - } - componentList := Components{ - Items: components, - } + projectName := "theProjectName" + projectVersion := "theProjectVersion" + projectLink := "theProjectLink" - sarif := CreateSarifResultFile(&vulns, &componentList) + sarif := CreateSarifResultFile(&vulns, projectName, projectVersion, projectLink) assert.Equal(t, "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json", sarif.Schema) assert.Equal(t, "2.1.0", sarif.Version) assert.Equal(t, 1, len(sarif.Runs)) - assert.Equal(t, "Blackduck Hub Detect", sarif.Runs[0].Tool.Driver.Name) + assert.Equal(t, "Black Duck", sarif.Runs[0].Tool.Driver.Name) assert.Equal(t, "unknown", sarif.Runs[0].Tool.Driver.Version) assert.Equal(t, 4, len(sarif.Runs[0].Tool.Driver.Rules)) assert.Equal(t, 5, len(sarif.Runs[0].Results)) diff --git a/pkg/checkmarx/checkmarx.go b/pkg/checkmarx/checkmarx.go index 01c1924bfc..a828711639 100644 --- a/pkg/checkmarx/checkmarx.go +++ b/pkg/checkmarx/checkmarx.go @@ -518,12 +518,17 @@ func (sys *SystemInstance) UpdateProjectConfiguration(projectID int, presetID in } else { // Check if the current project config needs to be updated json.Unmarshal(data, &projectScanSettings) - if projectScanSettings.Preset.PresetID == presetID && projectScanSettings.EngineConfiguration.EngineConfigurationID == engineConfigID { + if projectScanSettings.Preset.PresetID == presetID && (projectScanSettings.EngineConfiguration.EngineConfigurationID == engineConfigID || engineConfigID == 0) { sys.logger.Debugf("Project configuration does not need to be updated") return nil } } + // use the project-level value to configure the project if no value was provided in piper config + if engineConfigID == 0 { + engineConfigID = projectScanSettings.EngineConfiguration.EngineConfigurationID + } + jsonData := map[string]interface{}{ "projectId": projectID, "presetId": presetID, diff --git a/pkg/checkmarx/reporting.go b/pkg/checkmarx/reporting.go index d5af17cbae..2b4d73bf99 100644 --- a/pkg/checkmarx/reporting.go +++ b/pkg/checkmarx/reporting.go @@ -55,9 +55,9 @@ func CreateCustomReport(data map[string]interface{}, insecure, neutral []string) ReportTitle: "Checkmarx SAST Report", Subheaders: []reporting.Subheader{ {Description: "Project name", Details: fmt.Sprint(data["ProjectName"])}, - {Description: "Project ID", Details: fmt.Sprint(data["ProjectID"])}, + {Description: "Project ID", Details: fmt.Sprint(data["ProjectId"])}, {Description: "Owner", Details: fmt.Sprint(data["Owner"])}, - {Description: "Scan ID", Details: fmt.Sprint(data["ScanID"])}, + {Description: "Scan ID", Details: fmt.Sprint(data["ScanId"])}, {Description: "Team", Details: fmt.Sprint(data["Team"])}, {Description: "Team full path", Details: fmt.Sprint(data["TeamFullPathOnReportDate"])}, {Description: "Scan start", Details: fmt.Sprint(data["ScanStart"])}, @@ -65,8 +65,8 @@ func CreateCustomReport(data map[string]interface{}, insecure, neutral []string) {Description: "Scan type", Details: fmt.Sprint(data["ScanType"])}, {Description: "Preset", Details: fmt.Sprint(data["Preset"])}, {Description: "Report creation time", Details: fmt.Sprint(data["ReportCreationTime"])}, - {Description: "Lines of code scanned", Details: fmt.Sprint(data["LinesOfCodeScanned)"])}, - {Description: "Files scanned", Details: fmt.Sprint(data["FilesScanned)"])}, + {Description: "Lines of code scanned", Details: fmt.Sprint(data["LinesOfCodeScanned"])}, + {Description: "Files scanned", Details: fmt.Sprint(data["FilesScanned"])}, {Description: "Checkmarx version", Details: fmt.Sprint(data["CheckmarxVersion"])}, {Description: "Deep link", Details: deepLink}, }, diff --git a/pkg/checkmarx/reporting_test.go b/pkg/checkmarx/reporting_test.go index 5153c10f8b..b9c637f45c 100644 --- a/pkg/checkmarx/reporting_test.go +++ b/pkg/checkmarx/reporting_test.go @@ -216,3 +216,132 @@ func TestJsonReportWithNoLowVulnData(t *testing.T) { assert.Equal(t, 2, reportingData.InformationTotal) assert.Equal(t, 0, reportingData.InformationAudited) } + +func TestCreateCustomReport(t *testing.T) { + data := `<?xml version="1.0" encoding="utf-8"?> + <CxXMLResults InitiatorName="admin" Owner="admin" ScanId="1000005" ProjectId="2" ProjectName="Project 1" TeamFullPathOnReportDate="CxServer" DeepLink="http://WIN2K12-TEMP/CxWebClient/ViewerMain.aspx?scanid=1000005&projectid=2" ScanStart="Sunday, December 3, 2017 4:50:34 PM" Preset="Checkmarx Default" ScanTime="00h:03m:18s" LinesOfCodeScanned="6838" FilesScanned="34" ReportCreationTime="Sunday, December 3, 2017 6:13:45 PM" Team="CxServer" CheckmarxVersion="8.6.0" ScanComments="" ScanType="Incremental" SourceOrigin="LocalPath" Visibility="Public"> + <Query id="430" categories="PCI DSS v3.2;PCI DSS (3.2) - 6.5.1 - Injection flaws - particularly SQL injection,OWASP Top 10 2013;A1-Injection,FISMA 2014;System And Information Integrity,NIST SP 800-53;SI-10 Information Input Validation (P1),OWASP Top 10 2017;A1-Injection" cweId="89" name="SQL_Injection" group="CSharp_High_Risk" Severity="High" Language="CSharp" LanguageHash="1363215419077432" LanguageChangeDate="2017-12-03T00:00:00.0000000" SeverityIndex="3" QueryPath="CSharp\Cx\CSharp High Risk\SQL Injection Version:0" QueryVersionCode="430"> + </Query> + </CxXMLResults>` + + var xmlResult DetailedResult + xml.Unmarshal([]byte(data), &xmlResult) + resultMap := map[string]interface{}{} + resultMap["InitiatorName"] = xmlResult.InitiatorName + resultMap["Owner"] = xmlResult.Owner + resultMap["ScanId"] = xmlResult.ScanID + resultMap["ProjectId"] = xmlResult.ProjectID + resultMap["ProjectName"] = xmlResult.ProjectName + resultMap["Team"] = xmlResult.Team + resultMap["TeamFullPathOnReportDate"] = xmlResult.TeamFullPathOnReportDate + resultMap["ScanStart"] = xmlResult.ScanStart + resultMap["ScanTime"] = xmlResult.ScanTime + resultMap["LinesOfCodeScanned"] = xmlResult.LinesOfCodeScanned + resultMap["FilesScanned"] = xmlResult.FilesScanned + resultMap["CheckmarxVersion"] = xmlResult.CheckmarxVersion + resultMap["ScanType"] = xmlResult.ScanType + resultMap["Preset"] = xmlResult.Preset + resultMap["DeepLink"] = xmlResult.DeepLink + resultMap["ReportCreationTime"] = xmlResult.ReportCreationTime + resultMap["High"] = map[string]int{} + resultMap["Medium"] = map[string]int{} + resultMap["Low"] = map[string]int{} + resultMap["Information"] = map[string]int{} + submap := map[string]int{} + submap["Issues"] = 10 + submap["NotFalsePositive"] = 10 + resultMap["High"] = submap + + submap = map[string]int{} + submap["Issues"] = 4 + submap["NotFalsePositive"] = 0 + resultMap["Medium"] = submap + + submap = map[string]int{} + submap["Issues"] = 2 + submap["NotFalsePositive"] = 2 + submap["Confirmed"] = 1 + submap["NotExploitable"] = 1 + resultMap["Low"] = submap + + submap = map[string]int{} + submap["Issues"] = 5 + submap["NotFalsePositive"] = 5 + resultMap["Information"] = submap + + lowPerQuery := map[string]map[string]int{} + submap = map[string]int{} + submap["Issues"] = 4 + submap["Confirmed"] = 0 + submap["NotExploitable"] = 0 + lowPerQuery["Low_Query_Name_1"] = submap + + submap = map[string]int{} + submap["Issues"] = 5 + submap["Confirmed"] = 2 + submap["NotExploitable"] = 3 + lowPerQuery["Low_Query_Name_2"] = submap + + resultMap["LowPerQuery"] = lowPerQuery + + insecure := []string{"insecure"} + neutral := []string{"neutral"} + + reportingData := CreateCustomReport(resultMap, insecure, neutral) + assert.Equal(t, "Checkmarx SAST Report", reportingData.ReportTitle) + assert.Equal(t, 15, len(reportingData.Subheaders)) + assert.Equal(t, 2, len(reportingData.Overview)) + + subheaders := make(map[string]string) + for _, subheader := range reportingData.Subheaders { + subheaders[subheader.Description] = subheader.Details + } + assert.Equal(t, "Project 1", subheaders["Project name"]) + assert.Equal(t, "2", subheaders["Project ID"]) + assert.Equal(t, "admin", subheaders["Owner"]) + assert.Equal(t, "1000005", subheaders["Scan ID"]) + assert.Equal(t, "CxServer", subheaders["Team"]) + assert.Equal(t, "CxServer", subheaders["Team full path"]) + assert.Equal(t, "Sunday, December 3, 2017 4:50:34 PM", subheaders["Scan start"]) + assert.Equal(t, "00h:03m:18s", subheaders["Scan duration"]) + assert.Equal(t, "Incremental", subheaders["Scan type"]) + assert.Equal(t, "Checkmarx Default", subheaders["Preset"]) + assert.Equal(t, "Sunday, December 3, 2017 6:13:45 PM", subheaders["Report creation time"]) + assert.Equal(t, "6838", subheaders["Lines of code scanned"]) + assert.Equal(t, "34", subheaders["Files scanned"]) + assert.Equal(t, "8.6.0", subheaders["Checkmarx version"]) + assert.Equal(t, `<a href="http://WIN2K12-TEMP/CxWebClient/ViewerMain.aspx?scanid=1000005&projectid=2" target="_blank">Link to scan in CX UI</a>`, subheaders["Deep link"]) + + detailRows := make(map[string]string) + for _, detailRow := range reportingData.DetailTable.Rows { + detailRows[detailRow.Columns[0].Content] = detailRow.Columns[1].Content + } + assert.Equal(t, "10", detailRows["High issues"]) + assert.Equal(t, "10", detailRows["High not false positive issues"]) + assert.Equal(t, "0", detailRows["High not exploitable issues"]) + assert.Equal(t, "0", detailRows["High confirmed issues"]) + assert.Equal(t, "0", detailRows["High urgent issues"]) + assert.Equal(t, "0", detailRows["High proposed not exploitable issues"]) + assert.Equal(t, "0", detailRows["High to verify issues"]) + assert.Equal(t, "4", detailRows["Medium issues"]) + assert.Equal(t, "0", detailRows["Medium not false positive issues"]) + assert.Equal(t, "0", detailRows["Medium not exploitable issues"]) + assert.Equal(t, "0", detailRows["Medium confirmed issues"]) + assert.Equal(t, "0", detailRows["Medium urgent issues"]) + assert.Equal(t, "0", detailRows["Medium proposed not exploitable issues"]) + assert.Equal(t, "0", detailRows["Medium to verify issues"]) + assert.Equal(t, "2", detailRows["Low issues"]) + assert.Equal(t, "2", detailRows["Low not false positive issues"]) + assert.Equal(t, "1", detailRows["Low not exploitable issues"]) + assert.Equal(t, "1", detailRows["Low confirmed issues"]) + assert.Equal(t, "0", detailRows["Low urgent issues"]) + assert.Equal(t, "0", detailRows["Low proposed not exploitable issues"]) + assert.Equal(t, "0", detailRows["Low to verify issues"]) + assert.Equal(t, "5", detailRows["Informational issues"]) + assert.Equal(t, "5", detailRows["Informational not false positive issues"]) + assert.Equal(t, "0", detailRows["Informational not exploitable issues"]) + assert.Equal(t, "0", detailRows["Informational confirmed issues"]) + assert.Equal(t, "0", detailRows["Informational urgent issues"]) + assert.Equal(t, "0", detailRows["Informational proposed not exploitable issues"]) + assert.Equal(t, "0", detailRows["Informational to verify issues"]) +} diff --git a/pkg/cnbutils/buildpack.go b/pkg/cnbutils/buildpack.go index 1ecaaab3ff..5dc929f09d 100644 --- a/pkg/cnbutils/buildpack.go +++ b/pkg/cnbutils/buildpack.go @@ -28,7 +28,6 @@ type License struct { } func DownloadBuildpacks(path string, bpacks []string, dockerCreds string, utils BuildUtils) (Order, error) { - if dockerCreds != "" { os.Setenv("DOCKER_CONFIG", filepath.Dir(dockerCreds)) } diff --git a/pkg/cnbutils/sbom.go b/pkg/cnbutils/sbom.go deleted file mode 100644 index a8e790b673..0000000000 --- a/pkg/cnbutils/sbom.go +++ /dev/null @@ -1,184 +0,0 @@ -package cnbutils - -import ( - "archive/tar" - "bytes" - "fmt" - "io" - "os" - "path/filepath" - "regexp" - - "github.com/pkg/errors" - - "github.com/SAP/jenkins-library/pkg/log" - "github.com/anchore/syft/syft" - "github.com/anchore/syft/syft/sbom" - "github.com/anchore/syft/syft/source" - v1 "github.com/google/go-containerregistry/pkg/v1" -) - -var cycloneDxXML = syft.FormatByID(syft.CycloneDxXMLFormatID) - -func MergeSBOMFiles(pattern, output, img, dockerConfigFile string, utils BuildUtils) error { - if dockerConfigFile != "" { - os.Setenv("DOCKER_CONFIG", filepath.Dir(dockerConfigFile)) - defer os.Unsetenv("DOCKER_CONFIG") - } - - log.Entry().Debugf("reading remote image %s", img) - remoteImage, err := utils.GetRemoteImageInfo(img) - if err != nil { - return err - } - - imgConfig, err := remoteImage.ConfigFile() - if err != nil { - return err - } - - layerSHA, exists := imgConfig.Config.Labels["io.buildpacks.base.sbom"] - if !exists { - return fmt.Errorf("image %q does not contain label \"io.buildpacks.base.sbom\"", img) - } - - var bom *sbom.SBOM - log.Entry().Debug("found SBOM layer") - bom, err = readBOMFromLayer(remoteImage, layerSHA) - if err != nil { - return err - } - log.Entry().Debugf("initial source.ImageMetadata: %#v", bom.Source.ImageMetadata) - - imageMetaData, err := extractImageMetaData(remoteImage) - if err != nil { - return err - } - bom.Source.ImageMetadata = *imageMetaData - bom.Source.ImageMetadata.UserInput = img - log.Entry().Debugf("updated source.ImageMetadata: %#v", bom.Source.ImageMetadata) - - log.Entry().Debugf("search for sbom file using the pattern %s", pattern) - syftFiles, err := utils.Glob(pattern) - if err != nil { - return err - } - - for _, syftFile := range syftFiles { - log.Entry().Debugf("reading Syft SBOM file %q", syftFile) - f, err := utils.Open(syftFile) - if err != nil { - return err - } - defer f.Close() - - bill, _, err := syft.Decode(f) - if err != nil { - return err - } - - for p := range bill.Artifacts.PackageCatalog.Enumerate() { - bom.Artifacts.PackageCatalog.Add(p) - } - } - - outFile, err := utils.Abs(output) - if err != nil { - return err - } - - out, err := utils.Create(outFile) - if err != nil { - return err - } - defer out.Close() - - log.Entry().Debugf("saving CycloneDX SBOM file to %q", outFile) - err = cycloneDxXML.Encode(out, *bom) - if err != nil { - return err - } - - return nil -} - -func readBOMFromLayer(img v1.Image, layerDiffSHA string) (*sbom.SBOM, error) { - layerDiffDigest, err := v1.NewHash(layerDiffSHA) - if err != nil { - return nil, errors.Wrapf(err, "failed to parse layer sha %q", layerDiffSHA) - } - - log.Entry().Debugf("looking for the layer %q", layerDiffDigest.String()) - - sbomLayer, err := img.LayerByDiffID(layerDiffDigest) - if err != nil { - return nil, errors.Wrapf(err, "failed get layer %q", layerDiffDigest) - } - - rc, err := sbomLayer.Uncompressed() - if err != nil { - return nil, errors.Wrap(err, "failed to get uncompressed reader") - } - - tr := tar.NewReader(rc) - sbomRegex := regexp.MustCompile(`cnb/sbom/[a-z0-9]+\.syft\.json`) - for { - hdr, err := tr.Next() - if err == io.EOF { - break - } - if err != nil { - return nil, errors.Wrap(err, "failed to read tar content") - } - - log.Entry().Debugf("checking SBOM layer file %q", hdr.Name) - if sbomRegex.Match([]byte(hdr.Name)) { - log.Entry().Debugf("file %q matches the regex", hdr.Name) - buf := &bytes.Buffer{} - _, err = io.Copy(buf, tr) - if err != nil { - return nil, errors.Wrap(err, "failed to read SBOM file from the layer") - } - - bom, _, err := syft.Decode(buf) - return bom, errors.Wrap(err, "failed to decode SBOM file") - } - } - - return nil, errors.New("no sbom file found") -} - -func extractImageMetaData(img v1.Image) (*source.ImageMetadata, error) { - imageDigest, err := img.Digest() - if err != nil { - return nil, err - } - - imageMediaType, err := img.MediaType() - if err != nil { - return nil, err - } - - imageSize, err := img.Size() - if err != nil { - return nil, err - } - - imageRawManifest, err := img.RawManifest() - if err != nil { - return nil, err - } - - imageRawConfig, err := img.RawConfigFile() - if err != nil { - return nil, err - } - - return &source.ImageMetadata{ - ID: imageDigest.String(), - Size: imageSize, - MediaType: string(imageMediaType), - RawConfig: imageRawConfig, - RawManifest: imageRawManifest, - }, nil -} diff --git a/pkg/cnbutils/sbom_test.go b/pkg/cnbutils/sbom_test.go deleted file mode 100644 index 092c7fca12..0000000000 --- a/pkg/cnbutils/sbom_test.go +++ /dev/null @@ -1,118 +0,0 @@ -package cnbutils_test - -import ( - "archive/tar" - "bytes" - "crypto/sha256" - "encoding/hex" - "io" - "os" - "testing" - - "github.com/SAP/jenkins-library/pkg/cnbutils" - "github.com/SAP/jenkins-library/pkg/mock" - v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/fake" - "github.com/google/go-containerregistry/pkg/v1/partial" - "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/stretchr/testify/assert" -) - -type uncompressedLayer struct { - diffID v1.Hash - mediaType types.MediaType - content []byte -} - -// DiffID implements partial.UncompressedLayer -func (ul *uncompressedLayer) DiffID() (v1.Hash, error) { - return ul.diffID, nil -} - -// Uncompressed implements partial.UncompressedLayer -func (ul *uncompressedLayer) Uncompressed() (io.ReadCloser, error) { - return io.NopCloser(bytes.NewBuffer(ul.content)), nil -} - -// MediaType returns the media type of the layer -func (ul *uncompressedLayer) MediaType() (types.MediaType, error) { - return ul.mediaType, nil -} - -func fakeLayer(path string, content []byte) (v1.Layer, error) { - var b bytes.Buffer - hasher := sha256.New() - mw := io.MultiWriter(&b, hasher) - - // Write a single file with a random name and random contents. - tw := tar.NewWriter(mw) - if err := tw.WriteHeader(&tar.Header{ - Name: path, - Size: int64(len(content)), - Typeflag: tar.TypeRegA, - }); err != nil { - return nil, err - } - - if _, err := io.WriteString(tw, string(content)); err != nil { - return nil, err - } - if err := tw.Close(); err != nil { - return nil, err - } - - h := v1.Hash{ - Algorithm: "sha256", - Hex: hex.EncodeToString(hasher.Sum(make([]byte, 0, hasher.Size()))), - } - - return partial.UncompressedToLayer(&uncompressedLayer{ - mediaType: types.DockerLayer, - diffID: h, - content: b.Bytes(), - }) -} - -func TestMergeSBOMFiles(t *testing.T) { - var mockUtils = &cnbutils.MockUtils{ - ExecMockRunner: &mock.ExecMockRunner{}, - FilesMock: &mock.FilesMock{}, - DownloadMock: &mock.DownloadMock{}, - } - - fakeImg := &fake.FakeImage{} - fakeImg.ConfigFileReturns(&v1.ConfigFile{ - Config: v1.Config{Labels: map[string]string{"io.buildpacks.base.sbom": "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"}}, - }, nil) - - baseSBOM, err := os.ReadFile("testdata/base.syft.json") - assert.NoError(t, err) - fLayer, err := fakeLayer("cnb/sbom/test.syft.json", baseSBOM) - assert.NoError(t, err) - fakeImg.LayerByDiffIDReturns(fLayer, nil) - - mockUtils.ReturnImage = fakeImg - mockUtils.RemoteImageInfo = fakeImg - - sbom1, err := os.ReadFile("testdata/sbom1.syft.json") - assert.NoError(t, err) - mockUtils.FilesMock.AddFile("/layer/1/sbom.syft.json", sbom1) - sbom2, err := os.ReadFile("testdata/sbom2.syft.json") - assert.NoError(t, err) - mockUtils.FilesMock.AddFile("/layer/2/sbom.syft.json", sbom2) - - err = cnbutils.MergeSBOMFiles("layer/**/sbom.syft.json", "sbom.xml", "imageName", "", mockUtils) - assert.NoError(t, err) - - exists, err := mockUtils.FileExists("/sbom.xml") - assert.NoError(t, err) - assert.True(t, exists) - - content, err := mockUtils.ReadFile("/sbom.xml") - assert.NoError(t, err) - - assert.Contains(t, string(content), "base-files") - assert.Contains(t, string(content), "operating-system") - assert.Contains(t, string(content), "component1") - assert.Contains(t, string(content), "component2") -} diff --git a/pkg/http/http.go b/pkg/http/http.go index 7efa45be34..8e7c09e442 100644 --- a/pkg/http/http.go +++ b/pkg/http/http.go @@ -297,7 +297,7 @@ func (c *Client) initialize() *http.Client { } if len(c.trustedCerts) > 0 && !c.useDefaultTransport && !c.transportSkipVerification { - log.Entry().Info("adding certs for tls to trust") + log.Entry().Debug("adding certs for tls to trust") err := c.configureTLSToTrustCertificates(transport) if err != nil { log.Entry().Infof("adding certs for tls config failed : %v, continuing with the existing tsl config", err) @@ -381,11 +381,6 @@ func handleAuthentication(req *http.Request, username, password, token string) { if (len(username) > 0 || len(password) > 0) && len(req.Header.Get(authHeaderKey)) == 0 { req.SetBasicAuth(username, password) log.Entry().Debug("Using Basic Authentication ****/****\n") - log.Entry().Warning("------------------") - log.Entry().Warning("*** [WARNING] *** : Basic authentication is used, recommended method is API key/token authentication") - log.Entry().Warning("*** [WARNING] *** : Basic authentication will be deprecated in the near future, please use API key/token authentication.") - log.Entry().Warning("*** [WARNING] *** : For more details, please refer to BDBA documentation.") - log.Entry().Warning("------------------\n") } if len(token) > 0 && len(req.Header.Get(authHeaderKey)) == 0 { req.Header.Add(authHeaderKey, token) @@ -616,7 +611,7 @@ func (c *Client) configureTLSToTrustCertificates(transport *TransportWrapper) er return errors.Wrapf(err, "Download of TLS certificate %v failed with status code %v", certificate, response.StatusCode) } } else { - log.Entry().Infof("existing certificate file %v found, appending it to rootCA", target) + log.Entry().Debugf("existing certificate file %v found, appending it to rootCA", target) certs, err := ioutil.ReadFile(target) if err != nil { return errors.Wrapf(err, "failed to read cert file %v", certificate) @@ -626,7 +621,7 @@ func (c *Client) configureTLSToTrustCertificates(transport *TransportWrapper) er if !ok { return errors.Errorf("failed to append %v to root CA store", certificate) } - log.Entry().Infof("%v appended to root CA successfully", certificate) + log.Entry().Debugf("%v appended to root CA successfully", certificate) } } diff --git a/pkg/kubernetes/helm.go b/pkg/kubernetes/helm.go index e0f4520a78..11f4afd428 100644 --- a/pkg/kubernetes/helm.go +++ b/pkg/kubernetes/helm.go @@ -426,9 +426,7 @@ func (h *HelmExecute) RunHelmPublish() (string, error) { h.utils.SetOptions(repoClientOptions) - binary := fmt.Sprintf("%v", h.config.DeploymentName+"-"+h.config.PublishVersion+".tgz") - - targetPath := fmt.Sprintf("%v/%s", h.config.DeploymentName, binary) + binary := fmt.Sprintf("%s-%s.tgz", h.config.DeploymentName, h.config.PublishVersion) separator := "/" @@ -436,7 +434,7 @@ func (h *HelmExecute) RunHelmPublish() (string, error) { separator = "" } - targetURL := fmt.Sprintf("%s%s%s", h.config.TargetRepositoryURL, separator, targetPath) + targetURL := fmt.Sprintf("%s%s%s", h.config.TargetRepositoryURL, separator, binary) log.Entry().Infof("publishing artifact: %s", targetURL) diff --git a/pkg/kubernetes/helm_test.go b/pkg/kubernetes/helm_test.go index 872fa17353..b6debbb994 100644 --- a/pkg/kubernetes/helm_test.go +++ b/pkg/kubernetes/helm_test.go @@ -540,8 +540,8 @@ func TestRunHelmPublish(t *testing.T) { targetURL, err := helmExecute.RunHelmPublish() if assert.NoError(t, err) { assert.Equal(t, 1, len(utils.FileUploads)) - assert.Equal(t, "https://my.target.repository.local/test_helm_chart/test_helm_chart-1.2.3.tgz", targetURL) - assert.Equal(t, "https://my.target.repository.local/test_helm_chart/test_helm_chart-1.2.3.tgz", utils.FileUploads["test_helm_chart-1.2.3.tgz"]) + assert.Equal(t, "https://my.target.repository.local/test_helm_chart-1.2.3.tgz", targetURL) + assert.Equal(t, "https://my.target.repository.local/test_helm_chart-1.2.3.tgz", utils.FileUploads["test_helm_chart-1.2.3.tgz"]) } }) } diff --git a/pkg/mock/fileUtils.go b/pkg/mock/fileUtils.go index 5211ec6f54..414ec1edd4 100644 --- a/pkg/mock/fileUtils.go +++ b/pkg/mock/fileUtils.go @@ -4,8 +4,11 @@ package mock import ( + "archive/tar" "bytes" + "compress/gzip" "crypto/sha256" + "errors" "fmt" "io" "os" @@ -540,6 +543,46 @@ func (f *FilesMock) Symlink(oldname, newname string) error { return nil } +// CreateArchive creates in memory tar.gz archive, with the content provided. +func (f *FilesMock) CreateArchive(content map[string][]byte) ([]byte, error) { + if len(content) == 0 { + return nil, errors.New("mock archive content must not be empty") + } + + buf := bytes.NewBuffer(nil) + gw := gzip.NewWriter(buf) + tw := tar.NewWriter(gw) + + for fileName, fileContent := range content { + err := tw.WriteHeader(&tar.Header{ + Name: fileName, + Size: int64(len(fileContent)), + Typeflag: tar.TypeRegA, + }) + + if err != nil { + return nil, err + } + + _, err = tw.Write(fileContent) + if err != nil { + return nil, err + } + } + + err := tw.Close() + if err != nil { + return nil, err + } + + err = gw.Close() + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + // FileMock can be used in places where a io.Closer, io.StringWriter or io.Writer is expected. // It is the concrete type returned from FilesMock.OpenFile() type FileMock struct { diff --git a/pkg/mock/fileUtils_test.go b/pkg/mock/fileUtils_test.go index 53d6ab77f4..ba445745e1 100644 --- a/pkg/mock/fileUtils_test.go +++ b/pkg/mock/fileUtils_test.go @@ -1,7 +1,11 @@ package mock import ( + "archive/tar" + "bytes" + "compress/gzip" "errors" + "io" "os" "path/filepath" "testing" @@ -673,3 +677,42 @@ func TestFilesMockSymlink(t *testing.T) { assert.Equal(t, expectedErr, err) }) } + +func TestFilesMockCreateArchive(t *testing.T) { + t.Parallel() + t.Run("creates an archive with the provided content", func(t *testing.T) { + files := FilesMock{} + a, err := files.CreateArchive(map[string][]byte{ + "filename": []byte("file content"), + }) + assert.NoError(t, err) + + buf := bytes.NewBuffer(a) + zr, err := gzip.NewReader(buf) + assert.NoError(t, err) + defer zr.Close() + + tr := tar.NewReader(zr) + + for { + f, err := tr.Next() + if err == io.EOF { + break + } + assert.NoError(t, err) + assert.Equal(t, "filename", f.Name) + + content, err := io.ReadAll(tr) + assert.NoError(t, err) + assert.Equal(t, "file content", string(content)) + } + }) + + t.Run("fails if the content is empty", func(t *testing.T) { + files := FilesMock{} + a, err := files.CreateArchive(nil) + assert.Error(t, err) + assert.Equal(t, "mock archive content must not be empty", err.Error()) + assert.Nil(t, a) + }) +} diff --git a/pkg/orchestrator/gitHubActions.go b/pkg/orchestrator/gitHubActions.go index e656f937e9..60ff072b55 100644 --- a/pkg/orchestrator/gitHubActions.go +++ b/pkg/orchestrator/gitHubActions.go @@ -82,7 +82,7 @@ func (g *GitHubActionsConfigProvider) GetCommit() string { } func (g *GitHubActionsConfigProvider) GetRepoURL() string { - return getEnv("GITHUB_SERVER_URL", "n/a") + getEnv("GITHUB_REPOSITORY", "n/a") + return getEnv("GITHUB_SERVER_URL", "n/a") + "/" + getEnv("GITHUB_REPOSITORY", "n/a") } func (g *GitHubActionsConfigProvider) GetPullRequestConfig() PullRequestConfig { diff --git a/pkg/orchestrator/gitHubActions_test.go b/pkg/orchestrator/gitHubActions_test.go index a01c4c1e11..c93d15da6e 100644 --- a/pkg/orchestrator/gitHubActions_test.go +++ b/pkg/orchestrator/gitHubActions_test.go @@ -16,7 +16,7 @@ func TestGitHubActions(t *testing.T) { os.Setenv("GITHUB_REF", "refs/heads/feat/test-gh-actions") os.Setenv("GITHUB_RUN_ID", "42") os.Setenv("GITHUB_SHA", "abcdef42713") - os.Setenv("GITHUB_SERVER_URL", "github.com/") + os.Setenv("GITHUB_SERVER_URL", "github.com") os.Setenv("GITHUB_REPOSITORY", "foo/bar") p, _ := NewOrchestratorSpecificConfigProvider() diff --git a/pkg/piperenv/artifact.go b/pkg/piperenv/artifact.go index 03d82185f5..ee0c754662 100644 --- a/pkg/piperenv/artifact.go +++ b/pkg/piperenv/artifact.go @@ -1,6 +1,7 @@ package piperenv type Artifact struct { + Id string `json:"id,omitempty"` Name string `json:"name,omitempty"` } diff --git a/pkg/reporting/reporting.go b/pkg/reporting/reporting.go index dc2e91accf..b7fed1e607 100644 --- a/pkg/reporting/reporting.go +++ b/pkg/reporting/reporting.go @@ -327,7 +327,10 @@ func drawCell(cell ScanCell) string { } func shouldDrawTable(table ScanDetailTable) bool { - return len(table.Headers) > 0 + if len(table.Headers) > 0 { + return true + } + return false } func drawOverviewRow(row OverviewRow) string { diff --git a/pkg/reporting/reporting_test.go b/pkg/reporting/reporting_test.go index 1b0f0d379d..c933cb0aca 100644 --- a/pkg/reporting/reporting_test.go +++ b/pkg/reporting/reporting_test.go @@ -1,12 +1,58 @@ package reporting import ( + "io/ioutil" + "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" ) +func TestVulToMarkdown(t *testing.T) { + t.Parallel() + t.Run("success - empty", func(t *testing.T) { + t.Parallel() + vulReport := VulnerabilityReport{} + _, err := vulReport.ToMarkdown() + assert.NoError(t, err) + }) + + t.Run("success - filled", func(t *testing.T) { + t.Parallel() + vulReport := VulnerabilityReport{ + ProjectName: "theProjectName", + ProjectVersion: "theProjectVersion", + BlackDuckProjectLink: "https://the.link.to.the.project.version", + ArtifactID: "theArtifact", + Branch: "main", + CommitID: "acb123", + Description: "This is the test description.", + Origin: "Origin", + DependencyType: "direct", + Footer: "This is the test footer", + Group: "the.group", + PipelineName: "thePipelineName", + PipelineLink: "https://the.link.to.the.pipeline", + PublishDate: "2022-06-30", + Resolution: "This is the test resolution.", + Score: 7.8, + Severity: "high", + Version: "1.2.3", + PackageURL: "pkg:generic/the.group/theArtifact@1.2.3", + VulnerabilityLink: "https://the.link/to/the/vulnerability", + VulnerabilityName: "CVE-Test-001", + } + goldenFilePath := filepath.Join("testdata", "markdownVulnerability.golden") + expected, err := ioutil.ReadFile(goldenFilePath) + assert.NoError(t, err) + + res, err := vulReport.ToMarkdown() + assert.NoError(t, err) + assert.Equal(t, string(expected), string(res)) + }) +} + func TestToHTML(t *testing.T) { t.Run("empty table", func(t *testing.T) { report := ScanReport{ diff --git a/pkg/reporting/securityVulnerability.go b/pkg/reporting/securityVulnerability.go index 023443a75e..a4d34c61f0 100644 --- a/pkg/reporting/securityVulnerability.go +++ b/pkg/reporting/securityVulnerability.go @@ -14,32 +14,38 @@ import ( // VulnerabilityReport represents metadata for a report on a vulnerability type VulnerabilityReport struct { - ArtifactID string - Branch string - CommitID string - Description string - DirectDependency string - Footer string - Group string - PackageURL string - PipelineName string - PipelineLink string - PublishDate string - Resolution string - Score float64 - Severity string - Version string - VulnerabilityLink string - VulnerabilityName string + ProjectName string + ProjectVersion string + BlackDuckProjectLink string + ArtifactID string + Branch string + CommitID string + Description string + DependencyType string + Footer string + Group string + PackageURL string + PipelineName string + PipelineLink string + PublishDate string + Resolution string + Score float64 + Severity string + Version string + VulnerabilityLink string + VulnerabilityName string + Origin string } const vulnerabilityMdTemplate string = `# {{title .Severity }} ({{ .Score }}) Vulnerability {{ .VulnerabilityName }} - {{ .ArtifactID }} **Vulnerability link:** [{{ .VulnerabilityLink }}]({{ .VulnerabilityLink }}) +{{if .Resolution -}} ## Fix **{{ .Resolution }}** +{{- end}} ## Context @@ -51,14 +57,17 @@ Pipeline run: [{{ .PipelineName }}]({{ .PipelineLink }}) ### Detected in +**Project Version:** [{{ .ProjectName }} {{ .ProjectVersion }}]({{ .BlackDuckProjectLink }}) {{if .Branch}}**Branch:** {{ .Branch }}{{- end}} {{if .CommitID}}**CommitId:** {{ .CommitID }}{{- end}} -{{if .DirectDependency}}**Dependency:** {{if (eq .DirectDependency "true")}}direct{{ else }}indirect{{ end }}{{- end}} -{{if .ArtifactID}}**ArtifactId:** {{ .ArtifactID }}{{- end}} {{if .Group}}**Group:** {{ .Group }}{{- end}} +{{if .PublishDate}}**Publishing date:** {{.PublishDate }}{{- end}} + +{{if .ArtifactID}}**ArtifactId:** {{ .ArtifactID }}{{- end}} {{if .Version}}**Version:** {{ .Version }}{{- end}} +{{if .Origin}}**Origin:** {{ .Origin }}{{- end}} +{{if .DependencyType}}**Dependency:** {{ .DependencyType }}{{- end}} {{if .PackageURL}}**Package URL:** {{ .PackageURL }}{{- end}} -{{if .PublishDate}}**Publishing date:** {{.PublishDate }}{{- end}} ## Description @@ -91,6 +100,10 @@ func (v *VulnerabilityReport) ToMarkdown() ([]byte, error) { v.PipelineLink = provider.GetJobURL() v.PipelineName = provider.GetJobName() } + + if len(v.Branch) == 0 { + v.Branch = provider.GetBranch() + } } md := []byte{} diff --git a/pkg/reporting/securityVulnerability_test.go b/pkg/reporting/securityVulnerability_test.go index 0ee0130fba..8913635338 100644 --- a/pkg/reporting/securityVulnerability_test.go +++ b/pkg/reporting/securityVulnerability_test.go @@ -20,23 +20,27 @@ func TestVulnerabilityReportToMarkdown(t *testing.T) { t.Run("success - filled", func(t *testing.T) { t.Parallel() vulReport := VulnerabilityReport{ - ArtifactID: "theArtifact", - Branch: "main", - CommitID: "acb123", - Description: "This is the test description.", - DirectDependency: "true", - Footer: "This is the test footer", - Group: "the.group", - PipelineName: "thePipelineName", - PipelineLink: "https://the.link.to.the.pipeline", - PublishDate: "2022-06-30", - Resolution: "This is the test resolution.", - Score: 7.8, - Severity: "high", - Version: "1.2.3", - PackageURL: "pkg:generic/the.group/theArtifact@1.2.3", - VulnerabilityLink: "https://the.link/to/the/vulnerability", - VulnerabilityName: "CVE-Test-001", + BlackDuckProjectLink: "https://the.link.to.the.project.version", + ProjectName: "theProjectName", + ProjectVersion: "theProjectVersion", + ArtifactID: "theArtifact", + Branch: "main", + CommitID: "acb123", + Description: "This is the test description.", + DependencyType: "direct", + Origin: "Origin", + Footer: "This is the test footer", + Group: "the.group", + PipelineName: "thePipelineName", + PipelineLink: "https://the.link.to.the.pipeline", + PublishDate: "2022-06-30", + Resolution: "This is the test resolution.", + Score: 7.8, + Severity: "high", + Version: "1.2.3", + PackageURL: "pkg:generic/the.group/theArtifact@1.2.3", + VulnerabilityLink: "https://the.link/to/the/vulnerability", + VulnerabilityName: "CVE-Test-001", } goldenFilePath := filepath.Join("testdata", "markdownVulnerability.golden") expected, err := os.ReadFile(goldenFilePath) diff --git a/pkg/reporting/testdata/markdownVulnerability.golden b/pkg/reporting/testdata/markdownVulnerability.golden index acf3b96ef7..6051604dc1 100644 --- a/pkg/reporting/testdata/markdownVulnerability.golden +++ b/pkg/reporting/testdata/markdownVulnerability.golden @@ -14,14 +14,17 @@ Pipeline run: [thePipelineName](https://the.link.to.the.pipeline) ### Detected in +**Project Version:** [theProjectName theProjectVersion](https://the.link.to.the.project.version) **Branch:** main **CommitId:** acb123 -**Dependency:** direct -**ArtifactId:** theArtifact **Group:** the.group +**Publishing date:** 2022-06-30 + +**ArtifactId:** theArtifact **Version:** 1.2.3 +**Origin:** Origin +**Dependency:** direct **Package URL:** pkg:generic/the.group/theArtifact@1.2.3 -**Publishing date:** 2022-06-30 ## Description diff --git a/pkg/syft/syft.go b/pkg/syft/syft.go new file mode 100644 index 0000000000..4600323b6c --- /dev/null +++ b/pkg/syft/syft.go @@ -0,0 +1,123 @@ +package syft + +import ( + "archive/tar" + "compress/gzip" + "fmt" + "io" + "net/http" + "path/filepath" + "strings" + + "github.com/SAP/jenkins-library/pkg/command" + piperhttp "github.com/SAP/jenkins-library/pkg/http" + "github.com/SAP/jenkins-library/pkg/piperutils" + "github.com/pkg/errors" +) + +func GenerateSBOM(syftDownloadURL, dockerConfigDir string, execRunner command.ExecRunner, fileUtils piperutils.FileUtils, httpClient piperhttp.Sender, registryURL string, images []string) error { + if registryURL == "" { + return errors.New("syft: regisitry url must not be empty") + } + + if len(images) == 0 { + return errors.New("syft: no images provided") + } + + execRunner.AppendEnv([]string{fmt.Sprintf("DOCKER_CONFIG=%s", dockerConfigDir)}) + + tmpDir, err := fileUtils.TempDir("", "syft") + if err != nil { + return err + } + syftFile := filepath.Join(tmpDir, "syft") + + err = install(syftDownloadURL, syftFile, fileUtils, httpClient) + if err != nil { + return errors.Wrap(err, "failed to install syft") + } + + for index, image := range images { + if image == "" { + return errors.New("syft: image name must not be empty") + } + // TrimPrefix needed as syft needs containerRegistry name only + err = execRunner.RunExecutable(syftFile, "packages", fmt.Sprintf("registry:%s/%s", strings.TrimPrefix(registryURL, "https://"), image), "-o", "cyclonedx-xml", "--file", fmt.Sprintf("bom-docker-%v.xml", index), "-q") + if err != nil { + return fmt.Errorf("failed to generate SBOM: %w", err) + } + } + + return nil +} + +func install(syftDownloadURL, dest string, fileUtils piperutils.FileUtils, httpClient piperhttp.Sender) error { + response, err := httpClient.SendRequest(http.MethodGet, syftDownloadURL, nil, nil, nil) + if err != nil { + return fmt.Errorf("failed to download syft binary: %w", err) + } + defer response.Body.Close() + + err = extractSyft(response.Body, dest, fileUtils) + if err != nil { + return errors.Wrap(err, "failed to extract syft binary") + } + + err = fileUtils.Chmod(dest, 0755) + if err != nil { + return err + } + + return nil +} + +func extractSyft(archive io.Reader, dest string, fileUtils piperutils.FileUtils) error { + zr, err := gzip.NewReader(archive) + if err != nil { + return err + } + defer zr.Close() + + tr := tar.NewReader(zr) + + fileFound := false + for { + f, err := tr.Next() + if err == io.EOF { + break + } + + if err != nil { + return errors.Wrap(err, "failed to read archive") + } + + if filepath.Base(f.Name) == "syft" { + fileFound = true + + df, err := fileUtils.Create(dest) + if err != nil { + return errors.Wrapf(err, "failed to create file %q", dest) + } + + size, err := io.Copy(df, tr) + if err != nil { + return err + } + + err = df.Close() + if err != nil { + return err + } + + if size != f.Size { + return fmt.Errorf("only wrote %d bytes to %s; expected %d", size, dest, f.Size) + } + } + } + + if !fileFound { + return errors.New("no file with the name 'syft' was found") + } + + return nil +} diff --git a/pkg/syft/syft_test.go b/pkg/syft/syft_test.go new file mode 100644 index 0000000000..9906de081f --- /dev/null +++ b/pkg/syft/syft_test.go @@ -0,0 +1,91 @@ +package syft_test + +import ( + "net/http" + "testing" + + piperhttp "github.com/SAP/jenkins-library/pkg/http" + "github.com/SAP/jenkins-library/pkg/mock" + "github.com/SAP/jenkins-library/pkg/syft" + "github.com/jarcoal/httpmock" + "github.com/pkg/errors" + + "github.com/stretchr/testify/assert" +) + +func TestGenerateSBOM(t *testing.T) { + execMock := mock.ExecMockRunner{} + fileMock := mock.FilesMock{} + + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + fakeArchive, err := fileMock.CreateArchive(map[string][]byte{"syft": []byte("test")}) + assert.NoError(t, err) + + httpmock.RegisterResponder(http.MethodGet, "http://test-syft-gh-release.com/syft.tar.gz", httpmock.NewBytesResponder(http.StatusOK, fakeArchive)) + httpmock.RegisterResponder(http.MethodGet, "http://not-found.com/syft.tar.gz", httpmock.NewBytesResponder(http.StatusNotFound, nil)) + httpmock.RegisterResponder(http.MethodGet, "http://failure.com/syft.tar.gz", httpmock.NewErrorResponder(errors.New("network error"))) + client := &piperhttp.Client{} + client.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true}) + + t.Run("should generate SBOM", func(t *testing.T) { + err := syft.GenerateSBOM("http://test-syft-gh-release.com/syft.tar.gz", "", &execMock, &fileMock, client, "https://my-registry", []string{"image:latest", "image:1.2.3"}) + assert.NoError(t, err) + + assert.True(t, fileMock.HasFile("/tmp/syfttest/syft")) + fi, err := fileMock.Stat("/tmp/syfttest/syft") + assert.NoError(t, err) + assert.Equal(t, fi.Mode().Perm().String(), "-rwxr-xr-x") + + assert.Len(t, execMock.Calls, 2) + firstCall := execMock.Calls[0] + assert.Equal(t, firstCall.Exec, "/tmp/syfttest/syft") + assert.Equal(t, firstCall.Params, []string{"packages", "registry:my-registry/image:latest", "-o", "cyclonedx-xml", "--file", "bom-docker-0.xml", "-q"}) + + secondCall := execMock.Calls[1] + assert.Equal(t, secondCall.Exec, "/tmp/syfttest/syft") + assert.Equal(t, secondCall.Params, []string{"packages", "registry:my-registry/image:1.2.3", "-o", "cyclonedx-xml", "--file", "bom-docker-1.xml", "-q"}) + }) + + t.Run("error case: syft execution failed", func(t *testing.T) { + execMock = mock.ExecMockRunner{} + execMock.ShouldFailOnCommand = map[string]error{ + "/tmp/syfttest/syft packages registry:my-registry/image:latest -o cyclonedx-xml --file bom-docker-0.xml -q": errors.New("failed"), + } + + err := syft.GenerateSBOM("http://test-syft-gh-release.com/syft.tar.gz", "", &execMock, &fileMock, client, "https://my-registry", []string{"image:latest"}) + assert.Error(t, err) + assert.Equal(t, "failed to generate SBOM: failed", err.Error()) + }) + + t.Run("error case: no registry", func(t *testing.T) { + err := syft.GenerateSBOM("http://test-syft-gh-release.com/syft.tar.gz", "", &execMock, &fileMock, client, "", []string{"image:latest"}) + assert.Error(t, err) + assert.Equal(t, "syft: regisitry url must not be empty", err.Error()) + }) + + t.Run("error case: no images provided", func(t *testing.T) { + err := syft.GenerateSBOM("http://test-syft-gh-release.com/syft.tar.gz", "", &execMock, &fileMock, client, "my-registry", nil) + assert.Error(t, err) + assert.Equal(t, "syft: no images provided", err.Error()) + }) + + t.Run("error case: empty image name", func(t *testing.T) { + err := syft.GenerateSBOM("http://test-syft-gh-release.com/syft.tar.gz", "", &execMock, &fileMock, client, "my-registry", []string{""}) + assert.Error(t, err) + assert.Equal(t, "syft: image name must not be empty", err.Error()) + }) + + t.Run("error case: failed to download archive (not found)", func(t *testing.T) { + err := syft.GenerateSBOM("http://not-found.com/syft.tar.gz", "", &execMock, &fileMock, client, "my-registry", []string{"img"}) + assert.Error(t, err) + assert.Equal(t, "failed to install syft: failed to download syft binary: request to http://not-found.com/syft.tar.gz returned with response 404", err.Error()) + }) + + t.Run("error case: failed to download archive (network error)", func(t *testing.T) { + err := syft.GenerateSBOM("http://failure.com/syft.tar.gz", "", &execMock, &fileMock, client, "my-registry", []string{"img"}) + assert.Error(t, err) + assert.Equal(t, "failed to install syft: failed to download syft binary: HTTP GET request to http://failure.com/syft.tar.gz failed: Get \"http://failure.com/syft.tar.gz\": network error", err.Error()) + }) +} diff --git a/pkg/whitesource/whitesource.go b/pkg/whitesource/whitesource.go index 6a3acf8130..20bcb88abf 100644 --- a/pkg/whitesource/whitesource.go +++ b/pkg/whitesource/whitesource.go @@ -60,8 +60,16 @@ type Alert struct { Status string `json:"status,omitempty"` } +// DependencyType returns type of dependency: direct/transitive +func (a *Alert) DependencyType() string { + if a.DirectDependency == true { + return "direct" + } + return "transitive" +} + // Title returns the issue title representation of the contents -func (a *Alert) Title() string { +func (a Alert) Title() string { if a.Type == "SECURITY_VULNERABILITY" { return fmt.Sprintf("Security Vulnerability %v %v", a.Vulnerability.Name, a.Library.ArtifactID) } else if a.Type == "REJECTED_BY_POLICY_RESOURCE" { @@ -145,7 +153,7 @@ func consolidate(cvss2severity, cvss3severity string, cvss2score, cvss3score flo } // ToMarkdown returns the markdown representation of the contents -func (a *Alert) ToMarkdown() ([]byte, error) { +func (a Alert) ToMarkdown() ([]byte, error) { if a.Type == "SECURITY_VULNERABILITY" { score := consolidateScores(a.Vulnerability.Score, a.Vulnerability.CVSS3Score) @@ -153,10 +161,10 @@ func (a *Alert) ToMarkdown() ([]byte, error) { vul := reporting.VulnerabilityReport{ ArtifactID: a.Library.ArtifactID, // no information available about branch and commit, yet - Branch: "", - CommitID: "", - Description: a.Vulnerability.Description, - DirectDependency: fmt.Sprint(a.DirectDependency), + Branch: "", + CommitID: "", + Description: a.Vulnerability.Description, + DependencyType: a.DependencyType(), // no information available about footer, yet Footer: "", Group: a.Library.GroupID, diff --git a/resources/metadata/abapEnvironmentAssembleConfirm.yaml b/resources/metadata/abapEnvironmentAssembleConfirm.yaml index 527ea5739c..81746acd0d 100644 --- a/resources/metadata/abapEnvironmentAssembleConfirm.yaml +++ b/resources/metadata/abapEnvironmentAssembleConfirm.yaml @@ -1,8 +1,8 @@ metadata: name: abapEnvironmentAssembleConfirm - description: "Confirm the Delivery of Assembly for installation, support package or patch in SAP Cloud Platform ABAP Environment system" + description: "Confirm the Delivery of Assembly for installation, support package or patch in SAP BTP ABAP Environment system" longDescription: | - This step confirms the assemblies of provided [installations, support packages or patches] in SAP Cloud Platform ABAP Environment system + This step confirms the assemblies of provided [installations, support packages or patches] in SAP BTP ABAP Environment system spec: inputs: secrets: @@ -71,7 +71,7 @@ spec: - name: cloudFoundry/serviceKeyName - name: cfServiceKey - name: host - description: Specifies the host address of the SAP Cloud Platform ABAP Environment system + description: Specifies the host address of the SAP BTP ABAP Environment system type: string mandatory: false scope: diff --git a/resources/metadata/abapEnvironmentAssemblePackages.yaml b/resources/metadata/abapEnvironmentAssemblePackages.yaml index bb95640d6a..0d5263485b 100644 --- a/resources/metadata/abapEnvironmentAssemblePackages.yaml +++ b/resources/metadata/abapEnvironmentAssemblePackages.yaml @@ -1,6 +1,6 @@ metadata: name: abapEnvironmentAssemblePackages - description: "Assembly of installation, support package or patch in SAP Cloud Platform ABAP Environment system" + description: "Assembly of installation, support package or patch in SAP BTP ABAP Environment system" longDescription: | This step runs the assembly of a list of provided [installations, support packages or patches](https://help.sap.com/viewer/9043aa5d2f834ad385e1cdfdadc06b6f/LATEST/en-US/9a81f55473568c77e10000000a174cb4.html) in SAP Cloud Platform ABAP Environment system and saves the corresponding [SAR archive](https://launchpad.support.sap.com/#/notes/212876) to the filesystem. @@ -72,7 +72,7 @@ spec: - name: cloudFoundry/serviceKeyName - name: cfServiceKey - name: host - description: Specifies the host address of the SAP Cloud Platform ABAP Environment system + description: Specifies the host address of the SAP BTP ABAP Environment system type: string mandatory: false scope: diff --git a/resources/metadata/abapEnvironmentBuild.yaml b/resources/metadata/abapEnvironmentBuild.yaml index 4daa9cf6f0..c331e21781 100644 --- a/resources/metadata/abapEnvironmentBuild.yaml +++ b/resources/metadata/abapEnvironmentBuild.yaml @@ -71,7 +71,7 @@ spec: - name: cloudFoundry/serviceKeyName - name: cfServiceKey - name: host - description: Specifies the host address of the SAP Cloud Platform ABAP Environment system + description: Specifies the host address of the SAP BTP ABAP Environment system type: string mandatory: false scope: @@ -80,7 +80,7 @@ spec: - STEPS - GENERAL - name: abapSourceClient - description: Specifies the client of the SAP Cloud Platform ABAP Environment system, use only in combination with host + description: Specifies the client of the SAP BTP ABAP Environment system, use only in combination with host type: string mandatory: false scope: diff --git a/resources/metadata/abapEnvironmentRunATCCheck.yaml b/resources/metadata/abapEnvironmentRunATCCheck.yaml index b12144ce0f..cfdb9249a1 100644 --- a/resources/metadata/abapEnvironmentRunATCCheck.yaml +++ b/resources/metadata/abapEnvironmentRunATCCheck.yaml @@ -2,7 +2,7 @@ metadata: name: abapEnvironmentRunATCCheck description: Runs an ATC Check longDescription: | - This step is for triggering an [ATC](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/d8cec788fc104ff9ad9c3757b4dd13d4.html) test run on an SAP Cloud Platform ABAP Environment system. + This step is for triggering an [ATC](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/d8cec788fc104ff9ad9c3757b4dd13d4.html) test run on an SAP BTP ABAP Environment system. Please provide either of the following options: * The host and credentials the Cloud Platform ABAP Environment system itself. The credentials must be configured for the Communication Scenario [SAP_COM_0901](https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/d8cec788fc104ff9ad9c3757b4dd13d4.html). @@ -120,7 +120,7 @@ spec: param: password - name: host type: string - description: Specifies the host address of the SAP Cloud Platform ABAP Environment system + description: Specifies the host address of the SAP BTP ABAP Environment system scope: - PARAMETERS - STAGES diff --git a/resources/metadata/checkmarxExecuteScan.yaml b/resources/metadata/checkmarxExecuteScan.yaml index 802509a28b..1db30b0e40 100644 --- a/resources/metadata/checkmarxExecuteScan.yaml +++ b/resources/metadata/checkmarxExecuteScan.yaml @@ -36,12 +36,14 @@ spec: default: [] - name: avoidDuplicateProjectScans type: bool - description: Whether duplicate scans of the same project state shall be avoided or not + description: Tell Checkmarx to skip the scan if no code change is detected scope: - PARAMETERS - STAGES - STEPS default: true + aliases: + - name: notForceScan - name: filterPattern type: string description: The filter pattern used to zip the files relevant for scanning, patterns can be negated by setting an exclamation mark in front i.e. `!test/*.js` would avoid adding any javascript files located in the test directory @@ -199,14 +201,15 @@ spec: - PARAMETERS - STAGES - STEPS - - name: sourceEncoding + - name: engineConfigurationID type: string - description: The source encoding to be used, if not set explicitly the project's default will be used + description: The engine configuration ID to be used, if not set explicitly the project's default will be used scope: - PARAMETERS - STAGES - STEPS - default: "1" + aliases: + - name: sourceEncoding - name: teamId aliases: - name: checkmarxGroupId diff --git a/resources/metadata/cloudFoundryDeploy.yaml b/resources/metadata/cloudFoundryDeploy.yaml index 0c16c58a6e..68614f51a1 100644 --- a/resources/metadata/cloudFoundryDeploy.yaml +++ b/resources/metadata/cloudFoundryDeploy.yaml @@ -137,8 +137,8 @@ spec: type: string description: "Defines the type of deployment, either `standard` deployment which results in a system - downtime or a zero-downtime `blue-green` deployment.If 'cf_native' as deployType and 'blue-green' - as deployTool is used in combination, your manifest.yaml may only contain one application. + downtime or a zero-downtime `blue-green` deployment. If 'cf_native' as deployTool and 'blue-green' + as deployType is used in combination, your manifest.yaml may only contain one application. If this application has the option 'no-route' active the deployType will be changed to 'standard'." scope: - PARAMETERS diff --git a/resources/metadata/cnbBuild.yaml b/resources/metadata/cnbBuild.yaml index 3385170065..8d23e2cc45 100644 --- a/resources/metadata/cnbBuild.yaml +++ b/resources/metadata/cnbBuild.yaml @@ -258,12 +258,19 @@ spec: param: custom/buildSettingsInfo - name: createBOM type: bool - description: "**EXPERIMENTAL:** Creates the bill of materials (BOM) using CycloneDX plugin." + description: Creates the bill of materials (BOM) using Syft and stores it in a file in CycloneDX 1.4 format. scope: - GENERAL - STEPS - STAGES - PARAMETERS + - name: syftDownloadUrl + type: string + description: Specifies the download url of the Syft Linux amd64 tar binary file. This can be found at https://github.com/anchore/syft/releases/. + scope: + - PARAMETERS + - STEPS + default: "https://github.com/anchore/syft/releases/download/v0.62.3/syft_0.62.3_linux_amd64.tar.gz" - name: runImage type: string description: "Base image from which application images are built. Will be defaulted to the image provided by the builder." @@ -272,6 +279,14 @@ spec: - STEPS - STAGES - PARAMETERS + - name: defaultProcess + type: string + description: "Process that should be started by default. See https://buildpacks.io/docs/app-developer-guide/run-an-app/" + scope: + - GENERAL + - STEPS + - STAGES + - PARAMETERS outputs: resources: - name: commonPipelineEnvironment diff --git a/resources/metadata/detectExecuteScan.yaml b/resources/metadata/detectExecuteScan.yaml index 9e26747562..f1fb0476d1 100644 --- a/resources/metadata/detectExecuteScan.yaml +++ b/resources/metadata/detectExecuteScan.yaml @@ -2,7 +2,7 @@ metadata: name: detectExecuteScan description: Executes Synopsys Detect scan longDescription: | - This step executes [Synopsys Detect](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/62423113/Synopsys+Detect) scans. + This step executes [Synopsys Detect](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=introduction.html&_LANG=enus) 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: @@ -106,7 +106,7 @@ spec: - 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) + description: Properties passed to the Synopsis Detect (formerly BlackDuck) scan. You can find details in the [Synopsis Detect documentation](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=properties%2Fall-properties.html&_LANG=enus) aliases: - name: detect/scanProperties type: "[]string" @@ -143,7 +143,7 @@ spec: 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 values can be found at [Synopsys detect documentation](https://blackducksoftware.github.io/synopsys-detect/latest/properties/configuration/project/#fail-on-policy-violation-severities) + The list of accepted values can be found at [Synopsys detect documentation](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=properties%2Fconfiguration%2Fproject.html&anchor=fail-on-policy-violation-severities&_LANG=enus) aliases: - name: detect/failOn type: "[]string" @@ -247,7 +247,7 @@ spec: - name: includedPackageManagers description: "The package managers that need to be included for this scan. Providing the package manager names with this parameter will ensure that the build descriptor file of that package manager will be searched in the scan folder - For the complete list of possible values for this parameter, please refer [Synopsys detect documentation](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/631407160/Configuring+Detect+General+Properties#Detector-types-included-(Advanced))" + For the complete list of possible values for this parameter, please refer [Synopsys detect documentation](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=properties%2Fconfiguration%2Fdetector.html&_LANG=enus&anchor=detector-types-included-advanced)" aliases: - name: detect/includedPackageManagers type: "[]string" @@ -258,7 +258,7 @@ spec: - name: excludedPackageManagers description: "The package managers that need to be excluded for this scan. Providing the package manager names with this parameter will ensure that the build descriptor file of that package manager will be ignored in the scan folder - For the complete list of possible values for this parameter, please refer [Synopsys detect documentation](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/631407160/Configuring+Detect+General+Properties#%5BhardBreak%5DDetector-types-excluded-(Advanced))" + For the complete list of possible values for this parameter, please refer [Synopsys detect documentation](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=properties%2Fconfiguration%2Fdetector.html&_LANG=enus&anchor=detector-types-excluded-advanced)" aliases: - name: detect/excludedPackageManagers type: "[]string" @@ -278,7 +278,7 @@ spec: - name: detectTools description: "The type of BlackDuck scanners to include while running the BlackDuck scan. By default All scanners are included. - For the complete list of possible values, Please refer [Synopsys detect documentation](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/631407160/Configuring+Detect+General+Properties#Detect-tools-included)" + For the complete list of possible values, Please refer [Synopsys detect documentation](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=properties%2Fconfiguration%2Fpaths.html&_LANG=enus&anchor=detect-tools-included)" aliases: - name: detect/detectTools type: "[]string" @@ -299,7 +299,7 @@ spec: - name: customEnvironmentVariables description: "A list of environment variables which can be set to prepare the environment to run a BlackDuck scan. This includes a list of environment variables defined by - Synopsys. The full list can be found [here](https://synopsys.atlassian.net/wiki/spaces/IA/pages/1562214619/Shell+Script+Reference+6.9.0) + Synopsys. The full list can be found [here](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=configuring%2Fenvvars.html&_LANG=enus) This list affects the detect script downloaded while running the scan. By default detect7.sh will be used. To continue using different versions of detect, please use DETECT_LATEST_RELEASE_VERSION and set it to a valid value defined [here](https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=releasenotes.html&_LANG=enus) Additionally, please note, depending on the Project certain versions of detect will be required. @@ -436,18 +436,24 @@ spec: params: - filePattern: "**/*BlackDuck_RiskReport.pdf" type: blackduck-ip - - filePattern: "blackduck-ip.json" + - filePattern: "**/blackduck-ip.json" type: blackduck-ip - filePattern: "**/toolrun_detectExecute_*.json" type: blackduck-ip - - filePattern: "**/piper_detect_vulnerability_report.html" - type: blackduck-ip - - filePattern: "**/detectExecuteScan_oss_*.json" - type: blackduck-ip - filePattern: "**/piper_detect_policy_violation_report.html" type: blackduck-ip + - filePattern: "**/*BlackDuck_RiskReport.pdf" + type: blackduck-security - filePattern: "**/detectExecuteScan_policy_*.json" - type: blackduck-ip + type: blackduck-security + - filePattern: "**/piper_detect_vulnerability_report.html" + type: blackduck-security + - filePattern: "**/toolrun_detectExecute_*.json" + type: blackduck-security + - filePattern: "**/piper_detect_vulnerability.sarif" + type: blackduck-security + - filePattern: "**/piper_hub_detect_sbom.xml" + type: blackduck-security containers: - name: openjdk image: openjdk:11 diff --git a/resources/metadata/golangBuild.yaml b/resources/metadata/golangBuild.yaml index a25053e24a..87f1cbf593 100644 --- a/resources/metadata/golangBuild.yaml +++ b/resources/metadata/golangBuild.yaml @@ -241,6 +241,13 @@ spec: resourceRef: - name: commonPipelineEnvironment param: artifactVersion + - name: golangciLintUrl + type: string + description: Specifies the download url of the Golangci-Lint Linux amd64 tar binary file. This can be found at https://github.com/golangci/golangci-lint/releases. + scope: + - PARAMETERS + - STEPS + default: "https://github.com/golangci/golangci-lint/releases/download/v1.50.1/golangci-lint-1.50.1-linux-amd64.tar.gz" outputs: resources: - name: commonPipelineEnvironment diff --git a/resources/metadata/gradleExecuteBuild.yaml b/resources/metadata/gradleExecuteBuild.yaml index 61ce30fd9b..3c957c609e 100644 --- a/resources/metadata/gradleExecuteBuild.yaml +++ b/resources/metadata/gradleExecuteBuild.yaml @@ -115,6 +115,28 @@ spec: - STAGES - PARAMETERS default: false + - name: applyPublishingForAllProjects + type: bool + description: If set to false publishing logic will be applied in 'rootProject' directive, otherwise 'allprojects' will be directive used + scope: + - STEPS + - STAGES + - PARAMETERS + default: false + - name: excludeCreateBOMForProjects + description: Defines which projects/subprojects will be ignored during bom creation. Only if applyCreateBOMForAllProjects is set to true + scope: + - PARAMETERS + - STAGES + - STEPS + type: "[]string" + - name: excludePublishingForProjects + description: Defines which projects/subprojects will be ignored during publishing. Only if applyCreateBOMForAllProjects is set to true + scope: + - PARAMETERS + - STAGES + - STEPS + type: "[]string" outputs: resources: - name: reports diff --git a/resources/metadata/integrationArtifactDeploy.yaml b/resources/metadata/integrationArtifactDeploy.yaml index 40412223a7..742f3c8930 100644 --- a/resources/metadata/integrationArtifactDeploy.yaml +++ b/resources/metadata/integrationArtifactDeploy.yaml @@ -2,7 +2,7 @@ metadata: name: integrationArtifactDeploy description: Deploy a CPI integration flow longDescription: | - With this step you can deploy a integration flow artifact in to SAP Cloud Platform integration runtime using OData API. Learn more about the SAP Cloud Integration remote API for deploying an integration artifact [here](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/d1679a80543f46509a7329243b595bdb.html) + With this step you can deploy a integration flow artifact in to SAP BTP integration runtime using OData API. Learn more about the SAP Cloud Integration remote API for deploying an integration artifact [here](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/d1679a80543f46509a7329243b595bdb.html) spec: inputs: diff --git a/resources/metadata/integrationArtifactGetServiceEndpoint.yaml b/resources/metadata/integrationArtifactGetServiceEndpoint.yaml index c56810f631..9d5baa133b 100644 --- a/resources/metadata/integrationArtifactGetServiceEndpoint.yaml +++ b/resources/metadata/integrationArtifactGetServiceEndpoint.yaml @@ -2,7 +2,7 @@ metadata: name: integrationArtifactGetServiceEndpoint description: Get an deployed CPI intgeration flow service endpoint longDescription: | - With this step you can obtain information about the service endpoints exposed by SAP Cloud Platform Integration on a tenant using OData API. Learn more about the SAP Cloud Integration remote API for getting service endpoint of deployed integration artifact [here](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/d1679a80543f46509a7329243b595bdb.html). + With this step you can obtain information about the service endpoints exposed by SAP BTP Integration on a tenant using OData API. Learn more about the SAP Cloud Integration remote API for getting service endpoint of deployed integration artifact [here](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/d1679a80543f46509a7329243b595bdb.html). spec: inputs: diff --git a/resources/metadata/integrationArtifactTriggerIntegrationTest.yaml b/resources/metadata/integrationArtifactTriggerIntegrationTest.yaml index 8290eb3062..e06bae53f9 100644 --- a/resources/metadata/integrationArtifactTriggerIntegrationTest.yaml +++ b/resources/metadata/integrationArtifactTriggerIntegrationTest.yaml @@ -2,7 +2,7 @@ metadata: name: integrationArtifactTriggerIntegrationTest description: Test the service endpoint of your iFlow longDescription: | - With this step you can test your intergration flow exposed by SAP Cloud Platform Integration on a tenant using OData API.Learn more about the SAP Cloud Integration remote API for getting service endpoint of deployed integration artifact [here](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/d1679a80543f46509a7329243b595bdb.html). + With this step you can test your intergration flow exposed by SAP BTP Integration on a tenant using OData API.Learn more about the SAP Cloud Integration remote API for getting service endpoint of deployed integration artifact [here](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/d1679a80543f46509a7329243b595bdb.html). spec: inputs: diff --git a/resources/metadata/kanikoExecute.yaml b/resources/metadata/kanikoExecute.yaml index 3551ede529..9da817ee88 100644 --- a/resources/metadata/kanikoExecute.yaml +++ b/resources/metadata/kanikoExecute.yaml @@ -259,12 +259,19 @@ spec: - PARAMETERS - name: createBOM type: bool - description: Creates the bill of materials (BOM) using Syft and stored in a file of CycloneDX 1.4 format. + description: Creates the bill of materials (BOM) using Syft and stores it in a file in CycloneDX 1.4 format. scope: - GENERAL - STEPS - STAGES - PARAMETERS + - name: syftDownloadUrl + type: string + description: Specifies the download url of the Syft Linux amd64 tar binary file. This can be found at https://github.com/anchore/syft/releases/. + scope: + - PARAMETERS + - STEPS + default: "https://github.com/anchore/syft/releases/download/v0.62.3/syft_0.62.3_linux_amd64.tar.gz" outputs: resources: - name: commonPipelineEnvironment @@ -280,6 +287,11 @@ spec: - name: container/imageDigests type: "[]string" - name: custom/buildSettingsInfo + - name: reports + type: reports + params: + - filePattern: "**/bom-*.xml" + type: sbom containers: - image: gcr.io/kaniko-project/executor:debug command: diff --git a/resources/metadata/whitesourceExecuteScan.yaml b/resources/metadata/whitesourceExecuteScan.yaml index 4d249c5309..d6e27b3f19 100644 --- a/resources/metadata/whitesourceExecuteScan.yaml +++ b/resources/metadata/whitesourceExecuteScan.yaml @@ -633,18 +633,20 @@ spec: params: - filePattern: "**/whitesource-ip.json" type: whitesource-ip - - filePattern: "whitesource-riskReport.pdf" + - filePattern: "**/whitesource-riskReport.pdf" type: whitesource-ip - filePattern: "**/toolrun_whitesource_*.json" type: whitesource-ip - filePattern: "**/piper_whitesource_vulnerability_report.html" type: whitesource-security - - filePattern: "whitesource-riskReport.pdf" + - filePattern: "**/whitesource-riskReport.pdf" type: whitesource-security - filePattern: "**/toolrun_whitesource_*.json" type: whitesource-security - filePattern: "**/piper_whitesource_vulnerability.sarif" type: whitesource-security + - filePattern: "**/piper_whitesource_sbom.xml" + type: whitesource-security containers: - image: buildpack-deps:stretch-curl workingDir: /tmp diff --git a/test/groovy/MailSendNotificationTest.groovy b/test/groovy/MailSendNotificationTest.groovy index 52f1d76822..2857cee912 100644 --- a/test/groovy/MailSendNotificationTest.groovy +++ b/test/groovy/MailSendNotificationTest.groovy @@ -244,4 +244,57 @@ user3@domain.com noreply+github@domain.com''' assertThat(credentials, hasItem('')) assertJobStatusSuccess() } + + @Test + void testSendNotificationMailOnFirstBuild() throws Exception { + def emailExtCalls = [] + def buildMock = [ + fullProjectName: 'testProjectName', + displayName: 'testDisplayName', + result: 'SUCCESS', + getPreviousBuild: { + return null + } + ] + nullScript.currentBuild = buildMock + helper.registerAllowedMethod('emailext', [Map.class], { map -> + emailExtCalls.add(map) + return '' + }) + + stepRule.step.mailSendNotification( + script: nullScript, + notifyCulprits: false, + gitUrl: 'git@github.domain.com:IndustryCloudFoundation/pipeline-test-node.git' + ) + + assertThat(emailExtCalls, hasSize(0)) + } + + @Test + void testSendNotificationMailOnRecovery() throws Exception { + def emailExtCalls = [] + def buildMock = [ + fullProjectName: 'testProjectName', + displayName: 'testDisplayName', + result: 'SUCCESS', + getPreviousBuild: { + return [result: 'FAILURE'] + } + ] + nullScript.currentBuild = buildMock + helper.registerAllowedMethod('emailext', [Map.class], { map -> + emailExtCalls.add(map) + return '' + }) + + stepRule.step.mailSendNotification( + script: nullScript, + notifyCulprits: false, + gitUrl: 'git@github.domain.com:IndustryCloudFoundation/pipeline-test-node.git' + ) + + assertThat(emailExtCalls, hasSize(1)) + assertThat(emailExtCalls[0].subject, is("SUCCESS: Build testProjectName testDisplayName is back to normal")) + } } diff --git a/test/groovy/templates/AbapEnvironmentPipelineStageBuild.groovy b/test/groovy/templates/AbapEnvironmentPipelineStageBuild.groovy index 4d84a229c6..bf628ab921 100644 --- a/test/groovy/templates/AbapEnvironmentPipelineStageBuild.groovy +++ b/test/groovy/templates/AbapEnvironmentPipelineStageBuild.groovy @@ -59,7 +59,6 @@ class AbapEnvironmentPipelineStageBuildTest extends BasePiperTest { 'abapAddonAssemblyKitCreateTargetVector', 'abapAddonAssemblyKitPublishTargetVector')) assertThat(stepsCalled, not(hasItems('abapEnvironmentCreateTag'))) - } @Test @@ -80,4 +79,22 @@ class AbapEnvironmentPipelineStageBuildTest extends BasePiperTest { assertThat(stepsCalled, not(hasItems('cloudFoundryCreateServiceKey'))) } + @Test + void testAbapEnvironmentRunTest4TestBuild() { + nullScript.commonPipelineEnvironment.configuration.runStage = [ + 'Build': true + ] + jsr.step.abapEnvironmentPipelineStageBuild(script: nullScript, testBuild: true, generateTagForAddonComponentVersion: true) + + assertThat(stepsCalled, hasItems('cloudFoundryCreateServiceKey', + 'abapEnvironmentAssemblePackages', + 'abapEnvironmentBuild', + 'abapAddonAssemblyKitRegisterPackages', + 'abapAddonAssemblyKitCreateTargetVector')) + assertThat(stepsCalled, not(hasItems('abapAddonAssemblyKitReleasePackages', + 'abapEnvironmentAssembleConfirm', + 'abapAddonAssemblyKitPublishTargetVector', + 'abapEnvironmentCreateTag'))) + } + } diff --git a/test/groovy/templates/AbapEnvironmentPipelineStageIntegrationTestsTest.groovy b/test/groovy/templates/AbapEnvironmentPipelineStageIntegrationTestsTest.groovy index 06ba93c754..493221a379 100644 --- a/test/groovy/templates/AbapEnvironmentPipelineStageIntegrationTestsTest.groovy +++ b/test/groovy/templates/AbapEnvironmentPipelineStageIntegrationTestsTest.groovy @@ -97,4 +97,19 @@ class abapEnvironmentPipelineStageIntegrationTestsTest extends BasePiperTest { assertThat(stepsCalled, hasItems('cloudFoundryDeleteService')) } + @Test + void testIntegrationTestsTageSkipped4testBuild() { + + nullScript.commonPipelineEnvironment.configuration.runStage = [ + 'Integration Tests': true + ] + jsr.step.abapEnvironmentPipelineStageIntegrationTests(script: nullScript, testBuild: true) + + assertThat(stepsCalled, not(hasItems('input', + 'abapEnvironmentCreateSystem', + 'cloudFoundryDeleteService', + 'abapEnvironmentBuild', + 'cloudFoundryCreateServiceKey'))) + } + } diff --git a/test/groovy/templates/AbapEnvironmentPipelineStagePublishTest.groovy b/test/groovy/templates/AbapEnvironmentPipelineStagePublishTest.groovy index 05dce0bcc7..bb757a380a 100644 --- a/test/groovy/templates/AbapEnvironmentPipelineStagePublishTest.groovy +++ b/test/groovy/templates/AbapEnvironmentPipelineStagePublishTest.groovy @@ -48,4 +48,11 @@ class abapEnvironmentPipelineStagePublishTest extends BasePiperTest { assertThat(stepsCalled, hasItem('abapAddonAssemblyKitPublishTargetVector')) } + + @Test + void testPublishSkipped4testBuild() { + nullScript.commonPipelineEnvironment.configuration.runStage = [] + jsr.step.abapEnvironmentPipelineStagePublish(script: nullScript, testBuild: true) + assertThat(stepsCalled, not(hasItem('abapAddonAssemblyKitPublishTargetVector'))) + } } diff --git a/vars/abapEnvironmentPipelineStageBuild.groovy b/vars/abapEnvironmentPipelineStageBuild.groovy index e9d6ef346a..740f995994 100644 --- a/vars/abapEnvironmentPipelineStageBuild.groovy +++ b/vars/abapEnvironmentPipelineStageBuild.groovy @@ -19,15 +19,15 @@ import static com.sap.piper.Prerequisites.checkScript 'abapEnvironmentAssembleConfirm', 'abapAddonAssemblyKitCreateTargetVector', 'abapAddonAssemblyKitPublishTargetVector', - /** Parameter for host config */ - 'host', + 'host', // Parameter for host config + 'testBuild', // Parameter for test execution mode, if true stage will be skipped 'generateTagForAddonProductVersion', 'generateTagForAddonComponentVersion' ] @Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus(STAGE_STEP_KEYS) @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS /** - * This stage builds an AddOn for the SAP Cloud Platform ABAP Environment + * This stage builds an AddOn for the SAP BTP ABAP Environment */ void call(Map parameters = [:]) { def script = checkScript(this, parameters) ?: this @@ -41,6 +41,7 @@ void call(Map parameters = [:]) { .mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS) .mixinStageConfig(script.commonPipelineEnvironment, stageName, STEP_CONFIG_KEYS) .mixin(parameters, PARAMETER_KEYS) + .addIfEmpty('testBuild', false) .use() piperStageWrapper (script: script, stageName: stageName, stashContent: [], stageLocking: false) { @@ -50,24 +51,34 @@ void call(Map parameters = [:]) { abapEnvironmentAssemblePackages script: parameters.script abapEnvironmentBuild(script: parameters.script, phase: 'GENERATION', downloadAllResultFiles: true, useFieldsOfAddonDescriptor: '[{"use":"Name","renameTo":"SWC"}]') abapAddonAssemblyKitRegisterPackages script: parameters.script - abapAddonAssemblyKitReleasePackages script: parameters.script - abapEnvironmentAssembleConfirm script: parameters.script + if (!config.testBuild) { //Skip final steps which can hardly be undone in test mode #1 + abapAddonAssemblyKitReleasePackages script: parameters.script + abapEnvironmentAssembleConfirm script: parameters.script + } else { + echo "abapAddonAssemblyKitReleasePackages skipped as testBuild = true" + echo "abapEnvironmentAssembleConfirm skipped as testBuild = true" + } abapAddonAssemblyKitCreateTargetVector script: parameters.script - abapAddonAssemblyKitPublishTargetVector(script: parameters.script, targetVectorScope: 'T') - if (config.generateTagForAddonComponentVersion || config.generateTagForAddonProductVersion) { - try { - Set keys = [ 'cfServiceKeyName' ] - Map configClone = ConfigurationHelper.newInstance(this) - .mixin(ConfigurationLoader.defaultStageConfiguration(script, 'Clone Repositories')) - .mixinGeneralConfig(script.commonPipelineEnvironment, keys) - .mixinStepConfig(script.commonPipelineEnvironment, keys) - .mixinStageConfig(script.commonPipelineEnvironment, 'Clone Repositories', keys) - .mixin(parameters, keys) - .use() - abapEnvironmentCreateTag(script: parameters.script, cfServiceKeyName: configClone.cfServiceKeyName) - } catch (e) { - echo 'Tag creation failed: ' + e.message + if (!config.testBuild) { //Skip final steps which can hardly be undone in test mode #2 + abapAddonAssemblyKitPublishTargetVector(script: parameters.script, targetVectorScope: 'T') + if (config.generateTagForAddonComponentVersion || config.generateTagForAddonProductVersion) { + try { + Set keys = [ 'cfServiceKeyName' ] + Map configClone = ConfigurationHelper.newInstance(this) + .mixin(ConfigurationLoader.defaultStageConfiguration(script, 'Clone Repositories')) + .mixinGeneralConfig(script.commonPipelineEnvironment, keys) + .mixinStepConfig(script.commonPipelineEnvironment, keys) + .mixinStageConfig(script.commonPipelineEnvironment, 'Clone Repositories', keys) + .mixin(parameters, keys) + .use() + abapEnvironmentCreateTag(script: parameters.script, cfServiceKeyName: configClone.cfServiceKeyName) + } catch (e) { + echo 'Tag creation failed: ' + e.message + } } + } else { + echo "abapAddonAssemblyKitPublishTargetVector skipped as testBuild = true" + echo "abapEnvironmentCreateTag skipped as testBuild = true" } } } diff --git a/vars/abapEnvironmentPipelineStageConfirm.groovy b/vars/abapEnvironmentPipelineStageConfirm.groovy index e64219b0e8..9b216bc90c 100644 --- a/vars/abapEnvironmentPipelineStageConfirm.groovy +++ b/vars/abapEnvironmentPipelineStageConfirm.groovy @@ -9,7 +9,7 @@ import static com.sap.piper.Prerequisites.checkScript @Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus(STAGE_STEP_KEYS) @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS /** - * This stage asks for the approval to publish the previously built Add-on for the SAP Cloud Platform ABAP Environment + * This stage asks for the approval to publish the previously built Add-on for the SAP BTP ABAP Environment */ void call(Map parameters = [:]) { def script = checkScript(this, parameters) ?: this diff --git a/vars/abapEnvironmentPipelineStageInitialChecks.groovy b/vars/abapEnvironmentPipelineStageInitialChecks.groovy index ccc2bfa484..0d07359909 100644 --- a/vars/abapEnvironmentPipelineStageInitialChecks.groovy +++ b/vars/abapEnvironmentPipelineStageInitialChecks.groovy @@ -12,7 +12,7 @@ import static com.sap.piper.Prerequisites.checkScript @Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus(STAGE_STEP_KEYS) @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS /** - * This stage runs initial checks for the build process for an AddOn for the SAP Cloud Platform ABAP Environment + * This stage runs initial checks for the build process for an AddOn for the SAP BTP ABAP Environment */ void call(Map parameters = [:]) { def script = checkScript(this, parameters) ?: this diff --git a/vars/abapEnvironmentPipelineStageIntegrationTests.groovy b/vars/abapEnvironmentPipelineStageIntegrationTests.groovy index 71d2939fa4..cb3d9a7574 100644 --- a/vars/abapEnvironmentPipelineStageIntegrationTests.groovy +++ b/vars/abapEnvironmentPipelineStageIntegrationTests.groovy @@ -6,14 +6,15 @@ import static com.sap.piper.Prerequisites.checkScript @Field String STEP_NAME = getClass().getName() @Field Set GENERAL_CONFIG_KEYS = [ - /** Creates a SAP Cloud Platform ABAP Environment system via the cloud foundry command line interface */ + /** Creates a SAP BTP ABAP Environment system via the cloud foundry command line interface */ 'abapEnvironmentCreateSystem', - /** Deletes a SAP Cloud Platform ABAP Environment system via the cloud foundry command line interface */ + /** Deletes a SAP BTP ABAP Environment system via the cloud foundry command line interface */ 'cloudFoundryDeleteService', /** If set to true, a confirmation is required to delete the system */ 'confirmDeletion', /** If set to true, the system is never deleted */ - 'debug' + 'debug', + 'testBuild' // Parameter for test execution mode, if true stage will be skipped ] @Field Set STAGE_STEP_KEYS = GENERAL_CONFIG_KEYS @Field Set STEP_CONFIG_KEYS = STAGE_STEP_KEYS @@ -32,22 +33,27 @@ void call(Map parameters = [:]) { .mixin(parameters, PARAMETER_KEYS) .addIfEmpty('confirmDeletion', true) .addIfEmpty('debug', false) + .addIfEmpty('testBuild', false) .use() - piperStageWrapper (script: script, stageName: stageName, stashContent: [], stageLocking: false) { - try { - abapEnvironmentCreateSystem(script: parameters.script, includeAddon: true) - cloudFoundryCreateServiceKey(script: parameters.script) - abapEnvironmentBuild(script: parameters.script, phase: 'GENERATION', downloadAllResultFiles: true, useFieldsOfAddonDescriptor: '[{"use":"Name","renameTo":"SWC"}]') - } catch (Exception e) { - echo "Deployment test of add-on product failed." - throw e - } finally { - if (config.confirmDeletion) { - input message: "Deployment test has been executed. Once you proceed, the test system will be deleted." - } - if (!config.debug) { - cloudFoundryDeleteService script: parameters.script + if (config.testBuild) { + echo "Stage 'Integration Tests' skipped as parameter 'testBuild' is active" + } else { + piperStageWrapper (script: script, stageName: stageName, stashContent: [], stageLocking: false) { + try { + abapEnvironmentCreateSystem(script: parameters.script, includeAddon: true) + cloudFoundryCreateServiceKey(script: parameters.script) + abapEnvironmentBuild(script: parameters.script, phase: 'GENERATION', downloadAllResultFiles: true, useFieldsOfAddonDescriptor: '[{"use":"Name","renameTo":"SWC"}]') + } catch (Exception e) { + echo "Deployment test of add-on product failed." + throw e + } finally { + if (config.confirmDeletion) { + input message: "Deployment test has been executed. Once you proceed, the test system will be deleted." + } + if (!config.debug) { + cloudFoundryDeleteService script: parameters.script + } } } } diff --git a/vars/abapEnvironmentPipelineStagePost.groovy b/vars/abapEnvironmentPipelineStagePost.groovy index 642d2ce414..2078aae849 100644 --- a/vars/abapEnvironmentPipelineStagePost.groovy +++ b/vars/abapEnvironmentPipelineStagePost.groovy @@ -5,7 +5,7 @@ import static com.sap.piper.Prerequisites.checkScript @Field String STEP_NAME = getClass().getName() @Field Set GENERAL_CONFIG_KEYS = [ - /** Deletes a SAP Cloud Platform ABAP Environment instance via the cloud foundry command line interface */ + /** Deletes a SAP BTP ABAP Environment instance via the cloud foundry command line interface */ 'cloudFoundryDeleteService', /** If set to true, a confirmation is required to delete the system in case the pipeline was not successful */ 'confirmDeletion', diff --git a/vars/abapEnvironmentPipelineStagePrepareSystem.groovy b/vars/abapEnvironmentPipelineStagePrepareSystem.groovy index b15112f650..96b32fd3c2 100644 --- a/vars/abapEnvironmentPipelineStagePrepareSystem.groovy +++ b/vars/abapEnvironmentPipelineStagePrepareSystem.groovy @@ -6,7 +6,7 @@ import static com.sap.piper.Prerequisites.checkScript @Field String STEP_NAME = getClass().getName() @Field Set GENERAL_CONFIG_KEYS = [] @Field STAGE_STEP_KEYS = [ - /** Creates a SAP Cloud Platform ABAP Environment instance via the cloud foundry command line interface */ + /** Creates a SAP BTP ABAP Environment instance via the cloud foundry command line interface */ 'abapEnvironmentCreateSystem', /** Creates Communication Arrangements for ABAP Environment instance via the cloud foundry command line interface */ 'cloudFoundryCreateServiceKey' @@ -14,7 +14,7 @@ import static com.sap.piper.Prerequisites.checkScript @Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus(STAGE_STEP_KEYS) @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS /** - * This stage prepares the SAP Cloud Platform ABAP Environment systems + * This stage prepares the SAP BTP ABAP Environment systems */ void call(Map parameters = [:]) { def script = checkScript(this, parameters) ?: this diff --git a/vars/abapEnvironmentPipelineStagePublish.groovy b/vars/abapEnvironmentPipelineStagePublish.groovy index 8ac89c51ef..e72bb6955d 100644 --- a/vars/abapEnvironmentPipelineStagePublish.groovy +++ b/vars/abapEnvironmentPipelineStagePublish.groovy @@ -1,26 +1,37 @@ import groovy.transform.Field import com.sap.piper.Utils +import com.sap.piper.ConfigurationHelper import static com.sap.piper.Prerequisites.checkScript @Field String STEP_NAME = getClass().getName() @Field Set GENERAL_CONFIG_KEYS = [] @Field STAGE_STEP_KEYS = [ - 'abapEnvironmentAssemblyKitPublishTargetVector' + 'abapEnvironmentAssemblyKitPublishTargetVector', + 'testBuild' // Parameter for test execution mode, if true stage will be skipped ] @Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus(STAGE_STEP_KEYS) @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS /** - * This stage publishes an AddOn for the SAP Cloud Platform ABAP Environment + * This stage publishes an AddOn for the SAP BTP ABAP Environment */ void call(Map parameters = [:]) { def script = checkScript(this, parameters) ?: this def stageName = parameters.stageName?:env.STAGE_NAME - piperStageWrapper (script: script, stageName: stageName, stashContent: [], stageLocking: false) { - - abapAddonAssemblyKitPublishTargetVector(script: parameters.script, targetVectorScope: 'P') + Map config = ConfigurationHelper.newInstance(this) + .loadStepDefaults() + .mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS) + .mixinStageConfig(script.commonPipelineEnvironment, stageName, STEP_CONFIG_KEYS) + .mixin(parameters, PARAMETER_KEYS) + .addIfEmpty('testBuild', false) + .use() + if (config.testBuild) { + echo "Stage 'Publish' skipped as parameter 'testBuild' is active" + } else { + piperStageWrapper (script: script, stageName: stageName, stashContent: [], stageLocking: false) { + abapAddonAssemblyKitPublishTargetVector(script: parameters.script, targetVectorScope: 'P') + } } - } diff --git a/vars/checkmarxExecuteScan.groovy b/vars/checkmarxExecuteScan.groovy index c4d4ab4eb2..dab67463f3 100644 --- a/vars/checkmarxExecuteScan.groovy +++ b/vars/checkmarxExecuteScan.groovy @@ -6,6 +6,6 @@ import groovy.transform.Field //Metadata maintained in file project://resources/metadata/checkmarxExecuteScan.yaml void call(Map parameters = [:]) { - List credentials = [[type: 'usernamePassword', id: 'checkmarxCredentialsId', env: ['PIPER_username', 'PIPER_password']]] + List credentials = [[type: 'usernamePassword', id: 'checkmarxCredentialsId', env: ['PIPER_username', 'PIPER_password']], [type: 'token', id: 'githubTokenCredentialsId', env: ['PIPER_githubToken']]] piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials, true) } diff --git a/vars/mailSendNotification.groovy b/vars/mailSendNotification.groovy index 2e7133fea9..14612da192 100644 --- a/vars/mailSendNotification.groovy +++ b/vars/mailSendNotification.groovy @@ -252,5 +252,11 @@ def getDistinctRecipients(recipients){ } def hasRecovered(buildResult, currentBuild){ - return buildResult == 'SUCCESS' && currentBuild.getPreviousBuild()?.result != 'SUCCESS' + def previousBuild = currentBuild.getPreviousBuild() + + if (previousBuild) { + return buildResult == 'SUCCESS' && previousBuild.result != 'SUCCESS' + } + + return false } diff --git a/vars/multicloudDeploy.groovy b/vars/multicloudDeploy.groovy index b72ccaaed4..9dd9640204 100644 --- a/vars/multicloudDeploy.groovy +++ b/vars/multicloudDeploy.groovy @@ -38,7 +38,7 @@ import static com.sap.piper.Prerequisites.checkScript ]) @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus([ - /** The source file to deploy to SAP Cloud Platform.*/ + /** The source file to deploy to SAP BTP.*/ 'source', /** Closure which is executed before calling the deployment steps.*/ 'preDeploymentHook' @@ -47,7 +47,7 @@ import static com.sap.piper.Prerequisites.checkScript @Field Map CONFIG_KEY_COMPATIBILITY = [parallelExecution: 'features/parallelTestExecution'] /** - * Deploys an application to multiple platforms (Cloud Foundry, SAP Cloud Platform) or to multiple instances of multiple platforms or the same platform. + * Deploys an application to multiple platforms (Cloud Foundry, SAP BTP) or to multiple instances of multiple platforms or the same platform. */ @GenerateDocumentation void call(parameters = [:]) { diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index 81a53c8eb2..0906cf812e 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -16,7 +16,7 @@ import static com.sap.piper.Prerequisites.checkScript @Field Set GENERAL_CONFIG_KEYS = [ 'neo', /** - * The SAP Cloud Platform account to deploy to. + * The SAP BTP account to deploy to. * @parentConfigKey neo * @mandatory for deployMode=warParams */ @@ -43,7 +43,7 @@ import static com.sap.piper.Prerequisites.checkScript */ 'environment', /** - * The SAP Cloud Platform host to deploy to. + * The SAP BTP host to deploy to. * @parentConfigKey neo * @mandatory for deployMode=warParams */ @@ -55,13 +55,13 @@ import static com.sap.piper.Prerequisites.checkScript */ 'propertiesFile', /** - * Name of SAP Cloud Platform application runtime. + * Name of SAP BTP application runtime. * @parentConfigKey neo * @mandatory for deployMode=warParams */ 'runtime', /** - * Version of SAP Cloud Platform application runtime. + * Version of SAP BTP application runtime. * @parentConfigKey neo * @mandatory for deployMode=warParams */ @@ -83,12 +83,12 @@ import static com.sap.piper.Prerequisites.checkScript */ 'invalidateCache', /** - * Portal landscape region subscribed to in SAP Cloud Platform. + * Portal landscape region subscribed to in SAP BTP. * @parentConfigKey neo */ 'portalLandscape', /** - * UsernamePassword type credential containing SAP Cloud Platform OAuth client ID and client secret. + * UsernamePassword type credential containing SAP BTP OAuth client ID and client secret. * @parentConfigKey neo */ 'oauthCredentialId', @@ -151,7 +151,7 @@ import static com.sap.piper.Prerequisites.checkScript ]) /** - * Deploys an Application to SAP Cloud Platform (SAP CP) using the SAP Cloud Platform Console Client (Neo Java Web SDK). + * Deploys an Application to SAP BTP (SAP CP) using the SAP BTP Console Client (Neo Java Web SDK). */ @GenerateDocumentation void call(parameters = [:]) { @@ -393,7 +393,7 @@ private deploy(script, Map configuration, NeoCommandHelper neoCommandHelper, doc } catch (Exception ex) { - echo "Error while deploying to SAP Cloud Platform. Here are the neo.sh logs:" + echo "Error while deploying to SAP BTP. Here are the neo.sh logs:" try { sh "cat ${logFolder}/*" } catch(Exception e) { @@ -481,7 +481,7 @@ private boolean isAppRunning(NeoCommandHelper commandHelper) { private assertPasswordRules(String password) { if (password.startsWith("@")) { - error("Your password for the deployment to SAP Cloud Platform contains characters which are not " + + error("Your password for the deployment to SAP BTP contains characters which are not " + "supported by the neo tools. " + "For example it is not allowed that the password starts with @. " + "Please consult the documentation for the neo command line tool for more information: " + diff --git a/vars/tmsUpload.groovy b/vars/tmsUpload.groovy index 52039381b5..54a0a40d6b 100644 --- a/vars/tmsUpload.groovy +++ b/vars/tmsUpload.groovy @@ -54,12 +54,12 @@ import static com.sap.piper.Prerequisites.checkScript @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS + GENERAL_CONFIG_KEYS /** - * This step allows you to upload an MTA file (multi-target application archive) and multiple MTA extension descriptors into a TMS (SAP Cloud Platform Transport Management Service) landscape for further TMS-controlled distribution through a TMS-configured landscape. - * TMS lets you manage transports between SAP Cloud Platform accounts in Neo and Cloud Foundry, such as from DEV to TEST and PROD accounts. + * This step allows you to upload an MTA file (multi-target application archive) and multiple MTA extension descriptors into a TMS (SAP BTP Transport Management Service) landscape for further TMS-controlled distribution through a TMS-configured landscape. + * TMS lets you manage transports between SAP BTP accounts in Neo and Cloud Foundry, such as from DEV to TEST and PROD accounts. * For more information, see [official documentation of Transport Management Service](https://help.sap.com/viewer/p/TRANSPORT_MANAGEMENT_SERVICE) * * !!! note "Prerequisites" - * * You have subscribed to and set up TMS, as described in [Setup and Configuration of SAP Cloud Platform Transport Management](https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/66fd7283c62f48adb23c56fb48c84a60.html), which includes the configuration of a node to be used for uploading an MTA file. + * * You have subscribed to and set up TMS, as described in [Setup and Configuration of SAP BTP Transport Management](https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/66fd7283c62f48adb23c56fb48c84a60.html), which includes the configuration of a node to be used for uploading an MTA file. * * A corresponding service key has been created, as described in [Set Up the Environment to Transport Content Archives directly in an Application](https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/8d9490792ed14f1bbf8a6ac08a6bca64.html). This service key (JSON) must be stored as a secret text within the Jenkins secure store. * */