Repository: aquasecurity/starboard
Pull request #526 (2021-04-22 12:23:40)

chore: Upgrade OLM from v0.16.1 to 0.17.0
Resolves: #525

Signed-off-by: Daniel Pacak <pacak.daniel@gmail.com>


Patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7dec235..6d0a6f2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -264,16 +264,16 @@ $ kubectl delete -f deploy/crd/vulnerabilityreports.crd.yaml \
 To install [Operator Lifecycle Manager][olm] (OLM) run:
 
 ```
-$ kubectl apply -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/0.16.1/crds.yaml
-$ kubectl apply -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/0.16.1/olm.yaml
+$ kubectl apply -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.17.0/crds.yaml
+$ kubectl apply -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.17.0/olm.yaml
 ```
 
 or
 
 ```
-$ curl -L https://github.com/operator-framework/operator-lifecycle-manager/releases/download/0.16.1/install.sh -o install.sh
+$ curl -L https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.17.0/install.sh -o install.sh
 $ chmod +x install.sh
-$ ./install.sh 0.16.1
+$ ./install.sh v0.17.0
 ```
 
 ### Build the Catalog Image
@@ -311,8 +311,8 @@ Place the `starboard-catalog.Dockerfile` in the top-level directory of your clon
 it to your Kubernetes cluster:
 
 ```
-$ docker build -f starboard-catalog.Dockerfile -t starboard-catalog:dev .
-$ kind load docker-image starboard-catalog:dev
+$ docker build -f starboard-catalog.Dockerfile -t docker.io/<your account>/starboard-catalog:dev .
+$ docker push docker.io/<your account>/starboard-catalog:dev
 ```
 
 ### Register the Catalog Image
@@ -331,7 +331,7 @@ spec:
   publisher: Starboard Maintainers
   displayName: Starboard Catalog
   sourceType: grpc
-  image: starboard-catalog:dev
+  image: docker.io/<your account>/starboard-catalog:dev
 EOF
 ```
 
@@ -350,8 +350,8 @@ starboard-operator   Starboard Catalog   97s
 ```
 
 If the Starboard Operator appears in this list, the catalog was successfully parsed and it is now available to install.
-Follow the installation instructions for [OLM](https://aquasecurity.github.io/starboard/operator/installation/olm/).
-Make sure that the Subscription's `spec.source` property refers to the `starboard-catalog` source instead of `operatorhubio-catalog`.
+Follow the installation instructions for [OLM][starboard-install-olm]. Make sure that the Subscription's `spec.source`
+property refers to the `starboard-catalog` source instead of `operatorhubio-catalog`.
 
 You can find more details about testing Operators with Operator Framework [here][olm-testing-operators].
 
@@ -364,4 +364,5 @@ You can find more details about testing Operators with Operator Framework [here]
 [community-operators]: https://github.com/operator-framework/community-operators
 [olm-operator-groups]: https://github.com/operator-framework/operator-lifecycle-manager/blob/master/doc/design/operatorgroups.md
 [k8s-sample-controller]: https://github.com/kubernetes/sample-controller
+[starboard-install-olm]: https://aquasecurity.github.io/starboard/latest/operator/installation/olm
 [olm-testing-operators]: https://github.com/operator-framework/community-operators/blob/master/docs/testing-operators.md
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/docs/operator/installation/olm.md b/docs/operator/installation/olm.md
index c6255f0..2f6527a 100644
--- a/docs/operator/installation/olm.md
+++ b/docs/operator/installation/olm.md
@@ -10,7 +10,7 @@ configure it to watch the `default` namespaces:
 
 1. Install the Operator Lifecycle Manager:
    ```
-   curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/0.16.1/install.sh | bash -s 0.16.1
+   curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.17.0/install.sh | bash -s v0.17.0
    ```
 2. Create the namespace to install the operator in:
    ```
@@ -74,7 +74,7 @@ configure it to watch the `default` namespaces:
 6. After install, watch the operator come up using the following command:
    ```console
    $ kubectl get clusterserviceversions -n starboard-operator
-   NAME                        DISPLAY              VERSION   REPLACES                    PHASE
+   NAME                        DISPLAY              VERSION   REPLACES                     PHASE
    starboard-operator.{{ var.tag }}  Starboard Operator   {{ var.build.version }}    starboard-operator.{{ var.tag_prev }}   Succeeded
    ```
    If the above command succeeds and the ClusterServiceVersion has transitioned from `Installing` to `Succeeded` phase
diff --git a/embedded.go b/embedded.go
index aebdda4..e6adbfa 100644
--- a/embedded.go
+++ b/embedded.go
@@ -10,11 +10,33 @@ import (
 var (
 	//go:embed deploy/crd/vulnerabilityreports.crd.yaml
 	vulnerabilityReportsCRD []byte
+	//go:embed deploy/crd/configauditreports.crd.yaml
+	configAuditReportsCRD []byte
+	//go:embed deploy/crd/ciskubebenchreports.crd.yaml
+	kubeBenchReportsCRD []byte
+	//go:embed deploy/crd/kubehunterreports.crd.yaml
+	kubeHunterReportsCRD []byte
 )
 
 func GetVulnerabilityReportsCRD() (apiextensionsv1.CustomResourceDefinition, error) {
+	return getCRDFromBytes(vulnerabilityReportsCRD)
+}
+
+func GetConfigAuditReportsCRD() (apiextensionsv1.CustomResourceDefinition, error) {
+	return getCRDFromBytes(configAuditReportsCRD)
+}
+
+func GetCISKubeBenchReportsCRD() (apiextensionsv1.CustomResourceDefinition, error) {
+	return getCRDFromBytes(kubeBenchReportsCRD)
+}
+
+func GetKubeHunterReportsCRD() (apiextensionsv1.CustomResourceDefinition, error) {
+	return getCRDFromBytes(kubeHunterReportsCRD)
+}
+
+func getCRDFromBytes(bytes []byte) (apiextensionsv1.CustomResourceDefinition, error) {
 	var crd apiextensionsv1.CustomResourceDefinition
-	_, _, err := scheme.Codecs.UniversalDecoder().Decode(vulnerabilityReportsCRD, nil, &crd)
+	_, _, err := scheme.Codecs.UniversalDecoder().Decode(bytes, nil, &crd)
 	if err != nil {
 		return apiextensionsv1.CustomResourceDefinition{}, err
 	}
diff --git a/pkg/apis/aquasecurity/v1alpha1/cis_kube_bench_types.go b/pkg/apis/aquasecurity/v1alpha1/cis_kube_bench_types.go
index 333ec2f..a22e140 100644
--- a/pkg/apis/aquasecurity/v1alpha1/cis_kube_bench_types.go
+++ b/pkg/apis/aquasecurity/v1alpha1/cis_kube_bench_types.go
@@ -1,11 +1,7 @@
 package v1alpha1
 
 import (
-	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity"
-	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/labels"
-	"k8s.io/utils/pointer"
 )
 
 const (
@@ -15,79 +11,6 @@ const (
 	CISKubeBenchReportListKind  = "CISKubeBenchReportList"
 )
 
-var (
-	// TODO Once we migrate to Go 1.16 we can use the embed package to load the CRD from ./deploy/crd/ciskubebenchreports.crd.yaml
-	CISKubeBenchReportCRD = apiextensionsv1.CustomResourceDefinition{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: CISKubeBenchReportCRName,
-			Labels: labels.Set{
-				"app.kubernetes.io/managed-by": "starboard",
-			},
-		},
-		Spec: apiextensionsv1.CustomResourceDefinitionSpec{
-			Group: aquasecurity.GroupName,
-			Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
-				{
-					Name:    CISKubeBenchReportCRVersion,
-					Served:  true,
-					Storage: true,
-					AdditionalPrinterColumns: []apiextensionsv1.CustomResourceColumnDefinition{
-						{
-							JSONPath: ".report.scanner.name",
-							Type:     "string",
-							Name:     "Scanner",
-						},
-						{
-							JSONPath: ".metadata.creationTimestamp",
-							Type:     "date",
-							Name:     "Age",
-						},
-						{
-							JSONPath: ".report.summary.failCount",
-							Type:     "integer",
-							Name:     "Fail",
-							Priority: 1,
-						},
-						{
-							JSONPath: ".report.summary.warnCount",
-							Type:     "integer",
-							Name:     "Warn",
-							Priority: 1,
-						},
-						{
-							JSONPath: ".report.summary.infoCount",
-							Type:     "integer",
-							Name:     "Info",
-							Priority: 1,
-						},
-						{
-							JSONPath: ".report.summary.passCount",
-							Type:     "integer",
-							Name:     "Pass",
-							Priority: 1,
-						},
-					},
-					Schema: &apiextensionsv1.CustomResourceValidation{
-						OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
-							XPreserveUnknownFields: pointer.BoolPtr(true),
-							Type:                   "object",
-						},
-					},
-				},
-			},
-			Scope: apiextensionsv1.ClusterScoped,
-			Names: apiextensionsv1.CustomResourceDefinitionNames{
-				Singular:   "ciskubebenchreport",
-				Plural:     "ciskubebenchreports",
-				Kind:       CISKubeBenchReportKind,
-				ListKind:   CISKubeBenchReportListKind,
-				Categories: []string{"all"},
-				ShortNames: []string{"kubebench"},
-			},
-		},
-	}
-)
-
 // +genclient
 // +genclient:nonNamespaced
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
diff --git a/pkg/apis/aquasecurity/v1alpha1/config_audit_types.go b/pkg/apis/aquasecurity/v1alpha1/config_audit_types.go
index 27e7478..a84655d 100644
--- a/pkg/apis/aquasecurity/v1alpha1/config_audit_types.go
+++ b/pkg/apis/aquasecurity/v1alpha1/config_audit_types.go
@@ -1,11 +1,7 @@
 package v1alpha1
 
 import (
-	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity"
-	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/labels"
-	"k8s.io/utils/pointer"
 )
 
 const (
@@ -15,76 +11,9 @@ const (
 	ConfigAuditReportListKind  = "ConfigAuditReportList"
 )
 
-var (
-	// TODO Once we migrate to Go 1.16 we can use the embed package to load the CRD from ./deploy/crd/configauditreports.crd.yaml
-	ConfigAuditReportCRD = apiextensionsv1.CustomResourceDefinition{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: ConfigAuditReportCRName,
-			Labels: labels.Set{
-				"app.kubernetes.io/managed-by": "starboard",
-			},
-		},
-		Spec: apiextensionsv1.CustomResourceDefinitionSpec{
-			Group: aquasecurity.GroupName,
-			Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
-				{
-					Name:    ConfigAuditReportCRVersion,
-					Served:  true,
-					Storage: true,
-					AdditionalPrinterColumns: []apiextensionsv1.CustomResourceColumnDefinition{
-						{
-							JSONPath: ".report.scanner.name",
-							Type:     "string",
-							Name:     "Scanner",
-						},
-						{
-							JSONPath: ".metadata.creationTimestamp",
-							Type:     "date",
-							Name:     "Age",
-						},
-						{
-							JSONPath: ".report.summary.dangerCount",
-							Type:     "integer",
-							Name:     "Danger",
-							Priority: 1,
-						},
-						{
-							JSONPath: ".report.summary.warningCount",
-							Type:     "integer",
-							Name:     "Warning",
-							Priority: 1,
-						},
-						{
-							JSONPath: ".report.summary.passCount",
-							Type:     "integer",
-							Name:     "Pass",
-							Priority: 1,
-						},
-					},
-					Schema: &apiextensionsv1.CustomResourceValidation{
-						OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
-							XPreserveUnknownFields: pointer.BoolPtr(true),
-							Type:                   "object",
-						},
-					},
-				},
-			},
-			Scope: apiextensionsv1.NamespaceScoped,
-			Names: apiextensionsv1.CustomResourceDefinitionNames{
-				Singular:   "configauditreport",
-				Plural:     "configauditreports",
-				Kind:       ConfigAuditReportKind,
-				ListKind:   ConfigAuditReportListKind,
-				Categories: []string{"all"},
-				ShortNames: []string{"configaudit"},
-			},
-		},
-	}
-)
-
 const (
-	ConfigAuditDangerSeverity  = "danger"
-	ConfigAuditWarningSeverity = "warning"
+	ConfigAuditSeverityDanger  = "danger"
+	ConfigAuditSeverityWarning = "warning"
 )
 
 type ConfigAuditSummary struct {
diff --git a/pkg/apis/aquasecurity/v1alpha1/kube_hunter_types.go b/pkg/apis/aquasecurity/v1alpha1/kube_hunter_types.go
index f67b974..ae90e20 100644
--- a/pkg/apis/aquasecurity/v1alpha1/kube_hunter_types.go
+++ b/pkg/apis/aquasecurity/v1alpha1/kube_hunter_types.go
@@ -1,13 +1,7 @@
 package v1alpha1
 
 import (
-	"strconv"
-
-	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity"
-	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/labels"
-	"k8s.io/utils/pointer"
 )
 
 const (
@@ -17,156 +11,6 @@ const (
 	KubeHunterReportListKind  = "KubeHunterReportList"
 )
 
-var (
-	// TODO Once we migrate to Go 1.16 we can use the embed package to load the CRD from ./deploy/crd/kubehunterreports.crd.yaml
-	KubeHunterReportCRD = apiextensionsv1.CustomResourceDefinition{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: KubeHunterReportCRName,
-			Labels: labels.Set{
-				"app.kubernetes.io/managed-by": "starboard",
-			},
-		},
-		Spec: apiextensionsv1.CustomResourceDefinitionSpec{
-			Group: aquasecurity.GroupName,
-			Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
-				{
-					Name:    KubeHunterReportCRVersion,
-					Served:  true,
-					Storage: true,
-					AdditionalPrinterColumns: []apiextensionsv1.CustomResourceColumnDefinition{
-						{
-							JSONPath: ".report.scanner.name",
-							Type:     "string",
-							Name:     "Scanner",
-						},
-						{
-							JSONPath: ".metadata.creationTimestamp",
-							Type:     "date",
-							Name:     "Age",
-						},
-						{
-							JSONPath: ".report.summary.highCount",
-							Type:     "integer",
-							Name:     "High",
-							Priority: 1,
-						},
-						{
-							JSONPath: ".report.summary.mediumCount",
-							Type:     "integer",
-							Name:     "Medium",
-							Priority: 1,
-						},
-						{
-							JSONPath: ".report.summary.lowCount",
-							Type:     "integer",
-							Name:     "Low",
-							Priority: 1,
-						},
-					},
-					Schema: &apiextensionsv1.CustomResourceValidation{
-						OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
-							Type: "object",
-							Required: []string{
-								"apiVersion",
-								"kind",
-								"metadata",
-								"report",
-							},
-							Properties: map[string]apiextensionsv1.JSONSchemaProps{
-								"apiVersion": {Type: "string"},
-								"kind":       {Type: "string"},
-								"metadata":   {Type: "object"},
-								"report": {
-									Type: "object",
-									Required: []string{
-										"scanner",
-										"vulnerabilities",
-									},
-									Properties: map[string]apiextensionsv1.JSONSchemaProps{
-										"scanner": {
-											Type: "object",
-											Required: []string{
-												"name",
-												"vendor",
-												"version",
-											},
-											Properties: map[string]apiextensionsv1.JSONSchemaProps{
-												"name":    {Type: "string"},
-												"vendor":  {Type: "string"},
-												"version": {Type: "string"},
-											},
-										},
-										"summary": {
-											Type: "object",
-											Required: []string{
-												"highCount",
-												"mediumCount",
-												"lowCount",
-												"unknownCount",
-											},
-											Properties: map[string]apiextensionsv1.JSONSchemaProps{
-												"highCount":    {Type: "integer", Minimum: pointer.Float64Ptr(0)},
-												"mediumCount":  {Type: "integer", Minimum: pointer.Float64Ptr(0)},
-												"lowCount":     {Type: "integer", Minimum: pointer.Float64Ptr(0)},
-												"unknownCount": {Type: "integer", Minimum: pointer.Float64Ptr(0)},
-											},
-										},
-										"updateTimestamp": {
-											Type:   "string",
-											Format: "date-time",
-										},
-										"vulnerabilities": {
-											Type: "array",
-											Items: &apiextensionsv1.JSONSchemaPropsOrArray{
-												Schema: &apiextensionsv1.JSONSchemaProps{
-													Type: "object",
-													Required: []string{
-														"category",
-														"severity",
-														"vulnerability",
-														"description",
-														"evidence",
-													},
-													Properties: map[string]apiextensionsv1.JSONSchemaProps{
-														"id":       {Type: "string"},
-														"category": {Type: "string"},
-														"severity": {
-															Type: "string",
-															Enum: []apiextensionsv1.JSON{
-																{Raw: []byte(strconv.Quote(string(KubeHunterSeverityHigh)))},
-																{Raw: []byte(strconv.Quote(string(KubeHunterSeverityMedium)))},
-																{Raw: []byte(strconv.Quote(string(KubeHunterSeverityLow)))},
-																{Raw: []byte(strconv.Quote(string(KubeHunterSeverityUnknown)))},
-															},
-														},
-														"vulnerability": {Type: "string"},
-														"description":   {Type: "string"},
-														"evidence":      {Type: "string"},
-														"avd_reference": {Type: "string"},
-													},
-												},
-											},
-										},
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-			Scope: apiextensionsv1.ClusterScoped,
-			Names: apiextensionsv1.CustomResourceDefinitionNames{
-				Singular:   "kubehunterreport",
-				Plural:     "kubehunterreports",
-				Kind:       KubeHunterReportKind,
-				ListKind:   KubeHunterReportListKind,
-				Categories: []string{"all"},
-				ShortNames: []string{"kubehunter"},
-			},
-		},
-	}
-)
-
 const (
 	KubeHunterSeverityHigh    Severity = "high"
 	KubeHunterSeverityMedium  Severity = "medium"
diff --git a/pkg/configauditreport/builder.go b/pkg/configauditreport/builder.go
index e1ef872..ade1cdb 100644
--- a/pkg/configauditreport/builder.go
+++ b/pkg/configauditreport/builder.go
@@ -3,31 +3,117 @@ package configauditreport
 import (
 	"fmt"
 	"strings"
+	"time"
 
 	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
 	"github.com/aquasecurity/starboard/pkg/kube"
 	"github.com/aquasecurity/starboard/pkg/starboard"
+	batchv1 "k8s.io/api/batch/v1"
+	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/utils/pointer"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 )
 
-type Builder interface {
-	Controller(controller metav1.Object) Builder
-	PodSpecHash(hash string) Builder
-	PluginConfigHash(hash string) Builder
-	Result(result v1alpha1.ConfigAuditResult) Builder
-	Get() (v1alpha1.ConfigAuditReport, error)
+type ScanJobBuilder struct {
+	plugin        Plugin
+	pluginContext starboard.PluginContext
+	timeout       time.Duration
+	object        client.Object
 }
 
-func NewBuilder(scheme *runtime.Scheme) Builder {
-	return &builder{
-		scheme: scheme,
+func NewScanJob() *ScanJobBuilder {
+	return &ScanJobBuilder{}
+}
+
+func (s *ScanJobBuilder) WithPlugin(plugin Plugin) *ScanJobBuilder {
+	s.plugin = plugin
+	return s
+}
+
+func (s *ScanJobBuilder) WithPluginContext(pluginContext starboard.PluginContext) *ScanJobBuilder {
+	s.pluginContext = pluginContext
+	return s
+}
+
+func (s *ScanJobBuilder) WithTimeout(timeout time.Duration) *ScanJobBuilder {
+	s.timeout = timeout
+	return s
+}
+
+func (s *ScanJobBuilder) WithObject(object client.Object) *ScanJobBuilder {
+	s.object = object
+	return s
+}
+
+func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
+	jobSpec, secrets, err := s.plugin.GetScanJobSpec(s.pluginContext, s.object)
+	if err != nil {
+		return nil, nil, err
 	}
+
+	podSpec, err := kube.GetPodSpec(s.object)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	podSpecHash := kube.ComputeHash(podSpec)
+
+	pluginConfigHash, err := s.plugin.GetConfigHash(s.pluginContext)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	labels := map[string]string{
+		starboard.LabelResourceKind:             s.object.GetObjectKind().GroupVersionKind().Kind,
+		starboard.LabelResourceName:             s.object.GetName(),
+		starboard.LabelResourceNamespace:        s.object.GetNamespace(),
+		starboard.LabelPodSpecHash:              podSpecHash,
+		starboard.LabelPluginConfigHash:         pluginConfigHash,
+		starboard.LabelConfigAuditReportScanner: s.pluginContext.GetName(),
+		starboard.LabelK8SAppManagedBy:          starboard.AppStarboard,
+	}
+
+	for _, secret := range secrets {
+		if secret.Labels == nil {
+			secret.Labels = make(map[string]string)
+		}
+		for k, v := range labels {
+			secret.Labels[k] = v
+		}
+	}
+
+	return &batchv1.Job{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      GetScanJobName(s.object),
+			Namespace: s.pluginContext.GetNamespace(),
+			Labels:    labels,
+		},
+		Spec: batchv1.JobSpec{
+			BackoffLimit:          pointer.Int32Ptr(0),
+			Completions:           pointer.Int32Ptr(1),
+			ActiveDeadlineSeconds: kube.GetActiveDeadlineSeconds(s.timeout),
+			Template: corev1.PodTemplateSpec{
+				ObjectMeta: metav1.ObjectMeta{
+					Labels: labels,
+				},
+				Spec: jobSpec,
+			},
+		},
+	}, secrets, nil
+}
+
+func GetScanJobName(obj client.Object) string {
+	return fmt.Sprintf("scan-configauditreport-%s", kube.ComputeHash(kube.Object{
+		Kind:      kube.Kind(obj.GetObjectKind().GroupVersionKind().Kind),
+		Namespace: obj.GetNamespace(),
+		Name:      obj.GetName(),
+	}))
 }
 
-type builder struct {
+type ReportBuilder struct {
 	scheme           *runtime.Scheme
 	controller       metav1.Object
 	podSpecHash      string
@@ -35,27 +121,33 @@ type builder struct {
 	result           v1alpha1.ConfigAuditResult
 }
 
-func (b *builder) Controller(controller metav1.Object) Builder {
+func NewReportBuilder(scheme *runtime.Scheme) *ReportBuilder {
+	return &ReportBuilder{
+		scheme: scheme,
+	}
+}
+
+func (b *ReportBuilder) Controller(controller metav1.Object) *ReportBuilder {
 	b.controller = controller
 	return b
 }
 
-func (b *builder) PodSpecHash(hash string) Builder {
+func (b *ReportBuilder) PodSpecHash(hash string) *ReportBuilder {
 	b.podSpecHash = hash
 	return b
 }
 
-func (b *builder) PluginConfigHash(hash string) Builder {
+func (b *ReportBuilder) PluginConfigHash(hash string) *ReportBuilder {
 	b.pluginConfigHash = hash
 	return b
 }
 
-func (b *builder) Result(result v1alpha1.ConfigAuditResult) Builder {
+func (b *ReportBuilder) Data(result v1alpha1.ConfigAuditResult) *ReportBuilder {
 	b.result = result
 	return b
 }
 
-func (b *builder) reportName() (string, error) {
+func (b *ReportBuilder) reportName() (string, error) {
 	kind, err := kube.KindForObject(b.controller, b.scheme)
 	if err != nil {
 		return "", err
@@ -64,7 +156,7 @@ func (b *builder) reportName() (string, error) {
 		b.controller.GetName()), nil
 }
 
-func (b *builder) Get() (v1alpha1.ConfigAuditReport, error) {
+func (b *ReportBuilder) Get() (v1alpha1.ConfigAuditReport, error) {
 	kind, err := kube.KindForObject(b.controller, b.scheme)
 	if err != nil {
 		return v1alpha1.ConfigAuditReport{}, fmt.Errorf("getting kind for object: %w", err)
diff --git a/pkg/configauditreport/scanner.go b/pkg/configauditreport/scanner.go
index a2563b9..1baab65 100644
--- a/pkg/configauditreport/scanner.go
+++ b/pkg/configauditreport/scanner.go
@@ -5,17 +5,13 @@ import (
 	"fmt"
 
 	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
-	"github.com/aquasecurity/starboard/pkg/ext"
 	"github.com/aquasecurity/starboard/pkg/kube"
 	"github.com/aquasecurity/starboard/pkg/runner"
 	"github.com/aquasecurity/starboard/pkg/starboard"
-	batchv1 "k8s.io/api/batch/v1"
-	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/klog"
-	"k8s.io/utils/pointer"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
@@ -27,7 +23,6 @@ type Scanner struct {
 	logsReader     kube.LogsReader
 	plugin         Plugin
 	pluginContext  starboard.PluginContext
-	ext.IDGenerator
 }
 
 func NewScanner(
@@ -45,7 +40,6 @@ func NewScanner(
 		pluginContext:  pluginContext,
 		objectResolver: &kube.ObjectResolver{Client: client},
 		logsReader:     kube.NewLogsReader(clientset),
-		IDGenerator:    ext.NewGoogleUUIDGenerator(),
 	}
 }
 
@@ -58,7 +52,12 @@ func (s *Scanner) Scan(ctx context.Context, workload kube.Object) (v1alpha1.Conf
 	}
 
 	klog.V(3).Infof("Scanning with options: %+v", s.opts)
-	job, secrets, err := s.getScanJob(owner)
+	job, secrets, err := NewScanJob().
+		WithPlugin(s.plugin).
+		WithPluginContext(s.pluginContext).
+		WithTimeout(s.opts.ScanJobTimeout).
+		WithObject(owner).
+		Get()
 	if err != nil {
 		return v1alpha1.ConfigAuditReport{}, err
 	}
@@ -94,41 +93,19 @@ func (s *Scanner) Scan(ctx context.Context, workload kube.Object) (v1alpha1.Conf
 		_ = logsStream.Close()
 	}()
 
-	return NewBuilder(s.scheme).
+	podSpecHash, ok := job.Labels[starboard.LabelPodSpecHash]
+	if !ok {
+		return v1alpha1.ConfigAuditReport{}, fmt.Errorf("expected label %s not set", starboard.LabelPodSpecHash)
+	}
+	pluginConfigHash, ok := job.Labels[starboard.LabelPluginConfigHash]
+	if !ok {
+		return v1alpha1.ConfigAuditReport{}, fmt.Errorf("expected label %s not set", starboard.LabelPluginConfigHash)
+	}
+
+	return NewReportBuilder(s.scheme).
 		Controller(owner).
-		Result(result).
+		PodSpecHash(podSpecHash).
+		PluginConfigHash(pluginConfigHash).
+		Data(result).
 		Get()
 }
-
-func (s *Scanner) getScanJob(obj client.Object) (*batchv1.Job, []*corev1.Secret, error) {
-	jobSpec, secrets, err := s.plugin.GetScanJobSpec(s.pluginContext, obj)
-	if err != nil {
-		return nil, nil, err
-	}
-	return &batchv1.Job{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      s.GenerateID(),
-			Namespace: starboard.NamespaceName,
-			Labels: map[string]string{
-				starboard.LabelResourceKind:      obj.GetObjectKind().GroupVersionKind().Kind,
-				starboard.LabelResourceName:      obj.GetName(),
-				starboard.LabelResourceNamespace: obj.GetNamespace(),
-			},
-		},
-		Spec: batchv1.JobSpec{
-			BackoffLimit:          pointer.Int32Ptr(0),
-			Completions:           pointer.Int32Ptr(1),
-			ActiveDeadlineSeconds: kube.GetActiveDeadlineSeconds(s.opts.ScanJobTimeout),
-			Template: corev1.PodTemplateSpec{
-				ObjectMeta: metav1.ObjectMeta{
-					Labels: map[string]string{
-						starboard.LabelResourceKind:      obj.GetObjectKind().GroupVersionKind().Kind,
-						starboard.LabelResourceName:      obj.GetName(),
-						starboard.LabelResourceNamespace: obj.GetNamespace(),
-					},
-				},
-				Spec: jobSpec,
-			},
-		},
-	}, secrets, nil
-}
diff --git a/pkg/kube/cr_manager.go b/pkg/kube/cr_manager.go
index 81c16ff..f2db298 100644
--- a/pkg/kube/cr_manager.go
+++ b/pkg/kube/cr_manager.go
@@ -147,17 +147,29 @@ func (m *CRManager) Init(ctx context.Context) error {
 		return err
 	}
 
-	err = m.createOrUpdateCRD(ctx, &v1alpha1.CISKubeBenchReportCRD)
+	kubeBenchReportsCRD, err := embedded.GetCISKubeBenchReportsCRD()
+	if err != nil {
+		return err
+	}
+	err = m.createOrUpdateCRD(ctx, &kubeBenchReportsCRD)
 	if err != nil {
 		return err
 	}
 
-	err = m.createOrUpdateCRD(ctx, &v1alpha1.KubeHunterReportCRD)
+	kubeHunterReportsCRD, err := embedded.GetKubeHunterReportsCRD()
+	if err != nil {
+		return err
+	}
+	err = m.createOrUpdateCRD(ctx, &kubeHunterReportsCRD)
 	if err != nil {
 		return err
 	}
 
-	err = m.createOrUpdateCRD(ctx, &v1alpha1.ConfigAuditReportCRD)
+	configAuditReportsCRD, err := embedded.GetConfigAuditReportsCRD()
+	if err != nil {
+		return err
+	}
+	err = m.createOrUpdateCRD(ctx, &configAuditReportsCRD)
 	if err != nil {
 		return err
 	}
diff --git a/pkg/operator/controller/ciskubebenchreport.go b/pkg/operator/controller/ciskubebenchreport.go
index b6f807f..85ab9ad 100644
--- a/pkg/operator/controller/ciskubebenchreport.go
+++ b/pkg/operator/controller/ciskubebenchreport.go
@@ -163,10 +163,10 @@ func (r *CISKubeBenchReportReconciler) newScanJob(node *corev1.Node) (*batchv1.J
 			Name:      r.getScanJobName(node),
 			Namespace: r.Config.Namespace,
 			Labels: labels.Set{
-				starboard.LabelResourceKind:        string(kube.KindNode),
-				starboard.LabelResourceName:        node.Name,
-				starboard.LabelK8SAppManagedBy:     starboard.AppStarboardOperator,
-				starboard.LabelKubeBenchReportScan: "true",
+				starboard.LabelResourceKind:           string(kube.KindNode),
+				starboard.LabelResourceName:           node.Name,
+				starboard.LabelK8SAppManagedBy:        starboard.AppStarboard,
+				starboard.LabelKubeBenchReportScanner: "true",
 			},
 		},
 		Spec: batchv1.JobSpec{
@@ -176,10 +176,10 @@ func (r *CISKubeBenchReportReconciler) newScanJob(node *corev1.Node) (*batchv1.J
 			Template: corev1.PodTemplateSpec{
 				ObjectMeta: metav1.ObjectMeta{
 					Labels: labels.Set{
-						starboard.LabelResourceKind:        string(kube.KindNode),
-						starboard.LabelResourceName:        node.Name,
-						starboard.LabelK8SAppManagedBy:     starboard.AppStarboardOperator,
-						starboard.LabelKubeBenchReportScan: "true",
+						starboard.LabelResourceKind:           string(kube.KindNode),
+						starboard.LabelResourceName:           node.Name,
+						starboard.LabelK8SAppManagedBy:        starboard.AppStarboard,
+						starboard.LabelKubeBenchReportScanner: "true",
 					},
 				},
 				Spec: templateSpec,
diff --git a/pkg/operator/controller/configauditreport.go b/pkg/operator/controller/configauditreport.go
index 83eee89..4316a7e 100644
--- a/pkg/operator/controller/configauditreport.go
+++ b/pkg/operator/controller/configauditreport.go
@@ -1,6 +1,8 @@
 package controller
 
 import (
+	. "github.com/aquasecurity/starboard/pkg/operator/predicate"
+
 	"context"
 	"fmt"
 
@@ -8,7 +10,6 @@ import (
 	"github.com/aquasecurity/starboard/pkg/configauditreport"
 	"github.com/aquasecurity/starboard/pkg/kube"
 	"github.com/aquasecurity/starboard/pkg/operator/etc"
-	. "github.com/aquasecurity/starboard/pkg/operator/predicate"
 	"github.com/aquasecurity/starboard/pkg/starboard"
 	"github.com/go-logr/logr"
 	appsv1 "k8s.io/api/apps/v1"
@@ -17,7 +18,6 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/utils/pointer"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/builder"
 	"sigs.k8s.io/controller-runtime/pkg/client"
@@ -139,7 +139,7 @@ func (r *ConfigAuditReportReconciler) reconcileWorkload(workloadKind kube.Kind)
 		}
 
 		log.V(1).Info("Checking whether configuration audit has been scheduled")
-		_, job, err := r.hasActiveScanJob(ctx, workloadPartial, podSpecHash)
+		_, job, err := r.hasActiveScanJob(ctx, workloadObj, podSpecHash)
 		if err != nil {
 			return ctrl.Result{}, err
 		}
@@ -160,15 +160,23 @@ func (r *ConfigAuditReportReconciler) reconcileWorkload(workloadKind kube.Kind)
 			return ctrl.Result{RequeueAfter: r.Config.ScanJobRetryAfter}, nil
 		}
 
-		job, secrets, err := r.getScanJob(workloadPartial, workloadObj, podSpecHash)
+		job, secrets, err := configauditreport.NewScanJob().
+			WithPlugin(r.Plugin).
+			WithPluginContext(r.PluginContext).
+			WithTimeout(r.Config.ScanJobTimeout).
+			WithObject(workloadObj).
+			Get()
 		if err != nil {
 			return ctrl.Result{}, err
 		}
 
 		for _, secret := range secrets {
-			secret.Namespace = r.Config.Namespace
 			err := r.Client.Create(ctx, secret)
 			if err != nil {
+				if !errors.IsAlreadyExists(err) {
+					log.V(1).Info("Secret already exists", "secretName", secret.Name)
+					return ctrl.Result{}, nil
+				}
 				return ctrl.Result{}, fmt.Errorf("creating secret: %w", err)
 			}
 		}
@@ -178,6 +186,7 @@ func (r *ConfigAuditReportReconciler) reconcileWorkload(workloadKind kube.Kind)
 		if err != nil {
 			if errors.IsAlreadyExists(err) {
 				// TODO Delete secrets that were created in the previous step. Alternatively we can delete them on schedule.
+				log.V(1).Info("Job already exists", "jobName", job.Name)
 				return ctrl.Result{}, nil
 			}
 			return ctrl.Result{}, fmt.Errorf("creating job: %w", err)
@@ -211,8 +220,8 @@ func (r *ConfigAuditReportReconciler) hasReport(ctx context.Context, owner kube.
 	return false, nil
 }
 
-func (r *ConfigAuditReportReconciler) hasActiveScanJob(ctx context.Context, owner kube.Object, hash string) (bool, *batchv1.Job, error) {
-	jobName := r.getScanJobName(owner)
+func (r *ConfigAuditReportReconciler) hasActiveScanJob(ctx context.Context, obj client.Object, hash string) (bool, *batchv1.Job, error) {
+	jobName := configauditreport.GetScanJobName(obj)
 	job := &batchv1.Job{}
 	err := r.Client.Get(ctx, client.ObjectKey{Namespace: r.Config.Namespace, Name: jobName}, job)
 	if err != nil {
@@ -227,58 +236,6 @@ func (r *ConfigAuditReportReconciler) hasActiveScanJob(ctx context.Context, owne
 	return false, nil, nil
 }
 
-func (r *ConfigAuditReportReconciler) getScanJobName(workload kube.Object) string {
-	return fmt.Sprintf("scan-configauditreport-%s", kube.ComputeHash(workload))
-}
-
-func (r *ConfigAuditReportReconciler) getScanJob(workload kube.Object, obj client.Object, podSpecHash string) (*batchv1.Job, []*corev1.Secret, error) {
-	jobSpec, secrets, err := r.Plugin.GetScanJobSpec(r.PluginContext, obj)
-
-	if err != nil {
-		return nil, nil, err
-	}
-
-	configHash, err := r.Plugin.GetConfigHash(r.PluginContext)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	return &batchv1.Job{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      r.getScanJobName(workload),
-			Namespace: r.Config.Namespace,
-			Labels: map[string]string{
-				starboard.LabelResourceKind:          string(workload.Kind),
-				starboard.LabelResourceName:          workload.Name,
-				starboard.LabelResourceNamespace:     workload.Namespace,
-				starboard.LabelK8SAppManagedBy:       starboard.AppStarboardOperator,
-				starboard.LabelPodSpecHash:           podSpecHash,
-				starboard.LabelPluginConfigHash:      configHash,
-				starboard.LabelConfigAuditReportScan: "true",
-			},
-		},
-		Spec: batchv1.JobSpec{
-			BackoffLimit:          pointer.Int32Ptr(0),
-			Completions:           pointer.Int32Ptr(1),
-			ActiveDeadlineSeconds: kube.GetActiveDeadlineSeconds(r.Config.ScanJobTimeout),
-			Template: corev1.PodTemplateSpec{
-				ObjectMeta: metav1.ObjectMeta{
-					Labels: map[string]string{
-						starboard.LabelResourceKind:          string(workload.Kind),
-						starboard.LabelResourceName:          workload.Name,
-						starboard.LabelResourceNamespace:     workload.Namespace,
-						starboard.LabelK8SAppManagedBy:       starboard.AppStarboardOperator,
-						starboard.LabelPodSpecHash:           podSpecHash,
-						starboard.LabelPluginConfigHash:      configHash,
-						starboard.LabelConfigAuditReportScan: "true",
-					},
-				},
-				Spec: jobSpec,
-			},
-		},
-	}, secrets, nil
-}
-
 func (r *ConfigAuditReportReconciler) reconcileJobs() reconcile.Func {
 	return func(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 		log := r.Logger.WithValues("job", req.NamespacedName)
@@ -362,11 +319,11 @@ func (r *ConfigAuditReportReconciler) processCompleteScanJob(ctx context.Context
 		_ = logsStream.Close()
 	}()
 
-	report, err := configauditreport.NewBuilder(r.Client.Scheme()).
+	report, err := configauditreport.NewReportBuilder(r.Client.Scheme()).
 		Controller(ownerObj).
 		PodSpecHash(podSpecHash).
 		PluginConfigHash(pluginConfigHash).
-		Result(result).
+		Data(result).
 		Get()
 	if err != nil {
 		return err
diff --git a/pkg/operator/controller/limit_checker.go b/pkg/operator/controller/limit_checker.go
index c224cfa..98f7aa8 100644
--- a/pkg/operator/controller/limit_checker.go
+++ b/pkg/operator/controller/limit_checker.go
@@ -37,7 +37,7 @@ func (c *checker) Check(ctx context.Context) (bool, int, error) {
 func (c *checker) countScanJobs(ctx context.Context) (int, error) {
 	var scanJobs batchv1.JobList
 	err := c.client.List(ctx, &scanJobs, client.MatchingLabels{
-		starboard.LabelK8SAppManagedBy: starboard.AppStarboardOperator,
+		starboard.LabelK8SAppManagedBy: starboard.AppStarboard,
 	}, client.InNamespace(c.config.Namespace))
 	if err != nil {
 		return 0, err
diff --git a/pkg/operator/controller/vulnerabilityreport.go b/pkg/operator/controller/vulnerabilityreport.go
index c14911c..a5a1d83 100644
--- a/pkg/operator/controller/vulnerabilityreport.go
+++ b/pkg/operator/controller/vulnerabilityreport.go
@@ -237,12 +237,12 @@ func (r *VulnerabilityReportReconciler) submitScanJob(ctx context.Context, spec
 			Name:      jobName,
 			Namespace: r.Config.Namespace,
 			Labels: map[string]string{
-				starboard.LabelResourceKind:            string(owner.Kind),
-				starboard.LabelResourceName:            owner.Name,
-				starboard.LabelResourceNamespace:       owner.Namespace,
-				starboard.LabelPodSpecHash:             hash,
-				starboard.LabelK8SAppManagedBy:         starboard.AppStarboardOperator,
-				starboard.LabelVulnerabilityReportScan: "true",
+				starboard.LabelResourceKind:               string(owner.Kind),
+				starboard.LabelResourceName:               owner.Name,
+				starboard.LabelResourceNamespace:          owner.Namespace,
+				starboard.LabelPodSpecHash:                hash,
+				starboard.LabelK8SAppManagedBy:            starboard.AppStarboard,
+				starboard.LabelVulnerabilityReportScanner: "true",
 			},
 			Annotations: map[string]string{
 				starboard.AnnotationContainerImages: containerImagesAsJSON,
@@ -255,12 +255,12 @@ func (r *VulnerabilityReportReconciler) submitScanJob(ctx context.Context, spec
 			Template: corev1.PodTemplateSpec{
 				ObjectMeta: metav1.ObjectMeta{
 					Labels: map[string]string{
-						starboard.LabelResourceKind:            string(owner.Kind),
-						starboard.LabelResourceName:            owner.Name,
-						starboard.LabelResourceNamespace:       owner.Namespace,
-						starboard.LabelPodSpecHash:             hash,
-						starboard.LabelK8SAppManagedBy:         starboard.AppStarboardOperator,
-						starboard.LabelVulnerabilityReportScan: "true",
+						starboard.LabelResourceKind:               string(owner.Kind),
+						starboard.LabelResourceName:               owner.Name,
+						starboard.LabelResourceNamespace:          owner.Namespace,
+						starboard.LabelPodSpecHash:                hash,
+						starboard.LabelK8SAppManagedBy:            starboard.AppStarboard,
+						starboard.LabelVulnerabilityReportScanner: "true",
 					},
 				},
 				Spec: templateSpec,
diff --git a/pkg/operator/predicate/predicate.go b/pkg/operator/predicate/predicate.go
index 7c1c60c..de7b25f 100644
--- a/pkg/operator/predicate/predicate.go
+++ b/pkg/operator/predicate/predicate.go
@@ -59,13 +59,13 @@ var InNamespace = func(namespace string) predicate.Predicate {
 }
 
 // ManagedByStarboardOperator is a predicate.Predicate that returns true if the
-// specified client.Object is managed by the Starboard Operator.
+// specified client.Object is managed by Starboard.
 //
 // For example, pods controlled by jobs scheduled by Starboard Operator are
-// labeled with `app.kubernetes.io/managed-by=starboard-operator`.
+// labeled with `app.kubernetes.io/managed-by=starboard`.
 var ManagedByStarboardOperator = predicate.NewPredicateFuncs(func(obj client.Object) bool {
-	if managedBy, ok := obj.GetLabels()["app.kubernetes.io/managed-by"]; ok {
-		return managedBy == "starboard-operator"
+	if managedBy, ok := obj.GetLabels()[starboard.LabelK8SAppManagedBy]; ok {
+		return managedBy == starboard.AppStarboard
 	}
 	return false
 })
@@ -86,21 +86,21 @@ var JobHasAnyCondition = predicate.NewPredicateFuncs(func(obj client.Object) boo
 })
 
 var IsVulnerabilityReportScan = predicate.NewPredicateFuncs(func(obj client.Object) bool {
-	if _, ok := obj.GetLabels()[starboard.LabelVulnerabilityReportScan]; ok {
+	if _, ok := obj.GetLabels()[starboard.LabelVulnerabilityReportScanner]; ok {
 		return true
 	}
 	return false
 })
 
 var IsConfigAuditReportScan = predicate.NewPredicateFuncs(func(obj client.Object) bool {
-	if _, ok := obj.GetLabels()[starboard.LabelConfigAuditReportScan]; ok {
+	if _, ok := obj.GetLabels()[starboard.LabelConfigAuditReportScanner]; ok {
 		return true
 	}
 	return false
 })
 
 var IsKubeBenchReportScan = predicate.NewPredicateFuncs(func(obj client.Object) bool {
-	if _, ok := obj.GetLabels()[starboard.LabelKubeBenchReportScan]; ok {
+	if _, ok := obj.GetLabels()[starboard.LabelKubeBenchReportScanner]; ok {
 		return true
 	}
 	return false
diff --git a/pkg/plugin/factory.go b/pkg/plugin/factory.go
index 3bfe7ba..dec0895 100644
--- a/pkg/plugin/factory.go
+++ b/pkg/plugin/factory.go
@@ -91,7 +91,7 @@ func (r *Resolver) GetConfigAuditPlugin() (configauditreport.Plugin, starboard.P
 		WithNamespace(r.namespace).
 		WithServiceAccountName(r.serviceAccountName).
 		WithClient(r.client).
-		Build()
+		Get()
 
 	switch scanner {
 	case starboard.Polaris:
diff --git a/pkg/plugin/polaris/plugin.go b/pkg/plugin/polaris/plugin.go
index af84953..0004f20 100644
--- a/pkg/plugin/polaris/plugin.go
+++ b/pkg/plugin/polaris/plugin.go
@@ -207,9 +207,9 @@ func (p *plugin) configAuditSummaryFrom(podChecks []v1alpha1.Check, containerChe
 			continue
 		}
 		switch c.Severity {
-		case v1alpha1.ConfigAuditDangerSeverity:
+		case v1alpha1.ConfigAuditSeverityDanger:
 			summary.DangerCount++
-		case v1alpha1.ConfigAuditWarningSeverity:
+		case v1alpha1.ConfigAuditSeverityWarning:
 			summary.WarningCount++
 		}
 	}
@@ -220,9 +220,9 @@ func (p *plugin) configAuditSummaryFrom(podChecks []v1alpha1.Check, containerChe
 				continue
 			}
 			switch c.Severity {
-			case v1alpha1.ConfigAuditDangerSeverity:
+			case v1alpha1.ConfigAuditSeverityDanger:
 				summary.DangerCount++
-			case v1alpha1.ConfigAuditWarningSeverity:
+			case v1alpha1.ConfigAuditSeverityWarning:
 				summary.WarningCount++
 			}
 		}
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
 }
 
diff --git a/pkg/starboard/constants.go b/pkg/starboard/constants.go
index 370dc8b..ecf936e 100644
--- a/pkg/starboard/constants.go
+++ b/pkg/starboard/constants.go
@@ -26,12 +26,12 @@ const (
 	LabelPodSpecHash       = "pod-spec-hash"
 	LabelPluginConfigHash  = "plugin-config-hash"
 
-	LabelConfigAuditReportScan   = "configAuditReport.scanner"
-	LabelVulnerabilityReportScan = "vulnerabilityReport.scanner"
-	LabelKubeBenchReportScan     = "kubeBenchReport.scanner"
+	LabelConfigAuditReportScanner   = "configAuditReport.scanner"
+	LabelVulnerabilityReportScanner = "vulnerabilityReport.scanner"
+	LabelKubeBenchReportScanner     = "kubeBenchReport.scanner"
 
 	LabelK8SAppManagedBy = "app.kubernetes.io/managed-by"
-	AppStarboardOperator = "starboard-operator"
+	AppStarboard         = "starboard"
 )
 
 const (
diff --git a/pkg/starboard/plugin.go b/pkg/starboard/plugin.go
index 646da3e..1afcc6b 100644
--- a/pkg/starboard/plugin.go
+++ b/pkg/starboard/plugin.go
@@ -90,6 +90,6 @@ func (b *PluginContextBuilder) WithServiceAccountName(name string) *PluginContex
 	return b
 }
 
-func (b *PluginContextBuilder) Build() PluginContext {
+func (b *PluginContextBuilder) Get() PluginContext {
 	return b.ctx
 }


Test patch:
diff --git a/itest/matcher/matcher.go b/itest/matcher/matcher.go
index 5f8dfe7..11467f0 100644
--- a/itest/matcher/matcher.go
+++ b/itest/matcher/matcher.go
@@ -139,7 +139,7 @@ func (m *configAuditReportMatcher) Match(actual interface{}) (bool, error) {
 
 	matcher := MatchFields(IgnoreExtras, Fields{
 		"ObjectMeta": MatchFields(IgnoreExtras, Fields{
-			"Labels": MatchAllKeys(Keys{
+			"Labels": MatchKeys(IgnoreExtras, Keys{
 				starboard.LabelResourceKind:      Equal(gvk.Kind),
 				starboard.LabelResourceName:      Equal(m.owner.GetName()),
 				starboard.LabelResourceNamespace: Equal(m.owner.GetNamespace()),
diff --git a/pkg/configauditreport/builder_test.go b/pkg/configauditreport/builder_test.go
index 2149faf..4e83f31 100644
--- a/pkg/configauditreport/builder_test.go
+++ b/pkg/configauditreport/builder_test.go
@@ -1,22 +1,28 @@
 package configauditreport_test
 
 import (
+	. "github.com/onsi/gomega"
+
+	"io"
 	"testing"
+	"time"
 
 	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
 	"github.com/aquasecurity/starboard/pkg/configauditreport"
 	"github.com/aquasecurity/starboard/pkg/starboard"
-	"github.com/onsi/gomega"
 	appsv1 "k8s.io/api/apps/v1"
+	batchv1 "k8s.io/api/batch/v1"
+	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes/scheme"
 	"k8s.io/utils/pointer"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-func TestBuilder(t *testing.T) {
-	g := gomega.NewGomegaWithT(t)
+func TestReportBuilder(t *testing.T) {
+	g := NewGomegaWithT(t)
 
-	report, err := configauditreport.NewBuilder(scheme.Scheme).
+	report, err := configauditreport.NewReportBuilder(scheme.Scheme).
 		Controller(&appsv1.ReplicaSet{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      "some-owner",
@@ -25,10 +31,11 @@ func TestBuilder(t *testing.T) {
 		}).
 		PodSpecHash("xyz").
 		PluginConfigHash("nop").
-		Result(v1alpha1.ConfigAuditResult{}).Get()
+		Data(v1alpha1.ConfigAuditResult{}).
+		Get()
 
-	g.Expect(err).ToNot(gomega.HaveOccurred())
-	g.Expect(report).To(gomega.Equal(v1alpha1.ConfigAuditReport{
+	g.Expect(err).ToNot(HaveOccurred())
+	g.Expect(report).To(Equal(v1alpha1.ConfigAuditReport{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "replicaset-some-owner",
 			Namespace: "qa",
@@ -52,3 +59,84 @@ func TestBuilder(t *testing.T) {
 		Report: v1alpha1.ConfigAuditResult{},
 	}))
 }
+
+type testPlugin struct {
+	configHash string
+}
+
+func (p *testPlugin) GetScanJobSpec(ctx starboard.PluginContext, obj client.Object) (corev1.PodSpec, []*corev1.Secret, error) {
+	return corev1.PodSpec{}, nil, nil
+}
+
+func (p *testPlugin) ParseConfigAuditReportData(logsReader io.ReadCloser) (v1alpha1.ConfigAuditResult, error) {
+	return v1alpha1.ConfigAuditResult{}, nil
+}
+
+func (p *testPlugin) GetContainerName() string {
+	return ""
+}
+
+func (p *testPlugin) GetConfigHash(ctx starboard.PluginContext) (string, error) {
+	return p.configHash, nil
+}
+
+func TestScanJobBuilder(t *testing.T) {
+	g := NewGomegaWithT(t)
+	job, _, err := configauditreport.NewScanJob().
+		WithPlugin(&testPlugin{
+			configHash: "hash-test",
+		}).
+		WithPluginContext(starboard.NewPluginContext().
+			WithName("plugin-test").
+			WithNamespace("starboard-ns").
+			WithServiceAccountName("starboard-sa").
+			Get()).
+		WithTimeout(3 * time.Second).
+		WithObject(&appsv1.ReplicaSet{
+			TypeMeta: metav1.TypeMeta{
+				Kind:       "ReplicaSet",
+				APIVersion: "apps/v1",
+			},
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "nginx-6799fc88d8",
+				Namespace: "prod-ns",
+			},
+		}).
+		Get()
+	g.Expect(err).ToNot(HaveOccurred())
+	g.Expect(job).NotTo(BeNil())
+	g.Expect(job).To(Equal(&batchv1.Job{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "scan-configauditreport-fcc9884cb",
+			Namespace: "starboard-ns",
+			Labels: map[string]string{
+				starboard.LabelPodSpecHash:              "58b8989656",
+				starboard.LabelPluginConfigHash:         "hash-test",
+				starboard.LabelConfigAuditReportScanner: "plugin-test",
+				starboard.LabelK8SAppManagedBy:          "starboard",
+				starboard.LabelResourceKind:             "ReplicaSet",
+				starboard.LabelResourceName:             "nginx-6799fc88d8",
+				starboard.LabelResourceNamespace:        "prod-ns",
+			},
+		},
+		Spec: batchv1.JobSpec{
+			BackoffLimit:          pointer.Int32Ptr(0),
+			Completions:           pointer.Int32Ptr(1),
+			ActiveDeadlineSeconds: pointer.Int64Ptr(3),
+			Template: corev1.PodTemplateSpec{
+				ObjectMeta: metav1.ObjectMeta{
+					Labels: map[string]string{
+						starboard.LabelPodSpecHash:              "58b8989656",
+						starboard.LabelPluginConfigHash:         "hash-test",
+						starboard.LabelConfigAuditReportScanner: "plugin-test",
+						starboard.LabelK8SAppManagedBy:          "starboard",
+						starboard.LabelResourceKind:             "ReplicaSet",
+						starboard.LabelResourceName:             "nginx-6799fc88d8",
+						starboard.LabelResourceNamespace:        "prod-ns",
+					},
+				},
+				Spec: corev1.PodSpec{},
+			},
+		},
+	}))
+}
diff --git a/pkg/operator/controller/limit_checker_test.go b/pkg/operator/controller/limit_checker_test.go
index 2ad319a..3a72bbc 100644
--- a/pkg/operator/controller/limit_checker_test.go
+++ b/pkg/operator/controller/limit_checker_test.go
@@ -34,21 +34,21 @@ var _ = Describe("LimitChecker", func() {
 					Name:      "scan-vulnerabilityreport-hash1",
 					Namespace: "starboard-operator",
 					Labels: map[string]string{
-						starboard.LabelK8SAppManagedBy: starboard.AppStarboardOperator,
+						starboard.LabelK8SAppManagedBy: starboard.AppStarboard,
 					},
 				}},
 				&batchv1.Job{ObjectMeta: metav1.ObjectMeta{
 					Name:      "scan-vulnerabilityreport-hash2",
 					Namespace: "starboard-operator",
 					Labels: map[string]string{
-						starboard.LabelK8SAppManagedBy: starboard.AppStarboardOperator,
+						starboard.LabelK8SAppManagedBy: starboard.AppStarboard,
 					},
 				}},
 				&batchv1.Job{ObjectMeta: metav1.ObjectMeta{
 					Name:      "scan-configauditreport-hash2",
 					Namespace: "starboard-operator",
 					Labels: map[string]string{
-						starboard.LabelK8SAppManagedBy: starboard.AppStarboardOperator,
+						starboard.LabelK8SAppManagedBy: starboard.AppStarboard,
 					},
 				}},
 			).Build()
@@ -74,7 +74,7 @@ var _ = Describe("LimitChecker", func() {
 					Name:      "scan-vulnerabilityreport-hash1",
 					Namespace: "starboard-operator",
 					Labels: map[string]string{
-						starboard.LabelK8SAppManagedBy: starboard.AppStarboardOperator,
+						starboard.LabelK8SAppManagedBy: starboard.AppStarboard,
 					},
 				}},
 			).Build()
diff --git a/pkg/operator/predicate/predicate_test.go b/pkg/operator/predicate/predicate_test.go
index a60ea1c..08ad314 100644
--- a/pkg/operator/predicate/predicate_test.go
+++ b/pkg/operator/predicate/predicate_test.go
@@ -1,12 +1,13 @@
 package predicate_test
 
 import (
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+
 	"time"
 
 	"github.com/aquasecurity/starboard/pkg/operator/etc"
 	"github.com/aquasecurity/starboard/pkg/operator/predicate"
-	. "github.com/onsi/ginkgo"
-	. "github.com/onsi/gomega"
 	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -207,7 +208,7 @@ var _ = Describe("Predicate", func() {
 				obj := &corev1.Pod{
 					ObjectMeta: metav1.ObjectMeta{
 						Labels: map[string]string{
-							"app.kubernetes.io/managed-by": "starboard-operator",
+							"app.kubernetes.io/managed-by": "starboard",
 						},
 					},
 				}
diff --git a/pkg/plugin/conftest/plugin.go b/pkg/plugin/conftest/plugin.go
index 2a43550..a774c4f 100644
--- a/pkg/plugin/conftest/plugin.go
+++ b/pkg/plugin/conftest/plugin.go
@@ -24,8 +24,6 @@ const (
 	policyPrefix          = "conftest.policy."
 	workloadKey           = "starboard.workload.yaml"
 	defaultCheckCategory  = "Security"
-	severityWarning       = "WARNING"
-	severityDanger        = "DANGER"
 )
 
 type Config interface {
@@ -72,7 +70,7 @@ func (p *plugin) GetScanJobSpec(ctx starboard.PluginContext, obj client.Object)
 	var volumeMounts []corev1.VolumeMount
 	var volumeItems []corev1.KeyToPath
 
-	secretName := p.idGenerator.GenerateID()
+	secretName := configauditreport.GetScanJobName(obj) + "-volume"
 	secretData := make(map[string]string)
 
 	for policy, script := range policies {
@@ -212,7 +210,7 @@ func (p *plugin) ParseConfigAuditReportData(logsReader io.ReadCloser) (v1alpha1.
 		for _, warning := range cr.Warnings {
 			checks = append(checks, v1alpha1.Check{
 				ID:       p.getPolicyTitleFromResult(warning),
-				Severity: severityWarning,
+				Severity: v1alpha1.ConfigAuditSeverityWarning,
 				Message:  warning.Message,
 				Category: defaultCheckCategory,
 				Success:  false,
@@ -223,7 +221,7 @@ func (p *plugin) ParseConfigAuditReportData(logsReader io.ReadCloser) (v1alpha1.
 		for _, failure := range cr.Failures {
 			checks = append(checks, v1alpha1.Check{
 				ID:       p.getPolicyTitleFromResult(failure),
-				Severity: severityDanger,
+				Severity: v1alpha1.ConfigAuditSeverityDanger,
 				Message:  failure.Message,
 				Category: defaultCheckCategory,
 			})
diff --git a/pkg/plugin/conftest/plugin_test.go b/pkg/plugin/conftest/plugin_test.go
index 46f4a4e..16048b6 100644
--- a/pkg/plugin/conftest/plugin_test.go
+++ b/pkg/plugin/conftest/plugin_test.go
@@ -48,7 +48,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 				"foo":                                     "bar",    // This one should be skipped (no conftest.policy. prefix)
 				"conftest.policy.privileged":              "<REGO>", // This one should be skipped (no .rego suffix)
 			},
-		}).Build()).Build()
+		}).Build()).Get()
 
 	plugin := conftest.NewPlugin(sequence, fixedClock, config)
 
@@ -75,7 +75,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 		"Affinity":                     Equal(starboard.LinuxNodeAffinity()),
 		"Volumes": ConsistOf(
 			MatchFields(IgnoreExtras, Fields{
-				"Name": Equal("00000000-0000-0000-0000-000000000001"),
+				"Name": Equal("scan-configauditreport-5d4445db4f-volume"),
 				// We cannot inline assert here on other properties with the MatchFields matcher
 				// because the value of the Secret field is the pointer to v1.SecretVolumeSource.
 				// The MatchFields matcher only works with structs :-(
@@ -99,31 +99,31 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 				}),
 				"VolumeMounts": ConsistOf(
 					corev1.VolumeMount{
-						Name:      "00000000-0000-0000-0000-000000000001",
+						Name:      "scan-configauditreport-5d4445db4f-volume",
 						MountPath: "/project/policy/libkubernetes.rego",
 						SubPath:   "libkubernetes.rego",
 						ReadOnly:  true,
 					},
 					corev1.VolumeMount{
-						Name:      "00000000-0000-0000-0000-000000000001",
+						Name:      "scan-configauditreport-5d4445db4f-volume",
 						MountPath: "/project/policy/libutil.rego",
 						SubPath:   "libutil.rego",
 						ReadOnly:  true,
 					},
 					corev1.VolumeMount{
-						Name:      "00000000-0000-0000-0000-000000000001",
+						Name:      "scan-configauditreport-5d4445db4f-volume",
 						MountPath: "/project/policy/access_to_host_pid.rego",
 						SubPath:   "access_to_host_pid.rego",
 						ReadOnly:  true,
 					},
 					corev1.VolumeMount{
-						Name:      "00000000-0000-0000-0000-000000000001",
+						Name:      "scan-configauditreport-5d4445db4f-volume",
 						MountPath: "/project/policy/cpu_not_limited.rego",
 						SubPath:   "cpu_not_limited.rego",
 						ReadOnly:  true,
 					},
 					corev1.VolumeMount{
-						Name:      "00000000-0000-0000-0000-000000000001",
+						Name:      "scan-configauditreport-5d4445db4f-volume",
 						MountPath: "/project/workload.yaml",
 						SubPath:   "workload.yaml",
 						ReadOnly:  true,
@@ -149,7 +149,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 		"SecurityContext": Equal(&corev1.PodSecurityContext{}),
 	}))
 	g.Expect(*jobSpec.Volumes[0].VolumeSource.Secret).To(MatchFields(IgnoreExtras, Fields{
-		"SecretName": Equal("00000000-0000-0000-0000-000000000001"),
+		"SecretName": Equal("scan-configauditreport-5d4445db4f-volume"),
 		"Items": ConsistOf(
 			corev1.KeyToPath{
 				Key:  "conftest.policy.libkubernetes.rego",
@@ -176,7 +176,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 	g.Expect(secrets).To(ConsistOf(
 		&corev1.Secret{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:      "00000000-0000-0000-0000-000000000001",
+				Name:      "scan-configauditreport-5d4445db4f-volume",
 				Namespace: "starboard-ns",
 			},
 			StringData: map[string]string{
@@ -304,35 +304,35 @@ func TestPlugin_ParseConfigAuditReportData(t *testing.T) {
 				ID:       "Default capabilities: some containers do not drop all",
 				Message:  "container kubedns of deployment kube-dns in default namespace should add 'ALL' to securityContext.capabilities.drop",
 				Success:  false,
-				Severity: "DANGER",
+				Severity: "danger",
 				Category: "Security",
 			}),
 			"container dnsmasq of deployment kube-dns in default namespace should add 'ALL' to securityContext.capabilities.drop": Equal(v1alpha1.Check{
 				ID:       "Default capabilities: some containers do not drop all",
 				Message:  "container dnsmasq of deployment kube-dns in default namespace should add 'ALL' to securityContext.capabilities.drop",
 				Success:  false,
-				Severity: "DANGER",
+				Severity: "danger",
 				Category: "Security",
 			}),
 			"container sidecar of deployment kube-dns in default namespace should add 'ALL' to securityContext.capabilities.drop": Equal(v1alpha1.Check{
 				ID:       "Default capabilities: some containers do not drop all",
 				Message:  "container sidecar of deployment kube-dns in default namespace should add 'ALL' to securityContext.capabilities.drop",
 				Success:  false,
-				Severity: "DANGER",
+				Severity: "danger",
 				Category: "Security",
 			}),
 			"container prometheus-to-sd of deployment kube-dns in default namespace should add 'ALL' to securityContext.capabilities.drop": Equal(v1alpha1.Check{
 				ID:       "Default capabilities: some containers do not drop all",
 				Message:  "container prometheus-to-sd of deployment kube-dns in default namespace should add 'ALL' to securityContext.capabilities.drop",
 				Success:  false,
-				Severity: "DANGER",
+				Severity: "danger",
 				Category: "Security",
 			}),
 			"container dnsmasq of deployment kube-dns in default namespace should set securityContext.readOnlyRootFilesystem to true": Equal(v1alpha1.Check{
 				ID:       "Root file system is not read-only",
 				Message:  "container dnsmasq of deployment kube-dns in default namespace should set securityContext.readOnlyRootFilesystem to true",
 				Success:  false,
-				Severity: "DANGER",
+				Severity: "danger",
 				Category: "Security",
 			}),
 			"container prometheus-to-sd of deployment kube-dns in default namespace should set resources.requests.cpu": Equal(v1alpha1.Check{
@@ -342,7 +342,7 @@ func TestPlugin_ParseConfigAuditReportData(t *testing.T) {
 				ID:       "00000000-0000-0000-0000-000000000001",
 				Message:  "container prometheus-to-sd of deployment kube-dns in default namespace should set resources.requests.cpu",
 				Success:  false,
-				Severity: "DANGER",
+				Severity: "danger",
 				Category: "Security",
 			}),
 		}),
@@ -364,7 +364,7 @@ func TestPlugin_GetConfigHash(t *testing.T) {
 					Data: data,
 				}).
 				Build()).
-			Build()
+			Get()
 	}
 
 	t.Run("Should return different hash for different config data", func(t *testing.T) {
diff --git a/pkg/plugin/polaris/plugin_test.go b/pkg/plugin/polaris/plugin_test.go
index bddc07b..b534ffe 100644
--- a/pkg/plugin/polaris/plugin_test.go
+++ b/pkg/plugin/polaris/plugin_test.go
@@ -121,7 +121,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 				WithName(string(starboard.Polaris)).
 				WithNamespace(starboard.NamespaceName).
 				WithServiceAccountName(starboard.ServiceAccountName).
-				Build()
+				Get()
 			plugin := polaris.NewPlugin(fixedClock, tc.config)
 			jobSpec, secrets, err := plugin.GetScanJobSpec(pluginContext, tc.obj)
 
@@ -208,7 +208,7 @@ func TestPlugin_GetConfigHash(t *testing.T) {
 					Data: data,
 				}).
 				Build()).
-			Build()
+			Get()
 	}
 
 	t.Run("Should return different hash for different config data", func(t *testing.T) {
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) {
diff --git a/pkg/starboard/plugin_test.go b/pkg/starboard/plugin_test.go
index 050f3e9..bf7fd3a 100644
--- a/pkg/starboard/plugin_test.go
+++ b/pkg/starboard/plugin_test.go
@@ -36,7 +36,7 @@ func TestPluginContext_GetConfig(t *testing.T) {
 		WithName("polaris").
 		WithNamespace("starboard-ns").
 		WithClient(client).
-		Build()
+		Get()
 
 	cm, err := pluginContext.GetConfig()