From 4796e1b999824c643ebfde4b2d1486caff23af1c Mon Sep 17 00:00:00 2001 From: Dmitry Danchenko Date: Thu, 27 Feb 2025 02:06:04 +0200 Subject: [PATCH] fix: parseImageRef tag absence issue when digest in imageRef (#2418) * Add tests for ParseImageRef * Added tag calculation * Remove unnecessary digest calculation * update tests --------- Co-authored-by: Simar --- pkg/plugins/trivy/plugin.go | 5 +- pkg/plugins/trivy/plugin_test.go | 151 ++++++++++++++++++++++++++++++- 2 files changed, 151 insertions(+), 5 deletions(-) diff --git a/pkg/plugins/trivy/plugin.go b/pkg/plugins/trivy/plugin.go index 7ff32570d..965e2bf67 100644 --- a/pkg/plugins/trivy/plugin.go +++ b/pkg/plugins/trivy/plugin.go @@ -155,7 +155,7 @@ func (p *plugin) ParseReportData(ctx trivyoperator.PluginContext, imageRef strin imageDigest := p.getImageDigest(reports) - registry, artifact, err := p.parseImageRef(imageRef, imageDigest) + registry, artifact, err := ParseImageRef(imageRef, imageDigest) if err != nil { return vulnReport, secretReport, nil, err } @@ -213,7 +213,7 @@ func (p *plugin) NewConfigForConfigAudit(ctx trivyoperator.PluginContext) (confi return getConfig(ctx) } -func (p *plugin) parseImageRef(imageRef, imageDigest string) (v1alpha1.Registry, v1alpha1.Artifact, error) { +func ParseImageRef(imageRef, imageDigest string) (v1alpha1.Registry, v1alpha1.Artifact, error) { ref, err := containerimage.ParseReference(imageRef) if err != nil { return v1alpha1.Registry{}, v1alpha1.Artifact{}, err @@ -229,6 +229,7 @@ func (p *plugin) parseImageRef(imageRef, imageDigest string) (v1alpha1.Registry, artifact.Tag = t.TagStr() case containerimage.Digest: artifact.Digest = t.DigestStr() + artifact.Tag = strings.TrimPrefix(strings.TrimSuffix(strings.TrimPrefix(imageRef, ref.Context().Name()), "@"+artifact.Digest), ":") } if artifact.Digest == "" { artifact.Digest = imageDigest diff --git a/pkg/plugins/trivy/plugin_test.go b/pkg/plugins/trivy/plugin_test.go index ad0b8a719..856fa9b27 100644 --- a/pkg/plugins/trivy/plugin_test.go +++ b/pkg/plugins/trivy/plugin_test.go @@ -83,7 +83,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) { expectedJobSpec corev1.PodSpec }{ { - name: "Standalone mode without insecure registry", + name: "Standalone mode without insecure expectedRegistry", trivyOperatorConfig: map[string]string{ trivyoperator.KeyVulnerabilityScannerEnabled: "true", trivyoperator.KeyExposedSecretsScannerEnabled: "true", @@ -371,7 +371,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) { }, }, { - name: "Standalone mode with insecure registry", + name: "Standalone mode with insecure expectedRegistry", trivyOperatorConfig: map[string]string{ trivyoperator.KeyVulnerabilityScannerEnabled: "false", trivyoperator.KeyExposedSecretsScannerEnabled: "true", @@ -659,7 +659,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) { }, }, { - name: "Standalone mode with non-SSL registry", + name: "Standalone mode with non-SSL expectedRegistry", trivyOperatorConfig: map[string]string{ trivyoperator.KeyVulnerabilityScannerEnabled: "true", trivyoperator.KeyExposedSecretsScannerEnabled: "false", @@ -7629,3 +7629,148 @@ func TestExcludeImages(t *testing.T) { }) } } + +func TestParseImageRef(t *testing.T) { + testCases := []struct { + name string + inputImageRef string + inputImageID string + expectedRegistry v1alpha1.Registry + expectedArtifact v1alpha1.Artifact + expectedErr error + }{ + { + name: "short image ref with latest tag", + inputImageRef: "nginx:v1.3.4", + inputImageID: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + expectedRegistry: v1alpha1.Registry{ + Server: "index.docker.io", + }, + expectedArtifact: v1alpha1.Artifact{ + Repository: "library/nginx", + Digest: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + Tag: "v1.3.4", + }, + }, + { + name: "short repo with default lib with latest tag", + inputImageRef: "library/nginx:v.4.5.6", + inputImageID: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + expectedRegistry: v1alpha1.Registry{ + Server: "index.docker.io", + }, + expectedArtifact: v1alpha1.Artifact{ + Repository: "library/nginx", + Digest: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + Tag: "v.4.5.6", + }, + }, + { + name: "well known image without tag & digest", + inputImageRef: "quay.io/centos/centos", + inputImageID: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + expectedRegistry: v1alpha1.Registry{ + Server: "quay.io", + }, + expectedArtifact: v1alpha1.Artifact{ + Repository: "centos/centos", + Digest: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + Tag: "latest", + }, + }, + { + name: "docker expectedRegistry image ref with tag", + inputImageRef: "docker.io/library/alpine:v2.3.4", + inputImageID: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + expectedRegistry: v1alpha1.Registry{ + Server: "index.docker.io", + }, + expectedArtifact: v1alpha1.Artifact{ + Repository: "library/alpine", + Digest: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + Tag: "v2.3.4", + }, + }, + { + name: "short repo with private repo with tag", + inputImageRef: "my-private-repo.company.com/my-app:1.2.3", + inputImageID: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + expectedRegistry: v1alpha1.Registry{ + Server: "my-private-repo.company.com", + }, + expectedArtifact: v1alpha1.Artifact{ + Repository: "my-app", + Digest: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + Tag: "1.2.3", + }, + }, + { + name: "with tag", + inputImageRef: "quay.io/prometheus-operator/prometheus-operator:v0.63.0", + inputImageID: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + expectedRegistry: v1alpha1.Registry{ + Server: "quay.io", + }, + expectedArtifact: v1alpha1.Artifact{ + Repository: "prometheus-operator/prometheus-operator", + Digest: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + Tag: "v0.63.0", + }, + }, + { + name: "artifact registry image ref with tag", + inputImageRef: "europe-west4-docker.pkg.dev/my-project/my-repo/my-app:1.0.0", + inputImageID: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + expectedRegistry: v1alpha1.Registry{ + Server: "europe-west4-docker.pkg.dev", + }, + expectedArtifact: v1alpha1.Artifact{ + Repository: "my-project/my-repo/my-app", + Digest: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + Tag: "1.0.0", + }, + }, + { + name: "repo with digest", + inputImageRef: "quay.io/prometheus-operator/prometheus-operator@sha256:1420cefd4b20014b3361951c22593de6e9a2476bbbadd1759464eab5bfc0d34f", + inputImageID: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + expectedRegistry: v1alpha1.Registry{ + Server: "quay.io", + }, + expectedArtifact: v1alpha1.Artifact{ + Repository: "prometheus-operator/prometheus-operator", + Digest: "sha256:1420cefd4b20014b3361951c22593de6e9a2476bbbadd1759464eab5bfc0d34f", + Tag: "", + }, + }, + { + name: "private expectedRegistry image ref tag & with digest", + inputImageRef: "my-private-repo.company.com/my-app:some-tag@sha256:1420cefd4b20014b3361951c22593de6e9a2476bbbadd1759464eab5bfc0d34f", + inputImageID: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + expectedRegistry: v1alpha1.Registry{ + Server: "my-private-repo.company.com", + }, + expectedArtifact: v1alpha1.Artifact{ + Repository: "my-app", + Digest: "sha256:1420cefd4b20014b3361951c22593de6e9a2476bbbadd1759464eab5bfc0d34f", + Tag: "some-tag", + }, + }, + { + name: "incorrect input", + inputImageRef: "## some incorrect input ###", + inputImageID: "sha256:2bc57c6bcb194869d18676e003dfed47b87d257fce49667557fb8eb1f324d5d6", + expectedErr: errors.New("could not parse reference: ## some incorrect input ###"), + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + registry, artifact, err := trivy.ParseImageRef(tc.inputImageRef, tc.inputImageID) + if tc.expectedErr != nil { + require.Errorf(t, err, "expected: %v", tc.expectedErr) + } + assert.Equal(t, tc.expectedRegistry, registry) + assert.Equal(t, tc.expectedArtifact, artifact) + }) + } +}