Repository: aquasecurity/starboard
Pull request #530 (2021-04-23 09:31:43)

feat: Ensure default config should not create ConfigMap for Polaris when it is not chosen as plugin
Resolves: #524

Signed-off-by: Daniel Pacak <pacak.daniel@gmail.com>

codecov[bot]: # [Codecov](https://codecov.io/gh/aquasecurity/starboard/pull/530?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) Report
> Merging [#530](https://codecov.io/gh/aquasecurity/starboard/pull/530?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) (448844f) into [main](https://codecov.io/gh/aquasecurity/starboard/commit/21e893cb41c75144f9877735303bbf783c3f80bc?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) (21e893c) will **decrease** coverage by `34.02%`.
> The diff coverage is `81.81%`.

[![Impacted file tree graph](https://codecov.io/gh/aquasecurity/starboard/pull/530/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/530?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity)

```diff
@@             Coverage Diff             @@
##             main     #530       +/-   ##
===========================================
- Coverage   70.70%   36.67%   -34.03%     
===========================================
  Files          63       62        -1     
  Lines        4028     3915      -113     
===========================================
- Hits         2848     1436     -1412     
- Misses        871     2391     +1520     
+ Partials      309       88      -221     
```


| [Impacted Files](https://codecov.io/gh/aquasecurity/starboard/pull/530?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) | Coverage Δ | |
|---|---|---|
| [pkg/starboard/config.go](https://codecov.io/gh/aquasecurity/starboard/pull/530/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL3N0YXJib2FyZC9jb25maWcuZ28=) | `74.85% <81.81%> (+4.26%)` | :arrow_up: |
| [pkg/cmd/get.go](https://codecov.io/gh/aquasecurity/starboard/pull/530/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2NtZC9nZXQuZ28=) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/find.go](https://codecov.io/gh/aquasecurity/starboard/pull/530/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2NtZC9maW5kLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/root.go](https://codecov.io/gh/aquasecurity/starboard/pull/530/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2NtZC9yb290Lmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/scan.go](https://codecov.io/gh/aquasecurity/starboard/pull/530/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2NtZC9zY2FuLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/polaris.go](https://codecov.io/gh/aquasecurity/starboard/pull/530/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2NtZC9wb2xhcmlzLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/version.go](https://codecov.io/gh/aquasecurity/starboard/pull/530/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2NtZC92ZXJzaW9uLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/kube\_bench.go](https://codecov.io/gh/aquasecurity/starboard/pull/530/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2NtZC9rdWJlX2JlbmNoLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/kube\_hunter.go](https://codecov.io/gh/aquasecurity/starboard/pull/530/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2NtZC9rdWJlX2h1bnRlci5nbw==) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/find\_vulnerabilities.go](https://codecov.io/gh/aquasecurity/starboard/pull/530/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2NtZC9maW5kX3Z1bG5lcmFiaWxpdGllcy5nbw==) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| ... and [35 more](https://codecov.io/gh/aquasecurity/starboard/pull/530/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/530?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/530?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity). Last update [ca59eb2...448844f](https://codecov.io/gh/aquasecurity/starboard/pull/530?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/deploy/static/05-starboard-operator.config.yaml b/deploy/static/05-starboard-operator.config.yaml
index 73ac9d0..cb4d509 100644
--- a/deploy/static/05-starboard-operator.config.yaml
+++ b/deploy/static/05-starboard-operator.config.yaml
@@ -211,9 +211,3 @@ kind: Secret
 metadata:
   name: starboard
   namespace: starboard-operator
----
-apiVersion: v1
-kind: ConfigMap
-metadata:
-  name: starboard-conftest-config
-  namespace: starboard-operator
diff --git a/pkg/starboard/config.go b/pkg/starboard/config.go
index 4abc863..d5da9b7 100644
--- a/pkg/starboard/config.go
+++ b/pkg/starboard/config.go
@@ -284,12 +284,17 @@ func GetDefaultConfig() ConfigData {
 }
 
 // GetDefaultPolarisConfig returns the default Polaris configuration.
-func GetDefaultPolarisConfig() ConfigData {
+func GetDefaultPolarisConfig() map[string]string {
 	return map[string]string{
 		"polaris.config.yaml": polarisConfigYAML,
 	}
 }
 
+// GetDefaultConftestConfig return the defautl Conftest configuration.
+func GetDefaultConftestConfig() map[string]string {
+	return map[string]string{}
+}
+
 func (c ConfigData) GetVulnerabilityReportsScanner() (Scanner, error) {
 	var ok bool
 	var value string
@@ -424,49 +429,70 @@ type configManager struct {
 }
 
 func (c *configManager) EnsureDefault(ctx context.Context) error {
-	cm := &corev1.ConfigMap{
-		ObjectMeta: metav1.ObjectMeta{
-			Namespace: c.namespace,
-			Name:      ConfigMapName,
-			Labels: labels.Set{
-				"app.kubernetes.io/managed-by": "starboard",
+	cm, err := c.client.CoreV1().ConfigMaps(c.namespace).Get(ctx, ConfigMapName, metav1.GetOptions{})
+	if err != nil {
+		if !apierrors.IsNotFound(err) {
+			return fmt.Errorf("getting config: %w", err)
+		}
+
+		cm, err = c.client.CoreV1().ConfigMaps(c.namespace).Create(ctx, &corev1.ConfigMap{
+			ObjectMeta: metav1.ObjectMeta{
+				Namespace: c.namespace,
+				Name:      ConfigMapName,
+				Labels: labels.Set{
+					LabelK8SAppManagedBy: "starboard",
+				},
 			},
-		},
-		Data: GetDefaultConfig(),
-	}
-	_, err := c.client.CoreV1().ConfigMaps(c.namespace).Create(ctx, cm, metav1.CreateOptions{})
-	if err != nil && !apierrors.IsAlreadyExists(err) {
-		return err
+			Data: GetDefaultConfig(),
+		}, metav1.CreateOptions{})
+
+		if err != nil {
+			return fmt.Errorf("creating config: %w", err)
+		}
 	}
 
-	polarisCm := &corev1.ConfigMap{
+	secret := &corev1.Secret{
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: c.namespace,
-			Name:      GetPluginConfigMapName(string(Polaris)),
+			Name:      SecretName,
 			Labels: labels.Set{
-				"app.kubernetes.io/managed-by": "starboard",
+				LabelK8SAppManagedBy: "starboard",
 			},
 		},
-		Data: GetDefaultPolarisConfig(),
 	}
-	_, err = c.client.CoreV1().ConfigMaps(c.namespace).Create(ctx, polarisCm, metav1.CreateOptions{})
+	_, err = c.client.CoreV1().Secrets(c.namespace).Create(ctx, secret, metav1.CreateOptions{})
 	if err != nil && !apierrors.IsAlreadyExists(err) {
 		return err
 	}
 
-	secret := &corev1.Secret{
+	scanner, err := ConfigData(cm.Data).GetConfigAuditReportsScanner()
+	if err != nil {
+		return fmt.Errorf("getting scanner: %w", err)
+	}
+
+	var pluginConfigData map[string]string
+	switch scanner {
+	case Polaris:
+		pluginConfigData = GetDefaultPolarisConfig()
+	case Conftest:
+		pluginConfigData = GetDefaultConftestConfig()
+	}
+
+	pluginConfig := &corev1.ConfigMap{
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: c.namespace,
-			Name:      SecretName,
+			Name:      GetPluginConfigMapName(string(scanner)),
 			Labels: labels.Set{
-				"app.kubernetes.io/managed-by": "starboard",
+				LabelK8SAppManagedBy: "starboard",
 			},
 		},
+		Data: pluginConfigData,
 	}
-	_, err = c.client.CoreV1().Secrets(c.namespace).Create(ctx, secret, metav1.CreateOptions{})
+	_, err = c.client.CoreV1().ConfigMaps(c.namespace).Create(ctx, pluginConfig, metav1.CreateOptions{})
 	if err != nil && !apierrors.IsAlreadyExists(err) {
 		return err
 	}
+
 	return nil
 }
 


Test patch:
diff --git a/pkg/starboard/config_test.go b/pkg/starboard/config_test.go
index 82d9105..262ffdc 100644
--- a/pkg/starboard/config_test.go
+++ b/pkg/starboard/config_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/aquasecurity/starboard/pkg/starboard"
+	"github.com/onsi/gomega"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	corev1 "k8s.io/api/core/v1"
@@ -324,67 +325,204 @@ func TestConfigManager_Read(t *testing.T) {
 
 func TestConfigManager_EnsureDefault(t *testing.T) {
 
-	t.Run("Should create ConfigMap with default values, and empty secret", func(t *testing.T) {
+	t.Run("Should create ConfigMaps and Secret", func(t *testing.T) {
+		g := gomega.NewGomegaWithT(t)
+
+		namespace := "starboard-ns"
 		clientset := fake.NewSimpleClientset()
 
-		err := starboard.NewConfigManager(clientset, starboard.NamespaceName).EnsureDefault(context.TODO())
-		require.NoError(t, err)
+		err := starboard.NewConfigManager(clientset, namespace).EnsureDefault(context.TODO())
+		g.Expect(err).ToNot(gomega.HaveOccurred())
 
-		cm, err := clientset.CoreV1().
-			ConfigMaps(starboard.NamespaceName).
+		cm, err := clientset.CoreV1().ConfigMaps(namespace).
 			Get(context.TODO(), starboard.ConfigMapName, metav1.GetOptions{})
-		require.NoError(t, err)
-		assert.Equal(t, starboard.GetDefaultConfig(), starboard.ConfigData(cm.Data))
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+		g.Expect(cm.Data).To(gomega.BeEquivalentTo(starboard.GetDefaultConfig()))
 
-		secret, err := clientset.CoreV1().
-			Secrets(starboard.NamespaceName).
+		secret, err := clientset.CoreV1().Secrets(namespace).
 			Get(context.TODO(), starboard.SecretName, metav1.GetOptions{})
-		require.NoError(t, err)
-		assert.Equal(t, map[string][]byte(nil), secret.Data)
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+		g.Expect(secret.Data).To(gomega.BeEmpty())
+
+		pluginConfig, err := clientset.CoreV1().ConfigMaps(namespace).
+			Get(context.TODO(), starboard.GetPluginConfigMapName(string(starboard.Polaris)), metav1.GetOptions{})
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+		g.Expect(pluginConfig.Data).To(gomega.Equal(starboard.GetDefaultPolarisConfig()))
+
+		_, err = clientset.CoreV1().ConfigMaps(namespace).
+			Get(context.TODO(), starboard.GetPluginConfigMapName(string(starboard.Conftest)), metav1.GetOptions{})
+		g.Expect(err).To(gomega.MatchError(`configmaps "starboard-conftest-config" not found`))
 	})
 
-	t.Run("Should not modify ConfigMap nor secret if they already exist", func(t *testing.T) {
+	t.Run("Should not modify ConfigMaps nor Secret", func(t *testing.T) {
+		g := gomega.NewGomegaWithT(t)
+		namespace := "starboard-ns"
 		clientset := fake.NewSimpleClientset(
 			&corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
-					Namespace: starboard.NamespaceName,
+					Namespace: namespace,
 					Name:      starboard.ConfigMapName,
 				},
 				Data: map[string]string{
-					"foo": "bar",
+					"foo":                        "bar",
+					"configAuditReports.scanner": string(starboard.Conftest),
 				},
 			},
 			&corev1.Secret{
 				ObjectMeta: metav1.ObjectMeta{
-					Namespace: starboard.NamespaceName,
+					Namespace: namespace,
 					Name:      starboard.SecretName,
 				},
 				Data: map[string][]byte{
 					"baz": []byte("s3cret"),
 				},
 			},
+			&corev1.ConfigMap{
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: namespace,
+					Name:      starboard.GetPluginConfigMapName(string(starboard.Conftest)),
+				},
+				Data: map[string]string{
+					"conftest.policy.my-check.rego": "<REGO>",
+				},
+			},
 		)
 
-		err := starboard.NewConfigManager(clientset, starboard.NamespaceName).EnsureDefault(context.TODO())
-		require.NoError(t, err)
+		err := starboard.NewConfigManager(clientset, namespace).EnsureDefault(context.TODO())
+		g.Expect(err).ToNot(gomega.HaveOccurred())
 
-		cm, err := clientset.CoreV1().
-			ConfigMaps(starboard.NamespaceName).
+		cm, err := clientset.CoreV1().ConfigMaps(namespace).
 			Get(context.TODO(), starboard.ConfigMapName, metav1.GetOptions{})
-		require.NoError(t, err)
-		assert.Equal(t, map[string]string{
-			"foo": "bar",
-		}, cm.Data)
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+		g.Expect(cm.Data).To(gomega.Equal(map[string]string{
+			"foo":                        "bar",
+			"configAuditReports.scanner": "Conftest",
+		}))
 
-		secret, err := clientset.CoreV1().
-			Secrets(starboard.NamespaceName).
+		secret, err := clientset.CoreV1().Secrets(namespace).
 			Get(context.TODO(), starboard.SecretName, metav1.GetOptions{})
-		require.NoError(t, err)
-		assert.Equal(t, map[string][]byte{
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+		g.Expect(secret.Data).To(gomega.Equal(map[string][]byte{
 			"baz": []byte("s3cret"),
-		}, secret.Data)
+		}))
+
+		pluginConfig, err := clientset.CoreV1().ConfigMaps(namespace).
+			Get(context.TODO(), starboard.GetPluginConfigMapName(string(starboard.Conftest)), metav1.GetOptions{})
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+		g.Expect(pluginConfig.Data).To(gomega.Equal(map[string]string{
+			"conftest.policy.my-check.rego": "<REGO>",
+		}))
+
+		_, err = clientset.CoreV1().ConfigMaps(namespace).
+			Get(context.TODO(), starboard.GetPluginConfigMapName(string(starboard.Polaris)), metav1.GetOptions{})
+		g.Expect(err).To(gomega.MatchError(`configmaps "starboard-polaris-config" not found`))
 	})
 
+	t.Run("Should create ConfigMap for Polaris", func(t *testing.T) {
+		g := gomega.NewGomegaWithT(t)
+		namespace := "starboard-ns"
+		clientset := fake.NewSimpleClientset(
+			&corev1.ConfigMap{
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: namespace,
+					Name:      starboard.ConfigMapName,
+				},
+				Data: map[string]string{
+					"foo":                        "bar",
+					"configAuditReports.scanner": string(starboard.Polaris),
+				},
+			},
+			&corev1.Secret{
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: namespace,
+					Name:      starboard.SecretName,
+				},
+				Data: map[string][]byte{
+					"baz": []byte("s3cret"),
+				},
+			},
+		)
+
+		err := starboard.NewConfigManager(clientset, namespace).EnsureDefault(context.TODO())
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+
+		cm, err := clientset.CoreV1().ConfigMaps(namespace).
+			Get(context.TODO(), starboard.ConfigMapName, metav1.GetOptions{})
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+		g.Expect(cm.Data).To(gomega.Equal(map[string]string{
+			"foo":                        "bar",
+			"configAuditReports.scanner": "Polaris",
+		}))
+
+		secret, err := clientset.CoreV1().Secrets(namespace).
+			Get(context.TODO(), starboard.SecretName, metav1.GetOptions{})
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+		g.Expect(secret.Data).To(gomega.Equal(map[string][]byte{
+			"baz": []byte("s3cret"),
+		}))
+
+		pluginConfig, err := clientset.CoreV1().ConfigMaps(namespace).
+			Get(context.TODO(), starboard.GetPluginConfigMapName(string(starboard.Polaris)), metav1.GetOptions{})
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+		g.Expect(pluginConfig.Data).To(gomega.Equal(starboard.GetDefaultPolarisConfig()))
+
+		_, err = clientset.CoreV1().ConfigMaps(namespace).
+			Get(context.TODO(), starboard.GetPluginConfigMapName(string(starboard.Conftest)), metav1.GetOptions{})
+		g.Expect(err).To(gomega.MatchError(`configmaps "starboard-conftest-config" not found`))
+	})
+
+	t.Run("Should create ConfigMap for Conftest", func(t *testing.T) {
+		g := gomega.NewGomegaWithT(t)
+		namespace := "starboard-ns"
+		clientset := fake.NewSimpleClientset(
+			&corev1.ConfigMap{
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: namespace,
+					Name:      starboard.ConfigMapName,
+				},
+				Data: map[string]string{
+					"foo":                        "bar",
+					"configAuditReports.scanner": string(starboard.Conftest),
+				},
+			},
+			&corev1.Secret{
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: namespace,
+					Name:      starboard.SecretName,
+				},
+				Data: map[string][]byte{
+					"baz": []byte("s3cret"),
+				},
+			},
+		)
+
+		err := starboard.NewConfigManager(clientset, namespace).EnsureDefault(context.TODO())
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+
+		cm, err := clientset.CoreV1().ConfigMaps(namespace).
+			Get(context.TODO(), starboard.ConfigMapName, metav1.GetOptions{})
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+		g.Expect(cm.Data).To(gomega.Equal(map[string]string{
+			"foo":                        "bar",
+			"configAuditReports.scanner": "Conftest",
+		}))
+
+		secret, err := clientset.CoreV1().Secrets(namespace).
+			Get(context.TODO(), starboard.SecretName, metav1.GetOptions{})
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+		g.Expect(secret.Data).To(gomega.Equal(map[string][]byte{
+			"baz": []byte("s3cret"),
+		}))
+
+		pluginConfig, err := clientset.CoreV1().ConfigMaps(namespace).
+			Get(context.TODO(), starboard.GetPluginConfigMapName(string(starboard.Conftest)), metav1.GetOptions{})
+		g.Expect(err).ToNot(gomega.HaveOccurred())
+		g.Expect(pluginConfig.Data).To(gomega.BeEmpty())
+
+		_, err = clientset.CoreV1().ConfigMaps(namespace).
+			Get(context.TODO(), starboard.GetPluginConfigMapName(string(starboard.Polaris)), metav1.GetOptions{})
+		g.Expect(err).To(gomega.MatchError(`configmaps "starboard-polaris-config" not found`))
+	})
 }
 
 func TestConfigManager_Delete(t *testing.T) {