From fde437312fc8a404e212e593e0720a448bf5a9fa Mon Sep 17 00:00:00 2001 From: dwertent Date: Thu, 30 Dec 2021 11:52:17 +0200 Subject: [PATCH] report v1 to v2 --- cautils/datastructures.go | 36 +++-- cautils/datastructuresmethods.go | 67 +++++++-- opaprocessor/processorhandler.go | 203 ++++++++++++-------------- opaprocessor/processorhandler_test.go | 4 +- opaprocessor/processorhandlerutils.go | 40 ++++- opaprocessor/utils.go | 36 +++++ resultshandling/results.go | 95 ++++++++++++ 7 files changed, 335 insertions(+), 146 deletions(-) create mode 100644 opaprocessor/utils.go diff --git a/cautils/datastructures.go b/cautils/datastructures.go index 918edc4a..70f6a1c0 100644 --- a/cautils/datastructures.go +++ b/cautils/datastructures.go @@ -4,25 +4,31 @@ import ( "github.com/armosec/armoapi-go/armotypes" "github.com/armosec/k8s-interface/workloadinterface" "github.com/armosec/opa-utils/reporthandling" + "github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults" + reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2" ) // K8SResources map[//][] type K8SResources map[string][]string type OPASessionObj struct { - K8SResources *K8SResources // input k8s objects - Frameworks []reporthandling.Framework // list of frameworks to scan - AllResources map[string]workloadinterface.IMetadata // all scanned resources, map[] - PostureReport *reporthandling.PostureReport // scan results - Exceptions []armotypes.PostureExceptionPolicy // list of exceptions to apply on scan results - RegoInputData RegoInputData // input passed to rgo for scanning. map[][] + K8SResources *K8SResources // input k8s objects + Frameworks []reporthandling.Framework // list of frameworks to scan + AllResources map[string]workloadinterface.IMetadata // all scanned resources, map[] + ResourcesResult map[string]resourcesresults.Result // resources scan results, map[] + PostureReport *reporthandling.PostureReport // scan results v1 + Report *reporthandlingv2.PostureReport // scan results v2 + Exceptions []armotypes.PostureExceptionPolicy // list of exceptions to apply on scan results + RegoInputData RegoInputData // input passed to rgo for scanning. map[][] } func NewOPASessionObj(frameworks []reporthandling.Framework, k8sResources *K8SResources) *OPASessionObj { return &OPASessionObj{ - Frameworks: frameworks, - K8SResources: k8sResources, - AllResources: make(map[string]workloadinterface.IMetadata), + Report: &reporthandlingv2.PostureReport{}, + Frameworks: frameworks, + K8SResources: k8sResources, + AllResources: make(map[string]workloadinterface.IMetadata), + ResourcesResult: make(map[string]resourcesresults.Result), PostureReport: &reporthandling.PostureReport{ ClusterName: ClusterName, CustomerGUID: CustomerGUID, @@ -32,9 +38,10 @@ func NewOPASessionObj(frameworks []reporthandling.Framework, k8sResources *K8SRe func NewOPASessionObjMock() *OPASessionObj { return &OPASessionObj{ - Frameworks: nil, - K8SResources: nil, - AllResources: make(map[string]workloadinterface.IMetadata), + Frameworks: nil, + K8SResources: nil, + AllResources: make(map[string]workloadinterface.IMetadata), + ResourcesResult: make(map[string]resourcesresults.Result), PostureReport: &reporthandling.PostureReport{ ClusterName: "", CustomerGUID: "", @@ -60,3 +67,8 @@ type RegoInputData struct { // ClusterName string `json:"clusterName"` // K8sConfig RegoK8sConfig `json:"k8sconfig"` } + +type Policies struct { + Frameworks []string + Controls map[string]reporthandling.Control // map[] +} diff --git a/cautils/datastructuresmethods.go b/cautils/datastructuresmethods.go index 6cd9941e..ea1002a1 100644 --- a/cautils/datastructuresmethods.go +++ b/cautils/datastructuresmethods.go @@ -1,26 +1,63 @@ package cautils import ( - "encoding/json" + pkgcautils "github.com/armosec/utils-go/utils" - "github.com/open-policy-agent/opa/storage" - "github.com/open-policy-agent/opa/storage/inmem" - "github.com/open-policy-agent/opa/util" + "github.com/armosec/opa-utils/reporthandling" ) -func (data *RegoInputData) SetControlsInputs(controlsInputs map[string][]string) { - data.PostureControlInputs = controlsInputs +func NewPolicies() *Policies { + return &Policies{ + Frameworks: make([]string, 0), + Controls: make(map[string]reporthandling.Control), + } } -func (data *RegoInputData) TOStorage() (storage.Store, error) { - var jsonObj map[string]interface{} - bytesData, err := json.Marshal(*data) - if err != nil { - return nil, err +func (policies *Policies) Set(frameworks []reporthandling.Framework, version string) { + for i := range frameworks { + policies.Frameworks = append(policies.Frameworks, frameworks[i].Name) + for j := range frameworks[i].Controls { + compatibleRules := []reporthandling.PolicyRule{} + for r := range frameworks[i].Controls[j].Rules { + if !ruleWithArmoOpaDependency(frameworks[i].Controls[j].Rules[r].Attributes) && isRuleKubescapeVersionCompatible(frameworks[i].Controls[j].Rules[r].Attributes, version) { + compatibleRules = append(compatibleRules, frameworks[i].Controls[j].Rules[r]) + } + } + frameworks[i].Controls[j].Rules = compatibleRules + policies.Controls[frameworks[i].Controls[j].ControlID] = frameworks[i].Controls[j] + } } - // glog.Infof("RegoDependenciesData: %s", bytesData) - if err := util.UnmarshalJSON(bytesData, &jsonObj); err != nil { - return nil, err +} + +func ruleWithArmoOpaDependency(attributes map[string]interface{}) bool { + if attributes == nil { + return false } - return inmem.NewFromObject(jsonObj), nil + if s, ok := attributes["armoOpa"]; ok { // TODO - make global + return pkgcautils.StringToBool(s.(string)) + } + return false +} + +// Checks that kubescape version is in range of use for this rule +// In local build (BuildNumber = ""): +// returns true only if rule doesn't have the "until" attribute +func isRuleKubescapeVersionCompatible(attributes map[string]interface{}, version string) bool { + if from, ok := attributes["useFromKubescapeVersion"]; ok && from != nil { + if version != "" { + if from.(string) > BuildNumber { + return false + } + } + } + if until, ok := attributes["useUntilKubescapeVersion"]; ok && until != nil { + if version != "" { + if until.(string) <= BuildNumber { + return false + } + } else { + return false + } + } + return true } diff --git a/opaprocessor/processorhandler.go b/opaprocessor/processorhandler.go index 330d1aa6..8d2aea39 100644 --- a/opaprocessor/processorhandler.go +++ b/opaprocessor/processorhandler.go @@ -8,7 +8,8 @@ import ( "github.com/armosec/kubescape/cautils" "github.com/armosec/opa-utils/objectsenvelopes" "github.com/armosec/opa-utils/reporthandling" - "github.com/armosec/opa-utils/score" + "github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults" + "github.com/open-policy-agent/opa/storage" "github.com/golang/glog" @@ -58,41 +59,51 @@ func (opaHandler *OPAProcessorHandler) ProcessRulesListenner() { opaSessionObj := <-*opaHandler.processedPolicy opap := NewOPAProcessor(opaSessionObj, opaHandler.regoDependenciesData) + initializeSummaryDetails(&opap.Report.SummaryDetails, opap.Frameworks) + + policies := ConvertFrameworksToPolicies(opap.Frameworks, cautils.BuildNumber) + // process - if err := opap.Process(); err != nil { + if err := opap.Process(policies); err != nil { // fmt.Println(err) } // edit results opap.updateResults() - // update score - scoreutil := score.NewScore(opaSessionObj.AllResources) - scoreutil.Calculate(opaSessionObj.PostureReport.FrameworkReports) - // report *opaHandler.reportResults <- opaSessionObj } } -func (opap *OPAProcessor) Process() error { +func (opap *OPAProcessor) Process(policies *cautils.Policies) error { // glog.Infof(fmt.Sprintf("Starting 'Process'. reportID: %s", opap.PostureReport.ReportID)) cautils.ProgressTextDisplay(fmt.Sprintf("Scanning cluster %s", cautils.ClusterName)) cautils.StartSpinner() - frameworkReports := []reporthandling.FrameworkReport{} + var errs error - for i := range opap.Frameworks { - frameworkReport, err := opap.processFramework(&opap.Frameworks[i]) + for _, control := range policies.Controls { + + resourcesAssociatedControl, err := opap.processControl(&control) if err != nil { appendError(&errs, err) } - frameworkReports = append(frameworkReports, *frameworkReport) + // update resources with latest results + if len(resourcesAssociatedControl) != 0 { + for resourceID, controlResult := range resourcesAssociatedControl { + if _, ok := opap.ResourcesResult[resourceID]; !ok { + opap.ResourcesResult[resourceID] = resourcesresults.Result{ResourceID: resourceID} + } + t := opap.ResourcesResult[resourceID] + t.AssociatedControls = append(t.AssociatedControls, controlResult) + opap.ResourcesResult[resourceID] = t + } + } } - opap.PostureReport.FrameworkReports = frameworkReports - opap.PostureReport.ReportID = uuid.NewV4().String() - opap.PostureReport.ReportGenerationTime = time.Now().UTC() - // glog.Infof(fmt.Sprintf("Done 'Process'. reportID: %s", opap.PostureReport.ReportID)) + opap.Report.ReportID = uuid.NewV4().String() + opap.Report.ReportGenerationTime = time.Now().UTC() + cautils.StopSpinner() cautils.SuccessTextDisplay(fmt.Sprintf("Done scanning cluster %s", cautils.ClusterName)) return errs @@ -108,62 +119,46 @@ func appendError(errs *error, err error) { *errs = fmt.Errorf("%v\n%s", *errs, err.Error()) } } -func (opap *OPAProcessor) processFramework(framework *reporthandling.Framework) (*reporthandling.FrameworkReport, error) { + +func (opap *OPAProcessor) processControl(control *reporthandling.Control) (map[string]resourcesresults.ResourceAssociatedControl, error) { var errs error - frameworkReport := reporthandling.FrameworkReport{} - frameworkReport.Name = framework.Name + resourcesAssociatedControl := make(map[string]resourcesresults.ResourceAssociatedControl) - controlReports := []reporthandling.ControlReport{} - for i := range framework.Controls { - controlReport, err := opap.processControl(&framework.Controls[i]) - if err != nil { - appendError(&errs, err) - // errs = fmt.Errorf("%v\n%s", errs, err.Error()) - } - if controlReport != nil { - controlReports = append(controlReports, *controlReport) - } - } - frameworkReport.ControlReports = controlReports - return &frameworkReport, errs -} + controlResult := resourcesresults.ResourceAssociatedControl{} + controlResult.SetID(control.ControlID) -func (opap *OPAProcessor) processControl(control *reporthandling.Control) (*reporthandling.ControlReport, error) { - var errs error - - controlReport := reporthandling.ControlReport{} - controlReport.PortalBase = control.PortalBase - controlReport.ControlID = control.ControlID - controlReport.BaseScore = control.BaseScore - - controlReport.Control_ID = control.Control_ID // TODO: delete when 'id' is deprecated - - controlReport.Name = control.Name - controlReport.Description = control.Description - controlReport.Remediation = control.Remediation - - ruleReports := []reporthandling.RuleReport{} + // ruleResults := make(map[string][]resourcesresults.ResourceAssociatedRule) for i := range control.Rules { - ruleReport, err := opap.processRule(&control.Rules[i]) + resourceAssociatedRule, err := opap.processRule(&control.Rules[i]) if err != nil { appendError(&errs, err) } - if ruleReport != nil { - ruleReports = append(ruleReports, *ruleReport) + + // append failed rules to controls + if len(resourceAssociatedRule) != 0 { + for resourceID, ruleResponse := range resourceAssociatedRule { + if _, ok := resourcesAssociatedControl[resourceID]; ok { + controlResult.ResourceAssociatedRules = resourcesAssociatedControl[resourceID].ResourceAssociatedRules + } + if ruleResponse != nil { + controlResult.ResourceAssociatedRules = append(controlResult.ResourceAssociatedRules, *ruleResponse) + } + resourcesAssociatedControl[resourceID] = controlResult + } } } - if len(ruleReports) == 0 { - return nil, nil - } - controlReport.RuleReports = ruleReports - return &controlReport, errs + + return resourcesAssociatedControl, errs } -func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (*reporthandling.RuleReport, error) { - if ruleWithArmoOpaDependency(rule.Attributes) || !isRuleKubescapeVersionCompatible(rule) { - return nil, nil - } +func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (map[string]*resourcesresults.ResourceAssociatedRule, error) { + + postureControlInputs := opap.regoDependenciesData.GetFilteredPostureControlInputs(rule.ConfigInputs) // get store + + ruleResult := resourcesresults.ResourceAssociatedRule{} + ruleResult.SetName(rule.Name) + ruleResult.ControlConfigurations = postureControlInputs inputResources, err := reporthandling.RegoResourcesAggregator(rule, getAllSupportedObjects(opap.K8SResources, opap.AllResources, rule)) if err != nil { @@ -172,98 +167,80 @@ func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (*reporth inputRawResources := workloadinterface.ListMetaToMap(inputResources) - ruleReport, err := opap.runOPAOnSingleRule(rule, inputRawResources, ruleData) - if err != nil { - // ruleReport.RuleStatus.Status = reporthandling.StatusFailed - ruleReport.RuleStatus.Status = "failure" - ruleReport.RuleStatus.Message = err.Error() - glog.Error(err) - } else { - ruleReport.RuleStatus.Status = reporthandling.StatusPassed - } - + resources := map[string]*resourcesresults.ResourceAssociatedRule{} // the failed resources are a subgroup of the enumeratedData, so we store the enumeratedData like it was the input data enumeratedData, err := opap.enumerateData(rule, inputRawResources) if err != nil { return nil, err } inputResources = objectsenvelopes.ListMapToMeta(enumeratedData) - ruleReport.ListInputKinds = workloadinterface.ListMetaIDs(inputResources) - for i := range inputResources { - opap.AllResources[inputResources[i].GetID()] = inputResources[i] + resources[inputResources[i].GetID()] = nil } - failedResources := objectsenvelopes.ListMapToMeta(ruleReport.GetFailedResources()) - for i := range failedResources { - if r, ok := opap.AllResources[failedResources[i].GetID()]; !ok { - opap.AllResources[failedResources[i].GetID()] = r - } - } - warningResources := objectsenvelopes.ListMapToMeta(ruleReport.GetWarnignResources()) - for i := range warningResources { - if r, ok := opap.AllResources[warningResources[i].GetID()]; !ok { - opap.AllResources[warningResources[i].GetID()] = r + ruleResponses, err := opap.runOPAOnSingleRule(rule, inputRawResources, ruleData, postureControlInputs) + if err != nil { + // TODO - Handle error + glog.Error(err) + } else { + // ruleResponse to ruleResult + for i := range ruleResponses { + ruleResult.FailedPaths = ruleResponses[i].FailedPaths + failedResources := objectsenvelopes.ListMapToMeta(ruleResponses[i].GetFailedResources()) + for j := range failedResources { + resources[failedResources[j].GetID()] = &ruleResult + } } } - // remove all data from responses, leave only the metadata - keepFields := []string{"kind", "apiVersion", "metadata"} - keepMetadataFields := []string{"name", "namespace", "labels"} - ruleReport.RemoveData(keepFields, keepMetadataFields) - - return &ruleReport, err + return resources, err } -func (opap *OPAProcessor) runOPAOnSingleRule(rule *reporthandling.PolicyRule, k8sObjects []map[string]interface{}, getRuleData func(*reporthandling.PolicyRule) string) (reporthandling.RuleReport, error) { +func (opap *OPAProcessor) runOPAOnSingleRule(rule *reporthandling.PolicyRule, k8sObjects []map[string]interface{}, getRuleData func(*reporthandling.PolicyRule) string, postureControlInputs map[string][]string) ([]reporthandling.RuleResponse, error) { switch rule.RuleLanguage { case reporthandling.RegoLanguage, reporthandling.RegoLanguage2: - return opap.runRegoOnK8s(rule, k8sObjects, getRuleData) + return opap.runRegoOnK8s(rule, k8sObjects, getRuleData, postureControlInputs) default: - return reporthandling.RuleReport{}, fmt.Errorf("rule: '%s', language '%v' not supported", rule.Name, rule.RuleLanguage) + return nil, fmt.Errorf("rule: '%s', language '%v' not supported", rule.Name, rule.RuleLanguage) } } -func (opap *OPAProcessor) runRegoOnK8s(rule *reporthandling.PolicyRule, k8sObjects []map[string]interface{}, getRuleData func(*reporthandling.PolicyRule) string) (reporthandling.RuleReport, error) { +func (opap *OPAProcessor) runRegoOnK8s(rule *reporthandling.PolicyRule, k8sObjects []map[string]interface{}, getRuleData func(*reporthandling.PolicyRule) string, postureControlInputs map[string][]string) ([]reporthandling.RuleResponse, error) { var errs error - ruleReport := reporthandling.RuleReport{ - Name: rule.Name, - } // compile modules modules, err := getRuleDependencies() if err != nil { - return ruleReport, fmt.Errorf("rule: '%s', %s", rule.Name, err.Error()) + return nil, fmt.Errorf("rule: '%s', %s", rule.Name, err.Error()) } modules[rule.Name] = getRuleData(rule) compiled, err := ast.CompileModules(modules) if err != nil { - return ruleReport, fmt.Errorf("in 'runRegoOnSingleRule', failed to compile rule, name: %s, reason: %s", rule.Name, err.Error()) + return nil, fmt.Errorf("in 'runRegoOnSingleRule', failed to compile rule, name: %s, reason: %s", rule.Name, err.Error()) + } + + store, err := resources.TOStorage(postureControlInputs) + if err != nil { + return nil, err } // Eval - results, err := opap.regoEval(k8sObjects, compiled) + results, err := opap.regoEval(k8sObjects, compiled, &store) if err != nil { errs = fmt.Errorf("rule: '%s', %s", rule.Name, err.Error()) } - if results != nil { - ruleReport.RuleResponses = append(ruleReport.RuleResponses, results...) - } - return ruleReport, errs + return results, errs } -func (opap *OPAProcessor) regoEval(inputObj []map[string]interface{}, compiledRego *ast.Compiler) ([]reporthandling.RuleResponse, error) { - store, err := opap.regoDependenciesData.TOStorage() // get store - if err != nil { - return nil, err - } +func (opap *OPAProcessor) regoEval(inputObj []map[string]interface{}, compiledRego *ast.Compiler, store *storage.Store) ([]reporthandling.RuleResponse, error) { + // opap.regoDependenciesData.PostureControlInputs rego := rego.New( rego.Query("data.armo_builtins"), // get package name from rule rego.Compiler(compiledRego), rego.Input(inputObj), - rego.Store(store), + rego.Store(*store), ) // Run evaluation @@ -284,9 +261,15 @@ func (opap *OPAProcessor) enumerateData(rule *reporthandling.PolicyRule, k8sObje if ruleEnumeratorData(rule) == "" { return k8sObjects, nil } - ruleReport, err := opap.runOPAOnSingleRule(rule, k8sObjects, ruleEnumeratorData) + postureControlInputs := opap.regoDependenciesData.GetFilteredPostureControlInputs(rule.ConfigInputs) + + ruleResponse, err := opap.runOPAOnSingleRule(rule, k8sObjects, ruleEnumeratorData, postureControlInputs) if err != nil { return nil, err } - return ruleReport.GetFailedResources(), nil + failedResources := []map[string]interface{}{} + for _, ruleResponse := range ruleResponse { + failedResources = append(failedResources, ruleResponse.GetFailedResources()...) + } + return failedResources, nil } diff --git a/opaprocessor/processorhandler_test.go b/opaprocessor/processorhandler_test.go index d3ec4204..3433909a 100644 --- a/opaprocessor/processorhandler_test.go +++ b/opaprocessor/processorhandler_test.go @@ -30,11 +30,13 @@ func TestProcess(t *testing.T) { // set opaSessionObj opaSessionObj := cautils.NewOPASessionObjMock() opaSessionObj.Frameworks = []reporthandling.Framework{*reporthandling.MockFrameworkA()} + policies := ConvertFrameworksToPolicies(opaSessionObj.Frameworks, "") + opaSessionObj.K8SResources = &k8sResources opaSessionObj.AllResources = allResources opap := NewOPAProcessor(opaSessionObj, resources.NewRegoDependenciesDataMock()) - opap.Process() + opap.Process(policies) opap.updateResults() for _, f := range opap.PostureReport.FrameworkReports { for _, c := range f.ControlReports { diff --git a/opaprocessor/processorhandlerutils.go b/opaprocessor/processorhandlerutils.go index beb2c208..dddbf9fa 100644 --- a/opaprocessor/processorhandlerutils.go +++ b/opaprocessor/processorhandlerutils.go @@ -7,29 +7,53 @@ import ( "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/k8s-interface/workloadinterface" - "github.com/armosec/opa-utils/exceptions" "github.com/armosec/opa-utils/reporthandling" resources "github.com/armosec/opa-utils/resources" "github.com/golang/glog" ) +// updateResults update the results objects and report objects. This is a critical function - DO NOT CHANGE func (opap *OPAProcessor) updateResults() { + // remove data from all objects for i := range opap.AllResources { removeData(opap.AllResources[i]) } - for f := range opap.PostureReport.FrameworkReports { - // set exceptions - exceptions.SetFrameworkExceptions(&opap.PostureReport.FrameworkReports[f], opap.Exceptions, cautils.ClusterName) + // set exceptions + for i := range opap.ResourcesResult { - // set counters - reporthandling.SetUniqueResourcesCounter(&opap.PostureReport.FrameworkReports[f]) + t := opap.ResourcesResult[i] - // set default score - // reporthandling.SetDefaultScore(&opap.PostureReport.FrameworkReports[f]) + // first set exceptions + if resource, ok := opap.AllResources[i]; ok { + t.SetExceptions(resource, opap.Exceptions, cautils.ClusterName) + } + + // summarize the resources + opap.Report.AppendResourceResultToSummary(&t) + + // Add score + // TODO + + // save changes + opap.ResourcesResult[i] = t } + + // set result summary + opap.Report.SummaryDetails.InitResourcesSummary() + + // for f := range opap.PostureReport.FrameworkReports { + // // set exceptions + // exceptions.SetFrameworkExceptions(&opap.PostureReport.FrameworkReports[f], opap.Exceptions, cautils.ClusterName) + + // // set counters + // reporthandling.SetUniqueResourcesCounter(&opap.PostureReport.FrameworkReports[f]) + + // // set default score + // // reporthandling.SetDefaultScore(&opap.PostureReport.FrameworkReports[f]) + // } } func getAllSupportedObjects(k8sResources *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, rule *reporthandling.PolicyRule) []workloadinterface.IMetadata { diff --git a/opaprocessor/utils.go b/opaprocessor/utils.go new file mode 100644 index 00000000..7b21cb59 --- /dev/null +++ b/opaprocessor/utils.go @@ -0,0 +1,36 @@ +package opaprocessor + +import ( + "github.com/armosec/kubescape/cautils" + "github.com/armosec/opa-utils/reporthandling" + "github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary" +) + +// ConvertFrameworksToPolicies convert list of frameworks to list of policies +func ConvertFrameworksToPolicies(frameworks []reporthandling.Framework, version string) *cautils.Policies { + policies := cautils.NewPolicies() + policies.Set(frameworks, version) + return policies +} + +// initializeReport initialize the summary details for the report object +func initializeSummaryDetails(summaryDetails *reportsummary.SummaryDetails, frameworks []reporthandling.Framework) { + + for i := range frameworks { + controls := map[string]reportsummary.ControlSummary{} + for j := range frameworks[i].Controls { + id := frameworks[i].Controls[j].ControlID + c := reportsummary.ControlSummary{ + Name: frameworks[i].Controls[j].Name, + } + controls[frameworks[i].Controls[j].ControlID] = c + summaryDetails.Controls[id] = c + } + summaryDetails.Frameworks = append(summaryDetails.Frameworks, reportsummary.FrameworkSummary{ + Name: frameworks[i].Name, + Controls: controls, + }) + } + + // opap.Report.GenerateSummary() +} diff --git a/resultshandling/results.go b/resultshandling/results.go index 5dea6e4f..4cb9f4ba 100644 --- a/resultshandling/results.go +++ b/resultshandling/results.go @@ -7,6 +7,8 @@ import ( "github.com/armosec/kubescape/resultshandling/printer" "github.com/armosec/kubescape/resultshandling/reporter" "github.com/armosec/opa-utils/reporthandling" + v1 "github.com/armosec/opa-utils/reporthandling/helpers/v1" + "github.com/armosec/opa-utils/score" ) type ResultsHandler struct { @@ -27,6 +29,8 @@ func (resultsHandler *ResultsHandler) HandleResults(scanInfo *cautils.ScanInfo) opaSessionObj := <-*resultsHandler.opaSessionObj + resultsHandler.reportV2ToV1(opaSessionObj) + resultsHandler.printerObj.ActionPrint(opaSessionObj) if err := resultsHandler.reporterObj.ActionSendReport(opaSessionObj); err != nil { @@ -55,3 +59,94 @@ func CalculatePostureScore(postureReport *reporthandling.PostureReport) float32 return (float32(len(allResources)) - float32(len(failedResources))) / float32(len(allResources)) } + +func (resultsHandler *ResultsHandler) reportV2ToV1(opaSessionObj *cautils.OPASessionObj) { + opaSessionObj.PostureReport.ReportID = opaSessionObj.Report.ReportID + opaSessionObj.PostureReport.CustomerGUID = opaSessionObj.Report.CustomerGUID + opaSessionObj.PostureReport.ClusterCloudProvider = opaSessionObj.Report.ClusterCloudProvider + opaSessionObj.PostureReport.ClusterName = opaSessionObj.Report.ClusterName + + frameworks := []reporthandling.FrameworkReport{} + fwv1 := reporthandling.FrameworkReport{} + for _, fwv2 := range opaSessionObj.Report.SummaryDetails.Frameworks { + fwv1.Name = fwv2.GetName() + fwv1.Score = fwv2.GetScore() + fwv1.WarningResources = fwv2.NumberOf().Excluded() + fwv1.FailedResources = fwv2.NumberOf().Failed() + fwv1.TotalResources = fwv2.NumberOf().All() + + crv1 := reporthandling.ControlReport{} + for _, crv2 := range fwv2.Controls { + crv1.ControlID = crv2.GetID() + crv1.Name = crv2.GetName() + crv1.Score = crv2.GetScore() + crv1.WarningResources = crv2.NumberOf().Excluded() + crv1.FailedResources = crv2.NumberOf().Failed() + crv1.TotalResources = crv2.NumberOf().All() + + // TODO - add fields + // crv1.Description + // crv1.GUID + // crv1.Remediation + + rulesv1 := map[string]reporthandling.RuleReport{} // ruleName: rules + for _, resourceID := range crv2.List().All() { + if resource, ok := opaSessionObj.ResourcesResult[resourceID]; ok { + for _, rulev2 := range resource.ListRules() { + if _, ok := rulesv1[rulev2.GetName()]; !ok { + rulesv1[rulev2.GetName()] = reporthandling.RuleReport{} + } + rulev1 := reporthandling.RuleReport{} + rulev1.Name = rulev2.GetName() + // rulev1.Remediation + rulev1.ResourceUniqueCounter.TotalResources++ + if rulev2.GetStatus(&v1.Filters{FrameworkNames: []string{fwv2.GetName()}}).IsFailed() { + rulev1.ResourceUniqueCounter.FailedResources++ + } else if rulev2.GetStatus(&v1.Filters{FrameworkNames: []string{fwv2.GetName()}}).IsExcluded() { + rulev1.ResourceUniqueCounter.WarningResources++ + } + ruleResponse := reporthandling.RuleResponse{} + ruleResponse.Rulename = rulev2.GetName() + ruleResponse.FailedPaths = rulev2.FailedPaths + ruleResponse.RuleStatus = string(rulev2.GetStatus(&v1.Filters{FrameworkNames: []string{fwv2.GetName()}}).Status()) + if len(rulev2.Exception) > 0 { + ruleResponse.Exception = &rulev2.Exception[0] + } + + if fullRessource, ok := opaSessionObj.AllResources[resourceID]; ok { + ruleResponse.AlertObject.K8SApiObjects = append(ruleResponse.AlertObject.K8SApiObjects, fullRessource.GetObject()) + } + rulev1.RuleResponses = append(rulev1.RuleResponses, ruleResponse) + rulev1.ListInputKinds = append(rulev1.ListInputKinds, resourceID) + crv1.RuleReports = append(crv1.RuleReports, rulev1) + } + } + } + + // rulev1.ListInputKinds + + } + fwv1.ControlReports = append(fwv1.ControlReports, crv1) + + frameworks = append(frameworks, fwv1) + + } + + for f := range frameworks { + // // set exceptions + // exceptions.SetFrameworkExceptions(&opap.PostureReport.FrameworkReports[f], opap.Exceptions, cautils.ClusterName) + + // // set counters + // reporthandling.SetUniqueResourcesCounter(&opap.PostureReport.FrameworkReports[f]) + + // set default score + reporthandling.SetDefaultScore(&frameworks[f]) + } + + // update score + scoreutil := score.NewScore(opaSessionObj.AllResources) + scoreutil.Calculate(frameworks) + + opaSessionObj.PostureReport.FrameworkReports = frameworks + +}