From fd9d1a5ed79b8802d6031a22bbf8d0140bf1ab71 Mon Sep 17 00:00:00 2001 From: AlvoBen <144705560+AlvoBen@users.noreply.github.com> Date: Sun, 14 Jul 2024 11:45:13 +0300 Subject: [PATCH 1/2] CLI | Update the Cli Calls to SCA Risk Management Service to use Export Service (AST-42958) (#794) * Change SbomReportWrapper to WxportWrapper and added Export Service * Change SbomReportWrapper to WxportWrapper and added Export Service * delete scaLocalFlow and retrysbom flags * delete scaLocalFlow and retrysbom flags * delete unrelevant tests * added unitests for export service * added unitests for export service * fix linter * fix linter * resolve conversations * Revert "resolve conversations" This reverts commit 5035ae6c1373cb4e62b56eabaee89436e6224534. * refactor * fix linter --------- Co-authored-by: AlvoBen --- cmd/main.go | 7 +- internal/commands/result.go | 120 ++-------- internal/commands/result_test.go | 8 - internal/commands/root.go | 6 +- internal/commands/root_test.go | 4 +- internal/commands/scan.go | 43 ++-- internal/params/binds.go | 3 +- internal/params/envs.go | 3 +- internal/params/flags.go | 210 +++++++++--------- internal/params/keys.go | 3 +- internal/services/export.go | 102 +++++++++ internal/services/export_test.go | 69 ++++++ .../{results-sbom-http.go => export-http.go} | 63 ++---- internal/wrappers/export.go | 7 + internal/wrappers/mock/export-mock.go | 44 ++++ internal/wrappers/mock/results-sbom-mock.go | 56 ----- internal/wrappers/results-sbom.go | 8 - test/integration/result_test.go | 1 - test/integration/util_command.go | 7 +- 19 files changed, 382 insertions(+), 382 deletions(-) create mode 100644 internal/services/export.go create mode 100644 internal/services/export_test.go rename internal/wrappers/{results-sbom-http.go => export-http.go} (61%) create mode 100644 internal/wrappers/export.go create mode 100644 internal/wrappers/mock/export-mock.go delete mode 100644 internal/wrappers/mock/results-sbom-mock.go delete mode 100644 internal/wrappers/results-sbom.go diff --git a/cmd/main.go b/cmd/main.go index 7d5b45368..8bc97ccd5 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -46,8 +46,7 @@ func main() { descriptionsPath := viper.GetString(params.DescriptionsPathKey) tenantConfigurationPath := viper.GetString(params.TenantConfigurationPathKey) resultsPdfPath := viper.GetString(params.ResultsPdfReportPathKey) - resultsSbomPath := viper.GetString(params.ResultsSbomReportPathKey) - resultsSbomProxyPath := viper.GetString(params.ResultsSbomReportProxyPathKey) + exportPath := viper.GetString(params.ExportPathKey) featureFlagsPath := viper.GetString(params.FeatureFlagsKey) policyEvaluationPath := viper.GetString(params.PolicyEvaluationPathKey) sastMetadataPath := viper.GetString(params.SastMetadataPathKey) @@ -56,7 +55,7 @@ func main() { scansWrapper := wrappers.NewHTTPScansWrapper(scans) resultsPdfReportsWrapper := wrappers.NewResultsPdfReportsHTTPWrapper(resultsPdfPath) - resultsSbomReportsWrapper := wrappers.NewResultsSbomReportsHTTPWrapper(resultsSbomPath, resultsSbomProxyPath) + exportWrapper := wrappers.NewExportHTTPWrapper(exportPath) groupsWrapper := wrappers.NewHTTPGroupsWrapper(groups) logsWrapper := wrappers.NewLogsWrapper(logs) uploadsWrapper := wrappers.NewUploadsHTTPWrapper(uploads) @@ -90,7 +89,7 @@ func main() { astCli := commands.NewAstCLI( applicationsWrapper, scansWrapper, - resultsSbomReportsWrapper, + exportWrapper, resultsPdfReportsWrapper, resultsPredicatesWrapper, codeBashingWrapper, diff --git a/internal/commands/result.go b/internal/commands/result.go index 40bd7358c..c646b1c4d 100644 --- a/internal/commands/result.go +++ b/internal/commands/result.go @@ -20,6 +20,7 @@ import ( "github.com/checkmarx/ast-cli/internal/commands/util/printer" errorConstants "github.com/checkmarx/ast-cli/internal/constants/errors" "github.com/checkmarx/ast-cli/internal/logger" + "github.com/checkmarx/ast-cli/internal/services" "github.com/checkmarx/ast-cli/internal/wrappers" "golang.org/x/text/cases" "golang.org/x/text/language" @@ -73,26 +74,21 @@ const ( scanCanceledNumber = -3 scanPartialNumber = -4 defaultPaddingSize = -13 - boldFormat = "\033[1m%s\033[0m" scanPendingMessage = "Scan triggered in asynchronous mode or still running. Click more details to get the full status." directDependencyType = "Direct Dependency" indirectDependencyType = "Transitive Dependency" startedStatus = "started" requestedStatus = "requested" completedStatus = "completed" - exportingStatus = "Exporting" - pendingStatus = "Pending" pdfToEmailFlagDescription = "Send the PDF report to the specified email address." + " Use \",\" as the delimiter for multiple emails" pdfOptionsFlagDescription = "Sections to generate PDF report. Available options: Iac-Security,Sast,Sca," + defaultPdfOptionsDataSections sbomReportFlagDescription = "Sections to generate SBOM report. Available options: CycloneDxJson,CycloneDxXml,SpdxJson" - delayValueForReport = 10 reportNameScanReport = "scan-report" reportNameImprovedScanReport = "improved-scan-report" reportTypeEmail = "email" defaultPdfOptionsDataSections = "ScanSummary,ExecutiveSummary,ScanResults" - defaultSbomOption = "CycloneDxJson" exploitablePathFlagDescription = "Enable or disable exploitable path in scan. Available options: true,false" scaLastScanTimeFlagDescription = "SCA last scan time. Available options: integer above 1" projectPrivatePackageFlagDescription = "Enable or disable project private package. Available options: true,false" @@ -104,6 +100,7 @@ const ( sarifNodeFileLength = 2 fixLabel = "fix" redundantLabel = "redundant" + delayValueForReport = 10 ) var summaryFormats = []string{ @@ -158,7 +155,7 @@ var containerEngineUnsupportedAgents = []string{ func NewResultsCommand( resultsWrapper wrappers.ResultsWrapper, scanWrapper wrappers.ScansWrapper, - resultsSbomWrapper wrappers.ResultsSbomWrapper, + exportWrapper wrappers.ExportWrapper, resultsPdfReportsWrapper wrappers.ResultsPdfWrapper, codeBashingWrapper wrappers.CodeBashingWrapper, bflWrapper wrappers.BflWrapper, @@ -178,7 +175,7 @@ func NewResultsCommand( ), }, } - showResultCmd := resultShowSubCommand(resultsWrapper, scanWrapper, resultsSbomWrapper, resultsPdfReportsWrapper, + showResultCmd := resultShowSubCommand(resultsWrapper, scanWrapper, exportWrapper, resultsPdfReportsWrapper, risksOverviewWrapper, scsScanOverviewWrapper, policyWrapper, featureFlagsWrapper) codeBashingCmd := resultCodeBashing(codeBashingWrapper) bflResultCmd := resultBflSubCommand(bflWrapper) @@ -211,7 +208,7 @@ func exitCodeSubCommand(scanWrapper wrappers.ScansWrapper) *cobra.Command { func resultShowSubCommand( resultsWrapper wrappers.ResultsWrapper, scanWrapper wrappers.ScansWrapper, - resultsSbomWrapper wrappers.ResultsSbomWrapper, + exportWrapper wrappers.ExportWrapper, resultsPdfReportsWrapper wrappers.ResultsPdfWrapper, risksOverviewWrapper wrappers.RisksOverviewWrapper, scsScanOverviewWrapper wrappers.ScanOverviewWrapper, @@ -227,7 +224,7 @@ func resultShowSubCommand( $ cx results show --scan-id `, ), - RunE: runGetResultCommand(resultsWrapper, scanWrapper, resultsSbomWrapper, resultsPdfReportsWrapper, risksOverviewWrapper, scsScanOverviewWrapper, policyWrapper, featureFlagsWrapper), + RunE: runGetResultCommand(resultsWrapper, scanWrapper, exportWrapper, resultsPdfReportsWrapper, risksOverviewWrapper, scsScanOverviewWrapper, policyWrapper, featureFlagsWrapper), } addScanIDFlag(resultShowCmd, "ID to report on.") addResultFormatFlag( @@ -244,17 +241,12 @@ func resultShowSubCommand( printer.FormatGLSca, ) resultShowCmd.PersistentFlags().String(commonParams.ReportFormatPdfToEmailFlag, "", pdfToEmailFlagDescription) - resultShowCmd.PersistentFlags().String(commonParams.ReportSbomFormatFlag, defaultSbomOption, sbomReportFlagDescription) + resultShowCmd.PersistentFlags().String(commonParams.ReportSbomFormatFlag, services.DefaultSbomOption, sbomReportFlagDescription) resultShowCmd.PersistentFlags().String(commonParams.ReportFormatPdfOptionsFlag, defaultPdfOptionsDataSections, pdfOptionsFlagDescription) resultShowCmd.PersistentFlags().String(commonParams.TargetFlag, "cx_result", "Output file") resultShowCmd.PersistentFlags().String(commonParams.TargetPathFlag, ".", "Output Path") resultShowCmd.PersistentFlags().StringSlice(commonParams.FilterFlag, []string{}, filterResultsListFlagUsage) - resultShowCmd.PersistentFlags().Int(commonParams.RetrySBOMFlag, commonParams.RetrySBOMDefault, commonParams.RetrySBOMUsage) - - // Temporary flag until SCA supports new api - resultShowCmd.PersistentFlags().Bool(commonParams.ReportSbomFormatLocalFlowFlag, false, "") - _ = resultShowCmd.PersistentFlags().MarkHidden(commonParams.ReportSbomFormatLocalFlowFlag) resultShowCmd.PersistentFlags().IntP( commonParams.WaitDelayFlag, "", @@ -870,7 +862,7 @@ func generateScanSummaryURL(summary *wrappers.ResultSummary) string { func runGetResultCommand( resultsWrapper wrappers.ResultsWrapper, scanWrapper wrappers.ScansWrapper, - resultsSbomWrapper wrappers.ResultsSbomWrapper, + exportWrapper wrappers.ExportWrapper, resultsPdfReportsWrapper wrappers.ResultsPdfWrapper, risksOverviewWrapper wrappers.RisksOverviewWrapper, scsScanOverviewWrapper wrappers.ScanOverviewWrapper, @@ -884,8 +876,6 @@ func runGetResultCommand( formatPdfToEmail, _ := cmd.Flags().GetString(commonParams.ReportFormatPdfToEmailFlag) formatPdfOptions, _ := cmd.Flags().GetString(commonParams.ReportFormatPdfOptionsFlag) formatSbomOptions, _ := cmd.Flags().GetString(commonParams.ReportSbomFormatFlag) - useSCALocalFlow, _ := cmd.Flags().GetBool(commonParams.ReportSbomFormatLocalFlowFlag) - retrySBOM, _ := cmd.Flags().GetInt(commonParams.RetrySBOMFlag) sastRedundancy, _ := cmd.Flags().GetBool(commonParams.SastRedundancyFlag) agent, _ := cmd.Flags().GetString(commonParams.AgentFlag) @@ -928,10 +918,8 @@ func runGetResultCommand( resultsWrapper, risksOverviewWrapper, scsScanOverviewWrapper, - resultsSbomWrapper, + exportWrapper, policyResponseModel, - useSCALocalFlow, - retrySBOM, resultsPdfReportsWrapper, scan, format, @@ -1000,10 +988,8 @@ func CreateScanReport( resultsWrapper wrappers.ResultsWrapper, risksOverviewWrapper wrappers.RisksOverviewWrapper, scsScanOverviewWrapper wrappers.ScanOverviewWrapper, - resultsSbomWrapper wrappers.ResultsSbomWrapper, + exportWrapper wrappers.ExportWrapper, policyResponseModel *wrappers.PolicyResponseModel, - useSCALocalFlow bool, - retrySBOM int, resultsPdfReportsWrapper wrappers.ResultsPdfWrapper, scan *wrappers.ScanResponseModel, reportTypes, @@ -1046,7 +1032,7 @@ func CreateScanReport( } for _, reportType := range reportList { err = createReport(reportType, formatPdfToEmail, formatPdfOptions, formatSbomOptions, targetFile, - targetPath, results, summary, resultsSbomWrapper, resultsPdfReportsWrapper, useSCALocalFlow, retrySBOM, featureFlagsWrapper) + targetPath, results, summary, exportWrapper, resultsPdfReportsWrapper, featureFlagsWrapper) if err != nil { return err } @@ -1176,10 +1162,8 @@ func createReport(format, targetPath string, results *wrappers.ScanResultsCollection, summary *wrappers.ResultSummary, - resultsSbomWrapper wrappers.ResultsSbomWrapper, + exportWrapper wrappers.ExportWrapper, resultsPdfReportsWrapper wrappers.ResultsPdfWrapper, - useSCALocalFlow bool, - retrySBOM int, featureFlagsWrapper wrappers.FeatureFlagsWrapper) error { if printer.IsFormat(format, printer.FormatIndentedJSON) { return nil @@ -1243,7 +1227,7 @@ func createReport(format, return fmt.Errorf("unable to generate %s report - SCA engine did not complete successfully", printer.FormatSbom) } - return exportSbomResults(resultsSbomWrapper, summaryRpt, summary, formatSbomOptions, useSCALocalFlow, retrySBOM) + return services.ExportSbomResults(exportWrapper, summaryRpt, summary, formatSbomOptions) } return fmt.Errorf("bad report format %s", format) } @@ -1528,71 +1512,6 @@ func exportJSONSummaryResults(targetFile string, results *wrappers.ResultSummary return nil } -func exportSbomResults(sbomWrapper wrappers.ResultsSbomWrapper, - targetFile string, - results *wrappers.ResultSummary, - formatSbomOptions string, - useSCALocalFlow bool, - retrySBOM int) error { - payload := &wrappers.SbomReportsPayload{ - ScanID: results.ScanID, - FileFormat: defaultSbomOption, - } - if formatSbomOptions != "" && formatSbomOptions != defaultSbomOption { - format, err := validateSbomOptions(formatSbomOptions) - if err != nil { - return err - } - payload.FileFormat = format - } - if useSCALocalFlow { - pollingResp := &wrappers.SbomPollingResponse{} - - sbomresp, err := sbomWrapper.GenerateSbomReport(payload) - if err != nil { - return err - } - - log.Println("Generating SBOM report with " + payload.FileFormat + " file format") - pollingResp.ExportStatus = exportingStatus - for pollingResp.ExportStatus == exportingStatus || pollingResp.ExportStatus == pendingStatus { - pollingResp, err = sbomWrapper.GetSbomReportStatus(sbomresp.ExportID) - if err != nil { - return errors.Wrapf(err, "%s", "failed getting SBOM report status") - } - time.Sleep(delayValueForReport * time.Second) - } - if !strings.EqualFold(pollingResp.ExportStatus, completedStatus) { - return errors.Errorf("SBOM generating failed - Current status: %s", pollingResp.ExportStatus) - } - err = sbomWrapper.DownloadSbomReport(pollingResp.ExportID, targetFile) - if err != nil { - return errors.Wrapf(err, "%s", "Failed downloading SBOM report") - } - return nil - } - log.Println("Generating SBOM report with " + payload.FileFormat + " file format using SCA proxy...") - - i := 0 - for i < retrySBOM { - completed, err := sbomWrapper.GenerateSbomReportWithProxy(payload, targetFile) - if err != nil { - return err - } - if completed { - return nil - } - i++ - time.Sleep(delayValueForReport * time.Second) - logger.PrintIfVerbose( - fmt.Sprintf( - "Retry SBOM report: %d retry", - i, - ), - ) - } - return nil -} func exportPdfResults(pdfWrapper wrappers.ResultsPdfWrapper, summary *wrappers.ResultSummary, summaryRpt, formatPdfToEmail, pdfOptions string, featureFlagsWrapper wrappers.FeatureFlagsWrapper) error { pdfReportsPayload := &wrappers.PdfReportsPayload{} @@ -1667,19 +1586,6 @@ func exportPdfResults(pdfWrapper wrappers.ResultsPdfWrapper, summary *wrappers.R return nil } -func validateSbomOptions(sbomOption string) (string, error) { - var sbomOptionsStringMap = map[string]string{ - "cyclonedxjson": "CycloneDxJson", - "cyclonedxxml": "CycloneDxXml", - "spdxjson": "SpdxJson", - } - sbomOption = strings.ToLower(strings.ReplaceAll(sbomOption, " ", "")) - if sbomOptionsStringMap[sbomOption] != "" { - return sbomOptionsStringMap[sbomOption], nil - } - return "", errors.Errorf("invalid SBOM option: %s", sbomOption) -} - func parsePDFOptions(pdfOptions string, enabledEngines []string, reportName string) (pdfOptionsSections, pdfOptionsEngines []string, err error) { var pdfOptionsSectionsMap = map[string]string{ "scansummary": "ScanSummary", diff --git a/internal/commands/result_test.go b/internal/commands/result_test.go index 4d61cc122..21bcf9117 100644 --- a/internal/commands/result_test.go +++ b/internal/commands/result_test.go @@ -626,14 +626,6 @@ func TestSBOMReportXMLWithContainers(t *testing.T) { os.Remove(fmt.Sprintf("%s.%s", fileName+"_"+printer.FormatSbom, printer.FormatXML)) } -func TestSBOMReportXMLWithProxy(t *testing.T) { - execCmdNilAssertion(t, "results", "show", "--scan-id", "MOCK", "--report-format", "sbom", "--report-sbom-format", "CycloneDxXml", "--report-sbom-local-flow") - _, err := os.Stat(fmt.Sprintf("%s.%s", fileName+"_"+printer.FormatSbom, printer.FormatXML)) - assert.NilError(t, err, "Report file should exist for extension "+printer.FormatXML) - // Remove generated json file - os.Remove(fmt.Sprintf("%s.%s", fileName+"_"+printer.FormatSbom, printer.FormatXML)) -} - func TestRunGetResultsByScanIdGLFormat(t *testing.T) { execCmdNilAssertion(t, "results", "show", "--scan-id", "MOCK", "--report-format", "gl-sast") // Run test for gl-sast report type diff --git a/internal/commands/root.go b/internal/commands/root.go index 2cf974455..48d17d16f 100644 --- a/internal/commands/root.go +++ b/internal/commands/root.go @@ -23,7 +23,7 @@ import ( func NewAstCLI( applicationsWrapper wrappers.ApplicationsWrapper, scansWrapper wrappers.ScansWrapper, - resultsSbomWrapper wrappers.ResultsSbomWrapper, + exportWrapper wrappers.ExportWrapper, resultsPdfReportsWrapper wrappers.ResultsPdfWrapper, resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper, codeBashingWrapper wrappers.CodeBashingWrapper, @@ -150,7 +150,7 @@ func NewAstCLI( scanCmd := NewScanCommand( applicationsWrapper, scansWrapper, - resultsSbomWrapper, + exportWrapper, resultsPdfReportsWrapper, uploadsWrapper, resultsWrapper, @@ -172,7 +172,7 @@ func NewAstCLI( resultsCmd := NewResultsCommand( resultsWrapper, scansWrapper, - resultsSbomWrapper, + exportWrapper, resultsPdfReportsWrapper, codeBashingWrapper, bflWrapper, diff --git a/internal/commands/root_test.go b/internal/commands/root_test.go index 42662db65..ad14bc490 100644 --- a/internal/commands/root_test.go +++ b/internal/commands/root_test.go @@ -36,7 +36,7 @@ func TestMain(m *testing.M) { func createASTTestCommand() *cobra.Command { applicationWrapper := &mock.ApplicationsMockWrapper{} scansMockWrapper := &mock.ScansMockWrapper{} - resultsSbomWrapper := &mock.ResultsSbomWrapper{} + exportWrapper := &mock.ExportMockWrapper{} resultsPdfWrapper := &mock.ResultsPdfWrapper{} scansMockWrapper.Running = true resultsPredicatesMockWrapper := &mock.ResultsPredicatesMockWrapper{} @@ -70,7 +70,7 @@ func createASTTestCommand() *cobra.Command { return NewAstCLI( applicationWrapper, scansMockWrapper, - resultsSbomWrapper, + exportWrapper, resultsPdfWrapper, resultsPredicatesMockWrapper, codeBashingWrapper, diff --git a/internal/commands/scan.go b/internal/commands/scan.go index c24f7dd4a..cc09758e7 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -133,7 +133,7 @@ var ( func NewScanCommand( applicationsWrapper wrappers.ApplicationsWrapper, scansWrapper wrappers.ScansWrapper, - resultsSbomWrapper wrappers.ResultsSbomWrapper, + exportWrapper wrappers.ExportWrapper, resultsPdfReportsWrapper wrappers.ResultsPdfWrapper, uploadsWrapper wrappers.UploadsWrapper, resultsWrapper wrappers.ResultsWrapper, @@ -165,7 +165,7 @@ func NewScanCommand( createScanCmd := scanCreateSubCommand( scansWrapper, - resultsSbomWrapper, + exportWrapper, resultsPdfReportsWrapper, uploadsWrapper, resultsWrapper, @@ -456,7 +456,7 @@ func scanListSubCommand(scansWrapper wrappers.ScansWrapper, sastMetadataWrapper func scanCreateSubCommand( scansWrapper wrappers.ScansWrapper, - resultsSbomWrapper wrappers.ResultsSbomWrapper, + exportWrapper wrappers.ExportWrapper, resultsPdfReportsWrapper wrappers.ResultsPdfWrapper, uploadsWrapper wrappers.UploadsWrapper, resultsWrapper wrappers.ResultsWrapper, @@ -488,7 +488,7 @@ func scanCreateSubCommand( }, RunE: runCreateScanCommand( scansWrapper, - resultsSbomWrapper, + exportWrapper, resultsPdfReportsWrapper, uploadsWrapper, resultsWrapper, @@ -614,7 +614,7 @@ func scanCreateSubCommand( createScanCmd.PersistentFlags().String(commonParams.ProjecPrivatePackageFlag, "", projectPrivatePackageFlagDescription) createScanCmd.PersistentFlags().String(commonParams.ScaPrivatePackageVersionFlag, "", scaPrivatePackageVersionFlagDescription) createScanCmd.PersistentFlags().String(commonParams.ReportFormatPdfToEmailFlag, "", pdfToEmailFlagDescription) - createScanCmd.PersistentFlags().String(commonParams.ReportSbomFormatFlag, defaultSbomOption, sbomReportFlagDescription) + createScanCmd.PersistentFlags().String(commonParams.ReportSbomFormatFlag, services.DefaultSbomOption, sbomReportFlagDescription) createScanCmd.PersistentFlags().String(commonParams.ReportFormatPdfOptionsFlag, defaultPdfOptionsDataSections, pdfOptionsFlagDescription) createScanCmd.PersistentFlags().String(commonParams.TargetFlag, "cx_result", "Output file") createScanCmd.PersistentFlags().String(commonParams.TargetPathFlag, ".", "Output Path") @@ -647,11 +647,6 @@ func scanCreateSubCommand( createScanCmd.PersistentFlags().String(commonParams.SSHKeyFlag, "", "Path to ssh private key") - createScanCmd.PersistentFlags().Int(commonParams.RetrySBOMFlag, commonParams.RetrySBOMDefault, commonParams.RetrySBOMUsage) - // Temporary flag until SCA supports new api - createScanCmd.PersistentFlags().Bool(commonParams.ReportSbomFormatLocalFlowFlag, false, "") - _ = createScanCmd.PersistentFlags().MarkHidden(commonParams.ReportSbomFormatLocalFlowFlag) - createScanCmd.PersistentFlags().String(commonParams.SCSRepoTokenFlag, "", "Provide a token with read permission for the repo that you are scanning (for scorecard scans)") createScanCmd.PersistentFlags().String(commonParams.SCSRepoURLFlag, "", "The URL of the repo that you are scanning with scs (for scorecard scans)") createScanCmd.PersistentFlags().String(commonParams.SCSEnginesFlag, "", "Specify which scs engines will run (default: all licensed engines)") @@ -1552,7 +1547,7 @@ func definePathForZipFileOrDirectory(cmd *cobra.Command) (zipFile, sourceDir str func runCreateScanCommand( scansWrapper wrappers.ScansWrapper, - resultsSbomWrapper wrappers.ResultsSbomWrapper, + exportWrapper wrappers.ExportWrapper, resultsPdfReportsWrapper wrappers.ResultsPdfWrapper, uploadsWrapper wrappers.UploadsWrapper, resultsWrapper wrappers.ResultsWrapper, @@ -1624,7 +1619,7 @@ func runCreateScanCommand( waitDelay, timeoutMinutes, scansWrapper, - resultsSbomWrapper, + exportWrapper, resultsPdfReportsWrapper, resultsWrapper, risksOverviewWrapper, @@ -1647,7 +1642,7 @@ func runCreateScanCommand( } else { logger.PrintIfVerbose("Skipping policy evaluation") } - err = createReportsAfterScan(cmd, scanResponseModel.ID, scansWrapper, resultsSbomWrapper, resultsPdfReportsWrapper, + err = createReportsAfterScan(cmd, scanResponseModel.ID, scansWrapper, exportWrapper, resultsPdfReportsWrapper, resultsWrapper, risksOverviewWrapper, scsScanOverviewWrapper, policyResponseModel, featureFlagsWrapper) if err != nil { return err @@ -1658,7 +1653,7 @@ func runCreateScanCommand( return err } } else { - err = createReportsAfterScan(cmd, scanResponseModel.ID, scansWrapper, resultsSbomWrapper, resultsPdfReportsWrapper, resultsWrapper, + err = createReportsAfterScan(cmd, scanResponseModel.ID, scansWrapper, exportWrapper, resultsPdfReportsWrapper, resultsWrapper, risksOverviewWrapper, scsScanOverviewWrapper, nil, featureFlagsWrapper) if err != nil { return err @@ -1814,7 +1809,7 @@ func handleWait( waitDelay, timeoutMinutes int, scansWrapper wrappers.ScansWrapper, - resultsSbomWrapper wrappers.ResultsSbomWrapper, + exportWrapper wrappers.ExportWrapper, resultsPdfReportsWrapper wrappers.ResultsPdfWrapper, resultsWrapper wrappers.ResultsWrapper, risksOverviewWrapper wrappers.RisksOverviewWrapper, @@ -1826,7 +1821,7 @@ func handleWait( waitDelay, timeoutMinutes, scansWrapper, - resultsSbomWrapper, + exportWrapper, resultsPdfReportsWrapper, resultsWrapper, risksOverviewWrapper, @@ -1849,7 +1844,7 @@ func createReportsAfterScan( cmd *cobra.Command, scanID string, scansWrapper wrappers.ScansWrapper, - resultsSbomWrapper wrappers.ResultsSbomWrapper, + exportWrapper wrappers.ExportWrapper, resultsPdfReportsWrapper wrappers.ResultsPdfWrapper, resultsWrapper wrappers.ResultsWrapper, risksOverviewWrapper wrappers.RisksOverviewWrapper, @@ -1864,8 +1859,6 @@ func createReportsAfterScan( formatPdfToEmail, _ := cmd.Flags().GetString(commonParams.ReportFormatPdfToEmailFlag) formatPdfOptions, _ := cmd.Flags().GetString(commonParams.ReportFormatPdfOptionsFlag) formatSbomOptions, _ := cmd.Flags().GetString(commonParams.ReportSbomFormatFlag) - useSCALocalFlow, _ := cmd.Flags().GetBool(commonParams.ReportSbomFormatLocalFlowFlag) - retrySBOM, _ := cmd.Flags().GetInt(commonParams.RetrySBOMFlag) agent, _ := cmd.Flags().GetString(commonParams.AgentFlag) params, err := getFilters(cmd) @@ -1886,10 +1879,8 @@ func createReportsAfterScan( resultsWrapper, risksOverviewWrapper, scsScanOverviewWrapper, - resultsSbomWrapper, + exportWrapper, policyResponseModel, - useSCALocalFlow, - retrySBOM, resultsPdfReportsWrapper, scan, reportFormats, @@ -2030,7 +2021,7 @@ func waitForScanCompletion( waitDelay, timeoutMinutes int, scansWrapper wrappers.ScansWrapper, - resultsSbomWrapper wrappers.ResultsSbomWrapper, + exportWrapper wrappers.ExportWrapper, resultsPdfReportsWrapper wrappers.ResultsPdfWrapper, resultsWrapper wrappers.ResultsWrapper, risksOverviewWrapper wrappers.RisksOverviewWrapper, @@ -2050,7 +2041,7 @@ func waitForScanCompletion( waitDuration := fixedWait + variableWait logger.PrintfIfVerbose("Sleeping %v before polling", waitDuration) time.Sleep(waitDuration) - running, err := isScanRunning(scansWrapper, resultsSbomWrapper, resultsPdfReportsWrapper, resultsWrapper, + running, err := isScanRunning(scansWrapper, exportWrapper, resultsPdfReportsWrapper, resultsWrapper, risksOverviewWrapper, scsScanOverviewWrapper, scanResponseModel.ID, cmd, featureFlagsWrapper) if err != nil { return err @@ -2077,7 +2068,7 @@ func waitForScanCompletion( func isScanRunning( scansWrapper wrappers.ScansWrapper, - resultsSbomWrapper wrappers.ResultsSbomWrapper, + exportWrapper wrappers.ExportWrapper, resultsPdfReportsWrapper wrappers.ResultsPdfWrapper, resultsWrapper wrappers.ResultsWrapper, risksOverViewWrapper wrappers.RisksOverviewWrapper, @@ -2108,7 +2099,7 @@ func isScanRunning( cmd, scanResponseModel.ID, scansWrapper, - resultsSbomWrapper, + exportWrapper, resultsPdfReportsWrapper, resultsWrapper, risksOverViewWrapper, diff --git a/internal/params/binds.go b/internal/params/binds.go index b7c4ddc54..ff002adf0 100644 --- a/internal/params/binds.go +++ b/internal/params/binds.go @@ -58,8 +58,7 @@ var EnvVarsBinds = []struct { {TokenExpirySecondsKey, TokenExpirySecondsEnv, "300"}, {ClientTimeoutKey, ClientTimeoutEnv, "30"}, {ResultsPdfReportPathKey, ResultsPdfReportPathEnv, "api/reports"}, - {ResultsSbomReportPathKey, ResultsSbomReportPathEnv, "api/sca/export"}, - {ResultsSbomReportProxyPathKey, ResultsSbomReportProxyPathEnv, "api/sca/risk-management/risk-reports"}, + {ExportPathKey, ExportPathEnv, "api/sca/export"}, {FeatureFlagsKey, FeatureFlagsEnv, "api/flags"}, {PolicyEvaluationPathKey, PolicyEvaluationPathEnv, "api/policy_management_service_uri/evaluation"}, {AccessManagementPathKey, AccessManagementPathEnv, "api/access-management"}, diff --git a/internal/params/envs.go b/internal/params/envs.go index c004dff57..eb2b27353 100644 --- a/internal/params/envs.go +++ b/internal/params/envs.go @@ -55,8 +55,7 @@ const ( DescriptionsPathEnv = "CX_DESCRIPTIONS_PATH" TenantConfigurationPathEnv = "CX_TENANT_CONFIGURATION_PATH" ResultsPdfReportPathEnv = "CX_RESULTS_PDF_REPORT_PATH" - ResultsSbomReportPathEnv = "CX_RESULTS_SBOM_PATH" - ResultsSbomReportProxyPathEnv = "CX_RESULTS_SBOM_PROXY_PATH" + ExportPathEnv = "CX_EXPORT_PATH" FeatureFlagsEnv = "CX_FEATURE_FLAGS_PATH" UploadURLEnv = "CX_UPLOAD_URL" PolicyEvaluationPathEnv = "CX_POLICY_EVALUATION_PATH" diff --git a/internal/params/flags.go b/internal/params/flags.go index 8e4f000ef..466bf07c1 100644 --- a/internal/params/flags.go +++ b/internal/params/flags.go @@ -2,110 +2,109 @@ package params // Flags const ( - AgentFlag = "agent" - AgentFlagUsage = "Scan origin name" - ApplicationName = "application-name" - DefaultAgent = "ASTCLI" - DebugFlag = "debug" - DebugUsage = "Debug mode with detailed logs" - RetryFlag = "retry" - RetryDefault = 3 - RetryUsage = "Retry requests to Checkmarx One on connection failure" - RetryDelayFlag = "retry-delay" - RetryDelayDefault = 20 - RetryDelayPollingDefault = 60 - RetryDelayUsage = "Time between retries in seconds, use with --" + RetryFlag - SourcesFlag = "file-source" - SourcesFlagSh = "s" - TenantFlag = "tenant" - TenantFlagUsage = "Checkmarx tenant" - AsyncFlag = "async" - WaitDelayFlag = "wait-delay" - ScanTimeoutFlag = "scan-timeout" - PolicyTimeoutFlag = "policy-timeout" - IgnorePolicyFlag = "ignore-policy" - SourceDirFilterFlag = "file-filter" - SourceDirFilterFlagSh = "f" - ImportFilePath = "import-file-path" - IncludeFilterFlag = "file-include" - IncludeFilterFlagSh = "i" - ProjectIDFlag = "project-id" - BranchFlag = "branch" - BranchFlagSh = "b" - ScanIDFlag = "scan-id" - BranchFlagUsage = "Branch to scan" - MainBranchFlag = "branch" - ScaResolverFlag = "sca-resolver" - ScaResolverParamsFlag = "sca-resolver-params" - AccessKeyIDFlag = "client-id" - AccessKeySecretFlag = "client-secret" - AccessKeyIDFlagUsage = "The OAuth2 client ID" - AccessKeySecretFlagUsage = "The OAuth2 client secret" - InsecureFlag = "insecure" - InsecureFlagUsage = "Ignore TLS certificate validations" - ScanInfoFormatFlag = "scan-info-format" - FormatFlag = "format" - FormatFlagUsageFormat = "Format for the output. One of %s" - FilterFlag = "filter" - VorpalLatestVersion = "vorpal-latest-version" - BaseURIFlag = "base-uri" - ProxyFlag = "proxy" - ProxyFlagUsage = "Proxy server to send communication through" - IgnoreProxyFlag = "ignore-proxy" - IgnoreProxyFlagUsage = "Ignore proxy configuration" - ProxyTypeFlag = "proxy-auth-type" - ProxyTypeFlagUsage = "Proxy authentication type, (basic or ntlm)" - TimeoutFlag = "timeout" - TimeoutFlagUsage = "Timeout for network activity, (default 5 seconds)" - NtlmProxyDomainFlag = "proxy-ntlm-domain" - SastFastScanFlag = "sast-fast-scan" - NtlmProxyDomainFlagUsage = "Window domain when using NTLM proxy" - BaseURIFlagUsage = "The base system URI" - BaseAuthURIFlag = "base-auth-uri" - BaseAuthURIFlagUsage = "The base system IAM URI" - AstAPIKeyFlag = "apikey" - AstAPIKeyUsage = "The API Key to login to Checkmarx One" - ClientRolesFlag = "roles" - ClientRolesSh = "r" - ClientDescriptionFlag = "description" - ClientDescriptionSh = "d" - UsernameFlag = "username" - UsernameSh = "u" - PasswordFlag = "password" - PasswordSh = "p" - ProfileFlag = "profile" - ProfileFlagUsage = "The default configuration profile" - Help = "help" - TargetFlag = "output-name" - TargetPathFlag = "output-path" - TargetFormatFlag = "report-format" - ReportFormatPdfToEmailFlag = "report-pdf-email" - ReportFormatPdfOptionsFlag = "report-pdf-options" - ReportSbomFormatFlag = "report-sbom-format" - ReportSbomFormatLocalFlowFlag = "report-sbom-local-flow" - ProjectName = "project-name" - ScanTypes = "scan-types" - ScanTypeFlag = "scan-type" - ScanResubmit = "resubmit" - KicsRealtimeFile = "file" - KicsRealtimeEngine = "engine" - KicsRealtimeAdditionalParams = "additional-params" - ScaRealtimeProjectDir = "project-dir" - ScaRealtimeProjectDirSh = "p" - RemediationFiles = "package-files" - KicsRemediationFile = "results-file" - KicsProjectFile = "kics-files" - KicsSimilarityFilter = "similarity-ids" - RemediationPackage = "package" - RemediationPackageVersion = "package-version" - TagList = "tags" - GroupList = "groups" - ProjectGroupList = "project-groups" - ProjectTagList = "project-tags" - IncrementalSast = "sast-incremental" - PresetName = "sast-preset-name" - Threshold = "threshold" - ThresholdFlagUsage = "Local build threshold. Format -=. " + + AgentFlag = "agent" + AgentFlagUsage = "Scan origin name" + ApplicationName = "application-name" + DefaultAgent = "ASTCLI" + DebugFlag = "debug" + DebugUsage = "Debug mode with detailed logs" + RetryFlag = "retry" + RetryDefault = 3 + RetryUsage = "Retry requests to Checkmarx One on connection failure" + RetryDelayFlag = "retry-delay" + RetryDelayDefault = 20 + RetryDelayPollingDefault = 60 + RetryDelayUsage = "Time between retries in seconds, use with --" + RetryFlag + SourcesFlag = "file-source" + SourcesFlagSh = "s" + TenantFlag = "tenant" + TenantFlagUsage = "Checkmarx tenant" + AsyncFlag = "async" + WaitDelayFlag = "wait-delay" + ScanTimeoutFlag = "scan-timeout" + PolicyTimeoutFlag = "policy-timeout" + IgnorePolicyFlag = "ignore-policy" + SourceDirFilterFlag = "file-filter" + SourceDirFilterFlagSh = "f" + ImportFilePath = "import-file-path" + IncludeFilterFlag = "file-include" + IncludeFilterFlagSh = "i" + ProjectIDFlag = "project-id" + BranchFlag = "branch" + BranchFlagSh = "b" + ScanIDFlag = "scan-id" + BranchFlagUsage = "Branch to scan" + MainBranchFlag = "branch" + ScaResolverFlag = "sca-resolver" + ScaResolverParamsFlag = "sca-resolver-params" + AccessKeyIDFlag = "client-id" + AccessKeySecretFlag = "client-secret" + AccessKeyIDFlagUsage = "The OAuth2 client ID" + AccessKeySecretFlagUsage = "The OAuth2 client secret" + InsecureFlag = "insecure" + InsecureFlagUsage = "Ignore TLS certificate validations" + ScanInfoFormatFlag = "scan-info-format" + FormatFlag = "format" + FormatFlagUsageFormat = "Format for the output. One of %s" + FilterFlag = "filter" + VorpalLatestVersion = "vorpal-latest-version" + BaseURIFlag = "base-uri" + ProxyFlag = "proxy" + ProxyFlagUsage = "Proxy server to send communication through" + IgnoreProxyFlag = "ignore-proxy" + IgnoreProxyFlagUsage = "Ignore proxy configuration" + ProxyTypeFlag = "proxy-auth-type" + ProxyTypeFlagUsage = "Proxy authentication type, (basic or ntlm)" + TimeoutFlag = "timeout" + TimeoutFlagUsage = "Timeout for network activity, (default 5 seconds)" + NtlmProxyDomainFlag = "proxy-ntlm-domain" + SastFastScanFlag = "sast-fast-scan" + NtlmProxyDomainFlagUsage = "Window domain when using NTLM proxy" + BaseURIFlagUsage = "The base system URI" + BaseAuthURIFlag = "base-auth-uri" + BaseAuthURIFlagUsage = "The base system IAM URI" + AstAPIKeyFlag = "apikey" + AstAPIKeyUsage = "The API Key to login to Checkmarx One" + ClientRolesFlag = "roles" + ClientRolesSh = "r" + ClientDescriptionFlag = "description" + ClientDescriptionSh = "d" + UsernameFlag = "username" + UsernameSh = "u" + PasswordFlag = "password" + PasswordSh = "p" + ProfileFlag = "profile" + ProfileFlagUsage = "The default configuration profile" + Help = "help" + TargetFlag = "output-name" + TargetPathFlag = "output-path" + TargetFormatFlag = "report-format" + ReportFormatPdfToEmailFlag = "report-pdf-email" + ReportFormatPdfOptionsFlag = "report-pdf-options" + ReportSbomFormatFlag = "report-sbom-format" + ProjectName = "project-name" + ScanTypes = "scan-types" + ScanTypeFlag = "scan-type" + ScanResubmit = "resubmit" + KicsRealtimeFile = "file" + KicsRealtimeEngine = "engine" + KicsRealtimeAdditionalParams = "additional-params" + ScaRealtimeProjectDir = "project-dir" + ScaRealtimeProjectDirSh = "p" + RemediationFiles = "package-files" + KicsRemediationFile = "results-file" + KicsProjectFile = "kics-files" + KicsSimilarityFilter = "similarity-ids" + RemediationPackage = "package" + RemediationPackageVersion = "package-version" + TagList = "tags" + GroupList = "groups" + ProjectGroupList = "project-groups" + ProjectTagList = "project-tags" + IncrementalSast = "sast-incremental" + PresetName = "sast-preset-name" + Threshold = "threshold" + ThresholdFlagUsage = "Local build threshold. Format -=. " + "Example: scan --threshold \"sast-high=10;sca-high=5;iac-security-low=10\"" KeyValuePairSize = 2 WaitDelayDefault = 5 @@ -225,9 +224,6 @@ const ( BaseIAMURI = "" Tenant = "" Branch = "" - RetrySBOMFlag = "retry-sbom" - RetrySBOMDefault = 1000 - RetrySBOMUsage = "Retry requests to Checkmarx One on sbom creation" ScanPolicyDefaultTimeout = 4 ResultPolicyDefaultTimeout = 1 ) diff --git a/internal/params/keys.go b/internal/params/keys.go index 699bff0ad..fc8762180 100644 --- a/internal/params/keys.go +++ b/internal/params/keys.go @@ -57,8 +57,7 @@ var ( DescriptionsPathKey = strings.ToLower(DescriptionsPathEnv) TenantConfigurationPathKey = strings.ToLower(TenantConfigurationPathEnv) ResultsPdfReportPathKey = strings.ToLower(ResultsPdfReportPathEnv) - ResultsSbomReportPathKey = strings.ToLower(ResultsSbomReportPathEnv) - ResultsSbomReportProxyPathKey = strings.ToLower(ResultsSbomReportProxyPathEnv) + ExportPathKey = strings.ToLower(ExportPathEnv) FeatureFlagsKey = strings.ToLower(FeatureFlagsEnv) PolicyEvaluationPathKey = strings.ToLower(PolicyEvaluationPathEnv) AccessManagementPathKey = strings.ToLower(AccessManagementPathEnv) diff --git a/internal/services/export.go b/internal/services/export.go new file mode 100644 index 000000000..c05fbc483 --- /dev/null +++ b/internal/services/export.go @@ -0,0 +1,102 @@ +package services + +import ( + "log" + "strings" + "time" + + "github.com/checkmarx/ast-cli/internal/wrappers" + "github.com/pkg/errors" +) + +const ( + DefaultSbomOption = "CycloneDxJson" + exportingStatus = "Exporting" + delayValueForReport = 10 + pendingStatus = "Pending" + completedStatus = "completed" + pollingTimeout = 5 // minutes +) + +func ExportSbomResults( + exportWrapper wrappers.ExportWrapper, + targetFile string, + results *wrappers.ResultSummary, + formatSbomOptions string, +) error { + payload, err := preparePayload(results.ScanID, formatSbomOptions) + if err != nil { + return err + } + + log.Println("Generating SBOM report with " + payload.FileFormat + " file format") + sbomresp, err := exportWrapper.GenerateSbomReport(payload) + if err != nil { + return err + } + + pollingResp, err := pollForCompletion(exportWrapper, sbomresp.ExportID) + if err != nil { + return err + } + + if err := exportWrapper.DownloadSbomReport(pollingResp.ExportID, targetFile); err != nil { + return errors.Wrapf(err, "Failed downloading SBOM report") + } + return nil +} + +func preparePayload(scanID, formatSbomOptions string) (*wrappers.ExportRequestPayload, error) { + payload := &wrappers.ExportRequestPayload{ + ScanID: scanID, + FileFormat: DefaultSbomOption, + } + + if formatSbomOptions != "" && formatSbomOptions != DefaultSbomOption { + format, err := validateSbomOptions(formatSbomOptions) + if err != nil { + return nil, err + } + payload.FileFormat = format + } + + return payload, nil +} + +func pollForCompletion(exportWrapper wrappers.ExportWrapper, exportID string) (*wrappers.ExportPollingResponse, error) { + timeout := time.After(pollingTimeout * time.Minute) + pollingResp := &wrappers.ExportPollingResponse{ExportStatus: exportingStatus} + + for pollingResp.ExportStatus == exportingStatus || pollingResp.ExportStatus == pendingStatus { + select { + case <-timeout: + return nil, errors.Errorf("SBOM generating failed - Timed out after 5 minutes") + default: + resp, err := exportWrapper.GetSbomReportStatus(exportID) + if err != nil { + return nil, errors.Wrapf(err, "failed getting SBOM report status") + } + pollingResp = resp + time.Sleep(delayValueForReport * time.Second) + } + } + + if !strings.EqualFold(pollingResp.ExportStatus, completedStatus) { + return nil, errors.Errorf("SBOM generating failed - Current status: %s", pollingResp.ExportStatus) + } + + return pollingResp, nil +} + +func validateSbomOptions(sbomOption string) (string, error) { + var sbomOptionsStringMap = map[string]string{ + "cyclonedxjson": "CycloneDxJson", + "cyclonedxxml": "CycloneDxXml", + "spdxjson": "SpdxJson", + } + sbomOption = strings.ToLower(strings.ReplaceAll(sbomOption, " ", "")) + if sbomOptionsStringMap[sbomOption] != "" { + return sbomOptionsStringMap[sbomOption], nil + } + return "", errors.Errorf("invalid SBOM option: %s", sbomOption) +} diff --git a/internal/services/export_test.go b/internal/services/export_test.go new file mode 100644 index 000000000..87da03048 --- /dev/null +++ b/internal/services/export_test.go @@ -0,0 +1,69 @@ +package services + +import ( + "fmt" + "testing" + + "github.com/checkmarx/ast-cli/internal/wrappers" + "github.com/checkmarx/ast-cli/internal/wrappers/mock" + "github.com/stretchr/testify/assert" +) + +func TestExportSbomResults(t *testing.T) { + type args struct { + exportWrapper wrappers.ExportWrapper + targetFile string + results *wrappers.ResultSummary + formatSbomOptions string + } + tests := []struct { + name string + args args + wantErr assert.ErrorAssertionFunc + }{ + { + name: "Test ExportSbomResults", + args: args{ + exportWrapper: &mock.ExportMockWrapper{}, + targetFile: "test.txt", + results: &wrappers.ResultSummary{ + ScanID: "id123456", + }, + formatSbomOptions: "CycloneDxJson", + }, + wantErr: assert.NoError, + }, + { + name: "Test ExportSbomResults with invalid format", + args: args{ + exportWrapper: &mock.ExportMockWrapper{}, + targetFile: "test.txt", + results: &wrappers.ResultSummary{ + ScanID: "id123456", + }, + formatSbomOptions: "invalid", + }, + wantErr: assert.Error, + }, + { + name: "Test ExportSbomResults with error", + args: args{ + exportWrapper: &mock.ExportMockWrapper{}, + targetFile: "test.txt", + results: &wrappers.ResultSummary{ + ScanID: "err-scan-id", + }, + formatSbomOptions: "CycloneDxJson", + }, + wantErr: assert.Error, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + tt.wantErr(t, ExportSbomResults(tt.args.exportWrapper, tt.args.targetFile, tt.args.results, tt.args.formatSbomOptions), + fmt.Sprintf("ExportSbomResults(%v, %v, %v, %v)", tt.args.exportWrapper, tt.args.targetFile, tt.args.results, tt.args.formatSbomOptions)) + }) + } +} diff --git a/internal/wrappers/results-sbom-http.go b/internal/wrappers/export-http.go similarity index 61% rename from internal/wrappers/results-sbom-http.go rename to internal/wrappers/export-http.go index 9e218b3f3..d513c382f 100644 --- a/internal/wrappers/results-sbom-http.go +++ b/internal/wrappers/export-http.go @@ -15,33 +15,31 @@ import ( "github.com/pkg/errors" ) -type SbomReportsPayload struct { +type ExportRequestPayload struct { ScanID string `json:"ScanID"` FileFormat string `json:"FileFormat"` } -type SbomReportsResponse struct { +type ExportResponse struct { ExportID string `json:"exportId"` } -type SbomPollingResponse struct { +type ExportPollingResponse struct { ExportID string `json:"exportId"` ExportStatus string `json:"exportStatus"` FileURL string `json:"fileUrl"` } -type SbomHTTPWrapper struct { - path string - proxyPath string +type ExportHTTPWrapper struct { + path string } -func NewResultsSbomReportsHTTPWrapper(path, proxyPath string) ResultsSbomWrapper { - return &SbomHTTPWrapper{ - path: path, - proxyPath: proxyPath, +func NewExportHTTPWrapper(path string) ExportWrapper { + return &ExportHTTPWrapper{ + path: path, } } -func (r *SbomHTTPWrapper) GenerateSbomReport(payload *SbomReportsPayload) (*SbomReportsResponse, error) { +func (r *ExportHTTPWrapper) GenerateSbomReport(payload *ExportRequestPayload) (*ExportResponse, error) { clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey) params, err := json.Marshal(payload) if err != nil { @@ -58,7 +56,7 @@ func (r *SbomHTTPWrapper) GenerateSbomReport(payload *SbomReportsPayload) (*Sbom switch resp.StatusCode { case http.StatusAccepted: - model := SbomReportsResponse{} + model := ExportResponse{} decoder := json.NewDecoder(resp.Body) err = decoder.Decode(&model) if err != nil { @@ -72,42 +70,7 @@ func (r *SbomHTTPWrapper) GenerateSbomReport(payload *SbomReportsPayload) (*Sbom } } -func (r *SbomHTTPWrapper) GenerateSbomReportWithProxy(payload *SbomReportsPayload, targetFile string) (bool, error) { - clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey) - path := fmt.Sprintf("%s/%s/%s", r.proxyPath, payload.ScanID, "export") - params := map[string]string{"format": payload.FileFormat} - resp, err := SendPrivateHTTPRequestWithQueryParams(http.MethodGet, path, params, nil, clientTimeout) - if err != nil { - return true, err - } - - defer func() { - _ = resp.Body.Close() - }() - - if resp.StatusCode == http.StatusCreated || resp.StatusCode == http.StatusAccepted { - return false, nil - } - - if resp.StatusCode != http.StatusOK { - return true, errors.Errorf("response status code %d", resp.StatusCode) - } - - file, err := os.Create(targetFile) - if err != nil { - return true, errors.Wrapf(err, "Failed to create file %s", targetFile) - } - defer file.Close() - size, err := io.Copy(file, resp.Body) - if err != nil { - return true, errors.Wrapf(err, "Failed to write file %s", targetFile) - } - - log.Printf("Downloaded file: %s - %d bytes\n", targetFile, size) - return true, nil -} - -func (r *SbomHTTPWrapper) GetSbomReportStatus(reportID string) (*SbomPollingResponse, error) { +func (r *ExportHTTPWrapper) GetSbomReportStatus(reportID string) (*ExportPollingResponse, error) { clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey) path := fmt.Sprintf("%s/%s", r.path, "requests") params := map[string]string{"returnUrl": "true", "exportId": reportID} @@ -124,7 +87,7 @@ func (r *SbomHTTPWrapper) GetSbomReportStatus(reportID string) (*SbomPollingResp switch resp.StatusCode { case http.StatusOK: - model := SbomPollingResponse{} + model := ExportPollingResponse{} err = decoder.Decode(&model) if err != nil { return nil, errors.Wrapf(err, "failed to parse response body") @@ -135,7 +98,7 @@ func (r *SbomHTTPWrapper) GetSbomReportStatus(reportID string) (*SbomPollingResp } } -func (r *SbomHTTPWrapper) DownloadSbomReport(reportID, targetFile string) error { +func (r *ExportHTTPWrapper) DownloadSbomReport(reportID, targetFile string) error { clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey) customURL := fmt.Sprintf("%s/%s/%s/%s", r.path, "requests", reportID, "download") resp, err := SendHTTPRequest(http.MethodGet, customURL, http.NoBody, true, clientTimeout) diff --git a/internal/wrappers/export.go b/internal/wrappers/export.go new file mode 100644 index 000000000..03973554f --- /dev/null +++ b/internal/wrappers/export.go @@ -0,0 +1,7 @@ +package wrappers + +type ExportWrapper interface { + GenerateSbomReport(payload *ExportRequestPayload) (*ExportResponse, error) + GetSbomReportStatus(reportID string) (*ExportPollingResponse, error) + DownloadSbomReport(reportID, targetFile string) error +} diff --git a/internal/wrappers/mock/export-mock.go b/internal/wrappers/mock/export-mock.go new file mode 100644 index 000000000..f695047bc --- /dev/null +++ b/internal/wrappers/mock/export-mock.go @@ -0,0 +1,44 @@ +package mock + +import ( + "os" + + "github.com/checkmarx/ast-cli/internal/wrappers" + "github.com/pkg/errors" +) + +type ExportMockWrapper struct{} + +// GenerateSbomReport mock for tests +func (*ExportMockWrapper) GenerateSbomReport(payload *wrappers.ExportRequestPayload) (*wrappers.ExportResponse, error) { + if payload.ScanID == "err-scan-id" { + return nil, errors.New("error") + } + return &wrappers.ExportResponse{ + ExportID: "id123456", + }, nil +} + +// GetSbomReportStatus mock for tests +func (*ExportMockWrapper) GetSbomReportStatus(_ string) (*wrappers.ExportPollingResponse, error) { + return &wrappers.ExportPollingResponse{ + ExportID: "id1234", + ExportStatus: "Completed", + FileURL: "url", + }, nil +} + +// DownloadSbomReport mock for tests +func (*ExportMockWrapper) DownloadSbomReport(_, targetFile string) error { + file, err := os.Create(targetFile) + defer func() { + err = file.Close() + if err != nil { + panic(err) + } + }() + if err != nil { + return errors.Wrapf(err, "Failed to create file %s", targetFile) + } + return nil +} diff --git a/internal/wrappers/mock/results-sbom-mock.go b/internal/wrappers/mock/results-sbom-mock.go deleted file mode 100644 index 8f54a7d15..000000000 --- a/internal/wrappers/mock/results-sbom-mock.go +++ /dev/null @@ -1,56 +0,0 @@ -package mock - -import ( - "os" - - "github.com/checkmarx/ast-cli/internal/wrappers" - "github.com/pkg/errors" -) - -type ResultsSbomWrapper struct{} - -func (w *ResultsSbomWrapper) GenerateSbomReportWithProxy(payload *wrappers.SbomReportsPayload, targetFile string) (bool, error) { - file, err := os.Create(targetFile) - defer func() { - err = file.Close() - if err != nil { - panic(err) - } - }() - if err != nil { - return true, errors.Wrapf(err, "Failed to create file %s", targetFile) - } - - return true, nil -} - -// GenerateSbomReport mock for tests -func (*ResultsSbomWrapper) GenerateSbomReport(_ *wrappers.SbomReportsPayload) (*wrappers.SbomReportsResponse, error) { - return &wrappers.SbomReportsResponse{ - ExportID: "id123456", - }, nil -} - -// GetSbomReportStatus mock for tests -func (*ResultsSbomWrapper) GetSbomReportStatus(_ string) (*wrappers.SbomPollingResponse, error) { - return &wrappers.SbomPollingResponse{ - ExportID: "id1234", - ExportStatus: "Completed", - FileURL: "url", - }, nil -} - -// DownloadSbomReport mock for tests -func (*ResultsSbomWrapper) DownloadSbomReport(_, targetFile string) error { - file, err := os.Create(targetFile) - defer func() { - err = file.Close() - if err != nil { - panic(err) - } - }() - if err != nil { - return errors.Wrapf(err, "Failed to create file %s", targetFile) - } - return nil -} diff --git a/internal/wrappers/results-sbom.go b/internal/wrappers/results-sbom.go deleted file mode 100644 index e4220e2fd..000000000 --- a/internal/wrappers/results-sbom.go +++ /dev/null @@ -1,8 +0,0 @@ -package wrappers - -type ResultsSbomWrapper interface { - GenerateSbomReport(payload *SbomReportsPayload) (*SbomReportsResponse, error) - GenerateSbomReportWithProxy(payload *SbomReportsPayload, targetFile string) (bool, error) - GetSbomReportStatus(reportID string) (*SbomPollingResponse, error) - DownloadSbomReport(reportID, targetFile string) error -} diff --git a/test/integration/result_test.go b/test/integration/result_test.go index 9f39a9fa0..475b53c6e 100644 --- a/test/integration/result_test.go +++ b/test/integration/result_test.go @@ -387,7 +387,6 @@ func TestResultsGeneratingSBOM(t *testing.T) { flag(params.ScanIDFlag), scanID, flag(params.TargetFormatFlag), "sbom", flag(params.ReportSbomFormatFlag), "CycloneDxXml", - flag(params.ReportSbomFormatLocalFlowFlag), } executeCommand(t, args...) diff --git a/test/integration/util_command.go b/test/integration/util_command.go index a941615bc..e2af38a5d 100644 --- a/test/integration/util_command.go +++ b/test/integration/util_command.go @@ -77,8 +77,7 @@ func createASTIntegrationTestCommand(t *testing.T) *cobra.Command { prDecorationGitlabPath := viper.GetString(params.PRDecorationGitlabPathKey) tenantConfigurationPath := viper.GetString(params.TenantConfigurationPathKey) resultsPdfPath := viper.GetString(params.ResultsPdfReportPathKey) - resultsSbomPath := viper.GetString(params.ResultsSbomReportPathKey) - resultsSbomProxyPath := viper.GetString(params.ResultsSbomReportProxyPathKey) + exportPath := viper.GetString(params.ExportPathKey) featureFlagsPath := viper.GetString(params.FeatureFlagsKey) policyEvaluationPath := viper.GetString(params.PolicyEvaluationPathKey) sastIncrementalPath := viper.GetString(params.SastMetadataPathKey) @@ -88,7 +87,7 @@ func createASTIntegrationTestCommand(t *testing.T) *cobra.Command { scansWrapper := wrappers.NewHTTPScansWrapper(scans) applicationsWrapper := wrappers.NewApplicationsHTTPWrapper(applications) resultsPdfReportsWrapper := wrappers.NewResultsPdfReportsHTTPWrapper(resultsPdfPath) - resultsSbomReportsWrapper := wrappers.NewResultsSbomReportsHTTPWrapper(resultsSbomPath, resultsSbomProxyPath) + exportWrapper := wrappers.NewExportHTTPWrapper(exportPath) resultsPredicatesWrapper := wrappers.NewResultsPredicatesHTTPWrapper() groupsWrapper := wrappers.NewHTTPGroupsWrapper(groups) @@ -121,7 +120,7 @@ func createASTIntegrationTestCommand(t *testing.T) *cobra.Command { astCli := commands.NewAstCLI( applicationsWrapper, scansWrapper, - resultsSbomReportsWrapper, + exportWrapper, resultsPdfReportsWrapper, resultsPredicatesWrapper, codeBashingWrapper, From 32ca45d093d98f0a22ba905b2fec81c871c9a2c6 Mon Sep 17 00:00:00 2001 From: OrShamirCM Date: Sun, 14 Jul 2024 17:09:29 +0300 Subject: [PATCH 2/2] Add vendor to git Ignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ef37eb5d7..8d6f3a1df 100644 --- a/.gitignore +++ b/.gitignore @@ -59,4 +59,7 @@ override.tf.json # Ignore CLI configuration files and installation log files **/colima-Darwin-x86_64 -**/install.log \ No newline at end of file +**/install.log + +# Ignore pkgs directory +vendor/*