diff --git a/internal/commands/result.go b/internal/commands/result.go index 20033d332..ade69b204 100644 --- a/internal/commands/result.go +++ b/internal/commands/result.go @@ -394,7 +394,7 @@ func summaryReport( summary *wrappers.ResultSummary, policies *wrappers.PolicyResponseModel, risksOverviewWrapper wrappers.RisksOverviewWrapper, - resultsWrapper wrappers.ResultsWrapper, + results *wrappers.ScanResultsCollection, ) (*wrappers.ResultSummary, error) { if summary.HasAPISecurity() { apiSecRisks, err := getResultsForAPISecScanner(risksOverviewWrapper, summary.ScanID) @@ -408,10 +408,7 @@ func summaryReport( summary.Policies = filterViolatedRules(*policies) } - err := enhanceWithScanSummary(summary, resultsWrapper) - if err != nil { - return nil, err - } + enhanceWithScanSummary(summary, results) setNotAvailableNumberIfZero(summary, &summary.SastIssues, commonParams.SastType) setNotAvailableNumberIfZero(summary, &summary.ScaIssues, commonParams.ScaType) @@ -442,51 +439,11 @@ func setRiskMsgAndStyle(summary *wrappers.ResultSummary) { } } -func enhanceWithScanSummary(summary *wrappers.ResultSummary, resultsWrapper wrappers.ResultsWrapper) error { - scanSummary, errModel, err := resultsWrapper.GetScanSummariesByScanIDS(map[string]string{ - commonParams.ScanIDsQueryParam: summary.ScanID, - }) - if err != nil { - return err - } - if errModel != nil { - return errors.Errorf("%s: CODE: %d, %s", failedGettingScan, errModel.Code, errModel.Message) - } - - if len(scanSummary.ScansSummaries) != 1 { - return errors.Errorf("error - scan summary is nil or has more than one element") +func enhanceWithScanSummary(summary *wrappers.ResultSummary, results *wrappers.ScanResultsCollection) { + for _, result := range results.Results { + countResult(summary, result) } - - updateSummaryWithScanSummary(summary, &scanSummary.ScansSummaries[0]) summary.TotalIssues = summary.SastIssues + summary.ScaIssues + summary.KicsIssues - return nil -} - -func updateSummaryWithScanSummary(summary *wrappers.ResultSummary, scanSummary *wrappers.ScanSumaries) { - summary.SastIssues += scanSummary.SastCounters.TotalCounter - summary.KicsIssues += scanSummary.KicsCounters.TotalCounter - summary.ScaIssues += scanSummary.ScaCounters.TotalCounter - summary.ScaIssues += scanSummary.ScaContainersCounters.TotalVulnerabilitiesCounter - - updateSeverityCounts(summary, scanSummary.SastCounters.SeverityCounters) - updateSeverityCounts(summary, scanSummary.KicsCounters.SeverityCounters) - updateSeverityCounts(summary, scanSummary.ScaCounters.SeverityCounters) - updateSeverityCounts(summary, scanSummary.ScaContainersCounters.SeverityCounters) -} - -func updateSeverityCounts(summary *wrappers.ResultSummary, severityCounts []wrappers.SeverityCounters) { - for _, sev := range severityCounts { - switch strings.ToLower(sev.Severity) { - case highLabel: - summary.HighIssues += sev.Counter - case mediumLabel: - summary.MediumIssues += sev.Counter - case lowLabel: - summary.LowIssues += sev.Counter - case infoLabel: - summary.InfoIssues += sev.Counter - } - } } func writeHTMLSummary(targetFile string, summary *wrappers.ResultSummary) error { @@ -743,8 +700,7 @@ func CreateScanReport( if err != nil { return err } - isResultsNeeded := verifyFormatsByReportList(reportList, resultsFormats...) - if isResultsNeeded && !scanPending { + if !scanPending { results, err = ReadResults(resultsWrapper, scan, params) if err != nil { return err @@ -753,7 +709,7 @@ func CreateScanReport( } isSummaryNeeded := verifyFormatsByReportList(reportList, summaryFormats...) if isSummaryNeeded && !scanPending { - summary, err = summaryReport(summary, policyResponseModel, risksOverviewWrapper, resultsWrapper) + summary, err = summaryReport(summary, policyResponseModel, risksOverviewWrapper, results) if err != nil { return err } @@ -768,6 +724,32 @@ func CreateScanReport( return nil } +func countResult(summary *wrappers.ResultSummary, result *wrappers.ScanResult) { + engineType := strings.TrimSpace(result.Type) + if contains(summary.EnginesEnabled, engineType) && isExploitable(result.State) { + if engineType == commonParams.SastType { + summary.SastIssues++ + summary.TotalIssues++ + } else if engineType == commonParams.ScaType { + summary.ScaIssues++ + summary.TotalIssues++ + } else if engineType == commonParams.KicsType { + summary.KicsIssues++ + summary.TotalIssues++ + } + severity := strings.ToLower(result.Severity) + if severity == highLabel { + summary.HighIssues++ + } else if severity == lowLabel { + summary.LowIssues++ + } else if severity == mediumLabel { + summary.MediumIssues++ + } else if severity == infoLabel { + summary.InfoIssues++ + } + } +} + func verifyFormatsByReportList(reportFormats []string, formats ...string) bool { for _, reportFormat := range reportFormats { for _, format := range formats { diff --git a/internal/commands/result_test.go b/internal/commands/result_test.go index 4a8158938..4060ff65b 100644 --- a/internal/commands/result_test.go +++ b/internal/commands/result_test.go @@ -69,13 +69,6 @@ func TestRunGetResultsByScanIdSummaryHtmlFormat(t *testing.T) { func TestRunGetResultsByScanIdSummaryConsoleFormat(t *testing.T) { execCmdNilAssertion(t, "results", "show", "--scan-id", "MOCK", "--report-format", "summaryConsole") - - // Testing errors - err := execCmdNotNilAssertion(t, "results", "show", "--scan-id", "MOCKERR", "--report-format", "summaryConsole") - assert.Equal(t, err.Error(), "mock error") - - err = execCmdNotNilAssertion(t, "results", "show", "--scan-id", "MOCKWEBERR", "--report-format", "summaryConsole") - assert.ErrorContains(t, err, "web error") } func TestRunGetResultsByScanIdPDFFormat(t *testing.T) { diff --git a/internal/commands/util/help_test.go b/internal/commands/util/help_test.go index c3b6119fd..1d8bfe01a 100644 --- a/internal/commands/util/help_test.go +++ b/internal/commands/util/help_test.go @@ -4,7 +4,7 @@ import ( "testing" ) -//TODO: can we assert something? +// TODO: can we assert something? func TestRootHelpFunc(t *testing.T) { cmd := NewConfigCommand() cmd.Long = "" diff --git a/internal/wrappers/results-http.go b/internal/wrappers/results-http.go index 566cc259b..39f9b1b7c 100644 --- a/internal/wrappers/results-http.go +++ b/internal/wrappers/results-http.go @@ -19,6 +19,9 @@ const ( respStatusCode = "response status code %d" sort = "sort" sortResultsDefault = "-severity" + offset = "offset" + astAPIPageLen = 1000 + astAPIPagingValue = "1000" ) type ResultsHTTPWrapper struct { @@ -40,14 +43,53 @@ func (r *ResultsHTTPWrapper) GetAllResultsByScanID(params map[string]string) ( *WebError, error, ) { - clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey) - // AST has a limit of 10000 results, this makes it get all of them - DefaultMapValue(params, limit, limitValue) + var scanModelslice []ScanResultsCollection + var scanModel ScanResultsCollection + DefaultMapValue(params, limit, astAPIPagingValue) DefaultMapValue(params, sort, sortResultsDefault) - resp, err := SendPrivateHTTPRequestWithQueryParams(http.MethodGet, r.resultsPath, params, http.NoBody, clientTimeout) + webErr, err := getResultsWithPagination(r.resultsPath, params, &scanModelslice) if err != nil { - return nil, nil, err + return &scanModel, nil, err + } + if webErr != nil { + return &scanModel, webErr, nil + } + for _, resultsPage := range scanModelslice { + scanModel.Results = append(scanModel.Results, resultsPage.Results...) + } + return &scanModel, nil, nil +} +func getResultsWithPagination(resultPath string, queryParams map[string]string, slice *[]ScanResultsCollection) (*WebError, error) { + clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey) + var currentPage = 0 + for { + queryParams[offset] = fmt.Sprintf("%d", currentPage) + target, hasNextPage, weberr, err := getResultsByOffset(resultPath, queryParams, clientTimeout) + if err != nil { + return nil, err + } + + if weberr != nil { + return weberr, nil + } + + *slice = append(*slice, *target) + + if !hasNextPage { + break + } + if astAPIPageLen > int(target.TotalCount) { + break + } + currentPage++ + } + return nil, nil +} +func getResultsByOffset(resultPath string, params map[string]string, clientTimeout uint) (*ScanResultsCollection, bool, *WebError, error) { + resp, err := SendPrivateHTTPRequestWithQueryParams(http.MethodGet, resultPath, params, http.NoBody, clientTimeout) + if err != nil { + return nil, false, nil, err } defer func() { @@ -61,22 +103,26 @@ func (r *ResultsHTTPWrapper) GetAllResultsByScanID(params map[string]string) ( errorModel := WebError{} err = decoder.Decode(&errorModel) if err != nil { - return nil, nil, errors.Wrapf(err, failedToParseGetResults) + return nil, false, nil, errors.Wrapf(err, failedToParseGetResults) } - return nil, &errorModel, nil + return nil, false, &errorModel, nil case http.StatusOK: model := ScanResultsCollection{} err = decoder.Decode(&model) if err != nil { - return nil, nil, errors.Wrapf(err, failedToParseGetResults) + return nil, false, nil, errors.Wrapf(err, failedToParseGetResults) } - - return &model, nil, nil + if err != nil { + return nil, false, nil, errors.Wrapf(err, failedToParseGetResults) + } + if len(model.Results) == 0 { + return &model, false, nil, nil + } + return &model, true, nil, nil default: - return nil, nil, errors.Errorf(respStatusCode, resp.StatusCode) + return nil, false, nil, errors.Errorf(respStatusCode, resp.StatusCode) } } - func (r *ResultsHTTPWrapper) GetAllResultsPackageByScanID(params map[string]string) ( *[]ScaPackageCollection, *WebError, @@ -184,6 +230,7 @@ func (r *ResultsHTTPWrapper) GetResultsURL(projectID string) (string, error) { return baseURI, nil } +// GetScanSummariesByScanIDS will no longer be used because it does not support --filters flag func (r *ResultsHTTPWrapper) GetScanSummariesByScanIDS(params map[string]string) ( *ScanSummariesModel, *WebError, diff --git a/test/integration/root_test.go b/test/integration/root_test.go index 8fc39e4c3..29c1a08f6 100644 --- a/test/integration/root_test.go +++ b/test/integration/root_test.go @@ -38,7 +38,7 @@ func TestMain(m *testing.M) { log.Println("CLI integration tests started") viper.SetDefault(resolverEnvVar, resolverEnvVarDefault) exitVal := m.Run() - deleteScanAndProject() + //deleteScanAndProject() log.Println("CLI integration tests done") os.Exit(exitVal) } diff --git a/test/integration/scan_test.go b/test/integration/scan_test.go index 6dbed1754..26d009462 100644 --- a/test/integration/scan_test.go +++ b/test/integration/scan_test.go @@ -539,54 +539,54 @@ func pollScanUntilStatus(t *testing.T, scanID string, requiredStatus wrappers.Sc } } -// Get a scan workflow and assert its structure -//func TestScanWorkflow(t *testing.T) { -// scanID, _ := getRootScan(t) -// -// buffer := executeCmdNilAssertion( -// t, "Workflow should pass", "scan", "workflow", -// flag(params.ScanIDFlag), scanID, -// flag(params.FormatFlag), printer.FormatJSON, -// ) -// -// var workflow []ScanWorkflowResponse -// _ = unmarshall(t, buffer, &workflow, "Reading workflow output should work") -// -// //assert.Assert(t, len(workflow) > 0, "At least one item should exist in the workflow response") -//} +// Get a scan workflow and assert it fails +func TestScanWorkflow(t *testing.T) { + scanID, _ := getRootScan(t) + args := []string{ + "scan", "workflow", + flag(params.ScanIDFlag), scanID, + flag(params.FormatFlag), printer.FormatJSON, + } + cmd := createASTIntegrationTestCommand(t) + err := execute(cmd, args...) + assert.Assert(t, err != nil, "Failed showing a scan: response status code 404") +} -//func TestScanLogsSAST(t *testing.T) { -// scanID, _ := getRootScan(t) -// -// //executeCmdNilAssertion( -// // t, "Getting scan SAST log should pass", -// // "scan", "logs", -// // flag(params.ScanIDFlag), scanID, -// // flag(params.ScanTypeFlag), "sast", -// //) -//} +func TestScanLogsSAST(t *testing.T) { + scanID, _ := getRootScan(t) + args := []string{ + "scan", "logs", + flag(params.ScanIDFlag), scanID, + flag(params.ScanTypeFlag), "sast", + } + cmd := createASTIntegrationTestCommand(t) + err := execute(cmd, args...) + assert.Assert(t, err != nil, "response status code 404") +} -//func TestScanLogsKICSDeprecated(t *testing.T) { -// scanID, _ := getRootScan(t) -// -// executeCmdNilAssertion( -// t, "Getting scan KICS log should pass", -// "scan", "logs", -// flag(params.ScanIDFlag), scanID, -// flag(params.ScanTypeFlag), "kics", -// ) -//} +func TestScanLogsKICSDeprecated(t *testing.T) { + scanID, _ := getRootScan(t) + args := []string{ + "scan", "logs", + flag(params.ScanIDFlag), scanID, + flag(params.ScanTypeFlag), "kics", + } + cmd := createASTIntegrationTestCommand(t) + err := execute(cmd, args...) + assert.Assert(t, err != nil, "response status code 404") +} -//func TestScanLogsKICS(t *testing.T) { -// scanID, _ := getRootScan(t) -// -// executeCmdNilAssertion( -// t, "Getting scan KICS log should pass", -// "scan", "logs", -// flag(params.ScanIDFlag), scanID, -// flag(params.ScanTypeFlag), "iac-security", -// ) -//} +func TestScanLogsKICS(t *testing.T) { + scanID, _ := getRootScan(t) + args := []string{ + "scan", "logs", + flag(params.ScanIDFlag), scanID, + flag(params.ScanTypeFlag), "iac-security", + } + cmd := createASTIntegrationTestCommand(t) + err := execute(cmd, args...) + assert.Assert(t, err != nil, "response status code 404") +} func TestPartialScanWithWrongPreset(t *testing.T) { _, projectName := getRootProject(t)