From e829af7205d4966a8e690d4b4ffd2c3c7954b97d Mon Sep 17 00:00:00 2001 From: Daniel Grunberger Date: Mon, 31 Jul 2023 21:15:23 +0300 Subject: [PATCH] changes --- cmd/scan/framework.go | 5 +++ cmd/scan/image.go | 1 + cmd/scan/scan.go | 3 +- cmd/scan/workload.go | 3 +- core/cautils/getter/datastructures.go | 2 +- core/cautils/scaninfo.go | 4 ++ core/core/scan.go | 9 ++-- .../printer/v2/prettyprinter.go | 5 ++- .../printer/v2/prettyprinter/clusterscan.go | 2 +- .../printer/v2/prettyprinter/reposcan.go | 2 +- .../configurationprinter/categorytable.go | 3 +- .../configurationprinter/clusterscan.go | 8 +++- .../configurationprinter/datastructures.go | 41 ++++++++++++++++--- .../configurationprinter/reposcan.go | 21 ++++++++-- .../configurationprinter/utils.go | 11 +++++ .../configurationprinter/workloadscan.go | 6 +-- .../imageprinter/datastructures.go | 7 ++-- .../prettyprinter/tableprinter/utils/utils.go | 28 +++++++++++++ .../printer/v2/prettyprinter/utils.go | 27 ++++++++---- core/pkg/resultshandling/printer/v2/utils.go | 10 ++++- go.mod | 4 +- go.sum | 8 ++-- 22 files changed, 165 insertions(+), 45 deletions(-) diff --git a/cmd/scan/framework.go b/cmd/scan/framework.go index 9e3b5684..ad4a5499 100644 --- a/cmd/scan/framework.go +++ b/cmd/scan/framework.go @@ -87,6 +87,7 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm if cautils.StringInSlice(frameworks, "all") != cautils.ValueNotFound { scanInfo.ScanAll = true frameworks = getter.NativeFrameworks + } if len(args) > 1 { if len(args[1:]) == 0 || args[1] != "-" { @@ -110,6 +111,10 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm } scanInfo.FrameworkScan = true + if (scanInfo.IsNewOutputFormat) && (scanInfo.ScanType == cautils.ScanTypeRepo || scanInfo.ScanType == cautils.ScanTypeCluster) { + frameworks = append(frameworks, "clusterscan") + } + scanInfo.SetPolicyIdentifiers(frameworks, apisv1.KindFramework) ctx := context.TODO() diff --git a/cmd/scan/image.go b/cmd/scan/image.go index dad3bced..e26f6220 100644 --- a/cmd/scan/image.go +++ b/cmd/scan/image.go @@ -63,6 +63,7 @@ func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command } logger.L().Success("Image scan completed successfully") + scanInfo.IsNewOutputFormat = true scanInfo.SetScanType(cautils.ScanTypeImage) outputPrinters := core.GetOutputPrinters(scanInfo, ctx) diff --git a/cmd/scan/scan.go b/cmd/scan/scan.go index 0eea204a..b431f1ba 100644 --- a/cmd/scan/scan.go +++ b/cmd/scan/scan.go @@ -51,7 +51,7 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { - scanInfo.ScanType = cautils.ScanTypeCluster + scanInfo.SetScanType(cautils.ScanTypeCluster) return getFrameworkCmd(ks, &scanInfo).RunE(cmd, []string{strings.Join(getter.NativeFrameworks, ",")}) } return nil @@ -94,6 +94,7 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command { scanCmd.PersistentFlags().BoolVarP(&scanInfo.OmitRawResources, "omit-raw-resources", "", false, "Omit raw resources from the output. By default the raw resources are included in the output") scanCmd.PersistentFlags().BoolVarP(&scanInfo.PrintAttackTree, "print-attack-tree", "", false, "Print attack tree") scanCmd.PersistentFlags().BoolVarP(&scanInfo.ScanImages, "scan-images", "", false, "Scan images") + scanCmd.PersistentFlags().BoolVarP(&scanInfo.IsNewOutputFormat, "new-output", "", false, "Show new output") scanCmd.PersistentFlags().MarkDeprecated("silent", "use '--logger' flag instead. Flag will be removed at 1.May.2022") scanCmd.PersistentFlags().MarkDeprecated("fail-threshold", "use '--compliance-threshold' flag instead. Flag will be removed at 1.Dec.2023") diff --git a/cmd/scan/workload.go b/cmd/scan/workload.go index c13dfd1f..c10d99fd 100644 --- a/cmd/scan/workload.go +++ b/cmd/scan/workload.go @@ -71,7 +71,8 @@ func getWorkloadCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comma } scanInfo.ScanAll = true - scanInfo.ScanType = cautils.ScanTypeWorkload + scanInfo.IsNewOutputFormat = true + scanInfo.SetScanType(cautils.ScanTypeWorkload) scanInfo.ScanImages = true scanInfo.UseFrom = []string{"/Users/danielgrunberger/armo/merge/release/workloadscan.json"} diff --git a/core/cautils/getter/datastructures.go b/core/cautils/getter/datastructures.go index 26e30851..d5b7cd6d 100644 --- a/core/cautils/getter/datastructures.go +++ b/core/cautils/getter/datastructures.go @@ -8,7 +8,7 @@ import ( ) // NativeFrameworks identifies all pre-built, native frameworks. -var NativeFrameworks = []string{"clusterscan", "mitre", "nsa"} +var NativeFrameworks = []string{"mitre", "nsa"} // var NativeFrameworks = []string{"clusterscan"} diff --git a/core/cautils/scaninfo.go b/core/cautils/scaninfo.go index 1a937a6a..a3a57e8a 100644 --- a/core/cautils/scaninfo.go +++ b/core/cautils/scaninfo.go @@ -149,6 +149,7 @@ type ScanInfo struct { ChartPath string FilePath string ImageScanInfo ImageScanInfo + IsNewOutputFormat bool } type Getters struct { @@ -221,6 +222,9 @@ func (scanInfo *ScanInfo) Formats() []string { } func (scanInfo *ScanInfo) SetScanType(scanType ScanTypes) { + if !scanInfo.IsNewOutputFormat { + return + } scanInfo.ScanType = scanType } diff --git a/core/core/scan.go b/core/core/scan.go index 82e07d16..6b75137f 100644 --- a/core/core/scan.go +++ b/core/core/scan.go @@ -226,28 +226,27 @@ func scanImages(scanInfo *cautils.ScanInfo, scanData *cautils.OPASessionObj, ctx if scanInfo.ScanType == cautils.ScanTypeWorkload { containers, _ := workloadinterface.NewWorkloadObj(scanData.ScannedWorkload.GetObject()).GetContainers() for _, container := range containers { + // if !slices.Contains(imagesToScan, container.Image) { imagesToScan = append(imagesToScan, container.Image) + // } } } else { for _, workload := range scanData.AllResources { containers, _ := workloadinterface.NewWorkloadObj(workload.GetObject()).GetContainers() for _, container := range containers { + // if !slices.Contains(imagesToScan, container.Image) { imagesToScan = append(imagesToScan, container.Image) + // } } } } logger.L().Info("Scanning images") - progressListener := cautils.NewProgressHandler("") - progressListener.Start(len(imagesToScan)) - defer progressListener.Stop() - dbCfg, _ := imagescan.NewDefaultDBConfig() svc := imagescan.NewScanService(dbCfg) for _, img := range imagesToScan { scanSingleImage(ctx, img, svc, resultsHandling, *scanInfo) - progressListener.ProgressJob(1, fmt.Sprintf("image name: %s\n", img)) } logger.L().Success("Finished scanning images") diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter.go b/core/pkg/resultshandling/printer/v2/prettyprinter.go index 960806aa..0229771b 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter.go @@ -20,6 +20,7 @@ import ( "github.com/kubescape/opa-utils/objectsenvelopes" "github.com/kubescape/opa-utils/reporthandling/apis" "github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary" + "k8s.io/utils/strings/slices" ) const ( @@ -81,7 +82,9 @@ func (pp *PrettyPrinter) convertToImageScanSummary(imageScanData []cautils.Image } for _, imageScan := range imageScanData { - imageScanSummary.Images = append(imageScanSummary.Images, imageScan.Image) + if !slices.Contains(imageScanSummary.Images, imageScan.Image) { + imageScanSummary.Images = append(imageScanSummary.Images, imageScan.Image) + } presenterConfig := imageScan.PresenterConfig doc, err := models.NewDocument(presenterConfig.Packages, presenterConfig.Context, presenterConfig.Matches, presenterConfig.IgnoredMatches, presenterConfig.MetadataProvider, nil, presenterConfig.DBStatus) diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter/clusterscan.go b/core/pkg/resultshandling/printer/v2/prettyprinter/clusterscan.go index 264acbe4..ae2ce35b 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/clusterscan.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/clusterscan.go @@ -60,7 +60,7 @@ func (cp *ClusterPrinter) printTopWorkloads(summaryDetails *reportsummary.Summar ns := wl.Workload.GetNamespace() name := wl.Workload.GetName() kind := wl.Workload.GetKind() - cautils.SimpleDisplay(cp.writer, fmt.Sprintf("%d. namespace: %s, name: %s, kind: %s - '%s'\n", i+1, ns, name, kind, cp.getWorkloadScanCommand(ns, kind, name))) + cautils.SimpleDisplay(cp.writer, fmt.Sprintf("%d. namespace: %s, name: %s, kind: %s - '%s'\n", i+1, ns, name, kind, getCallToActionString(cp.getWorkloadScanCommand(ns, kind, name)))) } cautils.SimpleDisplay(cp.writer, "Read more about the most risky workloads here: https://docs.io/most-risky-workloads\n") diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter/reposcan.go b/core/pkg/resultshandling/printer/v2/prettyprinter/reposcan.go index 696c4927..fe705263 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/reposcan.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/reposcan.go @@ -62,7 +62,7 @@ func (rp *RepoPrinter) printTopWorkloads(summaryDetails *reportsummary.SummaryDe name := wl.Workload.GetName() kind := wl.Workload.GetKind() cmdPrefix := getWorkloadPrefixForCmd(ns, kind, name) - cautils.SimpleDisplay(rp.writer, fmt.Sprintf("%d. %s - '%s'\n", i+1, cmdPrefix, rp.getWorkloadScanCommand(ns, kind, name, wl.ResourceSource))) + cautils.SimpleDisplay(rp.writer, fmt.Sprintf("%d. %s - '%s'\n", i+1, cmdPrefix, getCallToActionString(rp.getWorkloadScanCommand(ns, kind, name, wl.ResourceSource)))) } cautils.InfoTextDisplay(rp.writer, "\n") diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/categorytable.go b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/categorytable.go index a1522cc4..cd01396a 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/categorytable.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/categorytable.go @@ -4,6 +4,7 @@ import ( "fmt" "io" + "github.com/fatih/color" "github.com/kubescape/kubescape/v2/core/cautils" "github.com/kubescape/kubescape/v2/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils" "github.com/kubescape/opa-utils/reporthandling/apis" @@ -73,7 +74,7 @@ func generateCategoryStatusRow(controlSummary reportsummary.IControlSummary, inf rows[0] = controlSummary.GetName() } - rows[1] = getStatus(status, controlSummary, infoToPrintInfo) + rows[1] = color.New(color.Bold, utils.GetStatusColor(controlSummary.GetStatus().Status())).SprintFunc()(getStatus(status, controlSummary, infoToPrintInfo)) rows[2] = getDocsForControl(controlSummary) diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/clusterscan.go b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/clusterscan.go index c4b1ec34..b2db57f5 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/clusterscan.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/clusterscan.go @@ -4,6 +4,7 @@ import ( "fmt" "io" + "github.com/fatih/color" "github.com/kubescape/kubescape/v2/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils" "github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary" ) @@ -68,7 +69,12 @@ func (cp *ClusterPrinter) generateCountingCategoryRow(controlSummary reportsumma row[0] = controlSummary.GetName() - row[1] = fmt.Sprintf("%d", controlSummary.NumberOfResources().Failed()) + failedResources := controlSummary.NumberOfResources().Failed() + if failedResources > 0 { + row[1] = string(color.New(color.FgYellow, color.Bold).SprintFunc()(fmt.Sprintf("%d", failedResources))) + } else { + row[1] = fmt.Sprintf("%d", failedResources) + } row[2] = cp.generateTableNextSteps(controlSummary) diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/datastructures.go b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/datastructures.go index 28bc3e1b..8a97983d 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/datastructures.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/datastructures.go @@ -1,15 +1,14 @@ package configurationprinter -import "github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary" +import ( + "github.com/kubescape/opa-utils/reporthandling/apis" + "github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary" +) type CategoryControls struct { CategoryName string controlSummaries []reportsummary.IControlSummary -} - -type Category struct { - Name string - Type CategoryType + Status apis.ScanningStatus } type CategoryType string @@ -42,6 +41,13 @@ var clusterCategoriesDisplayOrder = []string{ workloadsCategoryID, } +var repoCategoriesDisplayOrder = []string{ + workloadsCategoryID, + accessControlCategoryID, + secretsCategoryID, + networkCategoryID, +} + var workloadCategoriesDisplayOrder = []string{ supplyChainCategoryID, resourceManagementCategoryID, @@ -117,3 +123,26 @@ var mapWorkloadControlsToCategories = map[string]string{ "C-0055": nodeEscapeCategoryID, "C-0057": nodeEscapeCategoryID, } + +var mapRepoControlsToCategories = map[string]string{ + "C-0015": accessControlCategoryID, + "C-0002": accessControlCategoryID, + "C-0007": accessControlCategoryID, + "C-0063": accessControlCategoryID, + "C-0036": accessControlCategoryID, + "C-0039": accessControlCategoryID, + "C-0035": accessControlCategoryID, + "C-0188": accessControlCategoryID, + "C-0187": accessControlCategoryID, + + "C-0012": secretsCategoryID, + + "C-0260": networkCategoryID, + "C-0256": networkCategoryID, + + "C-0038": workloadsCategoryID, + "C-0041": workloadsCategoryID, + "C-0048": workloadsCategoryID, + "C-0057": workloadsCategoryID, + "C-0013": workloadsCategoryID, +} diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/reposcan.go b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/reposcan.go index 667363f2..cb565eff 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/reposcan.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/reposcan.go @@ -5,8 +5,10 @@ import ( "io" "strings" + "github.com/fatih/color" "github.com/kubescape/kubescape/v2/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils" "github.com/kubescape/opa-utils/reporthandling" + "github.com/kubescape/opa-utils/reporthandling/apis" "github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary" ) @@ -28,14 +30,18 @@ func (rp *RepoPrinter) PrintSummaryTable(writer io.Writer, summaryDetails *repor func (rp *RepoPrinter) PrintCategoriesTables(writer io.Writer, summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) { - categoriesToCategoryControls := mapCategoryToSummary(summaryDetails.ListControls(), mapClusterControlsToCategories) + categoriesToCategoryControls := mapCategoryToSummary(summaryDetails.ListControls(), mapRepoControlsToCategories) - for _, id := range clusterCategoriesDisplayOrder { + for _, id := range repoCategoriesDisplayOrder { categoryControl, ok := categoriesToCategoryControls[id] if !ok { continue } + if categoryControl.Status != apis.StatusFailed { + continue + } + rp.renderSingleCategoryTable(categoryControl.CategoryName, mapCategoryToType[id], writer, categoryControl.controlSummaries, utils.MapInfoToPrintInfoFromIface(categoryControl.controlSummaries)) } @@ -50,6 +56,10 @@ func (rp *RepoPrinter) renderSingleCategoryTable(categoryName string, categoryTy var rows [][]string for _, ctrls := range controlSummaries { + if ctrls.NumberOfResources().Failed() == 0 { + continue + } + var row []string if categoryType == TypeCounting { row = rp.generateCountingCategoryRow(ctrls, rp.inputPatterns) @@ -73,7 +83,12 @@ func (rp *RepoPrinter) generateCountingCategoryRow(controlSummary reportsummary. rows[0] = controlSummary.GetName() - rows[1] = fmt.Sprintf("%d", controlSummary.NumberOfResources().Failed()) + failedResources := controlSummary.NumberOfResources().Failed() + if failedResources > 0 { + rows[1] = string(color.New(color.FgYellow, color.Bold).SprintFunc()(fmt.Sprintf("%d", failedResources))) + } else { + rows[1] = fmt.Sprintf("%d", failedResources) + } rows[2] = rp.generateTableNextSteps(controlSummary, inputPatterns) diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/utils.go b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/utils.go index d237b3e6..dbbd5334 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/utils.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/utils.go @@ -8,6 +8,7 @@ import ( "github.com/kubescape/kubescape/v2/core/cautils" "github.com/kubescape/kubescape/v2/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils" + "github.com/kubescape/opa-utils/reporthandling/apis" "github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary" ) @@ -31,6 +32,7 @@ func mapCategoryToSummary(controlSummaries []reportsummary.IControlSummary, mapD if _, ok := mapCategoriesToCtrlSummary[controlSummaries[i].GetCategory().ID]; !ok { mapCategoryIDToName[controlSummaries[i].GetCategory().ID] = controlSummaries[i].GetCategory().Name // set category name mapCategoriesToCtrlSummary[controlSummaries[i].GetCategory().ID] = []reportsummary.IControlSummary{} + } mapCategoriesToCtrlSummary[controlSummaries[i].GetCategory().ID] = append(mapCategoriesToCtrlSummary[controlSummaries[i].GetCategory().ID], controlSummaries[i]) continue @@ -55,10 +57,19 @@ func mapCategoryToSummary(controlSummaries []reportsummary.IControlSummary, mapD func buildCategoryToControlsMap(mapCategoriesToCtrlSummary map[string][]reportsummary.IControlSummary, mapCategoryIDToName map[string]string) map[string]CategoryControls { mapCategoryToControls := make(map[string]CategoryControls) for categoryID, ctrls := range mapCategoriesToCtrlSummary { + status := apis.StatusPassed + for _, ctrl := range ctrls { + if ctrl.GetStatus().Status() == apis.StatusFailed { + status = apis.StatusFailed + break + } + } + categoryName := mapCategoryIDToName[categoryID] mapCategoryToControls[categoryID] = CategoryControls{ CategoryName: categoryName, controlSummaries: ctrls, + Status: status, } } return mapCategoryToControls diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/workloadscan.go b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/workloadscan.go index 57f46423..3b717a62 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/workloadscan.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/workloadscan.go @@ -46,11 +46,7 @@ func (wp *WorkloadPrinter) renderSingleCategoryTable(categoryName string, catego var rows [][]string for _, ctrls := range controlSummaries { var row []string - if categoryType == TypeCounting { - row = wp.generateCountingCategoryRow(ctrls, infoToPrintInfo) - } else { - row = generateCategoryStatusRow(ctrls, infoToPrintInfo) - } + row = generateCategoryStatusRow(ctrls, infoToPrintInfo) if len(row) > 0 { rows = append(rows, row) } diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/imageprinter/datastructures.go b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/imageprinter/datastructures.go index cc567537..2395b051 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/imageprinter/datastructures.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/imageprinter/datastructures.go @@ -22,7 +22,8 @@ type CVE struct { } type PackageScore struct { - Name string - Version string - Score int + Name string + Version string + Score int + MapSeverityToCVEsNumber map[string]int } diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils/utils.go b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils/utils.go index a7f1fa13..af2aa5ea 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils/utils.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils/utils.go @@ -111,3 +111,31 @@ func PrintInfo(writer io.Writer, infoToPrintInfo []InfoStars) { cautils.InfoDisplay(writer, fmt.Sprintf("%s %s\n", infoToPrintInfo[i].Stars, infoToPrintInfo[i].Info)) } } + +func GetStatusColor(status apis.ScanningStatus) color.Attribute { + switch status { + case apis.StatusPassed: + return color.FgGreen + case apis.StatusFailed: + return color.FgRed + case apis.StatusSkipped: + return color.FgCyan + default: + return color.FgWhite + } +} + +func getColor(controlSeverity int) color.Attribute { + switch controlSeverity { + case apis.SeverityCritical: + return color.FgRed + case apis.SeverityHigh: + return color.FgYellow + case apis.SeverityMedium: + return color.FgCyan + case apis.SeverityLow: + return color.FgWhite + default: + return color.FgWhite + } +} diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter/utils.go b/core/pkg/resultshandling/printer/v2/prettyprinter/utils.go index 6226648e..c34f46d9 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/utils.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/utils.go @@ -6,6 +6,7 @@ import ( "sort" "strings" + "github.com/fatih/color" "github.com/kubescape/kubescape/v2/core/cautils" "github.com/kubescape/kubescape/v2/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/imageprinter" "github.com/kubescape/kubescape/v2/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils" @@ -19,10 +20,10 @@ const ( linkToCICDSetup = "https://hub.armosec.io/docs/integrations" configScanVerboseRunText = "Run with '--verbose'/'-v' flag for detailed resources view" imageScanVerboseRunText = "Run with '--verbose'/'-v' flag for detailed vulnerabilities view" - clusterScanRunText = "Run a cluster scan: '$ kubescape scan'" ) var ( + clusterScanRunText = fmt.Sprintf("Run a cluster scan: %s", getCallToActionString("'$ kubescape scan'")) installHelmText = fmt.Sprintf("Install helm for continuos monitoring: %s", linkToHelm) CICDSetupText = fmt.Sprintf("Add Kubescape to CICD: %s", linkToCICDSetup) complianceFrameworks = []string{"nsa", "mitre"} @@ -127,9 +128,10 @@ func sortTopVulnerablePackages(pkgScores map[string]*imageprinter.PackageScore) for i := 0; i < len(ss) && i < TopPackagesNumber; i++ { sortedMap[ss[i]] = &imageprinter.PackageScore{ - Name: pkgScores[ss[i]].Name, - Score: pkgScores[ss[i]].Score, - Version: pkgScores[ss[i]].Version, + Name: pkgScores[ss[i]].Name, + Score: pkgScores[ss[i]].Score, + Version: pkgScores[ss[i]].Version, + MapSeverityToCVEsNumber: pkgScores[ss[i]].MapSeverityToCVEsNumber, } } @@ -145,8 +147,15 @@ func printTopVulnerabilities(writer *os.File, summary imageprinter.ImageScanSumm cautils.InfoTextDisplay(writer, "\nMost vulnerable components:\n") topVulnerablePackages := sortTopVulnerablePackages(summary.PackageScores) + for _, v := range topVulnerablePackages { - cautils.SimpleDisplay(writer, " * %s (%s)\n", v.Name, v.Version) + output := fmt.Sprintf(" * %s (%s) -", v.Name, v.Version) + for severity, numberOfCVEs := range v.MapSeverityToCVEsNumber { + output += fmt.Sprintf(" %d %s,", numberOfCVEs, severity) + } + output = output[:len(output)-1] + + cautils.SimpleDisplay(writer, output+"\n") } cautils.SimpleDisplay(writer, "\n") @@ -192,7 +201,7 @@ func printImageScanningSummary(writer *os.File, summary imageprinter.ImageScanSu func printImagesCommands(writer *os.File, summary imageprinter.ImageScanSummary) { for _, img := range summary.Images { imgWithoutTag := strings.Split(img, ":")[0] - cautils.SimpleDisplay(writer, fmt.Sprintf("Receive full report for %s image by running: '$ kubescape scan image %s'\n", imgWithoutTag, img)) + cautils.SimpleDisplay(writer, fmt.Sprintf("Receive full report for %s image by running: %s\n", imgWithoutTag, getCallToActionString(fmt.Sprintf("'$ kubescape scan image %s'", img)))) } cautils.InfoTextDisplay(writer, "\n") @@ -214,7 +223,11 @@ func printComplianceScore(writer *os.File, frameworks []reportsummary.IFramework cautils.SimpleDisplay(writer, "* %s: %.2f%%\n", fw.GetName(), fw.GetComplianceScore()) } - cautils.SimpleDisplay(writer, "View full compliance report by running:'$ kubescape scan framework nsa,mitre'\n") + cautils.SimpleDisplay(writer, fmt.Sprintf("View full compliance report by running: %s\n", getCallToActionString("'$ kubescape scan framework nsa,mitre'"))) cautils.InfoTextDisplay(writer, "\n") } + +func getCallToActionString(action string) string { + return color.New(color.Bold, color.FgHiBlue).SprintFunc()(action) +} diff --git a/core/pkg/resultshandling/printer/v2/utils.go b/core/pkg/resultshandling/printer/v2/utils.go index 0ea24f10..261c7a9a 100644 --- a/core/pkg/resultshandling/printer/v2/utils.go +++ b/core/pkg/resultshandling/printer/v2/utils.go @@ -109,10 +109,16 @@ func extractPkgNameToScoreMap(matches []models.Match) map[string]*imageprinter.P key := matches[i].Artifact.Name + matches[i].Artifact.Version if _, ok := mapPackageNameToScore[key]; !ok { mapPackageNameToScore[key] = &imageprinter.PackageScore{ - Version: matches[i].Artifact.Version, - Name: matches[i].Artifact.Name, + Version: matches[i].Artifact.Version, + Name: matches[i].Artifact.Name, + MapSeverityToCVEsNumber: make(map[string]int, 0), } } + if _, ok := mapPackageNameToScore[key].MapSeverityToCVEsNumber[matches[i].Vulnerability.Severity]; !ok { + mapPackageNameToScore[key].MapSeverityToCVEsNumber[matches[i].Vulnerability.Severity] = 1 + } else { + mapPackageNameToScore[key].MapSeverityToCVEsNumber[matches[i].Vulnerability.Severity] = mapPackageNameToScore[key].MapSeverityToCVEsNumber[matches[i].Vulnerability.Severity] + 1 + } mapPackageNameToScore[key].Score = mapPackageNameToScore[key].Score + utils.ImageSeverityToInt(matches[i].Vulnerability.Severity) } return mapPackageNameToScore diff --git a/go.mod b/go.mod index d92389c7..c43669d5 100644 --- a/go.mod +++ b/go.mod @@ -21,8 +21,8 @@ require ( github.com/johnfercher/maroto v0.42.0 github.com/json-iterator/go v1.1.12 github.com/kubescape/go-git-url v0.0.25 - github.com/kubescape/go-logger v0.0.14-0.20230730134225-e59751254525 - github.com/kubescape/k8s-interface v0.0.135-0.20230730135750-e6e709507847 + github.com/kubescape/go-logger v0.0.15 + github.com/kubescape/k8s-interface v0.0.135 github.com/kubescape/opa-utils v0.0.260-0.20230731053836-95235e06963a github.com/kubescape/rbac-utils v0.0.20 github.com/kubescape/regolibrary v1.0.286-rc.0 diff --git a/go.sum b/go.sum index e2d46f91..448506e3 100644 --- a/go.sum +++ b/go.sum @@ -1520,10 +1520,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kubescape/go-git-url v0.0.25 h1:i7SSSC1+1m/Dg+4LV3erp0YklnWj1Z0cVlRxCT3Zy/0= github.com/kubescape/go-git-url v0.0.25/go.mod h1:IbVT7Wsxlghsa+YxI5KOx4k9VQJaa3z0kTaQz5D3nKM= -github.com/kubescape/go-logger v0.0.14-0.20230730134225-e59751254525 h1:9wzR38LebiA58cGxRBnsF78k4eJGnk7UetoTPKkyz2A= -github.com/kubescape/go-logger v0.0.14-0.20230730134225-e59751254525/go.mod h1:Al+yTE+vemECb/Myn2G9+2o2uFmMtphbkQmxf4OEHxE= -github.com/kubescape/k8s-interface v0.0.135-0.20230730135750-e6e709507847 h1:GGuS6pE6KGa5q7j9fkRN3p1eQw16/jLUMnPR8FT3O6M= -github.com/kubescape/k8s-interface v0.0.135-0.20230730135750-e6e709507847/go.mod h1:eBd6few7RYplnNNlHoe6d7jMmoE6Kx1emapJ91euBbY= +github.com/kubescape/go-logger v0.0.15 h1:iCzVFlXXF7KYLd1cZumGOtuAZbltV8QiZI+kTe6TSN0= +github.com/kubescape/go-logger v0.0.15/go.mod h1:Al+yTE+vemECb/Myn2G9+2o2uFmMtphbkQmxf4OEHxE= +github.com/kubescape/k8s-interface v0.0.135 h1:DrhaJO+RbRRj3ai3Oy8rchs/0XJqvFSv7798ckaCObc= +github.com/kubescape/k8s-interface v0.0.135/go.mod h1:5sz+5Cjvo98lTbTVDiDA4MmlXxeHSVMW/wR0V3hV4K8= github.com/kubescape/opa-utils v0.0.260-0.20230731053836-95235e06963a h1:NnEHByzZbuLH/JP8Dh3eN//kMfWAxrGmyreP2eGjq1k= github.com/kubescape/opa-utils v0.0.260-0.20230731053836-95235e06963a/go.mod h1:0Be6E+vHqjavl/JneqgyC+oXOdfs6s+V6YnFvBkIAsA= github.com/kubescape/rbac-utils v0.0.20 h1:1MMxsCsCZ3ntDi8f9ZYYcY+K7bv50bDW5ZvnGnhMhJw=