diff --git a/core/core/scan.go b/core/core/scan.go index 67e3ddee..c9e53ab5 100644 --- a/core/core/scan.go +++ b/core/core/scan.go @@ -117,6 +117,11 @@ func GetOutputPrinters(scanInfo *cautils.ScanInfo, ctx context.Context) []printe outputPrinters := make([]printer.IPrinter, 0) for _, format := range formats { + if !resultshandling.ValidatePrinter(scanInfo.ScanType, format) { + logger.L().Ctx(ctx).Fatal(fmt.Sprintf("Unsupported output format: %s", format)) + continue + } + printerHandler := resultshandling.NewPrinter(ctx, format, scanInfo.FormatVersion, scanInfo.PrintAttackTree, scanInfo.VerboseMode, cautils.ViewTypes(scanInfo.View)) printerHandler.SetWriter(ctx, scanInfo.Output) outputPrinters = append(outputPrinters, printerHandler) diff --git a/core/pkg/resultshandling/printer/v2/htmlprinter.go b/core/pkg/resultshandling/printer/v2/htmlprinter.go index 285a419f..f90a3b35 100644 --- a/core/pkg/resultshandling/printer/v2/htmlprinter.go +++ b/core/pkg/resultshandling/printer/v2/htmlprinter.go @@ -56,6 +56,11 @@ func (hp *HtmlPrinter) PrintNextSteps() { } func (hp *HtmlPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils.OPASessionObj, imageScanData []cautils.ImageScanData) { + if opaSessionObj == nil { + logger.L().Ctx(ctx).Error("failed to print results, missing data") + return + } + tplFuncMap := template.FuncMap{ "sum": func(nums ...int) int { total := 0 diff --git a/core/pkg/resultshandling/printer/v2/jsonprinter.go b/core/pkg/resultshandling/printer/v2/jsonprinter.go index b08f38ef..cf516433 100644 --- a/core/pkg/resultshandling/printer/v2/jsonprinter.go +++ b/core/pkg/resultshandling/printer/v2/jsonprinter.go @@ -53,11 +53,11 @@ func (jp *JsonPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils.O } else if imageScanData != nil { err = jp.PrintImageScan(ctx, imageScanData[0].PresenterConfig) } else { - err = fmt.Errorf("failed to write results, no data provided") + err = fmt.Errorf("no data provided") } if err != nil { - logger.L().Ctx(ctx).Error("failed to write results", helpers.Error(err)) + logger.L().Ctx(ctx).Error("failed to write results in json format", helpers.Error(err)) return } @@ -75,7 +75,15 @@ func printConfigurationsScanning(opaSessionObj *cautils.OPASessionObj, ctx conte } func (jp *JsonPrinter) PrintImageScan(ctx context.Context, scanResults *models.PresenterConfig) error { - presenterConfig, _ := presenter.ValidatedConfig("json", "", false) + if scanResults == nil { + return fmt.Errorf("no image vulnerability data provided") + } + + presenterConfig, err := presenter.ValidatedConfig("json", "", false) + if err != nil { + return err + } + pres := presenter.GetPresenter(presenterConfig, *scanResults) return pres.Present(jp.writer) diff --git a/core/pkg/resultshandling/printer/v2/junit.go b/core/pkg/resultshandling/printer/v2/junit.go index 59a26bb7..fd01bb11 100644 --- a/core/pkg/resultshandling/printer/v2/junit.go +++ b/core/pkg/resultshandling/printer/v2/junit.go @@ -117,6 +117,11 @@ func (jp *JunitPrinter) PrintNextSteps() { } func (jp *JunitPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils.OPASessionObj, imageScanData []cautils.ImageScanData) { + if opaSessionObj == nil { + logger.L().Ctx(ctx).Error("failed to print results, missing data") + return + } + junitResult := testsSuites(opaSessionObj) postureReportStr, err := xml.Marshal(junitResult) if err != nil { diff --git a/core/pkg/resultshandling/printer/v2/pdf.go b/core/pkg/resultshandling/printer/v2/pdf.go index 8906c1ed..509c4d41 100644 --- a/core/pkg/resultshandling/printer/v2/pdf.go +++ b/core/pkg/resultshandling/printer/v2/pdf.go @@ -90,6 +90,11 @@ func (pp *PdfPrinter) PrintNextSteps() { } func (pp *PdfPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils.OPASessionObj, imageScanData []cautils.ImageScanData) { + if opaSessionObj == nil { + logger.L().Ctx(ctx).Error("failed to print results, missing data") + return + } + sortedControlIDs := getSortedControlsIDs(opaSessionObj.Report.SummaryDetails.Controls) infoToPrintInfo := mapInfoToPrintInfo(opaSessionObj.Report.SummaryDetails.Controls) diff --git a/core/pkg/resultshandling/printer/v2/prometheus.go b/core/pkg/resultshandling/printer/v2/prometheus.go index 49bb3c58..cc560e6f 100644 --- a/core/pkg/resultshandling/printer/v2/prometheus.go +++ b/core/pkg/resultshandling/printer/v2/prometheus.go @@ -56,6 +56,10 @@ func (pp *PrometheusPrinter) PrintImageScan(context.Context, *models.PresenterCo } func (pp *PrometheusPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils.OPASessionObj, imageScanData []cautils.ImageScanData) { + if opaSessionObj == nil { + logger.L().Ctx(ctx).Error("failed to print results, missing data") + return + } metrics := pp.generatePrometheusFormat(opaSessionObj.AllResources, opaSessionObj.ResourcesResult, &opaSessionObj.Report.SummaryDetails) diff --git a/core/pkg/resultshandling/printer/v2/sarifprinter.go b/core/pkg/resultshandling/printer/v2/sarifprinter.go index ac5d5bf8..fe3641a9 100644 --- a/core/pkg/resultshandling/printer/v2/sarifprinter.go +++ b/core/pkg/resultshandling/printer/v2/sarifprinter.go @@ -10,6 +10,7 @@ import ( "strconv" "strings" + "github.com/anchore/grype/grype/presenter" "github.com/anchore/grype/grype/presenter/models" logger "github.com/kubescape/go-logger" "github.com/kubescape/go-logger/helpers" @@ -110,7 +111,19 @@ func (sp *SARIFPrinter) addResult(scanRun *sarif.Run, ctl reportsummary.IControl }) } -func (sp *SARIFPrinter) PrintImageScan(context.Context, *models.PresenterConfig) { +func (sp *SARIFPrinter) printImageScan(scanResults *models.PresenterConfig) error { + if scanResults == nil { + return fmt.Errorf("no no image vulnerability data provided") + } + + presenterConfig, err := presenter.ValidatedConfig(printer.SARIFFormat, "", false) + if err != nil { + return err + } + + pres := presenter.GetPresenter(presenterConfig, *scanResults) + + return pres.Present(sp.writer) } func (sp *SARIFPrinter) PrintNextSteps() { @@ -118,9 +131,32 @@ func (sp *SARIFPrinter) PrintNextSteps() { } func (sp *SARIFPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils.OPASessionObj, imageScanData []cautils.ImageScanData) { + if opaSessionObj == nil { + if len(imageScanData) == 0 { + logger.L().Ctx(ctx).Fatal("failed to write results in sarif format: no data provided") + return + } + + // image scan + if err := sp.printImageScan(imageScanData[0].PresenterConfig); err != nil { + logger.L().Ctx(ctx).Error("failed to write results in sarif format", helpers.Error(err)) + return + } + } else { + // configuration scan + if err := sp.printConfigurationScan(ctx, opaSessionObj); err != nil { + logger.L().Ctx(ctx).Error("failed to write results in sarif format", helpers.Error(err)) + return + } + + } + printer.LogOutputFile(sp.writer.Name()) +} + +func (sp *SARIFPrinter) printConfigurationScan(ctx context.Context, opaSessionObj *cautils.OPASessionObj) error { report, err := sarif.New(sarif.Version210) if err != nil { - panic(err) + return err } run := sarif.NewRunWithInformationURI(toolName, toolInfoURI) @@ -161,7 +197,7 @@ func (sp *SARIFPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils. report.PrettyWrite(sp.writer) - printer.LogOutputFile(sp.writer.Name()) + return nil } func (sp *SARIFPrinter) resolveFixLocation(opaSessionObj *cautils.OPASessionObj, locationResolver *locationresolver.FixPathLocationResolver, ac *resourcesresults.ResourceAssociatedControl, resourceID string) locationresolver.Location { diff --git a/core/pkg/resultshandling/results.go b/core/pkg/resultshandling/results.go index 517a56c3..296782b2 100644 --- a/core/pkg/resultshandling/results.go +++ b/core/pkg/resultshandling/results.go @@ -131,3 +131,17 @@ func NewPrinter(ctx context.Context, printFormat, formatVersion string, verboseM return printerv2.NewPrettyPrinter(verboseMode, formatVersion, attackTree, viewType, "", nil) } } + +func ValidatePrinter(scanType cautils.ScanTypes, printFormat string) bool { + if scanType != cautils.ScanTypeImage { + return true + } + + // supported types for image scanning + switch printFormat { + case printer.JsonFormat, printer.PrettyFormat, printer.SARIFFormat: + return true + default: + return false + } +} diff --git a/core/pkg/resultshandling/results_test.go b/core/pkg/resultshandling/results_test.go index 5416c256..07b6267c 100644 --- a/core/pkg/resultshandling/results_test.go +++ b/core/pkg/resultshandling/results_test.go @@ -57,3 +57,96 @@ func TestResultsHandlerHandleResultsPrintsResultsToUI(t *testing.T) { t.Errorf("UI Printer was not called to print. Got calls: %d, want calls: %d", got, want) } } + +func TestValidatePrinter(t *testing.T) { + tests := []struct { + name string + scanType cautils.ScanTypes + format string + expected bool + }{ + { + name: "json format for cluster scan", + scanType: cautils.ScanTypeCluster, + format: printer.JsonFormat, + expected: true, + }, + { + name: "junit format for cluster scan", + scanType: cautils.ScanTypeCluster, + format: printer.JunitResultFormat, + expected: true, + }, + { + name: "sarif format for cluster scan", + scanType: cautils.ScanTypeCluster, + format: printer.SARIFFormat, + expected: true, + }, + { + name: "pretty format for cluster scan", + scanType: cautils.ScanTypeCluster, + format: printer.PrettyFormat, + expected: true, + }, + { + name: "html format for cluster scan", + scanType: cautils.ScanTypeCluster, + format: printer.HtmlFormat, + expected: true, + }, + { + name: "prometheus format for cluster scan", + scanType: cautils.ScanTypeCluster, + format: printer.PrometheusFormat, + expected: true, + }, + + { + name: "json format for image scan", + scanType: cautils.ScanTypeImage, + format: printer.JsonFormat, + expected: true, + }, + { + name: "junit format for image scan", + scanType: cautils.ScanTypeImage, + format: printer.JunitResultFormat, + expected: false, + }, + { + name: "sarif format for image scan", + scanType: cautils.ScanTypeImage, + format: printer.SARIFFormat, + expected: true, + }, + { + name: "pretty format for image scan", + scanType: cautils.ScanTypeImage, + format: printer.PrettyFormat, + expected: true, + }, + { + name: "html format for image scan", + scanType: cautils.ScanTypeImage, + format: printer.HtmlFormat, + expected: false, + }, + { + name: "prometheus format for image scan", + scanType: cautils.ScanTypeImage, + format: printer.PrometheusFormat, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := ValidatePrinter(tt.scanType, tt.format) + if got != tt.expected { + t.Errorf("%s failed - got = %v, want %v", tt.name, got, tt.expected) + } + }) + } + +}