Repository: aquasecurity/starboard
Pull request #345 (2021-01-16 20:28:38)

feat: Implement configauditreport.ReadWriter using client provided by controller-runtime module
Signed-off-by: Daniel Pacak <pacak.daniel@gmail.com>

codecov[bot]: # [Codecov](https://codecov.io/gh/aquasecurity/starboard/pull/345?src=pr&el=h1) Report
> Merging [#345](https://codecov.io/gh/aquasecurity/starboard/pull/345?src=pr&el=desc) (f25bd98) into [main](https://codecov.io/gh/aquasecurity/starboard/commit/dbc37264e21d4a153935666d0a8f8c0d4720e33b?el=desc) (dbc3726) will **decrease** coverage by `29.67%`.
> The diff coverage is `88.05%`.

[![Impacted file tree graph](https://codecov.io/gh/aquasecurity/starboard/pull/345/graphs/tree.svg?width=650&height=150&src=pr&token=qqTGKAJ0Wb)](https://codecov.io/gh/aquasecurity/starboard/pull/345?src=pr&el=tree)

```diff
@@             Coverage Diff             @@
##             main     #345       +/-   ##
===========================================
- Coverage   60.59%   30.92%   -29.68%     
===========================================
  Files          46       53        +7     
  Lines        2487     2626      +139     
===========================================
- Hits         1507      812      -695     
- Misses        759     1754      +995     
+ Partials      221       60      -161     
```


| [Impacted Files](https://codecov.io/gh/aquasecurity/starboard/pull/345?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pkg/configauditreport/io.go](https://codecov.io/gh/aquasecurity/starboard/pull/345/diff?src=pr&el=tree#diff-cGtnL2NvbmZpZ2F1ZGl0cmVwb3J0L2lvLmdv) | `85.71% <85.71%> (ø)` | |
| [pkg/vulnerabilityreport/io.go](https://codecov.io/gh/aquasecurity/starboard/pull/345/diff?src=pr&el=tree#diff-cGtnL3Z1bG5lcmFiaWxpdHlyZXBvcnQvaW8uZ28=) | `83.33% <100.00%> (ø)` | |
| [pkg/cmd/get.go](https://codecov.io/gh/aquasecurity/starboard/pull/345/diff?src=pr&el=tree#diff-cGtnL2NtZC9nZXQuZ28=) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/find.go](https://codecov.io/gh/aquasecurity/starboard/pull/345/diff?src=pr&el=tree#diff-cGtnL2NtZC9maW5kLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/root.go](https://codecov.io/gh/aquasecurity/starboard/pull/345/diff?src=pr&el=tree#diff-cGtnL2NtZC9yb290Lmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/scan.go](https://codecov.io/gh/aquasecurity/starboard/pull/345/diff?src=pr&el=tree#diff-cGtnL2NtZC9zY2FuLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/polaris.go](https://codecov.io/gh/aquasecurity/starboard/pull/345/diff?src=pr&el=tree#diff-cGtnL2NtZC9wb2xhcmlzLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/version.go](https://codecov.io/gh/aquasecurity/starboard/pull/345/diff?src=pr&el=tree#diff-cGtnL2NtZC92ZXJzaW9uLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/kube\_bench.go](https://codecov.io/gh/aquasecurity/starboard/pull/345/diff?src=pr&el=tree#diff-cGtnL2NtZC9rdWJlX2JlbmNoLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pkg/cmd/kube\_hunter.go](https://codecov.io/gh/aquasecurity/starboard/pull/345/diff?src=pr&el=tree#diff-cGtnL2NtZC9rdWJlX2h1bnRlci5nbw==) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| ... and [47 more](https://codecov.io/gh/aquasecurity/starboard/pull/345/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/aquasecurity/starboard/pull/345?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/aquasecurity/starboard/pull/345?src=pr&el=footer). Last update [dbc3726...f25bd98](https://codecov.io/gh/aquasecurity/starboard/pull/345?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/pkg/configauditreport/io.go b/pkg/configauditreport/io.go
new file mode 100644
index 0000000..06c1ecb
--- /dev/null
+++ b/pkg/configauditreport/io.go
@@ -0,0 +1,144 @@
+package configauditreport
+
+import (
+	"context"
+
+	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
+	"github.com/aquasecurity/starboard/pkg/generated/clientset/versioned"
+	"github.com/aquasecurity/starboard/pkg/kube"
+	"k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/labels"
+	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/klog"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// Writer is the interface that wraps the basic Write method.
+//
+// Write creates or updates the given v1alpha1.ConfigAuditReport instance.
+type Writer interface {
+	Write(ctx context.Context, report v1alpha1.ConfigAuditReport) error
+}
+
+// Reader is the interface that wraps basic FindByOwner method.
+//
+// FindByOwner returns a v1alpha1.ConfigAuditReport owned by the given
+// kube.Object or nil if the report is not found.
+type Reader interface {
+	FindByOwner(ctx context.Context, owner kube.Object) (*v1alpha1.ConfigAuditReport, error)
+}
+
+type ReadWriter interface {
+	Writer
+	Reader
+}
+
+type readWriter struct {
+	clientset versioned.Interface
+}
+
+// NewReadWriter constructs a new ReadWriter which is using the client-go
+// module for interacting with the Kubernetes API server.
+func NewReadWriter(clientset versioned.Interface) ReadWriter {
+	return &readWriter{
+		clientset: clientset,
+	}
+}
+
+func (r *readWriter) Write(ctx context.Context, report v1alpha1.ConfigAuditReport) error {
+	existing, err := r.clientset.AquasecurityV1alpha1().ConfigAuditReports(report.Namespace).
+		Get(ctx, report.Name, metav1.GetOptions{})
+
+	if err == nil {
+		klog.V(3).Infof("Updating ConfigAuditReport %q", report.Namespace+"/"+report.Name)
+		deepCopy := existing.DeepCopy()
+		deepCopy.Labels = report.Labels
+		deepCopy.Report = report.Report
+
+		_, err = r.clientset.AquasecurityV1alpha1().ConfigAuditReports(report.Namespace).
+			Update(ctx, deepCopy, metav1.UpdateOptions{})
+		return err
+	}
+
+	if errors.IsNotFound(err) {
+		klog.V(3).Infof("Creating ConfigAuditReport %q", report.Namespace+"/"+report.Name)
+		_, err = r.clientset.AquasecurityV1alpha1().ConfigAuditReports(report.Namespace).
+			Create(ctx, &report, metav1.CreateOptions{})
+		return err
+	}
+
+	return err
+}
+
+func (r *readWriter) FindByOwner(ctx context.Context, workload kube.Object) (*v1alpha1.ConfigAuditReport, error) {
+	list, err := r.clientset.AquasecurityV1alpha1().ConfigAuditReports(workload.Namespace).List(ctx, metav1.ListOptions{
+		LabelSelector: labels.Set{
+			kube.LabelResourceKind:      string(workload.Kind),
+			kube.LabelResourceName:      workload.Name,
+			kube.LabelResourceNamespace: workload.Namespace,
+		}.String(),
+	})
+	if err != nil {
+		return nil, err
+	}
+	// Only one config audit per specific workload exists on the cluster
+	if len(list.Items) > 0 {
+		return &list.DeepCopy().Items[0], nil
+	}
+	return nil, nil
+}
+
+type crReadWriter struct {
+	client client.Client
+}
+
+// NewControllerRuntimeReadWriter constructs a new ReadWriter which is
+// using the client package provided by the controller-runtime libraries for
+// interacting with the Kubernetes API server.
+func NewControllerRuntimeReadWriter(client client.Client) ReadWriter {
+	return &crReadWriter{
+		client: client,
+	}
+}
+
+func (r *crReadWriter) Write(ctx context.Context, report v1alpha1.ConfigAuditReport) error {
+	var existing v1alpha1.ConfigAuditReport
+	err := r.client.Get(ctx, types.NamespacedName{
+		Name:      report.Name,
+		Namespace: report.Namespace,
+	}, &existing)
+
+	if err == nil {
+		copied := existing.DeepCopy()
+		copied.Labels = report.Labels
+		copied.Report = report.Report
+
+		return r.client.Update(ctx, copied)
+	}
+
+	if errors.IsNotFound(err) {
+		return r.client.Create(ctx, &report)
+	}
+
+	return err
+}
+
+func (r *crReadWriter) FindByOwner(ctx context.Context, owner kube.Object) (*v1alpha1.ConfigAuditReport, error) {
+	var list v1alpha1.ConfigAuditReportList
+
+	err := r.client.List(ctx, &list, client.MatchingLabels{
+		kube.LabelResourceKind:      string(owner.Kind),
+		kube.LabelResourceNamespace: owner.Namespace,
+		kube.LabelResourceName:      owner.Name,
+	}, client.InNamespace(owner.Namespace))
+	if err != nil {
+		return nil, err
+	}
+
+	// Only one config audit per specific workload exists on the cluster
+	if len(list.Items) > 0 {
+		return &list.DeepCopy().Items[0], nil
+	}
+	return nil, nil
+}
diff --git a/pkg/configauditreport/writer.go b/pkg/configauditreport/writer.go
deleted file mode 100644
index 45d5381..0000000
--- a/pkg/configauditreport/writer.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package configauditreport
-
-import (
-	"context"
-
-	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
-	"github.com/aquasecurity/starboard/pkg/generated/clientset/versioned"
-	"github.com/aquasecurity/starboard/pkg/kube"
-	"k8s.io/apimachinery/pkg/api/errors"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/labels"
-	"k8s.io/klog"
-)
-
-// Write is the interface that wraps basic methods for persisting ConfigAudit reports.
-//
-// Write persists the given ConfigAuditReport report.
-type Writer interface {
-	Write(ctx context.Context, report v1alpha1.ConfigAuditReport) error
-}
-
-// Reader is the interface that wraps basic methods for reading ConfigAudit reports.
-//
-// Read will return a single ConfigAuditReport that match a specific workload
-type Reader interface {
-	FindByOwner(ctx context.Context, owner kube.Object) (*v1alpha1.ConfigAuditReport, error)
-}
-
-type ReadWriter interface {
-	Writer
-	Reader
-}
-
-type readWriter struct {
-	clientset versioned.Interface
-}
-
-func NewReadWriter(clientset versioned.Interface) ReadWriter {
-	return &readWriter{
-		clientset: clientset,
-	}
-}
-
-func (w *readWriter) Write(ctx context.Context, report v1alpha1.ConfigAuditReport) error {
-	existing, err := w.clientset.AquasecurityV1alpha1().ConfigAuditReports(report.Namespace).
-		Get(ctx, report.Name, metav1.GetOptions{})
-
-	if err == nil {
-		klog.V(3).Infof("Updating ConfigAuditReport %q", report.Namespace+"/"+report.Name)
-		deepCopy := existing.DeepCopy()
-		deepCopy.Labels = report.Labels
-		deepCopy.Report = report.Report
-
-		_, err = w.clientset.AquasecurityV1alpha1().ConfigAuditReports(report.Namespace).
-			Update(ctx, deepCopy, metav1.UpdateOptions{})
-		return err
-	}
-
-	if errors.IsNotFound(err) {
-		klog.V(3).Infof("Creating ConfigAuditReport %q", report.Namespace+"/"+report.Name)
-		_, err = w.clientset.AquasecurityV1alpha1().ConfigAuditReports(report.Namespace).
-			Create(ctx, &report, metav1.CreateOptions{})
-		return err
-	}
-
-	return err
-}
-
-func (w *readWriter) FindByOwner(ctx context.Context, workload kube.Object) (*v1alpha1.ConfigAuditReport, error) {
-	list, err := w.clientset.AquasecurityV1alpha1().ConfigAuditReports(workload.Namespace).List(ctx, metav1.ListOptions{
-		LabelSelector: labels.Set{
-			kube.LabelResourceKind:      string(workload.Kind),
-			kube.LabelResourceName:      workload.Name,
-			kube.LabelResourceNamespace: workload.Namespace,
-		}.String(),
-	})
-	if err != nil {
-		return nil, err
-	}
-	// Only one config audit per specific workload exists on the cluster
-	if len(list.Items) > 0 {
-		return &list.DeepCopy().Items[0], nil
-	}
-	return nil, nil
-}
diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go
index 475cc5a..1a5aa12 100644
--- a/pkg/operator/operator.go
+++ b/pkg/operator/operator.go
@@ -116,7 +116,7 @@ func Run(buildInfo starboard.BuildInfo, operatorConfig etc.Config) error {
 		return err
 	}
 
-	store := vulnerabilityreport.NewControllerRuntimeReadWriter(mgr.GetClient(), mgr.GetScheme())
+	store := vulnerabilityreport.NewControllerRuntimeReadWriter(mgr.GetClient())
 	idGenerator := ext.NewGoogleUUIDGenerator()
 
 	scanner, err := config.GetVulnerabilityReportPlugin(buildInfo, starboardConfig)
diff --git a/pkg/vulnerabilityreport/writer.go b/pkg/vulnerabilityreport/io.go
similarity index 63%
rename from pkg/vulnerabilityreport/writer.go
rename to pkg/vulnerabilityreport/io.go
index 500c04e..0432967 100644
--- a/pkg/vulnerabilityreport/writer.go
+++ b/pkg/vulnerabilityreport/io.go
@@ -4,21 +4,28 @@ import (
 	"context"
 
 	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
-	clientset "github.com/aquasecurity/starboard/pkg/generated/clientset/versioned"
+	"github.com/aquasecurity/starboard/pkg/generated/clientset/versioned"
 	"github.com/aquasecurity/starboard/pkg/kube"
 	"k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
-	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/klog"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
+// Writer is the interface that wraps the basic Write method.
+//
+// Write creates or updates the given slice of v1alpha1.VulnerabilityReport
+// instances.
 type Writer interface {
 	Write(context.Context, []v1alpha1.VulnerabilityReport) error
 }
 
+// Reader is the interface that wraps basic FindByOwner method.
+//
+// FindByOwner returns the slice of v1alpha1.VulnerabilityReport instances
+// owned by the given kube.Object or an empty slice if the reports are not found.
 type Reader interface {
 	FindByOwner(context.Context, kube.Object) ([]v1alpha1.VulnerabilityReport, error)
 }
@@ -29,20 +36,20 @@ type ReadWriter interface {
 }
 
 type readWriter struct {
-	client clientset.Interface
+	clientset versioned.Interface
 }
 
 // NewReadWriter constructs a new ReadWriter which is using the client-go
 // module for interacting with the Kubernetes API server.
-func NewReadWriter(client clientset.Interface) ReadWriter {
+func NewReadWriter(clientset versioned.Interface) ReadWriter {
 	return &readWriter{
-		client: client,
+		clientset: clientset,
 	}
 }
 
-func (s *readWriter) Write(ctx context.Context, reports []v1alpha1.VulnerabilityReport) error {
+func (r *readWriter) Write(ctx context.Context, reports []v1alpha1.VulnerabilityReport) error {
 	for _, report := range reports {
-		err := s.createOrUpdate(ctx, report)
+		err := r.createOrUpdate(ctx, report)
 		if err != nil {
 			return err
 		}
@@ -50,8 +57,8 @@ func (s *readWriter) Write(ctx context.Context, reports []v1alpha1.Vulnerability
 	return nil
 }
 
-func (s *readWriter) createOrUpdate(ctx context.Context, report v1alpha1.VulnerabilityReport) error {
-	existing, err := s.client.AquasecurityV1alpha1().VulnerabilityReports(report.Namespace).
+func (r *readWriter) createOrUpdate(ctx context.Context, report v1alpha1.VulnerabilityReport) error {
+	existing, err := r.clientset.AquasecurityV1alpha1().VulnerabilityReports(report.Namespace).
 		Get(ctx, report.Name, metav1.GetOptions{})
 
 	if err == nil {
@@ -60,14 +67,14 @@ func (s *readWriter) createOrUpdate(ctx context.Context, report v1alpha1.Vulnera
 		deepCopy.Labels = report.Labels
 		deepCopy.Report = report.Report
 
-		_, err = s.client.AquasecurityV1alpha1().VulnerabilityReports(report.Namespace).
+		_, err = r.clientset.AquasecurityV1alpha1().VulnerabilityReports(report.Namespace).
 			Update(ctx, deepCopy, metav1.UpdateOptions{})
 		return err
 	}
 
 	if errors.IsNotFound(err) {
 		klog.V(3).Infof("Creating VulnerabilityReport %q", report.Namespace+"/"+report.Name)
-		_, err = s.client.AquasecurityV1alpha1().VulnerabilityReports(report.Namespace).
+		_, err = r.clientset.AquasecurityV1alpha1().VulnerabilityReports(report.Namespace).
 			Create(ctx, &report, metav1.CreateOptions{})
 		return err
 	}
@@ -75,8 +82,8 @@ func (s *readWriter) createOrUpdate(ctx context.Context, report v1alpha1.Vulnera
 	return err
 }
 
-func (s *readWriter) FindByOwner(ctx context.Context, owner kube.Object) ([]v1alpha1.VulnerabilityReport, error) {
-	list, err := s.client.AquasecurityV1alpha1().VulnerabilityReports(owner.Namespace).List(ctx, metav1.ListOptions{
+func (r *readWriter) FindByOwner(ctx context.Context, owner kube.Object) ([]v1alpha1.VulnerabilityReport, error) {
+	list, err := r.clientset.AquasecurityV1alpha1().VulnerabilityReports(owner.Namespace).List(ctx, metav1.ListOptions{
 		LabelSelector: labels.Set{
 			kube.LabelResourceKind:      string(owner.Kind),
 			kube.LabelResourceName:      owner.Name,
@@ -91,22 +98,20 @@ func (s *readWriter) FindByOwner(ctx context.Context, owner kube.Object) ([]v1al
 
 type crReadWriter struct {
 	client client.Client
-	scheme *runtime.Scheme
 }
 
 // NewControllerRuntimeReadWriter constructs a new ReadWriter which is
 // using the client package provided by the controller-runtime libraries for
 // interacting with the Kubernetes API server.
-func NewControllerRuntimeReadWriter(client client.Client, scheme *runtime.Scheme) ReadWriter {
+func NewControllerRuntimeReadWriter(client client.Client) ReadWriter {
 	return &crReadWriter{
 		client: client,
-		scheme: scheme,
 	}
 }
 
-func (s *crReadWriter) Write(ctx context.Context, reports []v1alpha1.VulnerabilityReport) error {
+func (r *crReadWriter) Write(ctx context.Context, reports []v1alpha1.VulnerabilityReport) error {
 	for _, report := range reports {
-		err := s.createOrUpdate(ctx, report)
+		err := r.createOrUpdate(ctx, report)
 		if err != nil {
 			return err
 		}
@@ -114,9 +119,9 @@ func (s *crReadWriter) Write(ctx context.Context, reports []v1alpha1.Vulnerabili
 	return nil
 }
 
-func (s *crReadWriter) createOrUpdate(ctx context.Context, report v1alpha1.VulnerabilityReport) error {
+func (r *crReadWriter) createOrUpdate(ctx context.Context, report v1alpha1.VulnerabilityReport) error {
 	var existing v1alpha1.VulnerabilityReport
-	err := s.client.Get(ctx, types.NamespacedName{
+	err := r.client.Get(ctx, types.NamespacedName{
 		Name:      report.Name,
 		Namespace: report.Namespace,
 	}, &existing)
@@ -126,20 +131,20 @@ func (s *crReadWriter) createOrUpdate(ctx context.Context, report v1alpha1.Vulne
 		copied.Labels = report.Labels
 		copied.Report = report.Report
 
-		return s.client.Update(ctx, copied)
+		return r.client.Update(ctx, copied)
 	}
 
 	if errors.IsNotFound(err) {
-		return s.client.Create(ctx, &report)
+		return r.client.Create(ctx, &report)
 	}
 
 	return err
 }
 
-func (s *crReadWriter) FindByOwner(ctx context.Context, owner kube.Object) ([]v1alpha1.VulnerabilityReport, error) {
+func (r *crReadWriter) FindByOwner(ctx context.Context, owner kube.Object) ([]v1alpha1.VulnerabilityReport, error) {
 	var list v1alpha1.VulnerabilityReportList
 
-	err := s.client.List(ctx, &list, client.MatchingLabels{
+	err := r.client.List(ctx, &list, client.MatchingLabels{
 		kube.LabelResourceKind:      string(owner.Kind),
 		kube.LabelResourceNamespace: owner.Namespace,
 		kube.LabelResourceName:      owner.Name,


Test patch:
diff --git a/pkg/configauditreport/io_test.go b/pkg/configauditreport/io_test.go
new file mode 100644
index 0000000..b139464
--- /dev/null
+++ b/pkg/configauditreport/io_test.go
@@ -0,0 +1,322 @@
+package configauditreport_test
+
+import (
+	"context"
+	"testing"
+
+	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
+	"github.com/aquasecurity/starboard/pkg/configauditreport"
+	"github.com/aquasecurity/starboard/pkg/generated/clientset/versioned/fake"
+	"github.com/aquasecurity/starboard/pkg/kube"
+	"github.com/aquasecurity/starboard/pkg/starboard"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/types"
+	controllerFake "sigs.k8s.io/controller-runtime/pkg/client/fake"
+)
+
+func TestReadWriter(t *testing.T) {
+
+	t.Run("Should create ConfigAuditReport", func(t *testing.T) {
+		clientset := fake.NewSimpleClientset()
+		readWriter := configauditreport.NewReadWriter(clientset)
+		err := readWriter.Write(context.TODO(), v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "deployment-nginx",
+				Namespace: "qa",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      "Deployment",
+					kube.LabelResourceName:      "nginx",
+					kube.LabelResourceNamespace: "qa",
+					kube.LabelPodSpecHash:       "abc",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{},
+		})
+		require.NoError(t, err)
+
+		found, err := clientset.AquasecurityV1alpha1().ConfigAuditReports("qa").
+			Get(context.TODO(), "deployment-nginx", metav1.GetOptions{})
+		require.NoError(t, err)
+		assert.Equal(t, &v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "deployment-nginx",
+				Namespace: "qa",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      "Deployment",
+					kube.LabelResourceName:      "nginx",
+					kube.LabelResourceNamespace: "qa",
+					kube.LabelPodSpecHash:       "abc",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{},
+		}, found)
+	})
+
+	t.Run("Should update ConfigAuditReport", func(t *testing.T) {
+		clientset := fake.NewSimpleClientset(&v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "deployment-wordpress",
+				Namespace: "prod",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      "Deployment",
+					kube.LabelResourceName:      "wordpress",
+					kube.LabelResourceNamespace: "prod",
+					kube.LabelPodSpecHash:       "abc",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{},
+		})
+		readWriter := configauditreport.NewReadWriter(clientset)
+		err := readWriter.Write(context.TODO(), v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "deployment-wordpress",
+				Namespace: "prod",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      "Deployment",
+					kube.LabelResourceName:      "wordpress",
+					kube.LabelResourceNamespace: "prod",
+					kube.LabelPodSpecHash:       "xyz",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{},
+		})
+		require.NoError(t, err)
+		report, err := clientset.AquasecurityV1alpha1().ConfigAuditReports("prod").
+			Get(context.TODO(), "deployment-wordpress", metav1.GetOptions{})
+		require.NoError(t, err)
+		assert.Equal(t, &v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "deployment-wordpress",
+				Namespace: "prod",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      "Deployment",
+					kube.LabelResourceName:      "wordpress",
+					kube.LabelResourceNamespace: "prod",
+					kube.LabelPodSpecHash:       "xyz",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{},
+		}, report)
+	})
+
+	t.Run("Should find ConfigAuditReport", func(t *testing.T) {
+		clientset := fake.NewSimpleClientset(&v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "deployment-wordpress",
+				Namespace: "prod",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      "Deployment",
+					kube.LabelResourceName:      "wordpress",
+					kube.LabelResourceNamespace: "prod",
+					kube.LabelPodSpecHash:       "abc",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{},
+		}, &v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "deployment-wordpress",
+				Namespace: "qa",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      "Deployment",
+					kube.LabelResourceName:      "wordpress",
+					kube.LabelResourceNamespace: "qa",
+					kube.LabelPodSpecHash:       "abc",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{},
+		})
+
+		found, err := configauditreport.NewReadWriter(clientset).FindByOwner(context.TODO(), kube.Object{
+			Kind:      kube.KindDeployment,
+			Name:      "wordpress",
+			Namespace: "qa",
+		})
+		require.NoError(t, err)
+		assert.Equal(t, &v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "deployment-wordpress",
+				Namespace: "qa",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      "Deployment",
+					kube.LabelResourceName:      "wordpress",
+					kube.LabelResourceNamespace: "qa",
+					kube.LabelPodSpecHash:       "abc",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{},
+		}, found)
+	})
+
+}
+
+func TestControllerRuntimeReadWriter(t *testing.T) {
+
+	kubernetesScheme := starboard.NewScheme()
+
+	t.Run("Should create ConfigAuditReport", func(t *testing.T) {
+		client := controllerFake.NewClientBuilder().WithScheme(kubernetesScheme).Build()
+		readWriter := configauditreport.NewControllerRuntimeReadWriter(client)
+		err := readWriter.Write(context.TODO(), v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "deployment-app",
+				Namespace: "qa",
+				Labels: map[string]string{
+					"starboard.resource.kind":      "Deployment",
+					"starboard.resource.name":      "app",
+					"starboard.resource.namespace": "qa",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{
+				Summary: v1alpha1.ConfigAuditSummary{
+					WarningCount: 8,
+					DangerCount:  3,
+				},
+			},
+		})
+		require.NoError(t, err)
+
+		var found v1alpha1.ConfigAuditReport
+		err = client.Get(context.TODO(), types.NamespacedName{Namespace: "qa", Name: "deployment-app"}, &found)
+		require.NoError(t, err)
+
+		assert.Equal(t, v1alpha1.ConfigAuditReport{
+			TypeMeta: metav1.TypeMeta{
+				Kind:       "ConfigAuditReport",
+				APIVersion: "aquasecurity.github.io/v1alpha1",
+			},
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "deployment-app",
+				Namespace: "qa",
+				Labels: map[string]string{
+					"starboard.resource.kind":      "Deployment",
+					"starboard.resource.name":      "app",
+					"starboard.resource.namespace": "qa",
+				},
+				ResourceVersion: "1",
+			},
+			Report: v1alpha1.ConfigAuditResult{
+				Summary: v1alpha1.ConfigAuditSummary{
+					WarningCount: 8,
+					DangerCount:  3,
+				},
+			},
+		}, found)
+	})
+
+	t.Run("Should update ConfigAuditReport", func(t *testing.T) {
+		client := controllerFake.NewClientBuilder().WithScheme(kubernetesScheme).WithObjects(&v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "deployment-app",
+				Namespace: "qa",
+				Labels: map[string]string{
+					"starboard.resource.kind":      "Deployment",
+					"starboard.resource.name":      "app",
+					"starboard.resource.namespace": "qa",
+					"pod-spec-hash":                "h1",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{
+				Summary: v1alpha1.ConfigAuditSummary{
+					WarningCount: 8,
+					DangerCount:  3,
+				},
+			},
+		}).Build()
+		readWriter := configauditreport.NewControllerRuntimeReadWriter(client)
+		err := readWriter.Write(context.TODO(), v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "deployment-app",
+				Namespace: "qa",
+				Labels: map[string]string{
+					"starboard.resource.kind":      "Deployment",
+					"starboard.resource.name":      "app",
+					"starboard.resource.namespace": "qa",
+					"pod-spec-hash":                "h2",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{
+				Summary: v1alpha1.ConfigAuditSummary{
+					WarningCount: 9,
+					DangerCount:  2,
+				},
+			},
+		})
+		require.NoError(t, err)
+
+		var found v1alpha1.ConfigAuditReport
+		err = client.Get(context.TODO(), types.NamespacedName{Namespace: "qa", Name: "deployment-app"}, &found)
+		require.NoError(t, err)
+
+		assert.Equal(t, v1alpha1.ConfigAuditReport{
+			TypeMeta: metav1.TypeMeta{
+				Kind:       "ConfigAuditReport",
+				APIVersion: "aquasecurity.github.io/v1alpha1",
+			},
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "deployment-app",
+				Namespace: "qa",
+				Labels: map[string]string{
+					"starboard.resource.kind":      "Deployment",
+					"starboard.resource.name":      "app",
+					"starboard.resource.namespace": "qa",
+					"pod-spec-hash":                "h2",
+				},
+				ResourceVersion: "1",
+			},
+			Report: v1alpha1.ConfigAuditResult{
+				Summary: v1alpha1.ConfigAuditSummary{
+					WarningCount: 9,
+					DangerCount:  2,
+				},
+			},
+		}, found)
+	})
+
+	t.Run("Should find ConfigAuditReport", func(t *testing.T) {
+		client := controllerFake.NewClientBuilder().WithScheme(kubernetesScheme).WithObjects(&v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Namespace: "my-namespace",
+				Name:      "deployment-my-deploy-my",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      string(kube.KindDeployment),
+					kube.LabelResourceName:      "my-deploy",
+					kube.LabelResourceNamespace: "my-namespace",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{},
+		}, &v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Namespace: "my-namespace",
+				Name:      "my-sts",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      string(kube.KindStatefulSet),
+					kube.LabelResourceName:      "my-sts",
+					kube.LabelResourceNamespace: "my-namespace",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{},
+		}).Build()
+
+		readWriter := configauditreport.NewControllerRuntimeReadWriter(client)
+		found, err := readWriter.FindByOwner(context.TODO(), kube.Object{
+			Kind:      kube.KindDeployment,
+			Name:      "my-deploy",
+			Namespace: "my-namespace",
+		})
+		require.NoError(t, err)
+		assert.Equal(t, &v1alpha1.ConfigAuditReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Namespace: "my-namespace",
+				Name:      "deployment-my-deploy-my",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      string(kube.KindDeployment),
+					kube.LabelResourceName:      "my-deploy",
+					kube.LabelResourceNamespace: "my-namespace",
+				},
+			},
+			Report: v1alpha1.ConfigAuditResult{},
+		}, found)
+	})
+}
diff --git a/pkg/configauditreport/writer_test.go b/pkg/configauditreport/writer_test.go
deleted file mode 100644
index b05471a..0000000
--- a/pkg/configauditreport/writer_test.go
+++ /dev/null
@@ -1,121 +0,0 @@
-package configauditreport_test
-
-import (
-	"context"
-	"testing"
-
-	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
-	"github.com/aquasecurity/starboard/pkg/configauditreport"
-	"github.com/aquasecurity/starboard/pkg/generated/clientset/versioned/fake"
-	"github.com/aquasecurity/starboard/pkg/kube"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-func TestReadWriter(t *testing.T) {
-
-	t.Run("Should create ConfigAuditReport", func(t *testing.T) {
-		clientset := fake.NewSimpleClientset()
-		err := configauditreport.NewReadWriter(clientset).Write(context.TODO(), v1alpha1.ConfigAuditReport{
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      "deployment-nginx",
-				Namespace: "qa",
-				Labels: map[string]string{
-					kube.LabelResourceKind:      "Deployment",
-					kube.LabelResourceName:      "nginx",
-					kube.LabelResourceNamespace: "qa",
-					kube.LabelPodSpecHash:       "abc",
-				},
-			},
-			Report: v1alpha1.ConfigAuditResult{},
-		})
-		require.NoError(t, err)
-
-		_, err = clientset.AquasecurityV1alpha1().ConfigAuditReports("qa").
-			Get(context.TODO(), "deployment-nginx", metav1.GetOptions{})
-		require.NoError(t, err)
-	})
-
-	t.Run("Should update ConfigAuditReport", func(t *testing.T) {
-		clientset := fake.NewSimpleClientset(&v1alpha1.ConfigAuditReport{
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      "deployment-wordpress",
-				Namespace: "prod",
-				Labels: map[string]string{
-					kube.LabelResourceKind:      "Deployment",
-					kube.LabelResourceName:      "wordpress",
-					kube.LabelResourceNamespace: "prod",
-					kube.LabelPodSpecHash:       "abc",
-				},
-			},
-			Report: v1alpha1.ConfigAuditResult{},
-		})
-		err := configauditreport.NewReadWriter(clientset).Write(context.TODO(), v1alpha1.ConfigAuditReport{
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      "deployment-wordpress",
-				Namespace: "prod",
-				Labels: map[string]string{
-					kube.LabelResourceKind:      "Deployment",
-					kube.LabelResourceName:      "wordpress",
-					kube.LabelResourceNamespace: "prod",
-					kube.LabelPodSpecHash:       "xyz",
-				},
-			},
-			Report: v1alpha1.ConfigAuditResult{},
-		})
-		require.NoError(t, err)
-		report, err := clientset.AquasecurityV1alpha1().ConfigAuditReports("prod").
-			Get(context.TODO(), "deployment-wordpress", metav1.GetOptions{})
-		require.NoError(t, err)
-		assert.Equal(t, map[string]string{
-			kube.LabelResourceKind:      "Deployment",
-			kube.LabelResourceName:      "wordpress",
-			kube.LabelResourceNamespace: "prod",
-			kube.LabelPodSpecHash:       "xyz",
-		}, report.Labels)
-	})
-
-	t.Run("Should find ConfigAuditReport", func(t *testing.T) {
-		clientset := fake.NewSimpleClientset(&v1alpha1.ConfigAuditReport{
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      "deployment-wordpress",
-				Namespace: "prod",
-				Labels: map[string]string{
-					kube.LabelResourceKind:      "Deployment",
-					kube.LabelResourceName:      "wordpress",
-					kube.LabelResourceNamespace: "prod",
-					kube.LabelPodSpecHash:       "abc",
-				},
-			},
-			Report: v1alpha1.ConfigAuditResult{},
-		}, &v1alpha1.ConfigAuditReport{
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      "deployment-wordpress",
-				Namespace: "qa",
-				Labels: map[string]string{
-					kube.LabelResourceKind:      "Deployment",
-					kube.LabelResourceName:      "wordpress",
-					kube.LabelResourceNamespace: "qa",
-					kube.LabelPodSpecHash:       "abc",
-				},
-			},
-			Report: v1alpha1.ConfigAuditResult{},
-		})
-
-		report, err := configauditreport.NewReadWriter(clientset).FindByOwner(context.TODO(), kube.Object{
-			Kind:      kube.KindDeployment,
-			Name:      "wordpress",
-			Namespace: "qa",
-		})
-		require.NoError(t, err)
-		assert.Equal(t, "deployment-wordpress", report.Name)
-		assert.Equal(t, map[string]string{
-			kube.LabelResourceKind:      "Deployment",
-			kube.LabelResourceName:      "wordpress",
-			kube.LabelResourceNamespace: "qa",
-			kube.LabelPodSpecHash:       "abc",
-		}, report.Labels)
-	})
-
-}
diff --git a/pkg/polaris/plugin_test.go b/pkg/polaris/plugin_test.go
index 77b92a8..b12f7bd 100644
--- a/pkg/polaris/plugin_test.go
+++ b/pkg/polaris/plugin_test.go
@@ -156,22 +156,21 @@ func TestPlugin_ParseConfigAuditResult(t *testing.T) {
 			Category: "Networking",
 		},
 	}, result.PodChecks)
-	assert.Equal(t, map[string][]v1alpha1.Check{
-		"db": {
-			{
-				ID:       "cpuLimitsMissing",
-				Message:  "CPU limits are set",
-				Success:  false,
-				Severity: "warning",
-				Category: "Resources",
-			},
-			{
-				ID:       "cpuRequestsMissing",
-				Message:  "CPU requests are set",
-				Success:  true,
-				Severity: "warning",
-				Category: "Resources",
-			},
+	assert.Len(t, result.ContainerChecks, 1)
+	assert.ElementsMatch(t, []v1alpha1.Check{
+		{
+			ID:       "cpuLimitsMissing",
+			Message:  "CPU limits are set",
+			Success:  false,
+			Severity: "warning",
+			Category: "Resources",
+		},
+		{
+			ID:       "cpuRequestsMissing",
+			Message:  "CPU requests are set",
+			Success:  true,
+			Severity: "warning",
+			Category: "Resources",
 		},
-	}, result.ContainerChecks)
+	}, result.ContainerChecks["db"])
 }
diff --git a/pkg/vulnerabilityreport/writer_test.go b/pkg/vulnerabilityreport/io_test.go
similarity index 63%
rename from pkg/vulnerabilityreport/writer_test.go
rename to pkg/vulnerabilityreport/io_test.go
index d8dd0e6..94284b9 100644
--- a/pkg/vulnerabilityreport/writer_test.go
+++ b/pkg/vulnerabilityreport/io_test.go
@@ -21,7 +21,8 @@ func TestReadWriter(t *testing.T) {
 
 	t.Run("Should create VulnerabilityReport", func(t *testing.T) {
 		clientset := fake.NewSimpleClientset()
-		err := vulnerabilityreport.NewReadWriter(clientset).Write(context.TODO(), []v1alpha1.VulnerabilityReport{
+		readWriter := vulnerabilityreport.NewReadWriter(clientset)
+		err := readWriter.Write(context.TODO(), []v1alpha1.VulnerabilityReport{
 			{
 				ObjectMeta: metav1.ObjectMeta{
 					Namespace: "qa",
@@ -56,13 +57,37 @@ func TestReadWriter(t *testing.T) {
 				kube.LabelResourceName: "app"}.String(),
 			})
 		require.NoError(t, err)
-		reports := map[string]bool{}
+		reports := map[string]v1alpha1.VulnerabilityReport{}
 		for _, item := range list.Items {
-			reports[item.Name] = true
+			reports[item.Name] = item
 		}
-		assert.Equal(t, map[string]bool{
-			"deployment-app-c1": true,
-			"deployment-app-c2": true,
+		assert.Equal(t, map[string]v1alpha1.VulnerabilityReport{
+			"deployment-app-c1": {
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: "qa",
+					Name:      "deployment-app-c1",
+					Labels: map[string]string{
+						kube.LabelResourceKind:      "Deployment",
+						kube.LabelResourceName:      "app",
+						kube.LabelResourceNamespace: "qa",
+						kube.LabelContainerName:     "c1",
+						kube.LabelPodSpecHash:       "abc",
+					},
+				},
+			},
+			"deployment-app-c2": {
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: "qa",
+					Name:      "deployment-app-c2",
+					Labels: map[string]string{
+						kube.LabelResourceKind:      "Deployment",
+						kube.LabelResourceName:      "app",
+						kube.LabelResourceNamespace: "qa",
+						kube.LabelContainerName:     "c2",
+						kube.LabelPodSpecHash:       "def",
+					},
+				},
+			},
 		}, reports)
 	})
 
@@ -80,7 +105,8 @@ func TestReadWriter(t *testing.T) {
 				},
 			},
 		})
-		err := vulnerabilityreport.NewReadWriter(clientset).Write(context.TODO(), []v1alpha1.VulnerabilityReport{
+		readWriter := vulnerabilityreport.NewReadWriter(clientset)
+		err := readWriter.Write(context.TODO(), []v1alpha1.VulnerabilityReport{
 			{
 				ObjectMeta: metav1.ObjectMeta{
 					Namespace: "qa",
@@ -98,14 +124,19 @@ func TestReadWriter(t *testing.T) {
 		require.NoError(t, err)
 		report, err := clientset.AquasecurityV1alpha1().VulnerabilityReports("qa").Get(context.TODO(), "deployment-nginx", metav1.GetOptions{})
 		require.NoError(t, err)
-		assert.Equal(t, "deployment-nginx", report.Name)
-		assert.Equal(t, map[string]string{
-			kube.LabelResourceKind:      "Deployment",
-			kube.LabelResourceName:      "nginx",
-			kube.LabelResourceNamespace: "qa",
-			kube.LabelContainerName:     "nginx",
-			kube.LabelPodSpecHash:       "xyz",
-		}, report.Labels)
+		assert.Equal(t, &v1alpha1.VulnerabilityReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Namespace: "qa",
+				Name:      "deployment-nginx",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      "Deployment",
+					kube.LabelResourceName:      "nginx",
+					kube.LabelResourceNamespace: "qa",
+					kube.LabelContainerName:     "nginx",
+					kube.LabelPodSpecHash:       "xyz",
+				},
+			},
+		}, report)
 	})
 
 	t.Run("Should find VulnerabilityReports", func(t *testing.T) {
@@ -147,7 +178,8 @@ func TestReadWriter(t *testing.T) {
 			Report: v1alpha1.VulnerabilityScanResult{},
 		})
 
-		list, err := vulnerabilityreport.NewReadWriter(clientset).FindByOwner(context.TODO(), kube.Object{
+		readWriter := vulnerabilityreport.NewReadWriter(clientset)
+		list, err := readWriter.FindByOwner(context.TODO(), kube.Object{
 			Kind:      kube.KindDeployment,
 			Name:      "my-deploy",
 			Namespace: "my-namespace",
@@ -170,10 +202,9 @@ func TestControllerRuntimeReadWriter(t *testing.T) {
 	kubernetesScheme := starboard.NewScheme()
 
 	t.Run("Should create VulnerabilityReports", func(t *testing.T) {
-
-		client := controllerFake.NewFakeClientWithScheme(kubernetesScheme)
-		store := vulnerabilityreport.NewControllerRuntimeReadWriter(client, kubernetesScheme)
-		err := store.Write(context.TODO(), []v1alpha1.VulnerabilityReport{
+		client := controllerFake.NewClientBuilder().WithScheme(kubernetesScheme).Build()
+		readWriter := vulnerabilityreport.NewControllerRuntimeReadWriter(client)
+		err := readWriter.Write(context.TODO(), []v1alpha1.VulnerabilityReport{
 			{
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "deployment-app1-container1",
@@ -202,11 +233,47 @@ func TestControllerRuntimeReadWriter(t *testing.T) {
 			},
 		})
 		require.NoError(t, err)
-
+		var list v1alpha1.VulnerabilityReportList
+		err = client.List(context.TODO(), &list)
+		require.NoError(t, err)
+		reports := map[string]v1alpha1.VulnerabilityReport{}
+		for _, item := range list.Items {
+			reports[item.Name] = item
+		}
+		assert.Equal(t, map[string]v1alpha1.VulnerabilityReport{
+			"deployment-app1-container1": {
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: "qa",
+					Name:      "deployment-app1-container1",
+					Labels: map[string]string{
+						kube.LabelResourceKind:      "Deployment",
+						kube.LabelResourceName:      "app1",
+						kube.LabelResourceNamespace: "qa",
+						kube.LabelContainerName:     "container1",
+						kube.LabelPodSpecHash:       "h1",
+					},
+					ResourceVersion: "1",
+				},
+			},
+			"deployment-app1-container2": {
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: "qa",
+					Name:      "deployment-app1-container2",
+					Labels: map[string]string{
+						kube.LabelResourceKind:      "Deployment",
+						kube.LabelResourceName:      "app1",
+						kube.LabelResourceNamespace: "qa",
+						kube.LabelContainerName:     "container2",
+						kube.LabelPodSpecHash:       "h1",
+					},
+					ResourceVersion: "1",
+				},
+			},
+		}, reports)
 	})
 
 	t.Run("Should update VulnerabilityReports", func(t *testing.T) {
-		client := controllerFake.NewFakeClientWithScheme(kubernetesScheme,
+		client := controllerFake.NewClientBuilder().WithScheme(kubernetesScheme).WithObjects(
 			&v1alpha1.VulnerabilityReport{
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "deployment-app1-container1",
@@ -232,9 +299,9 @@ func TestControllerRuntimeReadWriter(t *testing.T) {
 						"pod-spec-hash":                "h2",
 					},
 				},
-			})
-		store := vulnerabilityreport.NewControllerRuntimeReadWriter(client, kubernetesScheme)
-		err := store.Write(context.TODO(), []v1alpha1.VulnerabilityReport{
+			}).Build()
+		readWriter := vulnerabilityreport.NewControllerRuntimeReadWriter(client)
+		err := readWriter.Write(context.TODO(), []v1alpha1.VulnerabilityReport{
 			{
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "deployment-app1-container1",
@@ -313,4 +380,61 @@ func TestControllerRuntimeReadWriter(t *testing.T) {
 			},
 		}, found)
 	})
+
+	t.Run("Should find VulnerabilityReports", func(t *testing.T) {
+		client := controllerFake.NewClientBuilder().WithScheme(kubernetesScheme).WithObjects(&v1alpha1.VulnerabilityReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Namespace: "my-namespace",
+				Name:      "deployment-my-deploy-my-container-01",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      string(kube.KindDeployment),
+					kube.LabelResourceName:      "my-deploy",
+					kube.LabelResourceNamespace: "my-namespace",
+					kube.LabelContainerName:     "my-container-01",
+				},
+			},
+			Report: v1alpha1.VulnerabilityScanResult{},
+		}, &v1alpha1.VulnerabilityReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Namespace: "my-namespace",
+				Name:      "deployment-my-deploy-my-container-02",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      string(kube.KindDeployment),
+					kube.LabelResourceName:      "my-deploy",
+					kube.LabelResourceNamespace: "my-namespace",
+					kube.LabelContainerName:     "my-container-02",
+				},
+			},
+			Report: v1alpha1.VulnerabilityScanResult{},
+		}, &v1alpha1.VulnerabilityReport{
+			ObjectMeta: metav1.ObjectMeta{
+				Namespace: "my-namespace",
+				Name:      "my-sts",
+				Labels: map[string]string{
+					kube.LabelResourceKind:      string(kube.KindStatefulSet),
+					kube.LabelResourceName:      "my-sts",
+					kube.LabelResourceNamespace: "my-namespace",
+					kube.LabelContainerName:     "my-sts-container",
+				},
+			},
+			Report: v1alpha1.VulnerabilityScanResult{},
+		}).Build()
+
+		readWriter := vulnerabilityreport.NewControllerRuntimeReadWriter(client)
+		list, err := readWriter.FindByOwner(context.TODO(), kube.Object{
+			Kind:      kube.KindDeployment,
+			Name:      "my-deploy",
+			Namespace: "my-namespace",
+		})
+		require.NoError(t, err)
+		reports := map[string]bool{}
+		for _, item := range list {
+			reports[item.Name] = true
+		}
+		assert.Equal(t, map[string]bool{
+			"deployment-my-deploy-my-container-01": true,
+			"deployment-my-deploy-my-container-02": true,
+		}, reports)
+	})
+
 }