diff --git a/core/cautils/datastructures.go b/core/cautils/datastructures.go index 63eca0e8..25d1802f 100644 --- a/core/cautils/datastructures.go +++ b/core/cautils/datastructures.go @@ -56,8 +56,7 @@ type OPASessionObj struct { Exceptions []armotypes.PostureExceptionPolicy // list of exceptions to apply on scan results OmitRawResources bool // omit raw resources from output ScanType ScanTypes // scan type - ResourceIDToImageMap map[string][]string - ScannedWorkload workloadinterface.IWorkload // single workload scan + ScannedWorkload workloadinterface.IWorkload // single workload scan } func NewOPASessionObj(ctx context.Context, frameworks []reporthandling.Framework, k8sResources K8SResources, scanInfo *ScanInfo) *OPASessionObj { diff --git a/core/cautils/scaninfo.go b/core/cautils/scaninfo.go index 7e16fbbc..1a937a6a 100644 --- a/core/cautils/scaninfo.go +++ b/core/cautils/scaninfo.go @@ -8,7 +8,6 @@ import ( "path/filepath" "strings" - "github.com/armosec/armoapi-go/identifiers" giturl "github.com/kubescape/go-git-url" "github.com/kubescape/go-logger" "github.com/kubescape/go-logger/helpers" @@ -94,9 +93,8 @@ const ( ) type PolicyIdentifier struct { - Identifier string // policy Identifier e.g. c-0012 for control, nsa,mitre for frameworks - Kind apisv1.NotificationPolicyKind // policy kind e.g. Framework,Control,Rule - Designators identifiers.PortalDesignator + Identifier string // policy Identifier e.g. c-0012 for control, nsa,mitre for frameworks + Kind apisv1.NotificationPolicyKind // policy kind e.g. Framework,Control,Rule } type WorkloadIdentifier struct { diff --git a/core/core/initutils.go b/core/core/initutils.go index 1c899f2c..1e1c82aa 100644 --- a/core/core/initutils.go +++ b/core/core/initutils.go @@ -65,13 +65,13 @@ func getRBACHandler(tenantConfig cautils.ITenantConfig, k8s *k8sinterface.Kubern return nil } -func getReporter(ctx context.Context, tenantConfig cautils.ITenantConfig, reportID string, submit, fwScan bool, scanningContext cautils.ScanningContext) reporter.IReport { +func getReporter(ctx context.Context, tenantConfig cautils.ITenantConfig, reportID string, submit, fwScan bool, scanInfo cautils.ScanInfo) reporter.IReport { _, span := otel.Tracer("").Start(ctx, "getReporter") defer span.End() if submit { submitData := reporterv2.SubmitContextScan - if scanningContext != cautils.ContextCluster { + if scanInfo.GetScanningContext() != cautils.ContextCluster { submitData = reporterv2.SubmitContextRepository } return reporterv2.NewReportEventReceiver(tenantConfig.GetConfigObj(), reportID, submitData) @@ -81,7 +81,8 @@ func getReporter(ctx context.Context, tenantConfig cautils.ITenantConfig, report return reporterv2.NewReportMock("", "") } var message string - if !fwScan { + + if !fwScan && scanInfo.ScanType != cautils.ScanTypeWorkload { message = "Kubescape does not submit scan results when scanning controls" } diff --git a/core/core/scan.go b/core/core/scan.go index 43ed6ba3..8bd6e905 100644 --- a/core/core/scan.go +++ b/core/core/scan.go @@ -7,6 +7,7 @@ import ( "github.com/kubescape/go-logger" "github.com/kubescape/go-logger/helpers" "github.com/kubescape/k8s-interface/k8sinterface" + "github.com/kubescape/k8s-interface/workloadinterface" "github.com/kubescape/kubescape/v2/core/cautils" "github.com/kubescape/kubescape/v2/core/cautils/getter" "github.com/kubescape/kubescape/v2/core/pkg/hostsensorutils" @@ -94,7 +95,7 @@ func getInterfaces(ctx context.Context, scanInfo *cautils.ScanInfo) componentInt // ================== setup reporter & printer objects ====================================== // reporting behavior - setup reporter - reportHandler := getReporter(ctx, tenantConfig, scanInfo.ScanID, scanInfo.Submit, scanInfo.FrameworkScan, scanInfo.GetScanningContext()) + reportHandler := getReporter(ctx, tenantConfig, scanInfo.ScanID, scanInfo.Submit, scanInfo.FrameworkScan, *scanInfo) // setup printers outputPrinters := GetOutputPrinters(scanInfo, ctx) @@ -193,7 +194,6 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res } // ======================== prioritization =================== - scanInfo.ScanType = cautils.ScanTypeRepo if scanInfo.PrintAttackTree || isPrioritizationScanType(scanInfo.ScanType) { _, spanPrioritization := otel.Tracer("").Start(ctxOpa, "prioritization") if priotizationHandler, err := resourcesprioritization.NewResourcesPrioritizationHandler(ctxOpa, scanInfo.Getters.AttackTracksGetter, scanInfo.PrintAttackTree); err != nil { @@ -207,7 +207,7 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res spanPrioritization.End() } - if scanInfo.ScanImages && len(scanData.ResourceIDToImageMap) > 0 { + if scanInfo.ScanImages { scanImages(scanInfo, scanData, ctx, resultsHandling) } // ========================= results handling ===================== @@ -221,17 +221,29 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res } func scanImages(scanInfo *cautils.ScanInfo, scanData *cautils.OPASessionObj, ctx context.Context, resultsHandling *resultshandling.ResultsHandler) { - logger.L().Ctx(ctx).Info("Scanning images") + logger.L().Info("Scanning images") dbCfg, _ := imagescan.NewDefaultDBConfig() svc := imagescan.NewScanService(dbCfg) - for _, imgs := range scanData.ResourceIDToImageMap { - for _, img := range imgs { - scanSingleImage(ctx, img, svc, resultsHandling, *scanInfo) + if scanInfo.ScanType == cautils.ScanTypeWorkload { + wlObj := workloadinterface.NewWorkloadObj(scanData.ScannedWorkload.GetObject()) + scanSingleWorkload(wlObj, ctx, svc, resultsHandling, scanInfo) + } else { + for _, workload := range scanData.AllResources { + wlObj := workloadinterface.NewWorkloadObj(workload.GetObject()) + scanSingleWorkload(wlObj, ctx, svc, resultsHandling, scanInfo) } } - logger.L().Ctx(ctx).Success("Finished scanning images") + + logger.L().Success("Finished scanning images") +} + +func scanSingleWorkload(wlObj *workloadinterface.Workload, ctx context.Context, svc imagescan.Service, resultsHandling *resultshandling.ResultsHandler, scanInfo *cautils.ScanInfo) { + containers, _ := wlObj.GetContainers() + for _, container := range containers { + scanSingleImage(ctx, container.Image, svc, resultsHandling, *scanInfo) + } } func scanSingleImage(ctx context.Context, img string, svc imagescan.Service, resultsHandling *resultshandling.ResultsHandler, scanInfo cautils.ScanInfo) { diff --git a/core/pkg/resourcehandler/fieldselector.go b/core/pkg/resourcehandler/fieldselector.go index 71eb3372..0ec86116 100644 --- a/core/pkg/resourcehandler/fieldselector.go +++ b/core/pkg/resourcehandler/fieldselector.go @@ -77,20 +77,24 @@ func getNamespacesSelector(kind, ns, operator string) string { } if kind == "namespaces" || kind == "Namespace" { - return getNameFieldSelector(ns, operator) + return getNameFieldSelectorString(ns, operator) } if k8sinterface.IsResourceInNamespaceScope(kind) { - return fmt.Sprintf("metadata.namespace%s%s", operator, ns) + return getNamespaceFieldSelectorString(ns, operator) } return "" } -func getNameFieldSelector(resourceName, operator string) string { +func getNameFieldSelectorString(resourceName, operator string) string { return fmt.Sprintf("metadata.name%s%s", operator, resourceName) } +func getNamespaceFieldSelectorString(namespace, operator string) string { + return fmt.Sprintf("metadata.namespace%s%s", operator, namespace) +} + func combineFieldSelectors(selectors ...string) string { var nonEmptyStrings []string for i := range selectors { diff --git a/core/pkg/resourcehandler/filesloader.go b/core/pkg/resourcehandler/filesloader.go index cec2766c..b1e49680 100644 --- a/core/pkg/resourcehandler/filesloader.go +++ b/core/pkg/resourcehandler/filesloader.go @@ -32,13 +32,12 @@ func NewFileResourceHandler(_ context.Context, inputPatterns []string, workloadI } } -func (fileHandler *FileResourceHandler) GetResources(ctx context.Context, sessionObj *cautils.OPASessionObj, _ *identifiers.PortalDesignator, progressListener opaprocessor.IJobProgressNotificationClient, scanInfo cautils.ScanInfo) (cautils.K8SResources, map[string]workloadinterface.IMetadata, cautils.KSResources, map[string]bool, map[string][]string, error) { +func (fileHandler *FileResourceHandler) GetResources(ctx context.Context, sessionObj *cautils.OPASessionObj, _ *identifiers.PortalDesignator, progressListener opaprocessor.IJobProgressNotificationClient, scanInfo cautils.ScanInfo) (cautils.K8SResources, map[string]workloadinterface.IMetadata, cautils.KSResources, map[string]bool, error) { allResources := map[string]workloadinterface.IMetadata{} ksResources := cautils.KSResources{} - resourceIDToImages := map[string][]string{} if len(fileHandler.inputPatterns) == 0 { - return nil, nil, nil, nil, nil, fmt.Errorf("missing input") + return nil, nil, nil, nil, fmt.Errorf("missing input") } logger.L().Info("Accessing local objects") @@ -56,29 +55,13 @@ func (fileHandler *FileResourceHandler) GetResources(ctx context.Context, sessio } else { workloadIDToSource, workloads, err = getResourcesFromPath(ctx, fileHandler.inputPatterns[path]) if err != nil { - return nil, allResources, nil, nil, nil, err + return nil, allResources, nil, nil, err } } if len(workloads) == 0 { logger.L().Debug("path ignored because contains only a non-kubernetes file", helpers.String("path", fileHandler.inputPatterns[path])) } - if scanInfo.ScanImages { - for i := range workloads { - wlObj := workloadinterface.NewWorkloadObj(workloads[i].GetObject()) - containers, err := wlObj.GetContainers() - if err != nil { - - } - for _, container := range containers { - if _, ok := resourceIDToImages[workloads[i].GetID()]; !ok { - resourceIDToImages[workloads[i].GetID()] = []string{} - } - resourceIDToImages[workloads[i].GetID()] = append(resourceIDToImages[workloads[i].GetID()], container.Image) - } - } - } - for k, v := range workloadIDToSource { sessionObj.ResourceSource[k] = v } @@ -90,7 +73,7 @@ func (fileHandler *FileResourceHandler) GetResources(ctx context.Context, sessio // locate input workload in the mapped resources - if not found or not a valid workload, return error inputWorkload, err := findWorkloadToScan(mappedResources, fileHandler.workloadIdentifier) if err != nil { - return nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, err } sessionObj.ScannedWorkload = inputWorkload @@ -117,7 +100,113 @@ func (fileHandler *FileResourceHandler) GetResources(ctx context.Context, sessio cautils.StopSpinner() logger.L().Success("Done accessing local objects") - return k8sResources, allResources, ksResources, excludedRulesMap, resourceIDToImages, nil + return k8sResources, allResources, ksResources, excludedRulesMap, nil +} + +func getWorkloadFromHelmChart(ctx context.Context, helmPath, workloadPath string) (map[string]reporthandling.Source, []workloadinterface.IMetadata, error) { + clonedRepo, err := cloneGitRepo(&helmPath) + if err != nil { + return nil, nil, err + } + if clonedRepo != "" { + defer os.RemoveAll(clonedRepo) + } + + helmSourceToWorkloads, helmSourceToChartName := cautils.LoadResourcesFromHelmCharts(ctx, helmPath) + + wlSource, _ := helmSourceToWorkloads[workloadPath] + + // Get repo root + repoRoot, gitRepo := extractGitRepo(helmPath) + + helmChartName := helmSourceToChartName[workloadPath] + + relSource, err := filepath.Rel(repoRoot, helmPath) + if err == nil { + helmPath = relSource + } + + var lastCommit reporthandling.LastCommit + if gitRepo != nil { + commitInfo, _ := gitRepo.GetFileLastCommit(helmPath) + if commitInfo != nil { + lastCommit = reporthandling.LastCommit{ + Hash: commitInfo.SHA, + Date: commitInfo.Author.Date, + CommitterName: commitInfo.Author.Name, + CommitterEmail: commitInfo.Author.Email, + Message: commitInfo.Message, + } + } + } + + workloadSource := reporthandling.Source{ + RelativePath: helmPath, + FileType: reporthandling.SourceTypeHelmChart, + HelmChartName: helmChartName, + LastCommit: lastCommit, + } + workloadIDToSource := make(map[string]reporthandling.Source, 0) + workloadIDToSource[wlSource[0].GetID()] = workloadSource + + workloads := []workloadinterface.IMetadata{} + workloads = append(workloads, wlSource...) + + return workloadIDToSource, workloads, nil + +} + +func getWorkloadFromHelmChart(ctx context.Context, helmPath, workloadPath string) (map[string]reporthandling.Source, []workloadinterface.IMetadata, error) { + clonedRepo, err := cloneGitRepo(&helmPath) + if err != nil { + return nil, nil, err + } + if clonedRepo != "" { + defer os.RemoveAll(clonedRepo) + } + + helmSourceToWorkloads, helmSourceToChartName := cautils.LoadResourcesFromHelmCharts(ctx, helmPath) + + wlSource, _ := helmSourceToWorkloads[workloadPath] + + // Get repo root + repoRoot, gitRepo := extractGitRepo(helmPath) + + helmChartName := helmSourceToChartName[workloadPath] + + relSource, err := filepath.Rel(repoRoot, helmPath) + if err == nil { + helmPath = relSource + } + + var lastCommit reporthandling.LastCommit + if gitRepo != nil { + commitInfo, _ := gitRepo.GetFileLastCommit(helmPath) + if commitInfo != nil { + lastCommit = reporthandling.LastCommit{ + Hash: commitInfo.SHA, + Date: commitInfo.Author.Date, + CommitterName: commitInfo.Author.Name, + CommitterEmail: commitInfo.Author.Email, + Message: commitInfo.Message, + } + } + } + + workloadSource := reporthandling.Source{ + RelativePath: helmPath, + FileType: reporthandling.SourceTypeHelmChart, + HelmChartName: helmChartName, + LastCommit: lastCommit, + } + workloadIDToSource := make(map[string]reporthandling.Source, 0) + workloadIDToSource[wlSource[0].GetID()] = workloadSource + + workloads := []workloadinterface.IMetadata{} + workloads = append(workloads, wlSource...) + + return workloadIDToSource, workloads, nil + } func getResourcesFromPath(ctx context.Context, path string) (map[string]reporthandling.Source, []workloadinterface.IMetadata, error) { diff --git a/core/pkg/resourcehandler/handlerpullresources.go b/core/pkg/resourcehandler/handlerpullresources.go index 47b2cb13..ce1be5ea 100644 --- a/core/pkg/resourcehandler/handlerpullresources.go +++ b/core/pkg/resourcehandler/handlerpullresources.go @@ -29,7 +29,7 @@ func CollectResources(ctx context.Context, rsrcHandler IResourceHandler, policyI setCloudMetadata(opaSessionObj) } - resourcesMap, allResources, ksResources, excludedRulesMap, resourceIDToImages, err := rsrcHandler.GetResources(ctx, opaSessionObj, &policyIdentifier[0].Designators, progressListener, scanInfo) + resourcesMap, allResources, ksResources, excludedRulesMap, err := rsrcHandler.GetResources(ctx, opaSessionObj, &policyIdentifier[0].Designators, progressListener, scanInfo) if err != nil { return err } @@ -38,7 +38,6 @@ func CollectResources(ctx context.Context, rsrcHandler IResourceHandler, policyI opaSessionObj.AllResources = allResources opaSessionObj.KubescapeResource = ksResources opaSessionObj.ExcludedRules = excludedRulesMap - opaSessionObj.ResourceIDToImageMap = resourceIDToImages if (opaSessionObj.K8SResources == nil || len(opaSessionObj.K8SResources) == 0) && (opaSessionObj.KubescapeResource == nil || len(opaSessionObj.KubescapeResource) == 0) { return fmt.Errorf("empty list of resources") diff --git a/core/pkg/resourcehandler/interface.go b/core/pkg/resourcehandler/interface.go index 09d4c837..aaab17db 100644 --- a/core/pkg/resourcehandler/interface.go +++ b/core/pkg/resourcehandler/interface.go @@ -11,7 +11,7 @@ import ( ) type IResourceHandler interface { - GetResources(context.Context, *cautils.OPASessionObj, *identifiers.PortalDesignator, opaprocessor.IJobProgressNotificationClient, cautils.ScanInfo) (cautils.K8SResources, map[string]workloadinterface.IMetadata, cautils.KSResources, map[string]bool, map[string][]string, error) + GetResources(context.Context, *cautils.OPASessionObj, *identifiers.PortalDesignator, opaprocessor.IJobProgressNotificationClient, cautils.ScanInfo) (cautils.K8SResources, map[string]workloadinterface.IMetadata, cautils.KSResources, map[string]bool, error) GetClusterAPIServerInfo(ctx context.Context) *version.Info GetWorkloadParentKind(workloadinterface.IWorkload) string } diff --git a/core/pkg/resourcehandler/k8sresources.go b/core/pkg/resourcehandler/k8sresources.go index 0d1d22b0..0f315a87 100644 --- a/core/pkg/resourcehandler/k8sresources.go +++ b/core/pkg/resourcehandler/k8sresources.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/armosec/armoapi-go/identifiers" logger "github.com/kubescape/go-logger" "github.com/kubescape/go-logger/helpers" "github.com/kubescape/kubescape/v2/core/cautils" @@ -20,15 +21,12 @@ import ( "github.com/kubescape/k8s-interface/k8sinterface" "github.com/kubescape/k8s-interface/workloadinterface" - "github.com/armosec/armoapi-go/identifiers" - v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" k8slabels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/version" - "k8s.io/client-go/dynamic" ) type cloudResourceGetter func(string, string) (workloadinterface.IMetadata, error) @@ -60,7 +58,7 @@ func NewK8sResourceHandler(k8s *k8sinterface.KubernetesApi, fieldSelector IField } } -func (k8sHandler *K8sResourceHandler) GetResources(ctx context.Context, sessionObj *cautils.OPASessionObj, designator *identifiers.PortalDesignator, progressListener opaprocessor.IJobProgressNotificationClient, scanInfo cautils.ScanInfo) (cautils.K8SResources, map[string]workloadinterface.IMetadata, cautils.KSResources, map[string]bool, map[string][]string, error) { +func (k8sHandler *K8sResourceHandler) GetResources(ctx context.Context, sessionObj *cautils.OPASessionObj, designator *identifiers.PortalDesignator, progressListener opaprocessor.IJobProgressNotificationClient, scanInfo cautils.ScanInfo) (cautils.K8SResources, map[string]workloadinterface.IMetadata, cautils.KSResources, map[string]bool, error) { // get k8s resources logger.L().Info("Accessing Kubernetes objects") @@ -68,7 +66,7 @@ func (k8sHandler *K8sResourceHandler) GetResources(ctx context.Context, sessionO workload, err := k8sHandler.findWorkloadToScan(k8sHandler.workloadIdentifier) if err != nil { - return nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, err } sessionObj.ScannedWorkload = workload @@ -78,28 +76,14 @@ func (k8sHandler *K8sResourceHandler) GetResources(ctx context.Context, sessionO queryableResources, excludedRulesMap := getQueryableResourceMapFromPolicies(k8sHandler, sessionObj.Policies, workload) ksResourceMap := setKSResourceMap(sessionObj.Policies, resourceToControl) - // get namespace and labels from designator (ignore cluster labels) - _, namespace, labels := identifiers.DigestPortalDesignator(designator) - // map of Kubescape resources to control_ids sessionObj.ResourceToControlsMap = resourceToControl // pull k8s resources - k8sResourcesMap, allResources, err := k8sHandler.pullResources(queryableResources, namespace, labels) + k8sResourcesMap, allResources, err := k8sHandler.pullResources(queryableResources) if err != nil { cautils.StopSpinner() - return k8sResourcesMap, allResources, ksResourceMap, nil, nil, err - } - - resourceIDToImages := make(map[string][]string, 0) - if scanInfo.ScanImages { - for _, workload := range allResources { - wlObj := workloadinterface.NewWorkloadObj(workload.GetObject()) - containers, _ := wlObj.GetContainers() - for _, container := range containers { - resourceIDToImages[workload.GetID()] = append(resourceIDToImages[workload.GetID()], container.Image) - } - } + return k8sResourcesMap, allResources, ksResourceMap, nil, err } // add workload to k8s resources map (for single workload scan) @@ -174,7 +158,7 @@ func (k8sHandler *K8sResourceHandler) GetResources(ctx context.Context, sessionO } } - return k8sResourcesMap, allResources, ksResourceMap, excludedRulesMap, resourceIDToImages, nil + return k8sResourcesMap, allResources, ksResourceMap, excludedRulesMap, nil } func (k8sHandler *K8sResourceHandler) findWorkloadToScan(workloadIdentifier *cautils.WorkloadIdentifier) (workloadinterface.IWorkload, error) { @@ -194,7 +178,11 @@ func (k8sHandler *K8sResourceHandler) findWorkloadToScan(workloadIdentifier *cau return nil, err } - result, err := k8sHandler.pullSingleResource(&gvr, workloadIdentifier.Namespace, nil, getNameFieldSelector(workloadIdentifier.Name, "=")) + fieldSelectors := getNameFieldSelectorString(workloadIdentifier.Name, "=") + if workloadIdentifier.Namespace != "" && k8sinterface.IsNamespaceScope(&gvr) { + fieldSelectors = combineFieldSelectors(fieldSelectors, getNamespaceFieldSelectorString(workloadIdentifier.Namespace, "=")) + } + result, err := k8sHandler.pullSingleResource(&gvr, nil, fieldSelectors) if err != nil { return nil, fmt.Errorf("failed to get resource %s, reason: %v", workloadIdentifier.String(), err) } @@ -327,7 +315,7 @@ func setMapNamespaceToNumOfResources(ctx context.Context, allResources map[strin sessionObj.SetMapNamespaceToNumberOfResources(mapNamespaceToNumberOfResources) } -func (k8sHandler *K8sResourceHandler) pullResources(queryableResources QueryableResources, namespace string, labels map[string]string) (cautils.K8SResources, map[string]workloadinterface.IMetadata, error) { +func (k8sHandler *K8sResourceHandler) pullResources(queryableResources QueryableResources) (cautils.K8SResources, map[string]workloadinterface.IMetadata, error) { k8sResources := queryableResources.ToK8sResourceMap() allResources := map[string]workloadinterface.IMetadata{} @@ -335,7 +323,7 @@ func (k8sHandler *K8sResourceHandler) pullResources(queryableResources Queryable for _, qr := range queryableResources { apiGroup, apiVersion, resource := k8sinterface.StringToResourceGroup(qr.GroupVersionResourceTriplet) gvr := schema.GroupVersionResource{Group: apiGroup, Version: apiVersion, Resource: resource} - result, err := k8sHandler.pullSingleResource(&gvr, namespace, labels, qr.FieldSelectors) + result, err := k8sHandler.pullSingleResource(&gvr, nil, qr.FieldSelectors) if err != nil { if !strings.Contains(err.Error(), "the server could not find the requested resource") { // handle error @@ -379,7 +367,7 @@ func (k8sHandler *K8sResourceHandler) GetWorkloadParentKind(workload workloadint return "" } -func (k8sHandler *K8sResourceHandler) pullSingleResource(resource *schema.GroupVersionResource, namespace string, labels map[string]string, fields string) ([]unstructured.Unstructured, error) { +func (k8sHandler *K8sResourceHandler) pullSingleResource(resource *schema.GroupVersionResource, labels map[string]string, fields string) ([]unstructured.Unstructured, error) { resourceList := []unstructured.Unstructured{} // set labels listOptions := metav1.ListOptions{} @@ -397,21 +385,12 @@ func (k8sHandler *K8sResourceHandler) pullSingleResource(resource *schema.GroupV } // set dynamic object - var clientResource dynamic.ResourceInterface - if namespace != "" { - clientResource = k8sHandler.k8s.DynamicClient.Resource(*resource) - } else if k8sinterface.IsNamespaceScope(resource) { - clientResource = k8sHandler.k8s.DynamicClient.Resource(*resource).Namespace(namespace) - } else if k8sHandler.fieldSelector.GetClusterScope(resource) { - clientResource = k8sHandler.k8s.DynamicClient.Resource(*resource) - } else { - continue - } + clientResource := k8sHandler.k8s.DynamicClient.Resource(*resource) // list resources result, err := clientResource.List(context.Background(), listOptions) if err != nil || result == nil { - return nil, fmt.Errorf("failed to get resource: %v, namespace: %s, labelSelector: %v, reason: %v", resource, namespace, listOptions.LabelSelector, err) + return nil, fmt.Errorf("failed to get resource: %v, labelSelector: %v, fieldSelector: %v, reason: %v", resource, listOptions.LabelSelector, listOptions.FieldSelector, err) } resourceList = append(resourceList, result.Items...) diff --git a/core/pkg/resourcehandler/resourcehandlerutils_test.go b/core/pkg/resourcehandler/resourcehandlerutils_test.go index ef0878f3..648622fd 100644 --- a/core/pkg/resourcehandler/resourcehandlerutils_test.go +++ b/core/pkg/resourcehandler/resourcehandlerutils_test.go @@ -133,7 +133,7 @@ func mockWorkload(apiVersion, kind, namespace, name, ownerReferenceKind string) type ResourceHandlerMock struct { } -func (mock *ResourceHandlerMock) GetResources(context.Context, *cautils.OPASessionObj, *armotypes.PortalDesignator, opaprocessor.IJobProgressNotificationClient) (cautils.K8SResources, map[string]workloadinterface.IMetadata, cautils.KSResources, map[string]bool, error) { +func (mock *ResourceHandlerMock) GetResources(context.Context, *cautils.OPASessionObj, opaprocessor.IJobProgressNotificationClient) (cautils.K8SResources, map[string]workloadinterface.IMetadata, cautils.KSResources, map[string]bool, error) { return nil, nil, nil, nil, nil } diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter.go b/core/pkg/resultshandling/printer/v2/prettyprinter.go index 9181cb9b..4673cb32 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter.go @@ -127,6 +127,10 @@ func (pp *PrettyPrinter) ActionPrint(_ context.Context, opaSessionObj *cautils.O } } + if pp.scanType == cautils.ScanTypeWorkload { + cautils.InfoDisplay(pp.writer, "Workload: %s/%s/%s\n", opaSessionObj.ScannedWorkload.GetNamespace(), opaSessionObj.ScannedWorkload.GetKind(), opaSessionObj.ScannedWorkload.GetName()) + } + pp.mainPrinter.PrintConfigurationsScanning(&opaSessionObj.Report.SummaryDetails, sortedControlIDs) // When writing to Stdout, we aren’t really writing to an output file, 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 41a17502..90c3539d 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/clusterscan.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/clusterscan.go @@ -24,7 +24,7 @@ func (cp *ClusterPrinter) PrintCategoriesTables(writer io.Writer, summaryDetails categoriesToCategoryControls := mapCategoryToSummary(summaryDetails.ListControls(), mapClusterControlsToCategories) - for _, id := range categoriesDisplayOrder { + for _, id := range clusterCategoriesDisplayOrder { categoryControl, ok := categoriesToCategoryControls[id] if !ok { continue 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 45bed48b..6cc3087b 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/datastructures.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/datastructures.go @@ -30,7 +30,7 @@ const ( nodeEscapeCategoryID = "Cat-9" ) -var categoriesDisplayOrder = []string{ +var clusterCategoriesDisplayOrder = []string{ controlPlaneCategoryID, accessControlCategoryID, secretsCategoryID, @@ -38,6 +38,15 @@ var categoriesDisplayOrder = []string{ workloadsCategoryID, } +var workloadCategoriesDisplayOrder = []string{ + supplyChainCategoryID, + resourceManagementCategoryID, + storageCategoryID, + secretsCategoryID, + networkCategoryID, + nodeEscapeCategoryID, +} + var mapCategoryToType = map[string]CategoryType{ controlPlaneCategoryID: TypeStatus, accessControlCategoryID: TypeCounting, 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 85f255be..c0f08f9e 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/reposcan.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/reposcan.go @@ -30,7 +30,7 @@ func (rp *RepoPrinter) PrintCategoriesTables(writer io.Writer, summaryDetails *r categoriesToCategoryControls := mapCategoryToSummary(summaryDetails.ListControls(), mapClusterControlsToCategories) - for _, id := range categoriesDisplayOrder { + for _, id := range clusterCategoriesDisplayOrder { categoryControl, ok := categoriesToCategoryControls[id] if !ok { continue 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 8c6a4862..0176f48b 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/workloadscan.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/configurationprinter/workloadscan.go @@ -26,7 +26,7 @@ func (wp *WorkloadPrinter) PrintCategoriesTables(writer io.Writer, summaryDetail categoriesToCategoryControls := mapCategoryToSummary(summaryDetails.ListControls(), mapWorkloadControlsToCategories) - for _, id := range categoriesDisplayOrder { + for _, id := range workloadCategoriesDisplayOrder { categoryControl, ok := categoriesToCategoryControls[id] if !ok { continue diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter/workloadscan.go b/core/pkg/resultshandling/printer/v2/prettyprinter/workloadscan.go index c692e0b7..a70ace1f 100644 --- a/core/pkg/resultshandling/printer/v2/prettyprinter/workloadscan.go +++ b/core/pkg/resultshandling/printer/v2/prettyprinter/workloadscan.go @@ -32,7 +32,7 @@ func (wp *WorkloadPrinter) printImageScanningSummary(summary *imageprinter.Image printImageScanningSummary(wp.writer, *summary, false) for _, img := range summary.Images { - cautils.InfoTextDisplay(wp.writer, fmt.Sprintf("Receive full report by running: 'kubescape scan image %s\n", img)) + cautils.SimpleDisplay(wp.writer, fmt.Sprintf("Receive full report by running: 'kubescape scan image %s'\n", img)) } cautils.InfoTextDisplay(wp.writer, "\n")