From 7cf7654d8a0dd9c0b6e866aaa57048af5097be33 Mon Sep 17 00:00:00 2001 From: smtan Date: Thu, 12 Sep 2024 16:46:42 +0800 Subject: [PATCH 1/3] Convert k8s metadata to slice --- pkg/k8s/report/report.go | 16 +++++--- pkg/k8s/report/report_test.go | 75 +++++++++++++++++++++-------------- 2 files changed, 55 insertions(+), 36 deletions(-) diff --git a/pkg/k8s/report/report.go b/pkg/k8s/report/report.go index e71c218bf864..b52391ec8239 100644 --- a/pkg/k8s/report/report.go +++ b/pkg/k8s/report/report.go @@ -57,9 +57,9 @@ type Resource struct { Namespace string `json:",omitempty"` Kind string Name string - Metadata types.Metadata `json:",omitempty"` - Results types.Results `json:",omitempty"` - Error string `json:",omitempty"` + Metadata []types.Metadata `json:",omitempty"` + Results types.Results `json:",omitempty"` + Error string `json:",omitempty"` // original report Report types.Report `json:"-"` @@ -99,11 +99,15 @@ func (r Report) consolidate() ConsolidatedReport { key := v.fullname() if res, ok := index[key]; ok { + // Combine metadata + metadata := lo.UniqBy(append(res.Metadata, v.Metadata...), func(x types.Metadata) string { + return x.ImageID + }) index[key] = Resource{ Namespace: res.Namespace, Kind: res.Kind, Name: res.Name, - Metadata: res.Metadata, + Metadata: metadata, Results: append(res.Results, v.Results...), Error: res.Error, } @@ -214,7 +218,7 @@ func infraResource(misConfig Resource) bool { func CreateResource(artifact *artifacts.Artifact, report types.Report, err error) Resource { r := createK8sResource(artifact, report.Results) - r.Metadata = report.Metadata + r.Metadata = []types.Metadata{report.Metadata} r.Report = report // if there was any error during the scan if err != nil { @@ -244,7 +248,7 @@ func createK8sResource(artifact *artifacts.Artifact, scanResults types.Results) Namespace: artifact.Namespace, Kind: artifact.Kind, Name: artifact.Name, - Metadata: types.Metadata{}, + Metadata: []types.Metadata{}, Results: results, Report: types.Report{ Results: results, diff --git a/pkg/k8s/report/report_test.go b/pkg/k8s/report/report_test.go index e9e9ae5e3a91..d42e4f3f6f47 100644 --- a/pkg/k8s/report/report_test.go +++ b/pkg/k8s/report/report_test.go @@ -14,12 +14,15 @@ var ( Namespace: "default", Kind: "Deploy", Name: "orion", - Metadata: types.Metadata{ - RepoTags: []string{ - "alpine:3.14", - }, - RepoDigests: []string{ - "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + Metadata: []types.Metadata{ + { + ImageID: "123", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, }, }, Results: types.Results{ @@ -69,12 +72,15 @@ var ( Namespace: "default", Kind: "Deploy", Name: "orion", - Metadata: types.Metadata{ - RepoTags: []string{ - "alpine:3.14", - }, - RepoDigests: []string{ - "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + Metadata: []types.Metadata{ + { + ImageID: "123", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, }, }, Results: types.Results{ @@ -117,12 +123,15 @@ var ( Namespace: "default", Kind: "Deploy", Name: "orion", - Metadata: types.Metadata{ - RepoTags: []string{ - "alpine:3.14", - }, - RepoDigests: []string{ - "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + Metadata: []types.Metadata{ + { + ImageID: "123", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, }, }, Results: types.Results{ @@ -204,12 +213,15 @@ var ( Namespace: "default", Kind: "Cronjob", Name: "hello", - Metadata: types.Metadata{ - RepoTags: []string{ - "alpine:3.14", - }, - RepoDigests: []string{ - "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + Metadata: []types.Metadata{ + { + ImageID: "123", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, }, }, Results: types.Results{ @@ -221,12 +233,15 @@ var ( Namespace: "default", Kind: "Pod", Name: "prometheus", - Metadata: types.Metadata{ - RepoTags: []string{ - "alpine:3.14", - }, - RepoDigests: []string{ - "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + Metadata: []types.Metadata{ + { + ImageID: "123", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, }, }, Results: types.Results{ From c99c6247293256225d2f977ca30f021e2354184f Mon Sep 17 00:00:00 2001 From: smtan Date: Thu, 12 Sep 2024 17:31:48 +0800 Subject: [PATCH 2/3] Add test for multi image pod scenario --- pkg/k8s/report/report_test.go | 138 ++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/pkg/k8s/report/report_test.go b/pkg/k8s/report/report_test.go index d42e4f3f6f47..0ce8cfa56128 100644 --- a/pkg/k8s/report/report_test.go +++ b/pkg/k8s/report/report_test.go @@ -1,6 +1,7 @@ package report import ( + "reflect" "testing" "github.com/stretchr/testify/assert" @@ -119,6 +120,104 @@ var ( }, } + image1WithVulns = Resource{ + Namespace: "default", + Kind: "Pod", + Name: "multi-image-pod", + Metadata: []types.Metadata{ + { + ImageID: "image1", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, + }, + }, + Results: types.Results{ + { + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2022-1111", + Vulnerability: dbTypes.Vulnerability{Severity: "LOW"}, + }, + }, + }, + }, + } + + image2WithVulns = Resource{ + Namespace: "default", + Kind: "Pod", + Name: "multi-image-pod", + Metadata: []types.Metadata{ + { + ImageID: "image2", + RepoTags: []string{ + "alpine:3.17.3", + }, + RepoDigests: []string{ + "alpine@sha256:124c7d2707904eea7431fffe91522a01e5a861a624ee31d03372cc1d138a3126", + }, + }, + }, + Results: types.Results{ + { + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2022-2222", + Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"}, + }, + }, + }, + }, + } + + multiImagePodWithVulns = Resource{ + Namespace: "default", + Kind: "Pod", + Name: "multi-image-pod", + Metadata: []types.Metadata{ + { + ImageID: "image1", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, + }, + { + ImageID: "image2", + RepoTags: []string{ + "alpine:3.17.3", + }, + RepoDigests: []string{ + "alpine@sha256:124c7d2707904eea7431fffe91522a01e5a861a624ee31d03372cc1d138a3126", + }, + }, + }, + Results: types.Results{ + { + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2022-1111", + Vulnerability: dbTypes.Vulnerability{Severity: "LOW"}, + }, + }, + }, + { + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2022-2222", + Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"}, + }, + }, + }, + }, + } + deployOrionWithBothVulnsAndMisconfigs = Resource{ Namespace: "default", Kind: "Deploy", @@ -392,6 +491,45 @@ func TestReport_consolidate(t *testing.T) { } } +func TestReport_consolidateMultiImagePod(t *testing.T) { + tests := []struct { + name string + report Report + expectedFindings map[string]Resource + }{ + { + name: "report with multi image pod containing vulnerabilities", + report: Report{ + Resources: []Resource{ + image1WithVulns, + image2WithVulns, + }, + }, + expectedFindings: map[string]Resource{ + "default/pod/multi-image-pod": multiImagePodWithVulns, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + consolidateReport := tt.report.consolidate() + for _, f := range consolidateReport.Findings { + key := f.fullname() + + expected, found := tt.expectedFindings[key] + if !found { + t.Errorf("key not found: %s", key) + } + + assert.True(t, reflect.DeepEqual(expected.Metadata, f.Metadata)) + + assert.True(t, reflect.DeepEqual(expected.Results, f.Results)) + } + }) + } +} + func TestResource_fullname(t *testing.T) { tests := []struct { expected string From ed599f1ae16da89793bc0c0a172a81706e0b6c85 Mon Sep 17 00:00:00 2001 From: smtan Date: Thu, 19 Sep 2024 14:31:09 +0800 Subject: [PATCH 3/3] Simplify test --- pkg/k8s/report/report_test.go | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/pkg/k8s/report/report_test.go b/pkg/k8s/report/report_test.go index 0ce8cfa56128..1a984eb71b23 100644 --- a/pkg/k8s/report/report_test.go +++ b/pkg/k8s/report/report_test.go @@ -1,7 +1,6 @@ package report import ( - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -472,31 +471,6 @@ func TestReport_consolidate(t *testing.T) { "default/cronjob/hello": cronjobHelloWithVulns, }, }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - consolidateReport := tt.report.consolidate() - for _, f := range consolidateReport.Findings { - key := f.fullname() - - expected, found := tt.expectedFindings[key] - if !found { - t.Errorf("key not found: %s", key) - } - - assert.Equal(t, expected, f) - } - }) - } -} - -func TestReport_consolidateMultiImagePod(t *testing.T) { - tests := []struct { - name string - report Report - expectedFindings map[string]Resource - }{ { name: "report with multi image pod containing vulnerabilities", report: Report{ @@ -522,9 +496,7 @@ func TestReport_consolidateMultiImagePod(t *testing.T) { t.Errorf("key not found: %s", key) } - assert.True(t, reflect.DeepEqual(expected.Metadata, f.Metadata)) - - assert.True(t, reflect.DeepEqual(expected.Results, f.Results)) + assert.Equal(t, expected, f) } }) }