diff --git a/pkg/engine/image_verify_test.go b/pkg/engine/image_verify_test.go index 25dec19112..604a737970 100644 --- a/pkg/engine/image_verify_test.go +++ b/pkg/engine/image_verify_test.go @@ -212,6 +212,7 @@ var cosignTestPolicy = `{ "imageReferences": [ "ghcr.io/kyverno/test-verify-image:*" ], + "useCache": true, "attestors": [ { "entries": [ @@ -266,6 +267,7 @@ var cosignTestPolicyUpdated = `{ "imageReferences": [ "ghcr.io/kyverno/test-verify-image:*" ], + "useCache": true, "attestors": [ { "entries": [ @@ -837,7 +839,6 @@ var testNestedAttestorPolicy = ` ` func Test_NestedAttestors(t *testing.T) { - policy := strings.Replace(testNestedAttestorPolicy, "KEY1", testVerifyImageKey, -1) policy = strings.Replace(policy, "KEY2", testVerifyImageKey, -1) policy = strings.Replace(policy, "COUNT", "0", -1) @@ -1112,6 +1113,30 @@ func Test_ImageVerifyCacheCosign(t *testing.T) { assert.Check(t, secondOperationTime < firstOperationTime/10, "cache entry is valid, so image verification should be from cache.", firstOperationTime, secondOperationTime) } +func Test_ImageVerifyCacheDisabled(t *testing.T) { + opts := []imageverifycache.Option{ + imageverifycache.WithCacheEnableFlag(false), + imageverifycache.WithMaxSize(1000), + imageverifycache.WithTTLDuration(24 * time.Hour), + } + imageVerifyCache, err := imageverifycache.New(opts...) + assert.NilError(t, err) + + image := "ghcr.io/kyverno/test-verify-image:signed" + policyContext := buildContext(t, cosignTestPolicy, cosignTestResource, "") + + start := time.Now() + er, ivm := testImageVerifyCache(imageVerifyCache, context.TODO(), registryclient.NewOrDie(), nil, policyContext, cfg) + firstOperationTime := time.Since(start) + errorAssertionUtil(t, image, ivm, er) + + start = time.Now() + er, ivm = testImageVerifyCache(imageVerifyCache, context.TODO(), registryclient.NewOrDie(), nil, policyContext, cfg) + secondOperationTime := time.Since(start) + errorAssertionUtil(t, image, ivm, er) + assert.Check(t, secondOperationTime > firstOperationTime/10 && secondOperationTime < firstOperationTime*10, "cache is disabled, so image verification should not be from cache.", firstOperationTime, secondOperationTime) +} + func Test_ImageVerifyCacheExpiredCosign(t *testing.T) { opts := []imageverifycache.Option{ imageverifycache.WithCacheEnableFlag(true), @@ -1193,6 +1218,7 @@ var verifyImageNotaryPolicy = `{ "imageReferences": [ "ghcr.io/kyverno/test-verify-image*" ], + "useCache": true, "attestors": [ { "count": 1, @@ -1242,6 +1268,7 @@ var verifyImageNotaryUpdatedPolicy = `{ "imageReferences": [ "ghcr.io/kyverno/test-verify-image*" ], + "useCache": true, "attestors": [ { "count": 1, diff --git a/pkg/engine/internal/imageverifier.go b/pkg/engine/internal/imageverifier.go index a628503fed..5718b157de 100644 --- a/pkg/engine/internal/imageverifier.go +++ b/pkg/engine/internal/imageverifier.go @@ -261,7 +261,7 @@ func (iv *ImageVerifier) Verify( start := time.Now() isInCache := false if iv.ivCache != nil { - found, err := iv.ivCache.Get(ctx, iv.policyContext.Policy(), iv.rule.Name, image) + found, err := iv.ivCache.Get(ctx, iv.policyContext.Policy(), iv.rule.Name, image, imageVerify.UseCache) if err != nil { iv.logger.Error(err, "error occurred during cache get") } else { @@ -280,7 +280,7 @@ func (iv *ImageVerifier) Verify( ruleResp, digest = iv.verifyImage(ctx, imageVerify, imageInfo, cfg) if ruleResp != nil && ruleResp.Status() == engineapi.RuleStatusPass { if iv.ivCache != nil { - setted, err := iv.ivCache.Set(ctx, iv.policyContext.Policy(), iv.rule.Name, image) + setted, err := iv.ivCache.Set(ctx, iv.policyContext.Policy(), iv.rule.Name, image, imageVerify.UseCache) if err != nil { iv.logger.Error(err, "error occurred during cache set") } else { diff --git a/pkg/imageverifycache/client.go b/pkg/imageverifycache/client.go index a64805c586..4d97896644 100644 --- a/pkg/imageverifycache/client.go +++ b/pkg/imageverifycache/client.go @@ -91,8 +91,12 @@ func generateKey(policy kyvernov1.PolicyInterface, ruleName string, imageRef str return string(policy.GetUID()) + ";" + policy.GetResourceVersion() + ";" + ruleName + ";" + imageRef } -func (c *cache) Set(ctx context.Context, policy kyvernov1.PolicyInterface, ruleName string, imageRef string) (bool, error) { +func (c *cache) Set(ctx context.Context, policy kyvernov1.PolicyInterface, ruleName string, imageRef string, useCache bool) (bool, error) { if !c.isCacheEnabled { + // If cache is globally disabled just return + return false, nil + } else if !useCache { + // Else If enabled globally then return if locally disabled return false, nil } key := generateKey(policy, ruleName, imageRef) @@ -105,8 +109,12 @@ func (c *cache) Set(ctx context.Context, policy kyvernov1.PolicyInterface, ruleN return false, nil } -func (c *cache) Get(ctx context.Context, policy kyvernov1.PolicyInterface, ruleName string, imageRef string) (bool, error) { +func (c *cache) Get(ctx context.Context, policy kyvernov1.PolicyInterface, ruleName string, imageRef string, useCache bool) (bool, error) { if !c.isCacheEnabled { + // If cache is globally disabled just return + return false, nil + } else if !useCache { + // Else If enabled globally then return if locally disabled return false, nil } key := generateKey(policy, ruleName, imageRef) diff --git a/pkg/imageverifycache/interface.go b/pkg/imageverifycache/interface.go index f521c6b0d3..4ebfd6fcaa 100644 --- a/pkg/imageverifycache/interface.go +++ b/pkg/imageverifycache/interface.go @@ -10,9 +10,9 @@ type Client interface { // Set Adds an image to the cache. The image is considered to be verified for the given rule in the policy // The entry outomatically expires after sometime // Returns true when the cache entry is added - Set(ctx context.Context, policy kyvernov1.PolicyInterface, ruleName string, imageRef string) (bool, error) + Set(ctx context.Context, policy kyvernov1.PolicyInterface, ruleName string, imageRef string, useCache bool) (bool, error) // Get Searches for the image verified using the rule in the policy in the cache // Returns true when the cache entry is found - Get(ctx context.Context, policy kyvernov1.PolicyInterface, ruleName string, imagerRef string) (bool, error) + Get(ctx context.Context, policy kyvernov1.PolicyInterface, ruleName string, imagerRef string, useCache bool) (bool, error) }