Repository: aquasecurity/starboard
Pull request #993 (2022-03-03 12:04:55)

refactor: parse severity from name
Signed-off-by: Daniel Pacak <pacak.daniel@gmail.com>

codecov[bot]: # [Codecov](https://codecov.io/gh/aquasecurity/starboard/pull/993?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) Report
> Merging [#993](https://codecov.io/gh/aquasecurity/starboard/pull/993?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) (6f99c9a) into [main](https://codecov.io/gh/aquasecurity/starboard/commit/2a71abd58546495e44471b30fb342b51f48c7b0c?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) (2a71abd) will **decrease** coverage by `21.44%`.
> The diff coverage is `80.64%`.

[![Impacted file tree graph](https://codecov.io/gh/aquasecurity/starboard/pull/993/graphs/tree.svg?width=650&height=150&src=pr&token=qqTGKAJ0Wb&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity)](https://codecov.io/gh/aquasecurity/starboard/pull/993?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity)

```diff
@@             Coverage Diff             @@
##             main     #993       +/-   ##
===========================================
- Coverage   62.51%   41.07%   -21.45%     
===========================================
  Files          59       45       -14     
  Lines        7328     6676      -652     
===========================================
- Hits         4581     2742     -1839     
- Misses       2287     3764     +1477     
+ Partials      460      170      -290     
```


| [Impacted Files](https://codecov.io/gh/aquasecurity/starboard/pull/993?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) | Coverage Δ | |
|---|---|---|
| [pkg/plugin/polaris/plugin.go](https://codecov.io/gh/aquasecurity/starboard/pull/993/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL3BsdWdpbi9wb2xhcmlzL3BsdWdpbi5nbw==) | `78.57% <40.00%> (-3.59%)` | :arrow_down: |
| [pkg/apis/aquasecurity/v1alpha1/common\_types.go](https://codecov.io/gh/aquasecurity/starboard/pull/993/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2FwaXMvYXF1YXNlY3VyaXR5L3YxYWxwaGExL2NvbW1vbl90eXBlcy5nbw==) | `100.00% <100.00%> (ø)` | |
| [pkg/kube/object.go](https://codecov.io/gh/aquasecurity/starboard/pull/993/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2t1YmUvb2JqZWN0Lmdv) | `45.00% <100.00%> (-7.80%)` | :arrow_down: |
| [pkg/plugin/conftest/plugin.go](https://codecov.io/gh/aquasecurity/starboard/pull/993/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL3BsdWdpbi9jb25mdGVzdC9wbHVnaW4uZ28=) | `77.18% <100.00%> (-1.33%)` | :arrow_down: |
| [pkg/plugin/factory.go](https://codecov.io/gh/aquasecurity/starboard/pull/993/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL3BsdWdpbi9mYWN0b3J5Lmdv) | `0.00% <0.00%> (-81.49%)` | :arrow_down: |
| [pkg/kubehunter/scanner.go](https://codecov.io/gh/aquasecurity/starboard/pull/993/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2t1YmVodW50ZXIvc2Nhbm5lci5nbw==) | `0.00% <0.00%> (-74.49%)` | :arrow_down: |
| [pkg/kube/runnable\_job.go](https://codecov.io/gh/aquasecurity/starboard/pull/993/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2t1YmUvcnVubmFibGVfam9iLmdv) | `0.00% <0.00%> (-63.73%)` | :arrow_down: |
| [pkg/kubehunter/model.go](https://codecov.io/gh/aquasecurity/starboard/pull/993/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2t1YmVodW50ZXIvbW9kZWwuZ28=) | `0.00% <0.00%> (-62.86%)` | :arrow_down: |
| [pkg/operator/controller/configauditreport.go](https://codecov.io/gh/aquasecurity/starboard/pull/993/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL29wZXJhdG9yL2NvbnRyb2xsZXIvY29uZmlnYXVkaXRyZXBvcnQuZ28=) | `0.00% <0.00%> (-61.56%)` | :arrow_down: |
| [pkg/vulnerabilityreport/scanner.go](https://codecov.io/gh/aquasecurity/starboard/pull/993/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL3Z1bG5lcmFiaWxpdHlyZXBvcnQvc2Nhbm5lci5nbw==) | `0.00% <0.00%> (-59.44%)` | :arrow_down: |
| ... and [36 more](https://codecov.io/gh/aquasecurity/starboard/pull/993/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/aquasecurity/starboard/pull/993?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/aquasecurity/starboard/pull/993?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity). Last update [2a71abd...6f99c9a](https://codecov.io/gh/aquasecurity/starboard/pull/993?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity).


Patch:
diff --git a/pkg/apis/aquasecurity/v1alpha1/common_types.go b/pkg/apis/aquasecurity/v1alpha1/common_types.go
index 5a40056..8eddf1b 100644
--- a/pkg/apis/aquasecurity/v1alpha1/common_types.go
+++ b/pkg/apis/aquasecurity/v1alpha1/common_types.go
@@ -1,5 +1,10 @@
 package v1alpha1
 
+import (
+	"fmt"
+	"strings"
+)
+
 const (
 	TTLReportAnnotation = "starboard.aquasecurity.github.io/report-ttl"
 )
@@ -13,10 +18,32 @@ const (
 	SeverityHigh     Severity = "HIGH"
 	SeverityMedium   Severity = "MEDIUM"
 	SeverityLow      Severity = "LOW"
-	SeverityNone     Severity = "NONE"
-	SeverityUnknown  Severity = "UNKNOWN"
+
+	SeverityNone    Severity = "NONE"
+	SeverityUnknown Severity = "UNKNOWN"
 )
 
+// StringToSeverity returns the enum constant of Severity with the specified
+// name. The name must match exactly an identifier used to declare an enum
+// constant. (Extraneous whitespace characters are not permitted.)
+//
+// Note that this method maps severity name `DANGER` to SeverityCritical
+// and `WARNING` to SeverityLow. This logic is in place to support Polaris
+// plugin, which has its own, proprietary severity levels.
+func StringToSeverity(name string) (Severity, error) {
+	s := strings.ToUpper(name)
+	switch s {
+	case "CRITICAL", "HIGH", "MEDIUM", "LOW", "NONE", "UNKNOWN":
+		return Severity(s), nil
+	case "DANGER":
+		return SeverityCritical, nil
+	case "WARNING":
+		return SeverityLow, nil
+	default:
+		return "", fmt.Errorf("unrecognized severity name literal: %s", name)
+	}
+}
+
 // Scanner is the spec for a scanner generating a security assessment report.
 type Scanner struct {
 	// Name the name of the scanner.
diff --git a/pkg/kube/object.go b/pkg/kube/object.go
index 99263ac..f8d841e 100644
--- a/pkg/kube/object.go
+++ b/pkg/kube/object.go
@@ -71,6 +71,19 @@ func IsBuiltInWorkload(controller *metav1.OwnerReference) bool {
 			controller.Kind == string(KindJob))
 }
 
+// IsWorkload returns true if the specified resource kinds represents Kubernetes
+// workload, false otherwise.
+func IsWorkload(kind string) bool {
+	return kind == "Pod" ||
+		kind == "Deployment" ||
+		kind == "ReplicaSet" ||
+		kind == "ReplicationController" ||
+		kind == "StatefulSet" ||
+		kind == "DaemonSet" ||
+		kind == "Job" ||
+		kind == "CronJob"
+}
+
 // IsClusterScopedKind returns true if the specified kind is ClusterRole,
 // ClusterRoleBinding, and CustomResourceDefinition.
 //
diff --git a/pkg/plugin/polaris/model.go b/pkg/plugin/polaris/model.go
index b6c1ebe..b69bcae 100644
--- a/pkg/plugin/polaris/model.go
+++ b/pkg/plugin/polaris/model.go
@@ -35,17 +35,10 @@ type ContainerResult struct {
 	Results map[string]Check `json:"Results"`
 }
 
-type Severity string
-
-const (
-	danger  Severity = "danger"
-	warning Severity = "warning"
-)
-
 type Check struct {
-	ID       string   `json:"ID"`
-	Message  string   `json:"Message"`
-	Success  bool     `json:"Success"`
-	Severity Severity `json:"Severity"`
-	Category string   `json:"Category"`
+	ID       string `json:"ID"`
+	Message  string `json:"Message"`
+	Success  bool   `json:"Success"`
+	Severity string `json:"Severity"`
+	Category string `json:"Category"`
 }
diff --git a/pkg/plugin/polaris/plugin.go b/pkg/plugin/polaris/plugin.go
index ac7e0b0..7f6f8f9 100644
--- a/pkg/plugin/polaris/plugin.go
+++ b/pkg/plugin/polaris/plugin.go
@@ -434,11 +434,15 @@ func (p *plugin) ParseConfigAuditReportData(ctx starboard.PluginContext, logsRea
 		return v1alpha1.ConfigAuditReportData{}, fmt.Errorf("unexpected report results count, got: %d, want: %d", len(report.Results), 1)
 	}
 	for _, pr := range report.Results[0].PodResult.Results {
+		severity, err := v1alpha1.StringToSeverity(pr.Severity)
+		if err != nil {
+			return v1alpha1.ConfigAuditReportData{}, err
+		}
 		check := v1alpha1.Check{
 			ID:       pr.ID,
 			Message:  pr.Message,
 			Success:  pr.Success,
-			Severity: p.toSeverity(pr.Severity),
+			Severity: severity,
 			Category: pr.Category,
 		}
 		checks = append(checks, check)
@@ -448,11 +452,15 @@ func (p *plugin) ParseConfigAuditReportData(ctx starboard.PluginContext, logsRea
 	for _, cr := range report.Results[0].PodResult.ContainerResults {
 		var containerChecks []v1alpha1.Check
 		for _, crr := range cr.Results {
+			severity, err := v1alpha1.StringToSeverity(crr.Severity)
+			if err != nil {
+				return v1alpha1.ConfigAuditReportData{}, err
+			}
 			containerChecks = append(containerChecks, v1alpha1.Check{
 				ID:       crr.ID,
 				Message:  crr.Message,
 				Success:  crr.Success,
-				Severity: p.toSeverity(crr.Severity),
+				Severity: severity,
 				Category: crr.Category,
 				Scope: &v1alpha1.CheckScope{
 					Type:  "Container",
@@ -490,17 +498,6 @@ func (p *plugin) ParseConfigAuditReportData(ctx starboard.PluginContext, logsRea
 	}, nil
 }
 
-func (p *plugin) toSeverity(value Severity) v1alpha1.Severity {
-	switch value {
-	case danger:
-		return v1alpha1.SeverityCritical
-	case warning:
-		return v1alpha1.SeverityLow
-	default:
-		return v1alpha1.SeverityUnknown
-	}
-}
-
 func (p *plugin) sourceNameFrom(obj client.Object) string {
 	gvk := obj.GetObjectKind().GroupVersionKind()
 	group := gvk.Group


Test patch:
diff --git a/pkg/apis/aquasecurity/v1alpha1/common_types_test.go b/pkg/apis/aquasecurity/v1alpha1/common_types_test.go
new file mode 100644
index 0000000..e9721f7
--- /dev/null
+++ b/pkg/apis/aquasecurity/v1alpha1/common_types_test.go
@@ -0,0 +1,58 @@
+package v1alpha1_test
+
+import (
+	"testing"
+
+	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestStringToSeverity(t *testing.T) {
+	testCases := []struct {
+		name             string
+		expectedSeverity v1alpha1.Severity
+		expectedError    string
+	}{
+		{
+			name:          "xxx",
+			expectedError: "unrecognized severity name literal: xxx",
+		},
+		{
+			name:             "CRITICAL",
+			expectedSeverity: v1alpha1.SeverityCritical,
+		},
+		{
+			name:             "HIGH",
+			expectedSeverity: v1alpha1.SeverityHigh,
+		},
+		{
+			name:             "MEDIUM",
+			expectedSeverity: v1alpha1.SeverityMedium,
+		},
+		{
+			name:             "LOW",
+			expectedSeverity: v1alpha1.SeverityLow,
+		},
+		{
+			name:             "danger",
+			expectedSeverity: v1alpha1.SeverityCritical,
+		},
+		{
+			name:             "warning",
+			expectedSeverity: v1alpha1.SeverityLow,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			severity, err := v1alpha1.StringToSeverity(tc.name)
+			if tc.expectedError != "" {
+				assert.EqualError(t, err, tc.expectedError)
+			} else {
+				assert.NoError(t, err)
+				assert.Equal(t, tc.expectedSeverity, severity)
+			}
+		})
+	}
+
+}
diff --git a/pkg/kube/object_test.go b/pkg/kube/object_test.go
index 6a77df2..91f9969 100644
--- a/pkg/kube/object_test.go
+++ b/pkg/kube/object_test.go
@@ -55,6 +55,60 @@ func TestIsBuiltInWorkload(t *testing.T) {
 	}
 }
 
+func TestIsWorkload(t *testing.T) {
+	testCases := []struct {
+		kind string
+		want bool
+	}{
+		{
+			kind: "Pod",
+			want: true,
+		},
+		{
+			kind: "Deployment",
+			want: true,
+		},
+		{
+			kind: "ReplicaSet",
+			want: true,
+		},
+		{
+			kind: "ReplicationController",
+			want: true,
+		},
+		{
+			kind: "StatefulSet",
+			want: true,
+		},
+		{
+			kind: "DaemonSet",
+			want: true,
+		},
+		{
+			kind: "Job",
+			want: true,
+		},
+		{
+			kind: "CronJob",
+			want: true,
+		},
+		{
+			kind: "ConfigMap",
+			want: false,
+		},
+		{
+			kind: "Ingress",
+			want: false,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.kind, func(t *testing.T) {
+			assert.Equal(t, tc.want, kube.IsWorkload(tc.kind))
+		})
+	}
+}
+
 func TestIsClusterScopedKind(t *testing.T) {
 	testCases := []struct {
 		kind string
diff --git a/pkg/plugin/conftest/plugin.go b/pkg/plugin/conftest/plugin.go
index d95d9ab..a933842 100644
--- a/pkg/plugin/conftest/plugin.go
+++ b/pkg/plugin/conftest/plugin.go
@@ -87,7 +87,7 @@ func (c Config) GetPoliciesByKind(kind string) (map[string]string, error) {
 			continue
 		}
 		for _, k := range strings.Split(value, ",") {
-			if k == kindWorkload && !c.IsWorkload(kind) {
+			if k == kindWorkload && !kube.IsWorkload(kind) {
 				continue
 			}
 			if k != kindAny && k != kindWorkload && k != kind {
@@ -106,18 +106,6 @@ func (c Config) GetPoliciesByKind(kind string) (map[string]string, error) {
 	return policies, nil
 }
 
-// TODO move to kube package?
-func (c Config) IsWorkload(kind string) bool {
-	return kind == "Pod" ||
-		kind == "Deployment" ||
-		kind == "ReplicaSet" ||
-		kind == "ReplicationController" ||
-		kind == "StatefulSet" ||
-		kind == "DaemonSet" ||
-		kind == "Job" ||
-		kind == "CronJob"
-}
-
 // GetResourceRequirements constructs ResourceRequirements from the Config.
 func (c Config) GetResourceRequirements() (corev1.ResourceRequirements, error) {
 	requirements := corev1.ResourceRequirements{