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..1a984eb71b23 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{ @@ -113,16 +119,117 @@ 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", 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 +311,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 +331,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{ @@ -358,6 +471,18 @@ func TestReport_consolidate(t *testing.T) { "default/cronjob/hello": cronjobHelloWithVulns, }, }, + { + 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 {