Skip to content

Commit

Permalink
fix compliance score- case of passed-irrelevant (#104)
Browse files Browse the repository at this point in the history
* fix compliance score- case of passed-irrelevant

Signed-off-by: YiscahLevySilas1 <[email protected]>

* minor refactor following review

Signed-off-by: YiscahLevySilas1 <[email protected]>

* delete log

Signed-off-by: YiscahLevySilas1 <[email protected]>

* move passed condition

Signed-off-by: YiscahLevySilas1 <[email protected]>

* shorten code, delete logs

Signed-off-by: YiscahLevySilas1 <[email protected]>

* add tests for coverage

Signed-off-by: YiscahLevySilas1 <[email protected]>

* clean code

Signed-off-by: YiscahLevySilas1 <[email protected]>

---------

Signed-off-by: YiscahLevySilas1 <[email protected]>
  • Loading branch information
YiscahLevySilas1 authored Apr 19, 2023
1 parent 7e12785 commit 365d5f1
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 28 deletions.
98 changes: 98 additions & 0 deletions objectsenvelopes/objectshandler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package objectsenvelopes

import (
"testing"

cloudsupportv1 "github.com/kubescape/k8s-interface/cloudsupport/v1"
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/opa-utils/objectsenvelopes/hostsensor"
"github.com/kubescape/opa-utils/objectsenvelopes/localworkload"
"github.com/stretchr/testify/assert"
)

func TestNewObject(t *testing.T) {
// Test nil input
assert.Nil(t, NewObject(nil))

// Test valid input
object := map[string]interface{}{
"kind": "Pod",
"apiVersion": "v1",
"metadata": map[string]interface{}{
"name": "test-pod",
},
}
workloadObj := NewObject(object)
assert.NotNil(t, workloadObj)
assert.Equal(t, "Pod", workloadObj.GetKind())

// Test unsupported input
unsupportedObject := map[string]interface{}{
"unknown": "unknown",
}
assert.Nil(t, NewObject(unsupportedObject))
}

func TestGetObjectType(t *testing.T) {
// Test unsupported input
unsupportedObject := map[string]interface{}{
"unknown": "unknown",
}
assert.Equal(t, workloadinterface.TypeUnknown, GetObjectType(unsupportedObject))

// Test RegoResponseVectorObject
relatedObjects := []map[string]interface{}{}
relatedObject := getMock(role)
relatedObject2 := getMock(rolebinding)
relatedObjects = append(relatedObjects, relatedObject)
relatedObjects = append(relatedObjects, relatedObject2)
subject := map[string]interface{}{"name": "[email protected]", "kind": "User", "namespace": "default", "group": "rbac.authorization.k8s.io", RelatedObjectsKey: relatedObjects}
assert.Equal(t, TypeRegoResponseVectorObject, GetObjectType(subject))

// Test CloudProviderDescribe
cloudProviderDescribe := map[string]interface{}{
"apiVersion": "container.googleapis.com/v1",
"kind": "ClusterDescribe",
}
assert.Equal(t, cloudsupportv1.TypeCloudProviderDescribe, GetObjectType(cloudProviderDescribe))

// Test HostSensor
hostSensor := map[string]interface{}{
"apiVersion": "hostdata.kubescape.cloud/v1",
"metadata": map[string]interface{}{
"name": "test-pod",
},
}
assert.Equal(t, hostsensor.TypeHostSensor, GetObjectType(hostSensor))

// Test LocalWorkload
localWorkload := map[string]interface{}{
"kind": "b",
"sourcePath": "/path/file",
}
assert.Equal(t, localworkload.TypeLocalWorkload, GetObjectType(localWorkload))

// Test WorkloadObject
workloadObject := map[string]interface{}{
"kind": "Pod",
"apiVersion": "v1",
"metadata": map[string]interface{}{
"name": "test-pod",
},
}
assert.Equal(t, workloadinterface.TypeWorkloadObject, GetObjectType(workloadObject))

// Test ListWorkloads
listWorkloads := map[string]interface{}{
"kind": "List",
"items": []interface{}{
map[string]interface{}{
"kind": "Pod",
"metadata": map[string]interface{}{
"name": "test-pod",
},
},
},
}
assert.Equal(t, workloadinterface.TypeListWorkloads, GetObjectType(listWorkloads))
}
39 changes: 11 additions & 28 deletions score/score.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"strings"
"sync"

"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
k8sinterface "github.com/kubescape/k8s-interface/k8sinterface"
"github.com/kubescape/k8s-interface/workloadinterface"
armoupautils "github.com/kubescape/opa-utils/objectsenvelopes"
Expand Down Expand Up @@ -363,7 +361,6 @@ func (su *ScoreUtil) SetPostureReportComplianceScores(report *v2.PostureReport)
for i := range report.SummaryDetails.Frameworks {
// set compliance score for framework and all controls in framework
report.SummaryDetails.Frameworks[i].ComplianceScore = su.GetFrameworkComplianceScore(&report.SummaryDetails.Frameworks[i])
logger.L().Debug("set framework score", helpers.String("framework name", report.SummaryDetails.Frameworks[i].GetName()), helpers.Int("ComplianceScore", int(report.SummaryDetails.Frameworks[i].GetComplianceScore())))
}
// set compliance score per control
sumScore := su.ControlsSummariesComplianceScore(&report.SummaryDetails.Controls, "")
Expand All @@ -384,15 +381,15 @@ func (su *ScoreUtil) ControlsSummariesComplianceScore(ctrls *reportsummary.Contr
ctrl.Score = 0
ctrl.Score = su.GetControlComplianceScore(&ctrl, frameworkName)
(*ctrls)[ctrlID] = ctrl
logger.L().Debug("set control score", helpers.String("controlID", ctrl.GetID()), helpers.Int("score", int(ctrl.GetScore())))
sumScore += ctrl.GetScore()
}
return sumScore
}

// GetFrameworkComplianceScore returns the compliance score for a given framework (as a percentage)
// The framework compliance score is the average of all controls scores in that framework
func (su *ScoreUtil) GetFrameworkComplianceScore(framework *reportsummary.FrameworkSummary) (frameworkScore float32) {
func (su *ScoreUtil) GetFrameworkComplianceScore(framework *reportsummary.FrameworkSummary) float32 {
frameworkScore := float32(0)
sumScore := su.ControlsSummariesComplianceScore(&framework.Controls, framework.GetName())
if len(framework.Controls) > 0 {
frameworkScore = sumScore / float32(len(framework.Controls))
Expand All @@ -401,32 +398,18 @@ func (su *ScoreUtil) GetFrameworkComplianceScore(framework *reportsummary.Framew
}

// GetControlComplianceScore returns the compliance score for a given control (as a percentage).
func (su *ScoreUtil) GetControlComplianceScore(ctrl reportsummary.IControlSummary, _ /*frameworkName*/ string) (ctrlScore float32) {
resourcesIDs := ctrl.ListResourcesIDs()
passedResourceIDS := resourcesIDs.Passed()
allResourcesIDSIter := resourcesIDs.All()

numOfPassedResources := float32(0)
numOfAllResources := float32(0)

for i := range passedResourceIDS {
if _, ok := su.resources[passedResourceIDS[i]]; ok {
numOfPassedResources += 1
}
func (su *ScoreUtil) GetControlComplianceScore(ctrl reportsummary.IControlSummary, _ /*frameworkName*/ string) float32 {
// If a control has status passed it should always be considered as having 100% compliance score
if ctrl.GetStatus().IsPassed() {
return 100
}

for allResourcesIDSIter.HasNext() {
resourceID := allResourcesIDSIter.Next()
if _, ok := su.resources[resourceID]; ok {
numOfAllResources += 1
}
}
resourcesIDs := ctrl.ListResourcesIDs()
numOfPassedResources := len(resourcesIDs.Passed())
numOfAllResources := resourcesIDs.All().Len()

if numOfAllResources > 0 {
ctrlScore = (numOfPassedResources / numOfAllResources) * 100
} else {
logger.L().Debug("no resources were given for this control, score is 0", helpers.String("controlID", ctrl.GetID()))
return (float32(numOfPassedResources) / float32(numOfAllResources)) * 100
}

return ctrlScore
return 0
}
40 changes: 40 additions & 0 deletions score/score_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,46 @@ func TestGetControlComplianceScore(t *testing.T) {
)
})

t.Run("skipped control", func(t *testing.T) {
t.Parallel()

resources := mockResources(t)
s := ScoreUtil{isDebugMode: true, resources: resources}
controlReport := reportsummary.ControlSummary{
Name: "skipped-control",
ControlID: "skipped1",
StatusInfo: apis.StatusInfo{
InnerInfo: "enable-host-scan flag not used. For more information: https://hub.armosec.io/docs/host-sensor",
InnerStatus: "skipped",
},
ResourceIDs: helpers.AllLists{},
}

require.Equal(t, float32(0), s.GetControlComplianceScore(&controlReport, ""),
"skipped control report should return a score equals to 0",
)
})

t.Run("passed (irrelevant) control", func(t *testing.T) {
t.Parallel()

resources := mockResources(t)
s := ScoreUtil{isDebugMode: true, resources: resources}
controlReport := reportsummary.ControlSummary{
Name: "irrelevant-control",
ControlID: "irrelevant1",
StatusInfo: apis.StatusInfo{
SubStatus: "irrelevant",
InnerStatus: "passed",
},
ResourceIDs: helpers.AllLists{},
}

require.Equal(t, float32(100), s.GetControlComplianceScore(&controlReport, ""),
"passed (irrelevant) control report should return a score equals to 100",
)
})

t.Run("with control report", func(t *testing.T) {
t.Parallel()

Expand Down

0 comments on commit 365d5f1

Please sign in to comment.