From b854b272160a5c37234fc5a24887f948e33b40cc Mon Sep 17 00:00:00 2001 From: Matthias Bertschy Date: Mon, 7 Aug 2023 16:10:22 +0200 Subject: [PATCH 1/2] use reference.Parse to parse imageID Signed-off-by: Matthias Bertschy --- internal/tools/tools.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/internal/tools/tools.go b/internal/tools/tools.go index 0dc153c..aa73d43 100644 --- a/internal/tools/tools.go +++ b/internal/tools/tools.go @@ -48,10 +48,17 @@ func sanitize(s string) string { // Each label is sanitized and verified to be a valid DNS1123 label. func LabelsFromImageID(imageID string) map[string]string { labels := map[string]string{} - match := reference.ReferenceRegexp.FindStringSubmatch(imageID) - labels[instanceidhandler.ImageIDMetadataKey] = sanitize(match[0]) - labels[instanceidhandler.ImageNameMetadataKey] = sanitize(match[1]) - labels[instanceidhandler.ImageTagMetadataKey] = sanitize(match[2]) + ref, err := reference.Parse(imageID) + if err != nil { + return labels + } + if named, ok := ref.(reference.Named); ok { + labels[instanceidhandler.ImageIDMetadataKey] = sanitize(named.String()) + labels[instanceidhandler.ImageNameMetadataKey] = sanitize(named.Name()) + } + if tagged, ok := ref.(reference.Tagged); ok { + labels[instanceidhandler.ImageTagMetadataKey] = sanitize(tagged.Tag()) + } // prune invalid labels for key, value := range labels { if errs := validation.IsDNS1123Label(value); len(errs) != 0 { From 5254aa968e82996554cd2bd4c3d67a3b343991f8 Mon Sep 17 00:00:00 2001 From: Matthias Bertschy Date: Tue, 8 Aug 2023 11:34:04 +0200 Subject: [PATCH 2/2] send normalized imageTag to backend Signed-off-by: Matthias Bertschy --- adapters/v1/armo.go | 2 +- adapters/v1/armo_utils.go | 4 +- adapters/v1/armo_utils_test.go | 21 +++++---- adapters/v1/domain_to_armo.go | 4 +- controllers/http.go | 22 +++++----- core/domain/scan.go | 25 ++++++----- internal/tools/tools.go | 8 ++++ internal/tools/tools_test.go | 80 ++++++++++++++++++++++++++++++++++ 8 files changed, 130 insertions(+), 36 deletions(-) diff --git a/adapters/v1/armo.go b/adapters/v1/armo.go index cb58d7e..20db9fe 100644 --- a/adapters/v1/armo.go +++ b/adapters/v1/armo.go @@ -111,7 +111,7 @@ func (a *ArmoAdapter) SendStatus(ctx context.Context, step int) error { ) report.Status = statuses[step] report.Target = fmt.Sprintf("vuln scan:: scanning wlid: %v , container: %v imageTag: %v imageHash: %s", - workload.Wlid, workload.ContainerName, workload.ImageTag, workload.ImageHash) + workload.Wlid, workload.ContainerName, workload.ImageTagNormalized, workload.ImageHash) report.ActionID = strconv.Itoa(lastAction) report.ActionIDN = lastAction report.ActionName = ActionName diff --git a/adapters/v1/armo_utils.go b/adapters/v1/armo_utils.go index 2f2de9e..34b017c 100644 --- a/adapters/v1/armo_utils.go +++ b/adapters/v1/armo_utils.go @@ -152,7 +152,7 @@ func summarize(report v1.ScanResultReport, vulnerabilities []containerscan.Commo ContainerScanID: report.ContainerScanID, WLID: workload.Wlid, ImageID: workload.ImageHash, - ImageTag: workload.ImageTag, + ImageTag: workload.ImageTagNormalized, ClusterName: report.Designators.Attributes[armotypes.AttributeCluster], Namespace: report.Designators.Attributes[armotypes.AttributeNamespace], ContainerName: report.Designators.Attributes[armotypes.AttributeContainerName], @@ -161,7 +161,7 @@ func summarize(report v1.ScanResultReport, vulnerabilities []containerscan.Commo HasRelevancyData: hasRelevancy, } - imageInfo, err := armometadata.ImageTagToImageInfo(workload.ImageTag) + imageInfo, err := armometadata.ImageTagToImageInfo(workload.ImageTagNormalized) if err == nil { summary.Registry = imageInfo.Registry summary.Version = imageInfo.VersionImage diff --git a/adapters/v1/armo_utils_test.go b/adapters/v1/armo_utils_test.go index 8ef98dd..e4b7fd0 100644 --- a/adapters/v1/armo_utils_test.go +++ b/adapters/v1/armo_utils_test.go @@ -214,9 +214,10 @@ func Test_summarize(t *testing.T) { args: args{ report: v1.ScanResultReport{}, workload: domain.ScanCommand{ - ImageHash: imageHash, - Wlid: wlid, - ImageTag: imageTag, + ImageHash: imageHash, + Wlid: wlid, + ImageTag: imageTag, + ImageTagNormalized: imageTag, Session: domain.Session{ JobIDs: jobIDs, }, @@ -318,9 +319,10 @@ func Test_summarize(t *testing.T) { }, }, workload: domain.ScanCommand{ - ImageHash: imageHash, - Wlid: wlid, - ImageTag: imageTag, + ImageHash: imageHash, + Wlid: wlid, + ImageTag: imageTag, + ImageTagNormalized: imageTag, Session: domain.Session{ JobIDs: jobIDs, }, @@ -446,9 +448,10 @@ func Test_summarize(t *testing.T) { }, }, workload: domain.ScanCommand{ - ImageHash: imageHash, - Wlid: wlid, - ImageTag: imageTag, + ImageHash: imageHash, + Wlid: wlid, + ImageTag: imageTag, + ImageTagNormalized: imageTag, Session: domain.Session{ JobIDs: jobIDs, }, diff --git a/adapters/v1/domain_to_armo.go b/adapters/v1/domain_to_armo.go index 970af87..75fd89c 100644 --- a/adapters/v1/domain_to_armo.go +++ b/adapters/v1/domain_to_armo.go @@ -91,7 +91,7 @@ func domainToArmo(ctx context.Context, grypeDocument v1beta1.GrypeDocument, vuln Vulnerability: containerscan.Vulnerability{ Name: match.Vulnerability.ID, ImageID: workload.ImageHash, - ImageTag: workload.ImageTag, + ImageTag: workload.ImageTagNormalized, RelatedPackageName: match.Artifact.Name, PackageVersion: match.Artifact.Version, Link: link, @@ -101,7 +101,7 @@ func domainToArmo(ctx context.Context, grypeDocument v1beta1.GrypeDocument, vuln Fixes: []containerscan.FixedIn{ { Name: match.Vulnerability.Fix.State, - ImgTag: workload.ImageTag, + ImgTag: workload.ImageTagNormalized, Version: version, }, }, diff --git a/controllers/http.go b/controllers/http.go index 20d61b6..50c49c0 100644 --- a/controllers/http.go +++ b/controllers/http.go @@ -12,6 +12,7 @@ import ( "github.com/kubescape/k8s-interface/names" "github.com/kubescape/kubevuln/core/domain" "github.com/kubescape/kubevuln/core/ports" + "github.com/kubescape/kubevuln/internal/tools" "schneider.vip/problem" ) @@ -126,16 +127,17 @@ func (h HTTPController) ScanCVE(c *gin.Context) { func websocketScanCommandToScanCommand(c wssc.WebsocketScanCommand) domain.ScanCommand { command := domain.ScanCommand{ - Credentialslist: c.Credentialslist, - ImageHash: c.ImageHash, - Wlid: c.Wlid, - ImageTag: c.ImageTag, - JobID: c.JobID, - ContainerName: c.ContainerName, - LastAction: c.LastAction, - ParentJobID: c.ParentJobID, - Args: c.Args, - Session: sessionChainToSession(c.Session), + Credentialslist: c.Credentialslist, + ImageHash: c.ImageHash, + Wlid: c.Wlid, + ImageTag: c.ImageTag, + ImageTagNormalized: tools.NormalizeReference(c.ImageTag), + JobID: c.JobID, + ContainerName: c.ContainerName, + LastAction: c.LastAction, + ParentJobID: c.ParentJobID, + Args: c.Args, + Session: sessionChainToSession(c.Session), } if slug, err := names.ImageInfoToSlug(c.ImageTag, c.ImageHash); err == nil { command.ImageSlug = slug diff --git a/core/domain/scan.go b/core/domain/scan.go index 6e959d1..38e2a4d 100644 --- a/core/domain/scan.go +++ b/core/domain/scan.go @@ -30,18 +30,19 @@ type TimestampKey struct{} type WorkloadKey struct{} type ScanCommand struct { - Credentialslist []types.AuthConfig - ImageHash string - ImageSlug string - InstanceID string - Wlid string - ImageTag string - JobID string - ContainerName string - LastAction int - ParentJobID string - Args map[string]interface{} - Session Session + Credentialslist []types.AuthConfig + ImageHash string + ImageSlug string + InstanceID string + Wlid string + ImageTag string + ImageTagNormalized string + JobID string + ContainerName string + LastAction int + ParentJobID string + Args map[string]interface{} + Session Session } type Session struct { diff --git a/internal/tools/tools.go b/internal/tools/tools.go index aa73d43..c8bf44a 100644 --- a/internal/tools/tools.go +++ b/internal/tools/tools.go @@ -105,3 +105,11 @@ func DeleteContents(dir string) error { } return nil } + +func NormalizeReference(ref string) string { + n, err := reference.ParseNormalizedNamed(ref) + if err != nil { + return ref + } + return n.String() +} diff --git a/internal/tools/tools_test.go b/internal/tools/tools_test.go index 1d15ce6..0ba4202 100644 --- a/internal/tools/tools_test.go +++ b/internal/tools/tools_test.go @@ -60,3 +60,83 @@ func TestLabelsFromImageID(t *testing.T) { }) } } + +func TestNormalizeReference(t *testing.T) { + type args struct { + ref string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "image tag", + args: args{ + ref: "nginx:latest", + }, + want: "docker.io/library/nginx:latest", + }, + { + name: "image sha", + args: args{ + ref: "nginx@sha256:73e957703f1266530db0aeac1fd6a3f87c1e59943f4c13eb340bb8521c6041d7", + }, + want: "docker.io/library/nginx@sha256:73e957703f1266530db0aeac1fd6a3f87c1e59943f4c13eb340bb8521c6041d7", + }, + { + name: "image tag sha", + args: args{ + ref: "nginx:latest@sha256:73e957703f1266530db0aeac1fd6a3f87c1e59943f4c13eb340bb8521c6041d7", + }, + want: "docker.io/library/nginx:latest@sha256:73e957703f1266530db0aeac1fd6a3f87c1e59943f4c13eb340bb8521c6041d7", + }, + { + name: "repo image tag", + args: args{ + ref: "docker.io/library/nginx:latest", + }, + want: "docker.io/library/nginx:latest", + }, + { + name: "repo image sha", + args: args{ + ref: "docker.io/library/nginx@sha256:73e957703f1266530db0aeac1fd6a3f87c1e59943f4c13eb340bb8521c6041d7", + }, + want: "docker.io/library/nginx@sha256:73e957703f1266530db0aeac1fd6a3f87c1e59943f4c13eb340bb8521c6041d7", + }, + { + name: "repo image tag sha", + args: args{ + ref: "docker.io/library/nginx:latest@sha256:73e957703f1266530db0aeac1fd6a3f87c1e59943f4c13eb340bb8521c6041d7", + }, + want: "docker.io/library/nginx:latest@sha256:73e957703f1266530db0aeac1fd6a3f87c1e59943f4c13eb340bb8521c6041d7", + }, + { + name: "quay image tag", + args: args{ + ref: "quay.io/kubescape/kubevuln:latest", + }, + want: "quay.io/kubescape/kubevuln:latest", + }, + { + name: "quay image sha", + args: args{ + ref: "quay.io/kubescape/kubevuln@sha256:616d1d4312551b94088deb6ddab232ecabbbff0c289949a0d5f12d4b527c3f8a", + }, + want: "quay.io/kubescape/kubevuln@sha256:616d1d4312551b94088deb6ddab232ecabbbff0c289949a0d5f12d4b527c3f8a", + }, + { + name: "quay image tag sha", + args: args{ + ref: "quay.io/kubescape/kubevuln:latest@sha256:616d1d4312551b94088deb6ddab232ecabbbff0c289949a0d5f12d4b527c3f8a", + }, + want: "quay.io/kubescape/kubevuln:latest@sha256:616d1d4312551b94088deb6ddab232ecabbbff0c289949a0d5f12d4b527c3f8a", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, NormalizeReference(tt.args.ref), "NormalizeReference(%v)", tt.args.ref) + }) + } +}