Repository: ratify-project/ratify
Pull request #1941 (2024-11-20 07:51:38)

feat: enables CRL configuration
# Description
This PR enables CRL configuration which configs the behavior of CRL and CRL fetcher.
Read input from `config.json` and parse into configuration defined in `crl_config.go`
To not change any existing interface, the implementation used a global variable to make the configuration accessible for both KMP and Notation Verifier.

## What this PR does / why we need it:
<!--Please include a summary of the changes and relevant context. -->
- [ ] Enable CRL config input in `config.json`
- [ ] Update CRL config from `CacheEnabled` to `CacheDisabled` to make sure the default value as false
- [ ] Update the Cache config setting in CRL Fetcher creatation


## Which issue(s) this PR fixes *(optional, using `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when the PR gets merged)*:
Fixes # 1888
 
## Type of change

Please delete options that are not relevant.

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Helm Chart Change (any edit/addition/update that is necessary for changes merged to the `main` branch)
- [ ] This change requires a documentation update

# How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Please also list any relevant details for your test configuration

- [ ] Test A
- [ ] Test B

# Checklist:

- [ ] Does the affected code have corresponding tests?
- [ ] Are the changes documented, not just with inline documentation, but also with conceptual documentation such as an overview of a new feature, or task-based documentation like a tutorial? Consider if this change should be announced on your project blog.
- [ ] Does this introduce breaking changes that would require an announcement or bumping the major version?
- [ ] Do all new files have appropriate license header?

# Post Merge Requirements
- [ ] MAINTAINERS: manually trigger the "Publish Package" workflow after merging any PR that indicates `Helm Chart Change`


junczhu: cc\ @yizha1  @FeynmanZhou for a heads-up
junczhu: May consider adding the config to the executor as a global variable.
Shall we have cx update the CRL related configuration in CR dynamically? @yizha1 
junczhu: May consider adding the config to the executor as a global variable.
Shall we have cx access the CRL related configuration. @yizha1 
junczhu: Looking into DCO check

susanshi: this PR is still targeting v1.4 , please tag maintainers for review once this is ready. thanks !
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/ratify-project/ratify/pull/1941?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ratify-project) Report
All modified and coverable lines are covered by tests :white_check_mark:

| [Files with missing lines](https://app.codecov.io/gh/ratify-project/ratify/pull/1941?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ratify-project) | Coverage Δ | |
|---|---|---|
| [config/config.go](https://app.codecov.io/gh/ratify-project/ratify/pull/1941?src=pr&el=tree&filepath=config%2Fconfig.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ratify-project#diff-Y29uZmlnL2NvbmZpZy5nbw==) | `39.02% <ø> (-10.98%)` | :arrow_down: |

... and [36 files with indirect coverage changes](https://app.codecov.io/gh/ratify-project/ratify/pull/1941/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ratify-project)


Patch:
diff --git a/cmd/ratify/cmd/verify.go b/cmd/ratify/cmd/verify.go
index c189fa6..ab24e95 100644
--- a/cmd/ratify/cmd/verify.go
+++ b/cmd/ratify/cmd/verify.go
@@ -91,6 +91,8 @@ func verify(opts verifyCmdOptions) error {
 		logger.GetLogger(context.Background(), logOpt).Warn(taggedReferenceWarning)
 	}
 
+	config.CRLConf = cf.CRLConfig
+
 	stores, err := sf.CreateStoresFromConfig(cf.StoresConfig, config.GetDefaultPluginPath())
 
 	if err != nil {
diff --git a/config/config.go b/config/config.go
index 7bc3e0f..e2a556c 100644
--- a/config/config.go
+++ b/config/config.go
@@ -52,6 +52,7 @@ type Config struct {
 	PoliciesConfig  pcConfig.PoliciesConfig  `json:"policy,omitempty"`
 	VerifiersConfig vfConfig.VerifiersConfig `json:"verifier,omitempty"`
 	ExecutorConfig  exConfig.ExecutorConfig  `json:"executor,omitempty"`
+	CRLConfig       CRLConfig                `json:"crl,omitempty"`
 	LoggerConfig    logger.Config            `json:"logger,omitempty"`
 	fileHash        string                   `json:"-"`
 }
diff --git a/config/configManager.go b/config/configManager.go
index cce09c6..5946e70 100644
--- a/config/configManager.go
+++ b/config/configManager.go
@@ -31,6 +31,7 @@ type GetExecutor func(context.Context) *ef.Executor
 var (
 	configHash string
 	executor   ef.Executor
+	CRLConf    CRLConfig
 )
 
 // Create a executor from configurationFile and setup config file watcher
@@ -43,6 +44,7 @@ func GetExecutorAndWatchForUpdate(configFilePath string) (GetExecutor, error) {
 	}
 
 	configHash = cf.fileHash
+	CRLConf = cf.CRLConfig
 
 	stores, verifiers, policyEnforcer, err := CreateFromConfig(cf)
 
diff --git a/config/crlConfig.go b/config/crlConfig.go
new file mode 100644
index 0000000..6059721
--- /dev/null
+++ b/config/crlConfig.go
@@ -0,0 +1,20 @@
+/*
+Copyright The Ratify Authors.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package config
+
+type CRLConfig struct {
+	CacheEnabled bool `json:"cacheEnabled,omitempty"`
+}
diff --git a/pkg/keymanagementprovider/refresh/kubeRefresh.go b/pkg/keymanagementprovider/refresh/kubeRefresh.go
index cd296e0..b2f1e85 100644
--- a/pkg/keymanagementprovider/refresh/kubeRefresh.go
+++ b/pkg/keymanagementprovider/refresh/kubeRefresh.go
@@ -120,6 +120,6 @@ func (kr *KubeRefresher) Create(config RefresherConfig) (Refresher, error) {
 		ProviderType:            config.ProviderType,
 		ProviderRefreshInterval: config.ProviderRefreshInterval,
 		Resource:                config.Resource,
-		CRLHandler:              nv.NewCRLHandler(),
+		CRLHandler:              nv.CreateCRLHandlerFromConfig(),
 	}, nil
 }
diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go
index 6726f39..b5e6e0d 100644
--- a/pkg/manager/manager.go
+++ b/pkg/manager/manager.go
@@ -82,7 +82,7 @@ func StartServer(httpServerAddress, configFilePath, certDirectory, caCertFile st
 		logrus.Errorf("server start failed %v", fmt.Errorf("error loading config %w", err))
 		os.Exit(1)
 	}
-
+	config.CRLConf = cf.CRLConfig
 	// initialize server
 	server, err := httpserver.NewServer(context.Background(), httpServerAddress, func(ctx context.Context) *ef.Executor {
 		namespace := ctxUtils.GetNamespace(ctx)
diff --git a/pkg/verifier/notation/notation.go b/pkg/verifier/notation/notation.go
index de54857..2453719 100644
--- a/pkg/verifier/notation/notation.go
+++ b/pkg/verifier/notation/notation.go
@@ -106,7 +106,7 @@ func (f *notationPluginVerifierFactory) Create(_ string, verifierConfig config.V
 	if err != nil {
 		return nil, re.ErrorCodePluginInitFailure.WithDetail("Failed to create the Notation Verifier").WithError(err)
 	}
-	verifyService, err := getVerifierService(ctx, conf, pluginDirectory, NewCRLHandler())
+	verifyService, err := getVerifierService(ctx, conf, pluginDirectory, CreateCRLHandlerFromConfig())
 	if err != nil {
 		return nil, re.ErrorCodePluginInitFailure.WithDetail("Failed to create the Notation Verifier").WithError(err)
 	}
diff --git a/pkg/verifier/notation/notationrevocationfactory.go b/pkg/verifier/notation/notationrevocationfactory.go
index 0753d38..80dd621 100644
--- a/pkg/verifier/notation/notationrevocationfactory.go
+++ b/pkg/verifier/notation/notationrevocationfactory.go
@@ -20,6 +20,7 @@ import (
 	"github.com/notaryproject/notation-core-go/revocation"
 	corecrl "github.com/notaryproject/notation-core-go/revocation/crl"
 	"github.com/notaryproject/notation-go/dir"
+	"github.com/ratify-project/ratify/config"
 	re "github.com/ratify-project/ratify/errors"
 )
 
@@ -33,9 +34,12 @@ var (
 	globalFetcher corecrl.Fetcher
 )
 
-// NewCRLHandler returns a new NewCRLHandler instance. Enable cache by default.
-func NewCRLHandler() RevocationFactory {
-	return &CRLHandler{CacheEnabled: true, httpClient: &http.Client{}}
+// CreateCRLHandlerFromConfig creates a new instance of CRLHandler using the configuration
+// provided in config.CRLConf. It returns a RevocationFactory interface.
+// The CRLHandler will have its CacheDisabled field set based on the configuration,
+// and it will use a default HTTP client.
+func CreateCRLHandlerFromConfig() RevocationFactory {
+	return &CRLHandler{CacheEnabled: config.CRLConf.CacheEnabled, httpClient: &http.Client{}}
 }
 
 // NewFetcher creates a new instance of a Fetcher if it doesn't already exist.
@@ -46,9 +50,6 @@ func (h *CRLHandler) NewFetcher() (corecrl.Fetcher, error) {
 	var err error
 	fetcherOnce.Do(func() {
 		globalFetcher, err = CreateCRLFetcher(h.httpClient, dir.PathCRLCache)
-		if err == nil {
-			h.configureCache(globalFetcher)
-		}
 	})
 	if err != nil {
 		return nil, err
@@ -66,14 +67,3 @@ func (h *CRLHandler) NewFetcher() (corecrl.Fetcher, error) {
 func (h *CRLHandler) NewValidator(opts revocation.Options) (revocation.Validator, error) {
 	return revocation.NewWithOptions(opts)
 }
-
-// configureCache disables the cache for the HTTPFetcher if caching is not enabled.
-// If the EnableCache field is set to false, this method sets the Cache field of the
-// HTTPFetcher to nil, effectively disabling caching for HTTP fetch operations.
-func (h *CRLHandler) configureCache(f corecrl.Fetcher) {
-	if !h.CacheEnabled {
-		if httpFetcher, ok := f.(*corecrl.HTTPFetcher); ok {
-			httpFetcher.Cache = nil
-		}
-	}
-}
diff --git a/pkg/verifier/notation/revocationfactory.go b/pkg/verifier/notation/revocationfactory.go
index d0c576f..c64cf94 100644
--- a/pkg/verifier/notation/revocationfactory.go
+++ b/pkg/verifier/notation/revocationfactory.go
@@ -23,6 +23,7 @@ import (
 	corecrl "github.com/notaryproject/notation-core-go/revocation/crl"
 	"github.com/notaryproject/notation-go/dir"
 	"github.com/notaryproject/notation-go/verifier/crl"
+	"github.com/ratify-project/ratify/config"
 	"github.com/ratify-project/ratify/internal/logger"
 )
 
@@ -43,10 +44,14 @@ func CreateCRLFetcher(httpClient *http.Client, cacheRoot string) (corecrl.Fetche
 	if err != nil {
 		return nil, err
 	}
-	crlFetcher.Cache, err = newFileCache(cacheRoot)
+	if !config.CRLConf.CacheEnabled {
+		return crlFetcher, nil
+	}
+	cache, err := newFileCache(cacheRoot)
 	if err != nil {
 		return nil, err
 	}
+	crlFetcher.Cache = cache
 	return crlFetcher, nil
 }
 


Test patch:
diff --git a/pkg/keymanagementprovider/refresh/kubeRefresh_test.go b/pkg/keymanagementprovider/refresh/kubeRefresh_test.go
index eee8ad9..859180e 100644
--- a/pkg/keymanagementprovider/refresh/kubeRefresh_test.go
+++ b/pkg/keymanagementprovider/refresh/kubeRefresh_test.go
@@ -55,7 +55,7 @@ func TestKubeRefresher_Refresh(t *testing.T) {
 			providerRawParameters: []byte(`{"contentType": "certificate", "value": "-----BEGIN CERTIFICATE-----\nMIID2jCCAsKgAwIBAgIQXy2VqtlhSkiZKAGhsnkjbDANBgkqhkiG9w0BAQsFADBvMRswGQYDVQQD\nExJyYXRpZnkuZXhhbXBsZS5jb20xDzANBgNVBAsTBk15IE9yZzETMBEGA1UEChMKTXkgQ29tcGFu\neTEQMA4GA1UEBxMHUmVkbW9uZDELMAkGA1UECBMCV0ExCzAJBgNVBAYTAlVTMB4XDTIzMDIwMTIy\nNDUwMFoXDTI0MDIwMTIyNTUwMFowbzEbMBkGA1UEAxMScmF0aWZ5LmV4YW1wbGUuY29tMQ8wDQYD\nVQQLEwZNeSBPcmcxEzARBgNVBAoTCk15IENvbXBhbnkxEDAOBgNVBAcTB1JlZG1vbmQxCzAJBgNV\nBAgTAldBMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL10bM81\npPAyuraORABsOGS8M76Bi7Guwa3JlM1g2D8CuzSfSTaaT6apy9GsccxUvXd5cmiP1ffna5z+EFmc\nizFQh2aq9kWKWXDvKFXzpQuhyqD1HeVlRlF+V0AfZPvGt3VwUUjNycoUU44ctCWmcUQP/KShZev3\n6SOsJ9q7KLjxxQLsUc4mg55eZUThu8mGB8jugtjsnLUYvIWfHhyjVpGrGVrdkDMoMn+u33scOmrt\nsBljvq9WVo4T/VrTDuiOYlAJFMUae2Ptvo0go8XTN3OjLblKeiK4C+jMn9Dk33oGIT9pmX0vrDJV\nX56w/2SejC1AxCPchHaMuhlwMpftBGkCAwEAAaNyMHAwDgYDVR0PAQH/BAQDAgeAMAkGA1UdEwQC\nMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHwYDVR0jBBgwFoAU0eaKkZj+MS9jCp9Dg1zdv3v/aKww\nHQYDVR0OBBYEFNHmipGY/jEvYwqfQ4Nc3b97/2isMA0GCSqGSIb3DQEBCwUAA4IBAQBNDcmSBizF\nmpJlD8EgNcUCy5tz7W3+AAhEbA3vsHP4D/UyV3UgcESx+L+Nye5uDYtTVm3lQejs3erN2BjW+ds+\nXFnpU/pVimd0aYv6mJfOieRILBF4XFomjhrJOLI55oVwLN/AgX6kuC3CJY2NMyJKlTao9oZgpHhs\nLlxB/r0n9JnUoN0Gq93oc1+OLFjPI7gNuPXYOP1N46oKgEmAEmNkP1etFrEjFRgsdIFHksrmlOlD\nIed9RcQ087VLjmuymLgqMTFX34Q3j7XgN2ENwBSnkHotE9CcuGRW+NuiOeJalL8DBmFXXWwHTKLQ\nPp5g6m1yZXylLJaFLKz7tdMmO355\n-----END CERTIFICATE-----\n"}`),
 			providerType:          "inline",
 			IsRefreshableFunc:     func() bool { return false },
-			NewCRLHandler:         nv.NewCRLHandler(),
+			NewCRLHandler:         nv.CreateCRLHandlerFromConfig(),
 			expectedResult:        ctrl.Result{},
 			expectedError:         false,
 		},
@@ -64,7 +64,7 @@ func TestKubeRefresher_Refresh(t *testing.T) {
 			providerRawParameters:   []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
 			providerType:            "test-kmp",
 			providerRefreshInterval: "",
-			NewCRLHandler:           nv.NewCRLHandler(),
+			NewCRLHandler:           nv.CreateCRLHandlerFromConfig(),
 			IsRefreshableFunc:       func() bool { return true },
 			expectedResult:          ctrl.Result{},
 			expectedError:           false,
@@ -74,7 +74,7 @@ func TestKubeRefresher_Refresh(t *testing.T) {
 			providerRawParameters:   []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
 			providerType:            "test-kmp",
 			providerRefreshInterval: "1m",
-			NewCRLHandler:           nv.NewCRLHandler(),
+			NewCRLHandler:           nv.CreateCRLHandlerFromConfig(),
 			IsRefreshableFunc:       func() bool { return true },
 			expectedResult:          ctrl.Result{RequeueAfter: time.Minute},
 			expectedError:           false,
@@ -84,7 +84,7 @@ func TestKubeRefresher_Refresh(t *testing.T) {
 			providerRawParameters:   []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
 			providerType:            "test-kmp",
 			providerRefreshInterval: "1mm",
-			NewCRLHandler:           nv.NewCRLHandler(),
+			NewCRLHandler:           nv.CreateCRLHandlerFromConfig(),
 			IsRefreshableFunc:       func() bool { return true },
 			expectedResult:          ctrl.Result{},
 			expectedError:           true,
@@ -98,7 +98,7 @@ func TestKubeRefresher_Refresh(t *testing.T) {
 			providerRawParameters: []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
 			providerType:          "test-kmp-error",
 			IsRefreshableFunc:     func() bool { return true },
-			NewCRLHandler:         nv.NewCRLHandler(),
+			NewCRLHandler:         nv.CreateCRLHandlerFromConfig(),
 			expectedError:         true,
 		},
 		{
@@ -110,7 +110,7 @@ func TestKubeRefresher_Refresh(t *testing.T) {
 			providerRawParameters: []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
 			providerType:          "test-kmp-error",
 			IsRefreshableFunc:     func() bool { return true },
-			NewCRLHandler:         nv.NewCRLHandler(),
+			NewCRLHandler:         nv.CreateCRLHandlerFromConfig(),
 			expectedError:         true,
 		},
 		{
@@ -124,7 +124,7 @@ func TestKubeRefresher_Refresh(t *testing.T) {
 			providerType:            "test-kmp",
 			providerRefreshInterval: "1m",
 			IsRefreshableFunc:       func() bool { return true },
-			NewCRLHandler:           &MockCRLHandler{CacheEnabled: true, httpClient: &http.Client{}},
+			NewCRLHandler:           &MockCRLHandler{CacheDisabled: false, httpClient: &http.Client{}},
 			expectedResult:          ctrl.Result{RequeueAfter: time.Minute},
 			expectedError:           false,
 		},
@@ -172,8 +172,8 @@ func TestKubeRefresher_Refresh(t *testing.T) {
 }
 
 type MockCRLHandler struct {
-	CacheEnabled bool
-	httpClient   *http.Client
+	CacheDisabled bool
+	httpClient    *http.Client
 }
 
 func (h *MockCRLHandler) NewFetcher() (corecrl.Fetcher, error) {
@@ -187,7 +187,7 @@ func (h *MockCRLHandler) NewValidator(_ revocation.Options) (revocation.Validato
 func TestKubeRefresher_GetResult(t *testing.T) {
 	kr := &KubeRefresher{
 		Result:     ctrl.Result{RequeueAfter: time.Minute},
-		CRLHandler: nv.NewCRLHandler(),
+		CRLHandler: nv.CreateCRLHandlerFromConfig(),
 	}
 
 	result := kr.GetResult()
@@ -203,7 +203,7 @@ func TestKubeRefresher_GetStatus(t *testing.T) {
 			"attribute1": "value1",
 			"attribute2": "value2",
 		},
-		CRLHandler: nv.NewCRLHandler(),
+		CRLHandler: nv.CreateCRLHandlerFromConfig(),
 	}
 
 	status := kr.GetStatus()
@@ -252,7 +252,7 @@ func TestKubeRefresher_Create(t *testing.T) {
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			kr := &KubeRefresher{CRLHandler: nv.NewCRLHandler()}
+			kr := &KubeRefresher{CRLHandler: nv.CreateCRLHandlerFromConfig()}
 			refresher, err := kr.Create(tt.config)
 			if err != nil {
 				t.Fatalf("Expected no error, but got %v", err)
diff --git a/pkg/verifier/notation/notationrevocationfactory_test.go b/pkg/verifier/notation/notationrevocationfactory_test.go
index ad82c8a..1cbd43e 100644
--- a/pkg/verifier/notation/notationrevocationfactory_test.go
+++ b/pkg/verifier/notation/notationrevocationfactory_test.go
@@ -14,21 +14,18 @@
 package notation
 
 import (
-	"context"
 	"net/http"
 	"runtime"
 	"testing"
 
 	"github.com/notaryproject/notation-core-go/revocation"
-	corecrl "github.com/notaryproject/notation-core-go/revocation/crl"
 	"github.com/notaryproject/notation-go/dir"
-	"github.com/notaryproject/notation-go/verifier/crl"
 	re "github.com/ratify-project/ratify/errors"
 	"github.com/stretchr/testify/assert"
 )
 
 func TestNewRevocationFactoryImpl(t *testing.T) {
-	factory := NewCRLHandler()
+	factory := CreateCRLHandlerFromConfig()
 	assert.NotNil(t, factory)
 }
 
@@ -76,7 +73,7 @@ func TestNewFetcher(t *testing.T) {
 }
 
 func TestNewValidator(t *testing.T) {
-	factory := NewCRLHandler()
+	factory := CreateCRLHandlerFromConfig()
 	opts := revocation.Options{}
 
 	validator, err := factory.NewValidator(opts)
@@ -112,54 +109,3 @@ func TestNewFileCache(t *testing.T) {
 		})
 	}
 }
-func TestConfigureCache(t *testing.T) {
-	testCache, _ := crl.NewFileCache(dir.PathCRLCache)
-	tests := []struct {
-		name         string
-		cacheEnabled bool
-		fetcher      corecrl.Fetcher
-		expectCache  bool
-	}{
-		{
-			name:         "cache enabled",
-			cacheEnabled: true,
-			fetcher:      &corecrl.HTTPFetcher{Cache: testCache},
-			expectCache:  true,
-		},
-		{
-			name:         "cache disabled",
-			cacheEnabled: false,
-			fetcher:      &corecrl.HTTPFetcher{Cache: testCache},
-			expectCache:  false,
-		},
-		{
-			name:         "non-HTTP fetcher",
-			cacheEnabled: false,
-			fetcher:      &mockFetcher{},
-			expectCache:  false,
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			handler := &CRLHandler{
-				CacheEnabled: tt.cacheEnabled,
-			}
-			handler.configureCache(tt.fetcher)
-
-			if httpFetcher, ok := tt.fetcher.(*corecrl.HTTPFetcher); ok {
-				if tt.expectCache {
-					assert.NotNil(t, httpFetcher.Cache)
-				} else {
-					assert.Nil(t, httpFetcher.Cache)
-				}
-			}
-		})
-	}
-}
-
-type mockFetcher struct{}
-
-func (m *mockFetcher) Fetch(_ context.Context, _ string) (*corecrl.Bundle, error) {
-	return nil, nil
-}
diff --git a/pkg/verifier/notation/revocationfactory_test.go b/pkg/verifier/notation/revocationfactory_test.go
index 8b29503..b443c21 100644
--- a/pkg/verifier/notation/revocationfactory_test.go
+++ b/pkg/verifier/notation/revocationfactory_test.go
@@ -21,26 +21,10 @@ import (
 	"testing"
 
 	corecrl "github.com/notaryproject/notation-core-go/revocation/crl"
+	"github.com/ratify-project/ratify/config"
 	"github.com/stretchr/testify/assert"
 )
 
-func TestCRLNewFetcher(t *testing.T) {
-	httpClient := &http.Client{}
-	cacheRoot := "/tmp/cache"
-
-	t.Run("successful fetcher creation", func(t *testing.T) {
-		fetcher, err := CreateCRLFetcher(httpClient, cacheRoot)
-		assert.NoError(t, err)
-		assert.NotNil(t, fetcher)
-	})
-
-	t.Run("error in creating HTTP fetcher", func(t *testing.T) {
-		// Simulate error by passing nil httpClient
-		fetcher, err := CreateCRLFetcher(nil, cacheRoot)
-		assert.Error(t, err)
-		assert.Nil(t, fetcher)
-	})
-}
 func TestSupportCRL(t *testing.T) {
 	t.Run("certificate with CRL distribution points", func(t *testing.T) {
 		cert := &x509.Certificate{
@@ -128,6 +112,34 @@ func TestIntermittentFailCacheCRL(t *testing.T) {
 	})
 }
 
+func TestCreateCRLFetcher(t *testing.T) {
+	httpClient := &http.Client{}
+	cacheRoot := "/tmp/cache"
+
+	t.Run("successful fetcher creation without cache", func(t *testing.T) {
+		// Disable cache
+		config.CRLConf.CacheEnabled = false
+		fetcher, err := CreateCRLFetcher(httpClient, cacheRoot)
+		assert.NoError(t, err)
+		assert.NotNil(t, fetcher)
+	})
+
+	t.Run("successful fetcher creation with cache", func(t *testing.T) {
+		// Enable cache
+		config.CRLConf.CacheEnabled = true
+		fetcher, err := CreateCRLFetcher(httpClient, cacheRoot)
+		assert.NoError(t, err)
+		assert.NotNil(t, fetcher)
+	})
+
+	t.Run("error in creating HTTP fetcher", func(t *testing.T) {
+		// Simulate error by passing nil httpClient
+		fetcher, err := CreateCRLFetcher(nil, cacheRoot)
+		assert.Error(t, err)
+		assert.Nil(t, fetcher)
+	})
+}
+
 // MockFetcher is a mock implementation of corecrl.Fetcher for testing purposes
 type MockFetcher struct {
 	flag      bool
diff --git a/test/bats/cli-test.bats b/test/bats/cli-test.bats
index 3732063..94b42dd 100644
--- a/test/bats/cli-test.bats
+++ b/test/bats/cli-test.bats
@@ -41,14 +41,13 @@ load helpers
     assert_cmd_verify_failure
 
     delete_crl_cache
-
+    check_crl_cache_deleted
     unrevoke_crl
 
     run bin/ratify verify -c $RATIFY_DIR/config_notation_crl.json -s $TEST_REGISTRY/notation:crl
     assert_cmd_verify_success
 
-    check_crl_cache
-    assert_success
+    check_crl_cache_created
 }
 
 @test "notation verifier with type test" {
diff --git a/test/bats/helpers.bash b/test/bats/helpers.bash
index e849aaa..af1a13d 100644
--- a/test/bats/helpers.bash
+++ b/test/bats/helpers.bash
@@ -130,8 +130,16 @@ delete_crl_cache() {
   rm -rf $HOME/.cache/notation/crl
 }
 
-check_crl_cache() {
+check_crl_cache_deleted() {
   if [[ -d "$HOME/.cache/notation/crl" ]]; then
-    return 0
+    echo "The directory exists."
+    return 1
+  fi
+}
+
+check_crl_cache_created() {
+  if [[ ! -d "$HOME/.cache/notation/crl" ]]; then
+    echo "The directory does not exist."
+    return 1
   fi
 }
\ No newline at end of file
diff --git a/test/bats/tests/config/config_notation_crl.json b/test/bats/tests/config/config_notation_crl.json
index 3fb4aea..cc038e1 100644
--- a/test/bats/tests/config/config_notation_crl.json
+++ b/test/bats/tests/config/config_notation_crl.json
@@ -46,5 +46,8 @@
                 }
             }
         ]
+    },
+    "crl": {
+        "cacheEnabled": true
     }
 }
\ No newline at end of file