Repository: aquasecurity/starboard
Pull request #80 (2020-07-07 14:20:07)

feat(api): Add method for getting vulnerability reports by the specified workload
Signed-off-by: Daniel Pacak <pacak.daniel@gmail.com>

codecov[bot]: # [Codecov](https://codecov.io/gh/aquasecurity/starboard/pull/80?src=pr&el=h1) Report
> Merging [#80](https://codecov.io/gh/aquasecurity/starboard/pull/80?src=pr&el=desc) into [master](https://codecov.io/gh/aquasecurity/starboard/commit/f87b3541ccf71fcdeb61cd796c5a476226e9e996&el=desc) will **not change** coverage.
> The diff coverage is `0.00%`.

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

```diff
@@          Coverage Diff           @@
##           master     #80   +/-   ##
======================================
  Coverage    9.25%   9.25%           
======================================
  Files          26      26           
  Lines        1156    1156           
======================================
  Hits          107     107           
  Misses       1044    1044           
  Partials        5       5           
```


| [Impacted Files](https://codecov.io/gh/aquasecurity/starboard/pull/80?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pkg/cmd/find\_vulnerabilities.go](https://codecov.io/gh/aquasecurity/starboard/pull/80/diff?src=pr&el=tree#diff-cGtnL2NtZC9maW5kX3Z1bG5lcmFiaWxpdGllcy5nbw==) | `0.00% <0.00%> (ø)` | |
| [pkg/docker/config.go](https://codecov.io/gh/aquasecurity/starboard/pull/80/diff?src=pr&el=tree#diff-cGtnL2RvY2tlci9jb25maWcuZ28=) | `90.00% <ø> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/aquasecurity/starboard/pull/80?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/80?src=pr&el=footer). Last update [f87b354...b3e289e](https://codecov.io/gh/aquasecurity/starboard/pull/80?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/pkg/cmd/find_vulnerabilities.go b/pkg/cmd/find_vulnerabilities.go
index 867411a..0066c4d 100644
--- a/pkg/cmd/find_vulnerabilities.go
+++ b/pkg/cmd/find_vulnerabilities.go
@@ -78,7 +78,7 @@ NAME is the name of a particular Kubernetes workload.
 			if err != nil {
 				return
 			}
-			err = crd.NewWriter(starboardClientset).Write(ctx, workload, reports)
+			err = crd.NewReadWriter(starboardClientset).Write(ctx, workload, reports)
 			return
 		},
 	}
diff --git a/pkg/docker/config.go b/pkg/docker/config.go
index b5b4d04..4d63e63 100644
--- a/pkg/docker/config.go
+++ b/pkg/docker/config.go
@@ -47,4 +47,3 @@ func encodeAuth(config map[string]ServerCredentials) (encodedConfig map[string]S
 	}
 	return
 }
-
diff --git a/pkg/find/vulnerabilities/crd/writer.go b/pkg/find/vulnerabilities/crd/writer.go
index 0a117fc..76b4188 100644
--- a/pkg/find/vulnerabilities/crd/writer.go
+++ b/pkg/find/vulnerabilities/crd/writer.go
@@ -4,6 +4,8 @@ import (
 	"context"
 	"fmt"
 
+	"k8s.io/apimachinery/pkg/labels"
+
 	"github.com/aquasecurity/starboard/pkg/kube"
 
 	starboard "github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
@@ -13,17 +15,17 @@ import (
 	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-type writer struct {
+type ReadWriter struct {
 	client clientset.Interface
 }
 
-func NewWriter(client clientset.Interface) vulnerabilities.Writer {
-	return &writer{
+func NewReadWriter(client clientset.Interface) *ReadWriter {
+	return &ReadWriter{
 		client: client,
 	}
 }
 
-func (s *writer) Write(ctx context.Context, workload kube.Object, reports map[string]starboard.VulnerabilityReport) (err error) {
+func (s *ReadWriter) Write(ctx context.Context, workload kube.Object, reports vulnerabilities.WorkloadVulnerabilities) (err error) {
 	for container, report := range reports {
 		err = s.createVulnerability(ctx, workload, container, report)
 		if err != nil {
@@ -33,7 +35,7 @@ func (s *writer) Write(ctx context.Context, workload kube.Object, reports map[st
 	return
 }
 
-func (s *writer) createVulnerability(ctx context.Context, workload kube.Object, container string, report starboard.VulnerabilityReport) (err error) {
+func (s *ReadWriter) createVulnerability(ctx context.Context, workload kube.Object, container string, report starboard.VulnerabilityReport) (err error) {
 	_, err = s.client.AquasecurityV1alpha1().Vulnerabilities(workload.Namespace).Create(ctx, &starboard.Vulnerability{
 		ObjectMeta: meta.ObjectMeta{
 			Name: fmt.Sprintf(uuid.New().String()),
@@ -49,3 +51,23 @@ func (s *writer) createVulnerability(ctx context.Context, workload kube.Object,
 
 	return err
 }
+
+func (s *ReadWriter) Read(ctx context.Context, workload kube.Object) (vulnerabilities.WorkloadVulnerabilities, error) {
+	list, err := s.client.AquasecurityV1alpha1().Vulnerabilities(workload.Namespace).List(ctx, meta.ListOptions{
+		LabelSelector: labels.Set{
+			kube.LabelResourceKind:      string(workload.Kind),
+			kube.LabelResourceName:      workload.Name,
+			kube.LabelResourceNamespace: workload.Namespace,
+		}.String(),
+	})
+	if err != nil {
+		return vulnerabilities.WorkloadVulnerabilities{}, err
+	}
+	reports := make(map[string]starboard.VulnerabilityReport)
+	for _, item := range list.Items {
+		if container, ok := item.Labels[kube.LabelContainerName]; ok {
+			reports[container] = item.Report
+		}
+	}
+	return reports, nil
+}
diff --git a/pkg/find/vulnerabilities/writer.go b/pkg/find/vulnerabilities/writer.go
index 2e6d1fe..9688255 100644
--- a/pkg/find/vulnerabilities/writer.go
+++ b/pkg/find/vulnerabilities/writer.go
@@ -3,10 +3,18 @@ package vulnerabilities
 import (
 	"context"
 
-	starboard "github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
 	"github.com/aquasecurity/starboard/pkg/kube"
 )
 
 type Writer interface {
-	Write(ctx context.Context, workload kube.Object, reports map[string]starboard.VulnerabilityReport) error
+	Write(ctx context.Context, workload kube.Object, reports WorkloadVulnerabilities) error
+}
+
+type Reader interface {
+	Read(ctx context.Context, workload kube.Object) (WorkloadVulnerabilities, error)
+}
+
+type ReadWriter interface {
+	Reader
+	Writer
 }


Test patch:
diff --git a/pkg/docker/config_test.go b/pkg/docker/config_test.go
index 2c2b841..001b2d6 100644
--- a/pkg/docker/config_test.go
+++ b/pkg/docker/config_test.go
@@ -92,4 +92,3 @@ func TestReadCredentialsFromBytes(t *testing.T) {
 
 	}
 }
-
diff --git a/pkg/find/vulnerabilities/crd/writer_test.go b/pkg/find/vulnerabilities/crd/writer_test.go
new file mode 100644
index 0000000..03c1cd2
--- /dev/null
+++ b/pkg/find/vulnerabilities/crd/writer_test.go
@@ -0,0 +1,92 @@
+package crd
+
+import (
+	"context"
+	"testing"
+
+	"github.com/aquasecurity/starboard/pkg/find/vulnerabilities"
+
+	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
+	"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"
+	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+var (
+	vulnerabilityReport01 = v1alpha1.VulnerabilityReport{
+		Vulnerabilities: []v1alpha1.VulnerabilityItem{
+			{VulnerabilityID: "CVE-2020-1832"},
+		},
+	}
+	vulnerabilityReport02 = v1alpha1.VulnerabilityReport{
+		Vulnerabilities: []v1alpha1.VulnerabilityItem{
+			{VulnerabilityID: "CVE-2019-8211"},
+		},
+	}
+)
+
+func TestReadWriter_Read(t *testing.T) {
+	clientset := fake.NewSimpleClientset(&v1alpha1.Vulnerability{
+		TypeMeta: meta.TypeMeta{
+			Kind:       "Vulnerability",
+			APIVersion: "v1alpha1",
+		},
+		ObjectMeta: meta.ObjectMeta{
+			Namespace: "my-namespace",
+			Name:      "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: vulnerabilityReport01,
+	}, &v1alpha1.Vulnerability{
+		TypeMeta: meta.TypeMeta{
+			Kind:       "Vulnerability",
+			APIVersion: "v1alpha1",
+		},
+		ObjectMeta: meta.ObjectMeta{
+			Namespace: "my-namespace",
+			Name:      "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: vulnerabilityReport02,
+	}, &v1alpha1.Vulnerability{
+		TypeMeta: meta.TypeMeta{
+			Kind:       "Vulnerability",
+			APIVersion: "v1alpha1",
+		},
+		ObjectMeta: meta.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.VulnerabilityReport{},
+	})
+
+	reports, err := NewReadWriter(clientset).Read(context.TODO(), kube.Object{
+		Kind:      kube.KindDeployment,
+		Name:      "my-deploy",
+		Namespace: "my-namespace",
+	})
+	require.NoError(t, err)
+
+	assert.Equal(t, vulnerabilities.WorkloadVulnerabilities{
+		"my-container-01": vulnerabilityReport01,
+		"my-container-02": vulnerabilityReport02,
+	}, reports)
+}