From 4d4d00c9d7a82f3005ece9d65c37ce87bde01ebe Mon Sep 17 00:00:00 2001
From: Binbin Li <libinbin@microsoft.com>
Date: Tue, 10 Sep 2024 14:24:41 +0800
Subject: [PATCH 1/8] feat: refactor cosign verification error messages (#1750)

---
 pkg/referrerstore/oras/cosign.go        |   4 +-
 pkg/referrerstore/oras/oras.go          |   8 +-
 pkg/verifier/cosign/cosign.go           |  40 +++----
 pkg/verifier/cosign/cosign_test.go      | 137 ++++++++++++++++++++----
 pkg/verifier/cosign/trustpolicies.go    |  20 ++--
 pkg/verifier/cosign/trustpolicy.go      |  44 ++++----
 pkg/verifier/cosign/trustpolicy_test.go |  90 +++++++++++++++-
 7 files changed, 265 insertions(+), 78 deletions(-)

diff --git a/pkg/referrerstore/oras/cosign.go b/pkg/referrerstore/oras/cosign.go
index a60f458ae..3db4b23bb 100644
--- a/pkg/referrerstore/oras/cosign.go
+++ b/pkg/referrerstore/oras/cosign.go
@@ -46,7 +46,7 @@ func getCosignReferences(ctx context.Context, subjectReference common.Reference,
 			return nil, nil
 		}
 		evictOnError(ctx, err, subjectReference.Original)
-		return nil, re.ErrorCodeRepositoryOperationFailure.WithError(err).WithComponentType(re.ReferrerStore)
+		return nil, re.ErrorCodeRepositoryOperationFailure.WithDetail(fmt.Sprintf("Failed to validate the signature of the artifact: %+v", subjectReference)).WithError(err)
 	}
 
 	references = append(references, ocispecs.ReferenceDescriptor{
@@ -64,7 +64,7 @@ func getCosignReferences(ctx context.Context, subjectReference common.Reference,
 func attachedImageTag(subjectReference common.Reference, tagSuffix string) (string, error) {
 	// sha256:d34db33f -> sha256-d34db33f.suffix
 	if subjectReference.Digest.String() == "" {
-		return "", re.ErrorCodeReferenceInvalid.WithComponentType(re.ReferrerStore).WithDetail("Cosign subject digest is empty")
+		return "", re.ErrorCodeReferenceInvalid.WithDetail("The digest of the artifact is empty")
 	}
 	tagStr := strings.ReplaceAll(subjectReference.Digest.String(), ":", "-") + tagSuffix
 	return fmt.Sprintf("%s:%s", subjectReference.Path, tagStr), nil
diff --git a/pkg/referrerstore/oras/oras.go b/pkg/referrerstore/oras/oras.go
index a8462d201..64679dd0a 100644
--- a/pkg/referrerstore/oras/oras.go
+++ b/pkg/referrerstore/oras/oras.go
@@ -208,7 +208,7 @@ func (store *orasStore) GetConfig() *config.StoreConfig {
 func (store *orasStore) ListReferrers(ctx context.Context, subjectReference common.Reference, _ []string, _ string, subjectDesc *ocispecs.SubjectDescriptor) (referrerstore.ListReferrersResult, error) {
 	repository, err := store.createRepository(ctx, store, subjectReference)
 	if err != nil {
-		return referrerstore.ListReferrersResult{}, re.ErrorCodeCreateRepositoryFailure.WithError(err).WithComponentType(re.ReferrerStore)
+		return referrerstore.ListReferrersResult{}, re.ErrorCodeRepositoryOperationFailure.WithDetail("Failed to connect to the remote registry").WithError(err)
 	}
 
 	// resolve subject descriptor if not provided
@@ -260,7 +260,7 @@ func (store *orasStore) GetBlobContent(ctx context.Context, subjectReference com
 
 	repository, err := store.createRepository(ctx, store, subjectReference)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeGetBlobContentFailure.WithDetail("Failed to connect to the remote registry").WithError(err)
 	}
 
 	// create a dummy Descriptor to check the local store cache
@@ -292,10 +292,10 @@ func (store *orasStore) GetBlobContent(ctx context.Context, subjectReference com
 		blobDesc, rc, err := repository.Blobs().FetchReference(ctx, ref)
 		if err != nil {
 			evictOnError(ctx, err, subjectReference.Original)
-			return nil, err
+			return nil, re.ErrorCodeRepositoryOperationFailure.WithDetail("Failed to fetch the artifact metadata from the registry").WithError(err)
 		}
 		if blobContent, err = io.ReadAll(rc); err != nil {
-			return nil, re.ErrorCodeGetBlobContentFailure.WithError(err)
+			return nil, re.ErrorCodeRepositoryOperationFailure.WithDetail("Failed to parse the artifact metadata").WithError(err)
 		}
 
 		// push fetched content to local ORAS cache
diff --git a/pkg/verifier/cosign/cosign.go b/pkg/verifier/cosign/cosign.go
index fb3efd714..cba6a1e9a 100644
--- a/pkg/verifier/cosign/cosign.go
+++ b/pkg/verifier/cosign/cosign.go
@@ -143,17 +143,17 @@ func (f *cosignVerifierFactory) Create(_ string, verifierConfig config.VerifierC
 	logger.GetLogger(context.Background(), logOpt).Debugf("creating cosign verifier with config %v, namespace '%v'", verifierConfig, namespace)
 	verifierName, hasName := verifierConfig[types.Name].(string)
 	if !hasName {
-		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail("missing name in verifier config")
+		return nil, re.ErrorCodeConfigInvalid.WithDetail("The name field is required in the Cosign Verifier configuration")
 	}
 
 	config, err := parseVerifierConfig(verifierConfig)
 	if err != nil {
-		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName)
+		return nil, re.ErrorCodeConfigInvalid.WithDetail("Failed to create the Cosign Verifier").WithError(err)
 	}
 
 	// if key or rekorURL is provided, trustPolicies should not be provided
 	if (config.KeyRef != "" || config.RekorURL != "") && len(config.TrustPolicies) > 0 {
-		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail("'key' and 'rekorURL' are part of cosign legacy configuration and cannot be used with `trustPolicies`")
+		return nil, re.ErrorCodeConfigInvalid.WithDetail("'key' and 'rekorURL' are part of Cosign legacy configuration and cannot be used with `trustPolicies` parameter")
 	}
 
 	var trustPolicies *TrustPolicies
@@ -163,7 +163,7 @@ func (f *cosignVerifierFactory) Create(_ string, verifierConfig config.VerifierC
 		logger.GetLogger(context.Background(), logOpt).Debugf("legacy cosign verifier configuration not found, creating trust policies")
 		trustPolicies, err = CreateTrustPolicies(config.TrustPolicies, verifierName)
 		if err != nil {
-			return nil, err
+			return nil, re.ErrorCodePluginInitFailure.WithDetail("Failed to create the Cosign Verifier").WithError(err)
 		}
 		legacy = false
 	}
@@ -224,18 +224,18 @@ func (v *cosignVerifier) verifyInternal(ctx context.Context, subjectReference co
 	// get the reference manifest (cosign oci image)
 	referenceManifest, err := referrerStore.GetReferenceManifest(ctx, subjectReference, referenceDescriptor)
 	if err != nil {
-		return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to get reference manifest: %w", err)), nil
+		return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyPluginFailure.WithDetail(fmt.Sprintf("Failed to get artifact metadata for %s", referenceDescriptor.Digest)).WithError(err)), nil
 	}
 
 	// manifest must be an OCI Image
 	if referenceManifest.MediaType != imgspec.MediaTypeImageManifest {
-		return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("reference manifest is not an image")), nil
+		return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyPluginFailure.WithDetail("The artifact metadata is not an OCI image")), nil
 	}
 
 	// get the subject image descriptor
 	subjectDesc, err := referrerStore.GetSubjectDescriptor(ctx, subjectReference)
 	if err != nil {
-		return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to create subject hash: %w", err)), nil
+		return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyReferenceFailure.WithDetail(fmt.Sprintf("Failed to validate the Cosign signature of the artifact: %+v", subjectReference)).WithError(err)), nil
 	}
 
 	// create the hash of the subject image descriptor (used as the hashed payload)
@@ -255,23 +255,23 @@ func (v *cosignVerifier) verifyInternal(ctx context.Context, subjectReference co
 		// fetch the blob content of the signature from the referrer store
 		blobBytes, err := referrerStore.GetBlobContent(ctx, subjectReference, blob.Digest)
 		if err != nil {
-			return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to get blob content: %w", err)), nil
+			return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeGetBlobContentFailure.WithDetail(fmt.Sprintf("Failed to get Cosign signature with digest %s", blob.Digest)).WithError(err)), nil
 		}
 		// convert the blob to a static signature
 		staticOpts, err := staticLayerOpts(blob)
 		if err != nil {
-			return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to parse static signature opts: %w", err)), nil
+			return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyPluginFailure.WithDetail(fmt.Sprintf("Failed to parse Cosign signature with digest %s", blob.Digest)).WithError(err)), nil
 		}
 		sig, err := static.NewSignature(blobBytes, blob.Annotations[static.SignatureAnnotationKey], staticOpts...)
 		if err != nil {
-			return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to generate static signature: %w", err)), nil
+			return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to validate the Cosign signature").WithError(err)), nil
 		}
 		if len(keysMap) > 0 {
 			// if keys are found, perform verification with keys
 			var verifications []cosignExtension
 			verifications, hasValidSignature, err = verifyWithKeys(ctx, keysMap, sig, blob.Annotations[static.SignatureAnnotationKey], blobBytes, staticOpts, &cosignOpts, subjectDescHash)
 			if err != nil {
-				return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to verify with keys: %w", err)), nil
+				return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to validate the Cosign signature with keys").WithError(err)), nil
 			}
 			extensionListEntry.Verifications = append(extensionListEntry.Verifications, verifications...)
 		} else {
@@ -295,7 +295,7 @@ func (v *cosignVerifier) verifyInternal(ctx context.Context, subjectReference co
 		), nil
 	}
 
-	errorResult := errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("no valid signatures found"))
+	errorResult := errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("no valid Cosign signatures found"))
 	errorResult.Extensions = Extension{SignatureExtension: sigExtensions, TrustPolicy: trustPolicy.GetName()}
 	return errorResult, nil
 }
@@ -485,7 +485,7 @@ func staticLayerOpts(desc imgspec.Descriptor) ([]static.Option, error) {
 
 // ErrorToVerifyResult returns a verifier result with the error message and isSuccess set to false
 func errorToVerifyResult(name string, verifierType string, err error) verifier.VerifierResult {
-	verifierErr := re.ErrorCodeVerifyReferenceFailure.WithDetail("Verification failed").WithError(err)
+	verifierErr := re.ErrorCodeVerifyReferenceFailure.WithDetail("Failed to validate the Cosign signature").WithError(err)
 	return verifier.NewVerifierResult(
 		"",
 		name,
@@ -540,14 +540,14 @@ func verifyWithKeys(ctx context.Context, keysMap map[PKKey]keymanagementprovider
 		if pubKey.ProviderType == azurekeyvault.ProviderName {
 			hashType, sig, err = processAKVSignature(sigEncoded, sig, pubKey.Key, payload, staticOpts)
 			if err != nil {
-				return verifications, false, fmt.Errorf("failed to process AKV signature: %w", err)
+				return verifications, false, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to validate the Cosign signature generated by AKV").WithError(err)
 			}
 		}
 
 		// return the correct verifier based on public key type and bytes
 		verifier, err := signature.LoadVerifier(pubKey.Key, hashType)
 		if err != nil {
-			return verifications, false, fmt.Errorf("failed to load public key from provider [%s] name [%s] version [%s]: %w", mapKey.Provider, mapKey.Name, mapKey.Version, err)
+			return verifications, false, re.ErrorCodeVerifyPluginFailure.WithDetail(fmt.Sprintf("Failed to load public key from provider [%s] name [%s] version [%s]", mapKey.Provider, mapKey.Name, mapKey.Version)).WithError(err)
 		}
 		cosignOpts.SigVerifier = verifier
 		// verify signature with cosign options + perform bundle verification
@@ -627,17 +627,17 @@ func processAKVSignature(sigEncoded string, staticSig oci.Signature, publicKey c
 		// EC verifiers in cosign have built in ASN.1 decoding, but RSA verifiers do not
 		base64DecodedBytes, err := base64.StdEncoding.DecodeString(sigEncoded)
 		if err != nil {
-			return crypto.SHA256, nil, fmt.Errorf("RSA key check: failed to decode base64 signature: %w", err)
+			return crypto.SHA256, nil, re.ErrorCodeVerifyPluginFailure.WithDetail("RSA key check: failed to decode base64 signature").WithError(err)
 		}
 		// decode ASN.1 signature to raw signature if it is ASN.1 encoded
 		decodedSigBytes, err := decodeASN1Signature(base64DecodedBytes)
 		if err != nil {
-			return crypto.SHA256, nil, fmt.Errorf("RSA key check: failed to decode ASN.1 signature: %w", err)
+			return crypto.SHA256, nil, re.ErrorCodeVerifyPluginFailure.WithDetail("RSA key check: failed to decode ASN.1 signature").WithError(err)
 		}
 		encodedBase64SigBytes := base64.StdEncoding.EncodeToString(decodedSigBytes)
 		staticSig, err = static.NewSignature(payloadBytes, encodedBase64SigBytes, staticOpts...)
 		if err != nil {
-			return crypto.SHA256, nil, fmt.Errorf("RSA key check: failed to generate static signature: %w", err)
+			return crypto.SHA256, nil, re.ErrorCodeVerifyPluginFailure.WithDetail("RSA key check: failed to generate static signature").WithError(err)
 		}
 	case *ecdsa.PublicKey:
 		switch keyType.Curve {
@@ -648,10 +648,10 @@ func processAKVSignature(sigEncoded string, staticSig oci.Signature, publicKey c
 		case elliptic.P521():
 			hashType = crypto.SHA512
 		default:
-			return crypto.SHA256, nil, fmt.Errorf("ECDSA key check: unsupported key curve: %s", keyType.Params().Name)
+			return crypto.SHA256, nil, fmt.Errorf("ECDSA key check: unsupported key curve [%s]", keyType.Params().Name)
 		}
 	default:
-		return crypto.SHA256, nil, fmt.Errorf("unsupported public key type: %T", publicKey)
+		return crypto.SHA256, nil, fmt.Errorf("unsupported public key type [%T]", publicKey)
 	}
 	return hashType, staticSig, nil
 }
diff --git a/pkg/verifier/cosign/cosign_test.go b/pkg/verifier/cosign/cosign_test.go
index b4e368617..aea1cf5a7 100644
--- a/pkg/verifier/cosign/cosign_test.go
+++ b/pkg/verifier/cosign/cosign_test.go
@@ -23,6 +23,7 @@ import (
 	"crypto/elliptic"
 	"crypto/rand"
 	"crypto/rsa"
+	"encoding/base64"
 	"fmt"
 	"io"
 	"slices"
@@ -114,6 +115,26 @@ func TestCreate(t *testing.T) {
 			},
 			wantErr: false,
 		},
+		{
+			name: "duplicate trust policies in config",
+			config: config.VerifierConfig{
+				"name":          "test",
+				"artifactTypes": "testtype",
+				"trustPolicies": []TrustPolicyConfig{
+					{
+						Name:    "test",
+						Keyless: KeylessConfig{CertificateIdentity: testIdentity, CertificateOIDCIssuer: testIssuer},
+						Scopes:  []string{"*"},
+					},
+					{
+						Name:    "test",
+						Keyless: KeylessConfig{CertificateIdentity: testIdentity, CertificateOIDCIssuer: testIssuer},
+						Scopes:  []string{"*"},
+					},
+				},
+			},
+			wantErr: true,
+		},
 		{
 			name: "invalid config with legacy and trust policies",
 			config: config.VerifierConfig{
@@ -407,8 +428,8 @@ func TestErrorToVerifyResult(t *testing.T) {
 	if verifierResult.Type != "cosign" {
 		t.Errorf("errorToVerifyResult() = %v, want %v", verifierResult.Type, "cosign")
 	}
-	if verifierResult.Message != "Verification failed" {
-		t.Errorf("errorToVerifyResult() = %v, want %v", verifierResult.Message, "Verification failed")
+	if verifierResult.Message != "Failed to validate the Cosign signature" {
+		t.Errorf("errorToVerifyResult() = %v, want %v", verifierResult.Message, "Failed to validate the Cosign signature")
 	}
 	if verifierResult.ErrorReason != "test error" {
 		t.Errorf("errorToVerifyResult() = %v, want %v", verifierResult.ErrorReason, "test error")
@@ -573,7 +594,7 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry
 			keys:                        map[PKKey]keymanagementprovider.PublicKey{},
 			getKeysError:                true,
 			store:                       &mocks.MemoryTestStore{},
-			expectedResultMessagePrefix: "Verification failed",
+			expectedResultMessagePrefix: "Failed to validate the Cosign signature",
 			expectedErrorReason:         "error",
 		},
 		{
@@ -581,8 +602,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry
 			keys:                        map[PKKey]keymanagementprovider.PublicKey{},
 			getKeysError:                false,
 			store:                       &mocks.MemoryTestStore{},
-			expectedResultMessagePrefix: "Verification failed",
-			expectedErrorReason:         "failed to get reference manifest: manifest not found",
+			expectedResultMessagePrefix: "Failed to validate the Cosign signature",
+			expectedErrorReason:         "manifest not found",
 		},
 		{
 			name:         "incorrect reference manifest media type error",
@@ -595,8 +616,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry
 					},
 				},
 			},
-			expectedResultMessagePrefix: "Verification failed",
-			expectedErrorReason:         "reference manifest is not an image",
+			expectedResultMessagePrefix: "Failed to validate the Cosign signature",
+			expectedErrorReason:         "The artifact metadata is not an OCI image",
 		},
 		{
 			name:         "failed subject descriptor fetch",
@@ -609,8 +630,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry
 					},
 				},
 			},
-			expectedResultMessagePrefix: "Verification failed",
-			expectedErrorReason:         "failed to create subject hash: subject not found for sha256:5678",
+			expectedResultMessagePrefix: "Failed to validate the Cosign signature",
+			expectedErrorReason:         "subject not found for sha256:5678",
 		},
 		{
 			name:         "failed to fetch blob",
@@ -636,8 +657,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry
 					},
 				},
 			},
-			expectedResultMessagePrefix: "Verification failed",
-			expectedErrorReason:         "failed to get blob content: blob not found",
+			expectedResultMessagePrefix: "Failed to validate the Cosign signature",
+			expectedErrorReason:         "blob not found",
 		},
 		{
 			name: "invalid key type for AKV",
@@ -668,8 +689,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry
 					blobDigest: validSignatureBlob,
 				},
 			},
-			expectedResultMessagePrefix: "Verification failed",
-			expectedErrorReason:         "failed to verify with keys: failed to process AKV signature: unsupported public key type: *ecdh.PublicKey",
+			expectedResultMessagePrefix: "Failed to validate the Cosign signature",
+			expectedErrorReason:         "unsupported public key type [*ecdh.PublicKey]",
 		},
 		{
 			name: "invalid RSA key size for AKV",
@@ -700,8 +721,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry
 					blobDigest: validSignatureBlob,
 				},
 			},
-			expectedResultMessagePrefix: "Verification failed",
-			expectedErrorReason:         "failed to verify with keys: failed to process AKV signature: RSA key check: unsupported key size: 128",
+			expectedResultMessagePrefix: "Failed to validate the Cosign signature",
+			expectedErrorReason:         "RSA key check: unsupported key size: 128",
 		},
 		{
 			name: "invalid ECDSA curve type for AKV",
@@ -732,8 +753,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry
 					blobDigest: validSignatureBlob,
 				},
 			},
-			expectedResultMessagePrefix: "Verification failed",
-			expectedErrorReason:         "failed to verify with keys: failed to process AKV signature: ECDSA key check: unsupported key curve: P-224",
+			expectedResultMessagePrefix: "Failed to validate the Cosign signature",
+			expectedErrorReason:         "ECDSA key check: unsupported key curve [P-224]",
 		},
 		{
 			name: "valid hash: 256 keysize: 2048 RSA key AKV",
@@ -965,8 +986,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry
 					"sha256:d1226e36bc8502978324cb2cb2116c6aa48edb2ea8f15b1c6f6f256ed43388f6": []byte(`{"critical":{"identity":{"docker-reference":"wabbitnetworks.azurecr.io/test/cosign-image"},"image":{"docker-manifest-digest":"sha256:623621b56649b5e0c2c7cf3ffd987932f8f9a5a01036e00d6f3ae9480087621c"},"type":"cosign container image signature"},"optional":null}`),
 				},
 			},
-			expectedResultMessagePrefix: "Verification failed",
-			expectedErrorReason:         "failed to parse static signature opts: failed to unmarshal bundle from blob payload: illegal base64 data at input byte 91",
+			expectedResultMessagePrefix: "Failed to validate the Cosign signature:",
+			expectedErrorReason:         "failed to unmarshal bundle from blob payload: illegal base64 data at input byte 91",
 		},
 	}
 
@@ -1051,3 +1072,81 @@ func TestVerificationMessage(t *testing.T) {
 		})
 	}
 }
+
+func TestProcessAKVSignature_RSAKey(t *testing.T) {
+	tests := []struct {
+		name             string
+		keySize          int
+		encodedSig       string
+		expectedErr      bool
+		expectedHashType crypto.Hash
+		expectedSigOut   bool
+	}{
+		{
+			name:             "RSA 2048 bits",
+			keySize:          256,
+			expectedErr:      false,
+			expectedHashType: crypto.SHA256,
+			expectedSigOut:   true,
+		},
+		{
+			name:             "RSA 3072 bits",
+			keySize:          384,
+			expectedErr:      false,
+			expectedHashType: crypto.SHA384,
+			expectedSigOut:   true,
+		},
+		{
+			name:             "RSA 4096 bits",
+			keySize:          512,
+			expectedErr:      false,
+			expectedHashType: crypto.SHA512,
+			expectedSigOut:   true,
+		},
+		{
+			name:        "Unsupported key size",
+			keySize:     128,
+			expectedErr: true,
+		},
+		{
+			name:        "Invalid base64 encoded signature",
+			keySize:     256,
+			encodedSig:  "ThisIsNot@ValidBase64%String!",
+			expectedErr: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			// Create a mock RSA public key
+			privateKey, err := rsa.GenerateKey(rand.Reader, tt.keySize*8)
+			if err != nil {
+				t.Fatalf("Failed to generate RSA key: %v", err)
+			}
+			rsaPublicKey := &privateKey.PublicKey
+
+			// Mock the signature as base64 encoded string
+			sig := "dummy_signature"
+			encodedSig := base64.StdEncoding.EncodeToString([]byte(sig))
+			if tt.encodedSig != "" {
+				encodedSig = tt.encodedSig
+			}
+
+			// Process the signature
+			hashType, sigOut, err := processAKVSignature(encodedSig, nil, rsaPublicKey, []byte("test payload"), []static.Option{})
+
+			if tt.expectedErr {
+				if err == nil {
+					t.Fatalf("Expected error but got nil")
+				}
+			} else {
+				if hashType != tt.expectedHashType {
+					t.Fatalf("Expected hash type %v but got %v", tt.expectedHashType, hashType)
+				}
+				if tt.expectedSigOut != (sigOut != nil) {
+					t.Fatalf("Expected signature output to be %v but got %v", tt.expectedSigOut, sigOut)
+				}
+			}
+		})
+	}
+}
diff --git a/pkg/verifier/cosign/trustpolicies.go b/pkg/verifier/cosign/trustpolicies.go
index 4858cfd47..6ba5521ed 100644
--- a/pkg/verifier/cosign/trustpolicies.go
+++ b/pkg/verifier/cosign/trustpolicies.go
@@ -35,14 +35,14 @@ var validScopeRegex = regexp.MustCompile(`^[a-z0-9\.\-:@\/]*\*?$`)
 // CreateTrustPolicies creates a set of trust policies from the given configuration
 func CreateTrustPolicies(configs []TrustPolicyConfig, verifierName string) (*TrustPolicies, error) {
 	if len(configs) == 0 {
-		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail("failed to create trust policies: no policies found")
+		return nil, re.ErrorCodeConfigInvalid.WithDetail("Failed to create trust policies: policy configuration not found").WithRemediation("Ensure that the trust policy configuration is correct.")
 	}
 
 	policies := make([]TrustPolicy, 0, len(configs))
 	names := make(map[string]struct{})
 	for _, policyConfig := range configs {
 		if _, ok := names[policyConfig.Name]; ok {
-			return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("failed to create trust policies: duplicate policy name %s", policyConfig.Name))
+			return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: duplicate policy name %s", policyConfig.Name)).WithRemediation("Ensure that trust policy names are unique.")
 		}
 		names[policyConfig.Name] = struct{}{}
 		policy, err := CreateTrustPolicy(policyConfig, verifierName)
@@ -86,7 +86,7 @@ func (tps *TrustPolicies) GetScopedPolicy(reference string) (TrustPolicy, error)
 	if globalPolicy != nil {
 		return globalPolicy, nil
 	}
-	return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to get trust policy: no policy found for reference %s", reference))
+	return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("No policy found for the artifact %s", reference))
 }
 
 // validateScopes validates the scopes in the trust policies
@@ -97,16 +97,16 @@ func validateScopes(policies []TrustPolicy) error {
 		policyName := policy.GetName()
 		scopes := policy.GetScopes()
 		if len(scopes) == 0 {
-			return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: no scopes defined for trust policy %s", policyName))
+			return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: scope parameter is required for trust policy %s", policyName))
 		}
 		// check for global wildcard character along with other scopes in the same policy
 		if len(scopes) > 1 && slices.Contains(scopes, string(GlobalWildcardCharacter)) {
-			return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: global wildcard character %c cannot be used with other scopes within the same trust policy %s", GlobalWildcardCharacter, policyName))
+			return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: global wildcard character %c cannot be used with other scopes within the same trust policy %s", GlobalWildcardCharacter, policyName))
 		}
 		// check for duplicate global wildcard characters across policies
 		if slices.Contains(scopes, string(GlobalWildcardCharacter)) {
 			if hasGlobalWildcard {
-				return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: global wildcard character %c can only be used once", GlobalWildcardCharacter))
+				return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: global wildcard character %c can only be used once", GlobalWildcardCharacter))
 			}
 			hasGlobalWildcard = true
 			continue
@@ -114,15 +114,15 @@ func validateScopes(policies []TrustPolicy) error {
 		for _, scope := range scopes {
 			// check for empty scope
 			if scope == "" {
-				return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: scope defined is empty for trust policy %s", policyName))
+				return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: scope value cannot be empty in trust policy %s", policyName))
 			}
 			// check scope is formatted correctly
 			if !validScopeRegex.MatchString(scope) {
-				return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: invalid scope %s for trust policy %s", scope, policyName))
+				return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: invalid scope %s for trust policy %s", scope, policyName))
 			}
 			// check for duplicate scopes
 			if _, ok := scopesMap[scope]; ok {
-				return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: duplicate scope %s for trust policy %s", scope, policyName))
+				return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: duplicate scope %s for trust policy %s", scope, policyName))
 			}
 			// check wildcard overlaps
 			for existingScope := range scopesMap {
@@ -144,7 +144,7 @@ func validateScopes(policies []TrustPolicy) error {
 					isConflict = strings.HasPrefix(existingScope, trimmedScope)
 				}
 				if isConflict {
-					return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: overlapping scopes %s and %s for trust policy %s", scope, existingScope, policyName))
+					return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: overlapping scopes %s and %s for trust policy %s", scope, existingScope, policyName))
 				}
 			}
 			scopesMap[scope] = struct{}{}
diff --git a/pkg/verifier/cosign/trustpolicy.go b/pkg/verifier/cosign/trustpolicy.go
index c49b86aa8..8d20a7320 100644
--- a/pkg/verifier/cosign/trustpolicy.go
+++ b/pkg/verifier/cosign/trustpolicy.go
@@ -97,7 +97,7 @@ func CreateTrustPolicy(config TrustPolicyConfig, verifierName string) (TrustPoli
 		config.Version = DefaultTrustPolicyConfigVersion
 	}
 
-	if err := validate(config, verifierName); err != nil {
+	if err := validate(config); err != nil {
 		return nil, err
 	}
 
@@ -107,7 +107,7 @@ func CreateTrustPolicy(config TrustPolicyConfig, verifierName string) (TrustPoli
 		if keyConfig.File != "" {
 			pubKey, err := loadKeyFromPath(keyConfig.File)
 			if err != nil {
-				return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: failed to load key from file %s", config.Name, keyConfig.File)).WithError(err)
+				return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy [%s]: failed to load the key from file %s", config.Name, keyConfig.File)).WithError(err).WithRemediation("Ensure that the key file path is correct and public key is correctly saved.")
 			}
 			keyMap[PKKey{Provider: fileProviderName, Name: keyConfig.File}] = keymanagementprovider.PublicKey{Key: pubKey, ProviderType: fileProviderName}
 		}
@@ -155,13 +155,13 @@ func (tp *trustPolicy) GetKeys(ctx context.Context, _ string) (map[PKKey]keymana
 		// get the key management provider resource which contains a map of keys
 		kmpResource, kmpErr := keymanagementprovider.GetKeysFromMap(ctx, keyConfig.Provider)
 		if kmpErr != nil {
-			return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(tp.verifierName).WithDetail(fmt.Sprintf("trust policy [%s] failed to access key management provider %s, err: %s", tp.config.Name, keyConfig.Provider, kmpErr.Error()))
+			return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy [%s]: failed to access key management provider %s", tp.config.Name, keyConfig.Provider)).WithError(kmpErr)
 		}
 		// get a specific key from the key management provider resource
 		if keyConfig.Name != "" {
 			pubKey, exists := kmpResource[keymanagementprovider.KMPMapKey{Name: keyConfig.Name, Version: keyConfig.Version}]
 			if !exists {
-				return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(tp.verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: key %s with version %s not found in key management provider %s", tp.config.Name, keyConfig.Name, keyConfig.Version, keyConfig.Provider))
+				return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy [%s]: key %s with version %s not found in key management provider %s", tp.config.Name, keyConfig.Name, keyConfig.Version, keyConfig.Provider))
 			}
 			keyMap[PKKey{Provider: keyConfig.Provider, Name: keyConfig.Name, Version: keyConfig.Version}] = pubKey
 		} else {
@@ -188,12 +188,12 @@ func (tp *trustPolicy) GetCosignOpts(ctx context.Context) (cosign.CheckOpts, err
 		// create the rekor client
 		cosignOpts.RekorClient, err = rekor.NewClient(tp.config.RekorURL)
 		if err != nil {
-			return cosignOpts, fmt.Errorf("failed to create Rekor client from URL %s: %w", tp.config.RekorURL, err)
+			return cosignOpts, re.ErrorCodeConfigInvalid.WithDetail(fmt.Errorf("Failed to create Rekor client from URL %s", tp.config.RekorURL)).WithRemediation("Ensure that the Rekor URL is valid.").WithError(err)
 		}
 		// Fetches the Rekor public keys from the Rekor server
 		cosignOpts.RekorPubKeys, err = cosign.GetRekorPubs(ctx)
 		if err != nil {
-			return cosignOpts, fmt.Errorf("failed to fetch Rekor public keys: %w", err)
+			return cosignOpts, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to fetch Rekor public keys").WithRemediation(fmt.Sprintf("Please check if the Rekor server %s is available", tp.config.RekorURL)).WithError(err)
 		}
 	} else {
 		cosignOpts.IgnoreTlog = true
@@ -203,20 +203,20 @@ func (tp *trustPolicy) GetCosignOpts(ctx context.Context) (cosign.CheckOpts, err
 	if tp.isKeyless {
 		roots, err := fulcio.GetRoots()
 		if err != nil || roots == nil {
-			return cosignOpts, fmt.Errorf("failed to get fulcio roots: %w", err)
+			return cosignOpts, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to get fulcio root").WithError(err).WithRemediation("Please check if Fulcio is available")
 		}
 		cosignOpts.RootCerts = roots
 		if tp.config.Keyless.CTLogVerify != nil && *tp.config.Keyless.CTLogVerify {
 			cosignOpts.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx)
 			if err != nil {
-				return cosignOpts, fmt.Errorf("failed to fetch certificate transparency log public keys: %w", err)
+				return cosignOpts, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to fetch certificate transparency log public keys").WithError(err).WithRemediation("Please check if TUF root is available")
 			}
 		} else {
 			cosignOpts.IgnoreSCT = true
 		}
 		cosignOpts.IntermediateCerts, err = fulcio.GetIntermediates()
 		if err != nil {
-			return cosignOpts, fmt.Errorf("failed to get fulcio intermediate certificates: %w", err)
+			return cosignOpts, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to get fulcio intermediate certificates").WithError(err).WithRemediation("Please check if Fulcio is available")
 		}
 		// Set the certificate identity and issuer for keyless verification
 		cosignOpts.Identities = []cosign.Identity{
@@ -234,42 +234,42 @@ func (tp *trustPolicy) GetCosignOpts(ctx context.Context) (cosign.CheckOpts, err
 
 // validate checks if the trust policy configuration is valid
 // returns an error if the configuration is invalid
-func validate(config TrustPolicyConfig, verifierName string) error {
+func validate(config TrustPolicyConfig) error {
 	// check if the trust policy version is supported
 	if !slices.Contains(SupportedTrustPolicyConfigVersions, config.Version) {
-		return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: unsupported version %s", config.Name, config.Version))
+		return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: unsupported version %s", config.Name, config.Version)).WithRemediation(fmt.Sprintf("Supported versions are: %v", SupportedTrustPolicyConfigVersions))
 	}
 
 	if config.Name == "" {
-		return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail("missing trust policy name")
+		return re.ErrorCodeConfigInvalid.WithDetail("name parameter is required in trust policy configuration").WithRemediation("Please provide a name for the trust policy.")
 	}
 
 	if len(config.Scopes) == 0 {
-		return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: no scopes defined", config.Name))
+		return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("scopes parameter is required in trust policy configuration %s", config.Name)).WithRemediation("Please provide at least one scope for the trust policy.")
 	}
 
 	// keys or keyless must be defined
 	if len(config.Keys) == 0 && config.Keyless == (KeylessConfig{}) {
-		return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: no keys defined and keyless section not configured", config.Name))
+		return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("keys or keyless parameter is required in trust policy configuration %s", config.Name))
 	}
 
 	// only one of keys or keyless can be defined
 	if len(config.Keys) > 0 && config.Keyless != (KeylessConfig{}) {
-		return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: both keys and keyless sections are defined", config.Name))
+		return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Only one of keys or keyless parameter is required in trust policy configuration %s", config.Name))
 	}
 
 	for _, keyConfig := range config.Keys {
 		// check if the key is defined by file path or by key management provider
 		if keyConfig.File == "" && keyConfig.Provider == "" {
-			return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: key management provider name is required when not using file path", config.Name))
+			return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: key management provider name is required when not using file path", config.Name))
 		}
 		// both file path and key management provider cannot be defined together
 		if keyConfig.File != "" && keyConfig.Provider != "" {
-			return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: 'name' and 'file' cannot be configured together", config.Name))
+			return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: 'name' and 'file' cannot be configured together", config.Name))
 		}
 		// key name is required when key version is defined
 		if keyConfig.Version != "" && keyConfig.Name == "" {
-			return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: key name is required when key version is defined", config.Name))
+			return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: key name is required when key version is defined", config.Name))
 		}
 	}
 
@@ -277,19 +277,19 @@ func validate(config TrustPolicyConfig, verifierName string) error {
 	if config.Keyless != (KeylessConfig{}) {
 		// validate certificate identity specified
 		if config.Keyless.CertificateIdentity == "" && config.Keyless.CertificateIdentityRegExp == "" {
-			return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: certificate identity or identity regex pattern is required", config.Name))
+			return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: certificate identity or identity regex pattern is required", config.Name))
 		}
 		// validate certificate OIDC issuer specified
 		if config.Keyless.CertificateOIDCIssuer == "" && config.Keyless.CertificateOIDCIssuerRegExp == "" {
-			return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: certificate OIDC issuer or issuer regex pattern is required", config.Name))
+			return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: certificate OIDC issuer or issuer regex pattern is required", config.Name))
 		}
 		// validate only expression or value is specified for certificate identity
 		if config.Keyless.CertificateIdentity != "" && config.Keyless.CertificateIdentityRegExp != "" {
-			return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: only one of certificate identity or identity regex pattern should be specified", config.Name))
+			return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: only one of certificate identity or identity regex pattern should be specified", config.Name))
 		}
 		// validate only expression or value is specified for certificate OIDC issuer
 		if config.Keyless.CertificateOIDCIssuer != "" && config.Keyless.CertificateOIDCIssuerRegExp != "" {
-			return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: only one of certificate OIDC issuer or issuer regex pattern should be specified", config.Name))
+			return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: only one of certificate OIDC issuer or issuer regex pattern should be specified", config.Name))
 		}
 	}
 
diff --git a/pkg/verifier/cosign/trustpolicy_test.go b/pkg/verifier/cosign/trustpolicy_test.go
index ea720c50e..65dcb84da 100644
--- a/pkg/verifier/cosign/trustpolicy_test.go
+++ b/pkg/verifier/cosign/trustpolicy_test.go
@@ -21,6 +21,7 @@ import (
 	"crypto/ecdsa"
 	"crypto/x509"
 	"fmt"
+	"os"
 	"testing"
 
 	ctxUtils "github.com/ratify-project/ratify/internal/context"
@@ -204,6 +205,20 @@ func TestGetKeys(t *testing.T) {
 			},
 			wantErr: true,
 		},
+		{
+			name: "access nonexistent key from KMP",
+			cfg: TrustPolicyConfig{
+				Name:   "test",
+				Scopes: []string{"*"},
+				Keys: []KeyConfig{
+					{
+						Provider: "ns/kmp",
+						Name:     "nonexistent",
+					},
+				},
+			},
+			wantErr: true,
+		},
 		{
 			name: "valid KMP",
 			cfg: TrustPolicyConfig{
@@ -423,7 +438,7 @@ func TestValidate(t *testing.T) {
 
 	for _, tt := range tc {
 		t.Run(tt.name, func(t *testing.T) {
-			actual := validate(tt.policyConfig, "test-verifier")
+			actual := validate(tt.policyConfig)
 			if (actual != nil) != tt.wantErr {
 				t.Fatalf("expected %v, got %v", tt.wantErr, actual)
 			}
@@ -447,3 +462,76 @@ func TestLoadKeyFromPath(t *testing.T) {
 		t.Fatalf("expected ecdsa.PublicKey, got %v", keyType)
 	}
 }
+
+func TestGetCosignOpts(t *testing.T) {
+	testCases := []struct {
+		name           string
+		tlogVerify     bool
+		rekorURL       string
+		rekorPubKeyEnv string
+		isKeyless      bool
+		CTLogVerify    bool
+		CTLogPubKeyEnv string
+		expectedErr    bool
+	}{
+		{
+			name:        "invalid rekor url",
+			tlogVerify:  true,
+			rekorURL:    string([]byte{0x7f}),
+			expectedErr: true,
+		},
+		{
+			name:           "failed to get rekor public key",
+			tlogVerify:     true,
+			rekorURL:       "https://rekor.sigstore.dev",
+			rekorPubKeyEnv: "invalid",
+			expectedErr:    true,
+		},
+		{
+			name:           "failed to get CT log public key",
+			tlogVerify:     false,
+			isKeyless:      true,
+			CTLogVerify:    true,
+			CTLogPubKeyEnv: "invalid",
+			expectedErr:    true,
+		},
+	}
+
+	for _, tc := range testCases {
+		tc := tc
+		t.Run(tc.name, func(t *testing.T) {
+			if tc.rekorPubKeyEnv != "" {
+				val := os.Getenv("SIGSTORE_REKOR_PUBLIC_KEY")
+				os.Setenv("SIGSTORE_REKOR_PUBLIC_KEY", tc.rekorPubKeyEnv)
+				t.Cleanup(func() {
+					os.Setenv("SIGSTORE_REKOR_PUBLIC_KEY", val)
+				})
+			}
+
+			if tc.CTLogPubKeyEnv != "" {
+				val := os.Getenv("SIGSTORE_CT_LOG_PUBLIC_KEY_FILE")
+				os.Setenv("SIGSTORE_CT_LOG_PUBLIC_KEY_FILE", tc.CTLogPubKeyEnv)
+				t.Cleanup(func() {
+					os.Setenv("SIGSTORE_CT_LOG_PUBLIC_KEY_FILE", val)
+				})
+			}
+
+			tp := trustPolicy{
+				config: TrustPolicyConfig{
+					TLogVerify: &tc.tlogVerify,
+					RekorURL:   tc.rekorURL,
+					Keyless: KeylessConfig{
+						CTLogVerify: &tc.CTLogVerify,
+					},
+				},
+				isKeyless: tc.isKeyless,
+			}
+			_, err := tp.GetCosignOpts(context.Background())
+			if tc.expectedErr {
+				if err == nil {
+					t.Fatalf("expected error, got nil")
+				}
+			}
+		})
+	}
+}

From 7657a3f8b2b9762168ae495fbd71b67dade8a2b6 Mon Sep 17 00:00:00 2001
From: Juncheng Zhu <74894646+junczhu@users.noreply.github.com>
Date: Tue, 10 Sep 2024 16:04:45 +0800
Subject: [PATCH 2/8] chore:  update CRD and related code to enable `type`
 field (#1779)

Co-authored-by: Binbin Li <libinbin@microsoft.com>
---
 .../keymanagementprovider_types.go            |  4 ++
 .../namespacedkeymanagementprovider_types.go  |  4 ++
 api/unversioned/namespacedverifier_types.go   |  9 ++--
 api/unversioned/verifier_types.go             |  9 ++--
 api/v1alpha1/zz_generated.conversion.go       |  1 +
 api/v1beta1/namespacedverifier_types.go       |  9 ++--
 api/v1beta1/verifier_types.go                 |  9 ++--
 api/v1beta1/zz_generated.conversion.go        |  8 ++++
 ...atify.deislabs.io_namespacedverifiers.yaml |  9 ++--
 .../config.ratify.deislabs.io_verifiers.yaml  |  9 ++--
 .../clusterresource/verifier_controller.go    |  2 +-
 .../namespaceresource/verifier_controller.go  |  2 +-
 pkg/controllers/utils/verifier.go             | 19 ++++++++
 pkg/controllers/utils/verifier_test.go        | 43 +++++++++++++++++++
 14 files changed, 117 insertions(+), 20 deletions(-)

diff --git a/api/unversioned/keymanagementprovider_types.go b/api/unversioned/keymanagementprovider_types.go
index 9b3a77db9..b347b9692 100644
--- a/api/unversioned/keymanagementprovider_types.go
+++ b/api/unversioned/keymanagementprovider_types.go
@@ -32,6 +32,10 @@ type KeyManagementProviderSpec struct {
 	// Name of the key management provider
 	Type string `json:"type,omitempty"`
 
+	// Refresh interval for fetching the certificate/key files from the provider. Only for providers that are refreshable. The value is in the format of "1h30m" where "h" means hour and "m" means minute. Valid time units are units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
+	// +kubebuilder:default=""
+	RefreshInterval string `json:"refreshInterval,omitempty"`
+
 	// Parameters of the key management provider
 	Parameters runtime.RawExtension `json:"parameters,omitempty"`
 }
diff --git a/api/unversioned/namespacedkeymanagementprovider_types.go b/api/unversioned/namespacedkeymanagementprovider_types.go
index 70dcf557c..cdccfe7f1 100644
--- a/api/unversioned/namespacedkeymanagementprovider_types.go
+++ b/api/unversioned/namespacedkeymanagementprovider_types.go
@@ -33,6 +33,10 @@ type NamespacedKeyManagementProviderSpec struct {
 	// Name of the key management provider
 	Type string `json:"type,omitempty"`
 
+	// Refresh interval for fetching the certificate/key files from the provider. Only for providers that are refreshable. The value is in the format of "1h30m" where "h" means hour and "m" means minute. Valid time units are units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
+	// +kubebuilder:default=""
+	RefreshInterval string `json:"refreshInterval,omitempty"`
+
 	// +kubebuilder:pruning:PreserveUnknownFields
 	// Parameters of the key management provider
 	Parameters runtime.RawExtension `json:"parameters,omitempty"`
diff --git a/api/unversioned/namespacedverifier_types.go b/api/unversioned/namespacedverifier_types.go
index 7e196a233..994e9d1f8 100644
--- a/api/unversioned/namespacedverifier_types.go
+++ b/api/unversioned/namespacedverifier_types.go
@@ -27,19 +27,22 @@ type NamespacedVerifierSpec struct {
 	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
 	// Important: Run "make" to regenerate code after modifying this file
 
-	// Name of the verifier
+	// Name of the verifier. Deprecated
 	Name string `json:"name"`
 
+	// Type of the verifier. Optional
+	Type string `json:"type,omitempty"`
+
 	// Version of the verifier plugin. Optional
 	Version string `json:"version,omitempty"`
 
 	// The type of artifact this verifier handles
 	ArtifactTypes string `json:"artifactTypes"`
 
-	// # Optional. URL/file path
+	// URL/file path. Optional
 	Address string `json:"address,omitempty"`
 
-	// OCI Artifact source to download the plugin from, optional
+	// OCI Artifact source to download the plugin from. Optional
 	Source *PluginSource `json:"source,omitempty"`
 
 	// Parameters for this verifier
diff --git a/api/unversioned/verifier_types.go b/api/unversioned/verifier_types.go
index 74b8bdf73..fbdd69b43 100644
--- a/api/unversioned/verifier_types.go
+++ b/api/unversioned/verifier_types.go
@@ -26,19 +26,22 @@ import (
 type VerifierSpec struct {
 	// Important: Run "make" to regenerate code after modifying this file
 
-	// Name of the verifier
+	// Name of the verifier. Deprecated
 	Name string `json:"name,omitempty"`
 
+	// Type of the verifier. Optional
+	Type string `json:"type,omitempty"`
+
 	// Version of the verifier plugin. Optional
 	Version string `json:"version,omitempty"`
 
 	// The type of artifact this verifier handles
 	ArtifactTypes string `json:"artifactTypes,omitempty"`
 
-	// # Optional. URL/file path
+	// URL/file path. Optional
 	Address string `json:"address,omitempty"`
 
-	// OCI Artifact source to download the plugin from, optional
+	// OCI Artifact source to download the plugin from. Optional
 	Source *PluginSource `json:"source,omitempty"`
 
 	// Parameters for this verifier
diff --git a/api/v1alpha1/zz_generated.conversion.go b/api/v1alpha1/zz_generated.conversion.go
index 467a815ca..9be9f8190 100644
--- a/api/v1alpha1/zz_generated.conversion.go
+++ b/api/v1alpha1/zz_generated.conversion.go
@@ -642,6 +642,7 @@ func Convert_v1alpha1_VerifierSpec_To_unversioned_VerifierSpec(in *VerifierSpec,
 
 func autoConvert_unversioned_VerifierSpec_To_v1alpha1_VerifierSpec(in *unversioned.VerifierSpec, out *VerifierSpec, s conversion.Scope) error {
 	out.Name = in.Name
+	// WARNING: in.Type requires manual conversion: does not exist in peer-type
 	// WARNING: in.Version requires manual conversion: does not exist in peer-type
 	out.ArtifactTypes = in.ArtifactTypes
 	out.Address = in.Address
diff --git a/api/v1beta1/namespacedverifier_types.go b/api/v1beta1/namespacedverifier_types.go
index 31e1c8e9f..17809a456 100644
--- a/api/v1beta1/namespacedverifier_types.go
+++ b/api/v1beta1/namespacedverifier_types.go
@@ -29,19 +29,22 @@ type NamespacedVerifierSpec struct {
 	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
 	// Important: Run "make" to regenerate code after modifying this file
 
-	// Name of the verifier
+	// Name of the verifier. Deprecated
 	Name string `json:"name"`
 
+	// Type of the verifier. Optional
+	Type string `json:"type,omitempty"`
+
 	// Version of the verifier plugin. Optional
 	Version string `json:"version,omitempty"`
 
 	// The type of artifact this verifier handles
 	ArtifactTypes string `json:"artifactTypes"`
 
-	// # Optional. URL/file path
+	// URL/file path. Optional
 	Address string `json:"address,omitempty"`
 
-	// OCI Artifact source to download the plugin from, optional
+	// OCI Artifact source to download the plugin from. Optional
 	Source *PluginSource `json:"source,omitempty"`
 
 	// +kubebuilder:pruning:PreserveUnknownFields
diff --git a/api/v1beta1/verifier_types.go b/api/v1beta1/verifier_types.go
index 5d4bf0974..b273a4898 100644
--- a/api/v1beta1/verifier_types.go
+++ b/api/v1beta1/verifier_types.go
@@ -25,19 +25,22 @@ import (
 type VerifierSpec struct {
 	// Important: Run "make install-crds" to regenerate code after modifying this file
 
-	// Name of the verifier
+	// Name of the verifier. Deprecated
 	Name string `json:"name"`
 
+	// Type of the verifier. Optional
+	Type string `json:"type,omitempty"`
+
 	// Version of the verifier plugin. Optional
 	Version string `json:"version,omitempty"`
 
 	// The type of artifact this verifier handles
 	ArtifactTypes string `json:"artifactTypes"`
 
-	// # Optional. URL/file path
+	// URL/file path. Optional
 	Address string `json:"address,omitempty"`
 
-	// OCI Artifact source to download the plugin from, optional
+	// OCI Artifact source to download the plugin from. Optional
 	Source *PluginSource `json:"source,omitempty"`
 
 	// +kubebuilder:pruning:PreserveUnknownFields
diff --git a/api/v1beta1/zz_generated.conversion.go b/api/v1beta1/zz_generated.conversion.go
index fafb65bab..0b69afaf9 100644
--- a/api/v1beta1/zz_generated.conversion.go
+++ b/api/v1beta1/zz_generated.conversion.go
@@ -569,6 +569,7 @@ func Convert_unversioned_KeyManagementProviderList_To_v1beta1_KeyManagementProvi
 
 func autoConvert_v1beta1_KeyManagementProviderSpec_To_unversioned_KeyManagementProviderSpec(in *KeyManagementProviderSpec, out *unversioned.KeyManagementProviderSpec, s conversion.Scope) error {
 	out.Type = in.Type
+	out.RefreshInterval = in.RefreshInterval
 	out.Parameters = in.Parameters
 	return nil
 }
@@ -580,6 +581,7 @@ func Convert_v1beta1_KeyManagementProviderSpec_To_unversioned_KeyManagementProvi
 
 func autoConvert_unversioned_KeyManagementProviderSpec_To_v1beta1_KeyManagementProviderSpec(in *unversioned.KeyManagementProviderSpec, out *KeyManagementProviderSpec, s conversion.Scope) error {
 	out.Type = in.Type
+	out.RefreshInterval = in.RefreshInterval
 	out.Parameters = in.Parameters
 	return nil
 }
@@ -673,6 +675,7 @@ func Convert_unversioned_NamespacedKeyManagementProviderList_To_v1beta1_Namespac
 
 func autoConvert_v1beta1_NamespacedKeyManagementProviderSpec_To_unversioned_NamespacedKeyManagementProviderSpec(in *NamespacedKeyManagementProviderSpec, out *unversioned.NamespacedKeyManagementProviderSpec, s conversion.Scope) error {
 	out.Type = in.Type
+	out.RefreshInterval = in.RefreshInterval
 	out.Parameters = in.Parameters
 	return nil
 }
@@ -684,6 +687,7 @@ func Convert_v1beta1_NamespacedKeyManagementProviderSpec_To_unversioned_Namespac
 
 func autoConvert_unversioned_NamespacedKeyManagementProviderSpec_To_v1beta1_NamespacedKeyManagementProviderSpec(in *unversioned.NamespacedKeyManagementProviderSpec, out *NamespacedKeyManagementProviderSpec, s conversion.Scope) error {
 	out.Type = in.Type
+	out.RefreshInterval = in.RefreshInterval
 	out.Parameters = in.Parameters
 	return nil
 }
@@ -983,6 +987,7 @@ func Convert_unversioned_NamespacedVerifierList_To_v1beta1_NamespacedVerifierLis
 
 func autoConvert_v1beta1_NamespacedVerifierSpec_To_unversioned_NamespacedVerifierSpec(in *NamespacedVerifierSpec, out *unversioned.NamespacedVerifierSpec, s conversion.Scope) error {
 	out.Name = in.Name
+	out.Type = in.Type
 	out.Version = in.Version
 	out.ArtifactTypes = in.ArtifactTypes
 	out.Address = in.Address
@@ -998,6 +1003,7 @@ func Convert_v1beta1_NamespacedVerifierSpec_To_unversioned_NamespacedVerifierSpe
 
 func autoConvert_unversioned_NamespacedVerifierSpec_To_v1beta1_NamespacedVerifierSpec(in *unversioned.NamespacedVerifierSpec, out *NamespacedVerifierSpec, s conversion.Scope) error {
 	out.Name = in.Name
+	out.Type = in.Type
 	out.Version = in.Version
 	out.ArtifactTypes = in.ArtifactTypes
 	out.Address = in.Address
@@ -1319,6 +1325,7 @@ func Convert_unversioned_VerifierList_To_v1beta1_VerifierList(in *unversioned.Ve
 
 func autoConvert_v1beta1_VerifierSpec_To_unversioned_VerifierSpec(in *VerifierSpec, out *unversioned.VerifierSpec, s conversion.Scope) error {
 	out.Name = in.Name
+	out.Type = in.Type
 	out.Version = in.Version
 	out.ArtifactTypes = in.ArtifactTypes
 	out.Address = in.Address
@@ -1334,6 +1341,7 @@ func Convert_v1beta1_VerifierSpec_To_unversioned_VerifierSpec(in *VerifierSpec,
 
 func autoConvert_unversioned_VerifierSpec_To_v1beta1_VerifierSpec(in *unversioned.VerifierSpec, out *VerifierSpec, s conversion.Scope) error {
 	out.Name = in.Name
+	out.Type = in.Type
 	out.Version = in.Version
 	out.ArtifactTypes = in.ArtifactTypes
 	out.Address = in.Address
diff --git a/config/crd/bases/config.ratify.deislabs.io_namespacedverifiers.yaml b/config/crd/bases/config.ratify.deislabs.io_namespacedverifiers.yaml
index 784bcb5f5..b61b07734 100644
--- a/config/crd/bases/config.ratify.deislabs.io_namespacedverifiers.yaml
+++ b/config/crd/bases/config.ratify.deislabs.io_namespacedverifiers.yaml
@@ -48,20 +48,20 @@ spec:
             description: NamespacedVerifierSpec defines the desired state of NamespacedVerifier
             properties:
               address:
-                description: '# Optional. URL/file path'
+                description: URL/file path. Optional
                 type: string
               artifactTypes:
                 description: The type of artifact this verifier handles
                 type: string
               name:
-                description: Name of the verifier
+                description: Name of the verifier. Deprecated
                 type: string
               parameters:
                 description: Parameters for this verifier
                 type: object
                 x-kubernetes-preserve-unknown-fields: true
               source:
-                description: OCI Artifact source to download the plugin from, optional
+                description: OCI Artifact source to download the plugin from. Optional
                 properties:
                   artifact:
                     description: OCI Artifact source to download the plugin from
@@ -72,6 +72,9 @@ spec:
                     type: object
                     x-kubernetes-preserve-unknown-fields: true
                 type: object
+              type:
+                description: Type of the verifier. Optional
+                type: string
               version:
                 description: Version of the verifier plugin. Optional
                 type: string
diff --git a/config/crd/bases/config.ratify.deislabs.io_verifiers.yaml b/config/crd/bases/config.ratify.deislabs.io_verifiers.yaml
index a23d9819f..8d08f76e5 100644
--- a/config/crd/bases/config.ratify.deislabs.io_verifiers.yaml
+++ b/config/crd/bases/config.ratify.deislabs.io_verifiers.yaml
@@ -107,20 +107,20 @@ spec:
             description: VerifierSpec defines the desired state of Verifier
             properties:
               address:
-                description: '# Optional. URL/file path'
+                description: URL/file path. Optional
                 type: string
               artifactTypes:
                 description: The type of artifact this verifier handles
                 type: string
               name:
-                description: Name of the verifier
+                description: Name of the verifier. Deprecated
                 type: string
               parameters:
                 description: Parameters for this verifier
                 type: object
                 x-kubernetes-preserve-unknown-fields: true
               source:
-                description: OCI Artifact source to download the plugin from, optional
+                description: OCI Artifact source to download the plugin from. Optional
                 properties:
                   artifact:
                     description: OCI Artifact source to download the plugin from
@@ -131,6 +131,9 @@ spec:
                     type: object
                     x-kubernetes-preserve-unknown-fields: true
                 type: object
+              type:
+                description: Type of the verifier. Optional
+                type: string
               version:
                 description: Version of the verifier plugin. Optional
                 type: string
diff --git a/pkg/controllers/clusterresource/verifier_controller.go b/pkg/controllers/clusterresource/verifier_controller.go
index c8c8cd838..f752fa154 100644
--- a/pkg/controllers/clusterresource/verifier_controller.go
+++ b/pkg/controllers/clusterresource/verifier_controller.go
@@ -85,7 +85,7 @@ func (r *VerifierReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 
 // creates a verifier reference from CR spec and add verifier to map
 func verifierAddOrReplace(spec configv1beta1.VerifierSpec, objectName string) error {
-	verifierConfig, err := cutils.SpecToVerifierConfig(spec.Parameters.Raw, objectName, spec.Name, spec.ArtifactTypes, spec.Source)
+	verifierConfig, err := cutils.SpecToVerifierConfig(spec.Parameters.Raw, objectName, cutils.GetVerifierType(spec), spec.ArtifactTypes, spec.Source)
 	if err != nil {
 		errMsg := fmt.Sprintf("Unable to apply cluster-wide resource %s of Verifier kind", objectName)
 		logrus.Error(err, errMsg)
diff --git a/pkg/controllers/namespaceresource/verifier_controller.go b/pkg/controllers/namespaceresource/verifier_controller.go
index 4b19b6178..a2926efe9 100644
--- a/pkg/controllers/namespaceresource/verifier_controller.go
+++ b/pkg/controllers/namespaceresource/verifier_controller.go
@@ -84,7 +84,7 @@ func (r *VerifierReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 
 // creates a verifier reference from CRD spec and add store to map
 func verifierAddOrReplace(spec configv1beta1.NamespacedVerifierSpec, objectName string, namespace string) error {
-	verifierConfig, err := cutils.SpecToVerifierConfig(spec.Parameters.Raw, objectName, spec.Name, spec.ArtifactTypes, spec.Source)
+	verifierConfig, err := cutils.SpecToVerifierConfig(spec.Parameters.Raw, objectName, cutils.GetVerifierType(spec), spec.ArtifactTypes, spec.Source)
 	if err != nil {
 		errMsg := fmt.Sprintf("Unable to apply the resource %s of NamespacedVerifier kind in the namespace %s", objectName, namespace)
 		logrus.Error(err, errMsg)
diff --git a/pkg/controllers/utils/verifier.go b/pkg/controllers/utils/verifier.go
index e65a05973..43a9e858d 100644
--- a/pkg/controllers/utils/verifier.go
+++ b/pkg/controllers/utils/verifier.go
@@ -72,3 +72,22 @@ func SpecToVerifierConfig(raw []byte, verifierName, verifierType, artifactTypes
 
 	return verifierConfig, nil
 }
+
+// GetVerifierType returns verifier type and is backward compatible with the deprecated name field
+func GetVerifierType(verifierSpec interface{}) string {
+	switch spec := verifierSpec.(type) {
+	case configv1beta1.VerifierSpec:
+		if spec.Type == "" {
+			return spec.Name
+		}
+		return spec.Type
+	case configv1beta1.NamespacedVerifierSpec:
+		if spec.Type == "" {
+			return spec.Name
+		}
+		return spec.Type
+	default:
+		logrus.Error("unable to assert verifierSpec type", spec)
+	}
+	return ""
+}
diff --git a/pkg/controllers/utils/verifier_test.go b/pkg/controllers/utils/verifier_test.go
index 8ccf9a6d7..349653a07 100644
--- a/pkg/controllers/utils/verifier_test.go
+++ b/pkg/controllers/utils/verifier_test.go
@@ -119,3 +119,46 @@ func TestSpecToVerifierConfig(t *testing.T) {
 func resetVerifierMap() {
 	controllers.NamespacedVerifiers = verifiers.NewActiveVerifiers()
 }
+
+func TestGetType(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    interface{}
+		expected string
+	}{
+		{
+			name:     "cluster verifier spec with name",
+			input:    configv1beta1.VerifierSpec{Name: "clusterV"},
+			expected: "clusterV",
+		},
+		{
+			name:     "cluster verifier spec with type",
+			input:    configv1beta1.VerifierSpec{Type: "clusterV"},
+			expected: "clusterV",
+		},
+		{
+			name:     "namespaced verifier spec with name",
+			input:    configv1beta1.NamespacedVerifierSpec{Name: "namespacedV"},
+			expected: "namespacedV",
+		},
+		{
+			name:     "namespaced verifier spec with type",
+			input:    configv1beta1.NamespacedVerifierSpec{Type: "namespacedV"},
+			expected: "namespacedV",
+		},
+		{
+			name:     "verifier spec with no name or type",
+			input:    "",
+			expected: "",
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			output := GetVerifierType(tt.input)
+			if tt.expected != output {
+				t.Fatalf("GetType() expected %v, actual %v", tt.expected, output)
+			}
+		})
+	}
+}

From acf60d1a4a7be3d8103e7b9efe53014a39980cb6 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 11 Sep 2024 13:57:46 +0800
Subject: [PATCH 3/8] chore: Bump step-security/harden-runner from 2.9.1 to
 2.10.0 (#1794)

---
 .github/workflows/build-pr.yml              | 2 +-
 .github/workflows/cache-cleanup.yml         | 2 +-
 .github/workflows/clean-dev-package.yml     | 2 +-
 .github/workflows/codeql.yml                | 2 +-
 .github/workflows/e2e-aks.yml               | 2 +-
 .github/workflows/e2e-cli.yml               | 8 ++++----
 .github/workflows/e2e-k8s.yml               | 2 +-
 .github/workflows/golangci-lint.yml         | 2 +-
 .github/workflows/high-availability.yml     | 2 +-
 .github/workflows/pr-to-main.yml            | 2 +-
 .github/workflows/publish-charts.yml        | 2 +-
 .github/workflows/publish-cosign-sample.yml | 2 +-
 .github/workflows/publish-dev-assets.yml    | 2 +-
 .github/workflows/publish-package.yml       | 2 +-
 .github/workflows/publish-sample.yml        | 2 +-
 .github/workflows/quick-start.yml           | 2 +-
 .github/workflows/release.yml               | 2 +-
 .github/workflows/run-full-validation.yml   | 2 +-
 .github/workflows/scan-vulns.yaml           | 4 ++--
 .github/workflows/scorecards.yml            | 2 +-
 .github/workflows/sync-gh-pages.yml         | 2 +-
 21 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml
index 0af3612f8..920d6f43d 100644
--- a/.github/workflows/build-pr.yml
+++ b/.github/workflows/build-pr.yml
@@ -70,7 +70,7 @@ jobs:
     environment: azure-test
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/cache-cleanup.yml b/.github/workflows/cache-cleanup.yml
index 5fbb3d0c8..b2b69de3f 100644
--- a/.github/workflows/cache-cleanup.yml
+++ b/.github/workflows/cache-cleanup.yml
@@ -12,7 +12,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:      
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/clean-dev-package.yml b/.github/workflows/clean-dev-package.yml
index 98cc5cfff..ce9e17ac3 100644
--- a/.github/workflows/clean-dev-package.yml
+++ b/.github/workflows/clean-dev-package.yml
@@ -13,7 +13,7 @@ jobs:
         packages: write
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 82ddd78ea..35955608d 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -27,7 +27,7 @@ jobs:
 
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/e2e-aks.yml b/.github/workflows/e2e-aks.yml
index a202673ea..a5700a861 100644
--- a/.github/workflows/e2e-aks.yml
+++ b/.github/workflows/e2e-aks.yml
@@ -28,7 +28,7 @@ jobs:
       contents: read
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/e2e-cli.yml b/.github/workflows/e2e-cli.yml
index 324de264f..c4c64ea19 100644
--- a/.github/workflows/e2e-cli.yml
+++ b/.github/workflows/e2e-cli.yml
@@ -14,7 +14,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
@@ -35,7 +35,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
@@ -64,7 +64,7 @@ jobs:
       contents: read
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
@@ -92,7 +92,7 @@ jobs:
       runs-on: ubuntu-latest
       steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/e2e-k8s.yml b/.github/workflows/e2e-k8s.yml
index 57a04b69a..4736406d5 100644
--- a/.github/workflows/e2e-k8s.yml
+++ b/.github/workflows/e2e-k8s.yml
@@ -26,7 +26,7 @@ jobs:
       contents: read
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml
index dd5bec53a..c40ca040a 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -15,7 +15,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/high-availability.yml b/.github/workflows/high-availability.yml
index e711f94f8..34f04f251 100644
--- a/.github/workflows/high-availability.yml
+++ b/.github/workflows/high-availability.yml
@@ -30,7 +30,7 @@ jobs:
         DAPR_VERSION: ["1.13.2"]
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/pr-to-main.yml b/.github/workflows/pr-to-main.yml
index 3aecd8b89..e8869cc5b 100644
--- a/.github/workflows/pr-to-main.yml
+++ b/.github/workflows/pr-to-main.yml
@@ -13,7 +13,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/publish-charts.yml b/.github/workflows/publish-charts.yml
index cfb578923..34df4e587 100644
--- a/.github/workflows/publish-charts.yml
+++ b/.github/workflows/publish-charts.yml
@@ -13,7 +13,7 @@ jobs:
       contents: write
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/publish-cosign-sample.yml b/.github/workflows/publish-cosign-sample.yml
index 925284a8c..ee656a0f7 100644
--- a/.github/workflows/publish-cosign-sample.yml
+++ b/.github/workflows/publish-cosign-sample.yml
@@ -20,7 +20,7 @@ jobs:
       id-token: write
     steps:            
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/publish-dev-assets.yml b/.github/workflows/publish-dev-assets.yml
index c5dc1ef6a..60b0d8ce8 100644
--- a/.github/workflows/publish-dev-assets.yml
+++ b/.github/workflows/publish-dev-assets.yml
@@ -17,7 +17,7 @@ jobs:
     environment: azure-publish
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
       - name: Checkout
diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml
index 32a893d36..17b49127c 100644
--- a/.github/workflows/publish-package.yml
+++ b/.github/workflows/publish-package.yml
@@ -16,7 +16,7 @@ jobs:
       contents: read
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
       - name: Checkout
diff --git a/.github/workflows/publish-sample.yml b/.github/workflows/publish-sample.yml
index b21e8840e..3dfd19456 100644
--- a/.github/workflows/publish-sample.yml
+++ b/.github/workflows/publish-sample.yml
@@ -19,7 +19,7 @@ jobs:
       packages: write
     steps:            
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/quick-start.yml b/.github/workflows/quick-start.yml
index 6e26af5cb..930f9a343 100644
--- a/.github/workflows/quick-start.yml
+++ b/.github/workflows/quick-start.yml
@@ -30,7 +30,7 @@ jobs:
         KUBERNETES_VERSION: ["1.29.2"]
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 13f91853e..85e0f217d 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -16,7 +16,7 @@ jobs:
       contents: write
     steps:
     - name: Harden Runner
-      uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+      uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
       with:
         egress-policy: audit
 
diff --git a/.github/workflows/run-full-validation.yml b/.github/workflows/run-full-validation.yml
index 71db17f86..930400c43 100644
--- a/.github/workflows/run-full-validation.yml
+++ b/.github/workflows/run-full-validation.yml
@@ -58,7 +58,7 @@ jobs:
     environment: azure-test
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/scan-vulns.yaml b/.github/workflows/scan-vulns.yaml
index 7c0ff23c4..66e274256 100644
--- a/.github/workflows/scan-vulns.yaml
+++ b/.github/workflows/scan-vulns.yaml
@@ -23,7 +23,7 @@ jobs:
     timeout-minutes: 15
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
@@ -39,7 +39,7 @@ jobs:
     timeout-minutes: 15
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index 970cd1182..63d2cc90c 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -30,7 +30,7 @@ jobs:
     
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/sync-gh-pages.yml b/.github/workflows/sync-gh-pages.yml
index fd44a65d1..0837d5cdf 100644
--- a/.github/workflows/sync-gh-pages.yml
+++ b/.github/workflows/sync-gh-pages.yml
@@ -17,7 +17,7 @@ jobs:
       repository-projects: write
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
+        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
         with:
           egress-policy: audit
 

From 5381e0ceaed1b78f7c0d32e7e6a1bc2e556aadba Mon Sep 17 00:00:00 2001
From: Juncheng Zhu <74894646+junczhu@users.noreply.github.com>
Date: Wed, 11 Sep 2024 14:26:43 +0800
Subject: [PATCH 4/8] fix: showing verifier config parse detail in err log
 (#1791)

---
 pkg/verifier/notation/notation.go                            | 5 ++++-
 test/bats/tests/config/config_v1beta1_verifier_notation.yaml | 2 +-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/pkg/verifier/notation/notation.go b/pkg/verifier/notation/notation.go
index f25b21c10..e825db11d 100644
--- a/pkg/verifier/notation/notation.go
+++ b/pkg/verifier/notation/notation.go
@@ -237,7 +237,10 @@ func normalizeVerificationCertsStores(conf *NotationPluginVerifierConfig) error
 		}
 	}
 	if isCertStoresByType && isLegacyCertStore {
-		return re.ErrorCodeConfigInvalid.WithDetail("The verificationCertStores is misconfigured with both legacy and new formats").WithRemediation("Please provide only one format for the VerificationCertStores. Refer to the Notation Verifier configuration guide: https://ratify.dev/docs/plugins/verifier/notation#configuration")
+		// showing configuration content in the log with error details for better user experience
+		err := re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("The verificationCertStores is misconfigured with both legacy and new formats: %+v", conf)).WithRemediation("Please provide only one format for the VerificationCertStores. Refer to the Notation Verifier configuration guide: https://ratify.dev/docs/plugins/verifier/notation#configuration")
+		logger.GetLogger(context.Background(), logOpt).Error(err)
+		return err
 	} else if !isCertStoresByType && isLegacyCertStore {
 		legacyCertStore, err := normalizeLegacyCertStore(conf)
 		if err != nil {
diff --git a/test/bats/tests/config/config_v1beta1_verifier_notation.yaml b/test/bats/tests/config/config_v1beta1_verifier_notation.yaml
index bb1564a44..2fdfc94dd 100644
--- a/test/bats/tests/config/config_v1beta1_verifier_notation.yaml
+++ b/test/bats/tests/config/config_v1beta1_verifier_notation.yaml
@@ -9,7 +9,7 @@ spec:
     verificationCertStores:
       ca:
         ca-certs:
-        - certstore-inline
+          - certstore-inline
     trustPolicyDoc:
       version: "1.0"
       trustPolicies:

From b7cab8822cfabbe5d22066a4fa30b265de32da79 Mon Sep 17 00:00:00 2001
From: Binbin Li <libinbin@microsoft.com>
Date: Thu, 12 Sep 2024 02:01:26 +0800
Subject: [PATCH 5/8] chore: update error messages for cosign validation
 (#1792)

---
 pkg/referrerstore/oras/cosign.go | 2 +-
 pkg/verifier/cosign/cosign.go    | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/pkg/referrerstore/oras/cosign.go b/pkg/referrerstore/oras/cosign.go
index 3db4b23bb..4f6fc2457 100644
--- a/pkg/referrerstore/oras/cosign.go
+++ b/pkg/referrerstore/oras/cosign.go
@@ -46,7 +46,7 @@ func getCosignReferences(ctx context.Context, subjectReference common.Reference,
 			return nil, nil
 		}
 		evictOnError(ctx, err, subjectReference.Original)
-		return nil, re.ErrorCodeRepositoryOperationFailure.WithDetail(fmt.Sprintf("Failed to validate the signature of the artifact: %+v", subjectReference)).WithError(err)
+		return nil, re.ErrorCodeRepositoryOperationFailure.WithDetail(fmt.Sprintf("Failed to validate existence of Cosign signature of the artifact: %+v", subjectReference)).WithError(err)
 	}
 
 	references = append(references, ocispecs.ReferenceDescriptor{
diff --git a/pkg/verifier/cosign/cosign.go b/pkg/verifier/cosign/cosign.go
index cba6a1e9a..86442859a 100644
--- a/pkg/verifier/cosign/cosign.go
+++ b/pkg/verifier/cosign/cosign.go
@@ -224,7 +224,7 @@ func (v *cosignVerifier) verifyInternal(ctx context.Context, subjectReference co
 	// get the reference manifest (cosign oci image)
 	referenceManifest, err := referrerStore.GetReferenceManifest(ctx, subjectReference, referenceDescriptor)
 	if err != nil {
-		return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyPluginFailure.WithDetail(fmt.Sprintf("Failed to get artifact metadata for %s", referenceDescriptor.Digest)).WithError(err)), nil
+		return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyPluginFailure.WithDetail(fmt.Sprintf("Failed to get Cosign signature metadata for %s", referenceDescriptor.Digest)).WithError(err)), nil
 	}
 
 	// manifest must be an OCI Image
@@ -540,7 +540,7 @@ func verifyWithKeys(ctx context.Context, keysMap map[PKKey]keymanagementprovider
 		if pubKey.ProviderType == azurekeyvault.ProviderName {
 			hashType, sig, err = processAKVSignature(sigEncoded, sig, pubKey.Key, payload, staticOpts)
 			if err != nil {
-				return verifications, false, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to validate the Cosign signature generated by AKV").WithError(err)
+				return verifications, false, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to validate the Cosign signature generated by Azure Key Vault").WithError(err)
 			}
 		}
 

From 4b04c08fcd3fc1c2d9dc0ddc81af9feceba53202 Mon Sep 17 00:00:00 2001
From: Akash Singhal <akashsinghal@microsoft.com>
Date: Wed, 11 Sep 2024 22:24:25 -0700
Subject: [PATCH 6/8] chore: bump support GK version matrix to include v3.17.0
 (#1795)

---
 .github/workflows/build-pr.yml            | 6 +++---
 .github/workflows/e2e-aks.yml             | 2 +-
 .github/workflows/e2e-k8s.yml             | 2 +-
 .github/workflows/run-full-validation.yml | 4 ++--
 Makefile                                  | 2 +-
 charts/ratify/README.md                   | 2 +-
 charts/ratify/values.yaml                 | 2 +-
 dev.helmfile.yaml                         | 2 +-
 dev.high-availability.helmfile.yaml       | 2 +-
 scripts/azure-ci-test.sh                  | 2 +-
 10 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml
index 920d6f43d..a90b8fdb2 100644
--- a/.github/workflows/build-pr.yml
+++ b/.github/workflows/build-pr.yml
@@ -25,7 +25,7 @@ jobs:
       fail-fast: false
       matrix:
         KUBERNETES_VERSION: ["1.29.2"]
-        GATEKEEPER_VERSION: ["3.16.0"]
+        GATEKEEPER_VERSION: ["3.17.0"]
     uses: ./.github/workflows/e2e-k8s.yml 
     with:
       k8s_version: ${{ matrix.KUBERNETES_VERSION }}
@@ -38,7 +38,7 @@ jobs:
       fail-fast: false
       matrix:
         KUBERNETES_VERSION: ["1.28.12", "1.29.2"]
-        GATEKEEPER_VERSION: ["3.14.0", "3.15.0", "3.16.0"]
+        GATEKEEPER_VERSION: ["3.15.0", "3.16.0", "3.17.0"]
     uses: ./.github/workflows/e2e-k8s.yml 
     with:
       k8s_version: ${{ matrix.KUBERNETES_VERSION }}
@@ -54,7 +54,7 @@ jobs:
       fail-fast: false
       matrix:
         KUBERNETES_VERSION: ["1.28.12", "1.29.2"]
-        GATEKEEPER_VERSION: ["3.14.0", "3.15.0", "3.16.0"]
+        GATEKEEPER_VERSION: ["3.15.0", "3.16.0", "3.17.0"]
     uses: ./.github/workflows/e2e-aks.yml
     with:
       k8s_version: ${{ matrix.KUBERNETES_VERSION }}
diff --git a/.github/workflows/e2e-aks.yml b/.github/workflows/e2e-aks.yml
index a5700a861..c710833fc 100644
--- a/.github/workflows/e2e-aks.yml
+++ b/.github/workflows/e2e-aks.yml
@@ -14,7 +14,7 @@ on:
       gatekeeper_version:
         description: 'Gatekeeper version'
         required: true
-        default: '3.16.0'
+        default: '3.17.0'
         type: string
 
 jobs:
diff --git a/.github/workflows/e2e-k8s.yml b/.github/workflows/e2e-k8s.yml
index 4736406d5..a04d7f7c8 100644
--- a/.github/workflows/e2e-k8s.yml
+++ b/.github/workflows/e2e-k8s.yml
@@ -14,7 +14,7 @@ on:
       gatekeeper_version:
         description: 'Gatekeeper version'
         required: true
-        default: '3.16.0'
+        default: '3.17.0'
         type: string
 
 jobs:
diff --git a/.github/workflows/run-full-validation.yml b/.github/workflows/run-full-validation.yml
index 930400c43..6f4892a30 100644
--- a/.github/workflows/run-full-validation.yml
+++ b/.github/workflows/run-full-validation.yml
@@ -27,7 +27,7 @@ jobs:
       fail-fast: false
       matrix:
         KUBERNETES_VERSION: ["1.28.12", "1.29.2"]
-        GATEKEEPER_VERSION: ["3.14.0", "3.15.0", "3.16.0"]
+        GATEKEEPER_VERSION: ["3.15.0", "3.16.0", "3.17.0"]
     uses: ./.github/workflows/e2e-k8s.yml 
     with:
       k8s_version: ${{ matrix.KUBERNETES_VERSION }}
@@ -42,7 +42,7 @@ jobs:
       fail-fast: false
       matrix:
         KUBERNETES_VERSION: ["1.28.12", "1.29.2"]
-        GATEKEEPER_VERSION: ["3.14.0", "3.15.0", "3.16.0"]
+        GATEKEEPER_VERSION: ["3.15.0", "3.16.0", "3.17.0"]
     uses: ./.github/workflows/e2e-aks.yml
     with:
       k8s_version: ${{ matrix.KUBERNETES_VERSION }}
diff --git a/Makefile b/Makefile
index f6895c911..376a2d170 100644
--- a/Makefile
+++ b/Makefile
@@ -28,7 +28,7 @@ LDFLAGS += -X $(GO_PKG)/internal/version.GitTag=$(GIT_TAG)
 KIND_VERSION ?= 0.22.0
 KUBERNETES_VERSION ?= 1.29.2
 KIND_KUBERNETES_VERSION ?= 1.29.2
-GATEKEEPER_VERSION ?= 3.16.0
+GATEKEEPER_VERSION ?= 3.17.0
 DAPR_VERSION ?= 1.12.5
 COSIGN_VERSION ?= 2.2.3
 NOTATION_VERSION ?= 1.2.0
diff --git a/charts/ratify/README.md b/charts/ratify/README.md
index 10ec62582..af3600209 100644
--- a/charts/ratify/README.md
+++ b/charts/ratify/README.md
@@ -77,7 +77,7 @@ Values marked `# DEPRECATED` in the `values.yaml` as well as **DEPRECATED** in t
 | resources.requests.memory                          | Memory request of Ratify Deployment                                                                                                                                                                                                                                                                                                                                    | `512Mi`                           |
 | serviceAccount.create                              | Create new dedicated Ratify service account                                                                                                                                                                                                                                                                                                                            | `true`                            |
 | serviceAccount.name                                | Name of Ratify service account to create                                                                                                                                                                                                                                                                                                                               | `ratify-admin`                    |
-| gatekeeper.version                                 | Determines the Gatekeeper CRD versioning                                                                                                                                                                                                                                                                                                                               | `3.16.0`                          |
+| gatekeeper.version                                 | Determines the Gatekeeper CRD versioning                                                                                                                                                                                                                                                                                                                               | `3.17.0`                          |
 | gatekeeper.namespace                               | Namespace Gatekeeper is installed                                                                                                                                                                                                                                                                                                                                      | `gatekeeper-system`               |
 | instrumentation.metricsEnabled                     | Initializes the configured metrics provider                                                                                                                                                                                                                                                                                                                            | `true`                            |
 | instrumentation.metricsType                        | Specifies the metrics provider type                                                                                                                                                                                                                                                                                                                                    | `prometheus`                      |
diff --git a/charts/ratify/values.yaml b/charts/ratify/values.yaml
index 2bc52a02d..aa08d898e 100644
--- a/charts/ratify/values.yaml
+++ b/charts/ratify/values.yaml
@@ -53,7 +53,7 @@ serviceAccount:
   create: true
   name: ratify-admin
 gatekeeper:
-  version: "3.16.0"
+  version: "3.17.0"
   namespace: # default is gatekeeper-system
 instrumentation:
   metricsEnabled: true
diff --git a/dev.helmfile.yaml b/dev.helmfile.yaml
index 0a3f4060a..bec894af9 100644
--- a/dev.helmfile.yaml
+++ b/dev.helmfile.yaml
@@ -10,7 +10,7 @@ releases:
     namespace: gatekeeper-system
     createNamespace: true
     chart: gatekeeper/gatekeeper
-    version: 3.16.0
+    version: 3.17.0
     wait: true
     set:
       - name: enableExternalData
diff --git a/dev.high-availability.helmfile.yaml b/dev.high-availability.helmfile.yaml
index 3436a1c55..29c40fe8a 100644
--- a/dev.high-availability.helmfile.yaml
+++ b/dev.high-availability.helmfile.yaml
@@ -20,7 +20,7 @@ releases:
     namespace: gatekeeper-system
     createNamespace: true
     chart: gatekeeper/gatekeeper
-    version: 3.16.0
+    version: 3.17.0
     wait: true
     set:
       - name: enableExternalData
diff --git a/scripts/azure-ci-test.sh b/scripts/azure-ci-test.sh
index c5c7be9c5..b5ddce9ce 100755
--- a/scripts/azure-ci-test.sh
+++ b/scripts/azure-ci-test.sh
@@ -28,7 +28,7 @@ export KEYVAULT_NAME="${KEYVAULT_NAME:-ratify-akv-${SUFFIX}}"
 export USER_ASSIGNED_IDENTITY_NAME="${USER_ASSIGNED_IDENTITY_NAME:-ratify-e2e-identity-${SUFFIX}}"
 export LOCATION="westus2"
 export KUBERNETES_VERSION=${1:-1.29.2}
-GATEKEEPER_VERSION=${2:-3.16.0}
+GATEKEEPER_VERSION=${2:-3.17.0}
 TENANT_ID=$3
 export RATIFY_NAMESPACE=${4:-gatekeeper-system}
 CERT_DIR=${5:-"~/ratify/certs"}

From 630a2bd2ab16eea66ec5656abf8ec21d4e32aa65 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 12 Sep 2024 14:07:53 +0800
Subject: [PATCH 7/8] chore: Bump step-security/harden-runner from 2.10.0 to
 2.10.1 (#1796)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 .github/workflows/build-pr.yml              | 2 +-
 .github/workflows/cache-cleanup.yml         | 2 +-
 .github/workflows/clean-dev-package.yml     | 2 +-
 .github/workflows/codeql.yml                | 2 +-
 .github/workflows/e2e-aks.yml               | 2 +-
 .github/workflows/e2e-cli.yml               | 8 ++++----
 .github/workflows/e2e-k8s.yml               | 2 +-
 .github/workflows/golangci-lint.yml         | 2 +-
 .github/workflows/high-availability.yml     | 2 +-
 .github/workflows/pr-to-main.yml            | 2 +-
 .github/workflows/publish-charts.yml        | 2 +-
 .github/workflows/publish-cosign-sample.yml | 2 +-
 .github/workflows/publish-dev-assets.yml    | 2 +-
 .github/workflows/publish-package.yml       | 2 +-
 .github/workflows/publish-sample.yml        | 2 +-
 .github/workflows/quick-start.yml           | 2 +-
 .github/workflows/release.yml               | 2 +-
 .github/workflows/run-full-validation.yml   | 2 +-
 .github/workflows/scan-vulns.yaml           | 4 ++--
 .github/workflows/scorecards.yml            | 2 +-
 .github/workflows/sync-gh-pages.yml         | 2 +-
 21 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml
index a90b8fdb2..c2a31ba42 100644
--- a/.github/workflows/build-pr.yml
+++ b/.github/workflows/build-pr.yml
@@ -70,7 +70,7 @@ jobs:
     environment: azure-test
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/cache-cleanup.yml b/.github/workflows/cache-cleanup.yml
index b2b69de3f..a248774bf 100644
--- a/.github/workflows/cache-cleanup.yml
+++ b/.github/workflows/cache-cleanup.yml
@@ -12,7 +12,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:      
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/clean-dev-package.yml b/.github/workflows/clean-dev-package.yml
index ce9e17ac3..e355094ca 100644
--- a/.github/workflows/clean-dev-package.yml
+++ b/.github/workflows/clean-dev-package.yml
@@ -13,7 +13,7 @@ jobs:
         packages: write
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 35955608d..4d15ab240 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -27,7 +27,7 @@ jobs:
 
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/e2e-aks.yml b/.github/workflows/e2e-aks.yml
index c710833fc..90799a297 100644
--- a/.github/workflows/e2e-aks.yml
+++ b/.github/workflows/e2e-aks.yml
@@ -28,7 +28,7 @@ jobs:
       contents: read
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/e2e-cli.yml b/.github/workflows/e2e-cli.yml
index c4c64ea19..895d77f26 100644
--- a/.github/workflows/e2e-cli.yml
+++ b/.github/workflows/e2e-cli.yml
@@ -14,7 +14,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
@@ -35,7 +35,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
@@ -64,7 +64,7 @@ jobs:
       contents: read
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
@@ -92,7 +92,7 @@ jobs:
       runs-on: ubuntu-latest
       steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/e2e-k8s.yml b/.github/workflows/e2e-k8s.yml
index a04d7f7c8..22eaa69fc 100644
--- a/.github/workflows/e2e-k8s.yml
+++ b/.github/workflows/e2e-k8s.yml
@@ -26,7 +26,7 @@ jobs:
       contents: read
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml
index c40ca040a..769e06009 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -15,7 +15,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/high-availability.yml b/.github/workflows/high-availability.yml
index 34f04f251..af3ec3b2f 100644
--- a/.github/workflows/high-availability.yml
+++ b/.github/workflows/high-availability.yml
@@ -30,7 +30,7 @@ jobs:
         DAPR_VERSION: ["1.13.2"]
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/pr-to-main.yml b/.github/workflows/pr-to-main.yml
index e8869cc5b..909d7b24c 100644
--- a/.github/workflows/pr-to-main.yml
+++ b/.github/workflows/pr-to-main.yml
@@ -13,7 +13,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/publish-charts.yml b/.github/workflows/publish-charts.yml
index 34df4e587..44b774b5e 100644
--- a/.github/workflows/publish-charts.yml
+++ b/.github/workflows/publish-charts.yml
@@ -13,7 +13,7 @@ jobs:
       contents: write
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/publish-cosign-sample.yml b/.github/workflows/publish-cosign-sample.yml
index ee656a0f7..2dd20426f 100644
--- a/.github/workflows/publish-cosign-sample.yml
+++ b/.github/workflows/publish-cosign-sample.yml
@@ -20,7 +20,7 @@ jobs:
       id-token: write
     steps:            
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/publish-dev-assets.yml b/.github/workflows/publish-dev-assets.yml
index 60b0d8ce8..0bc23c8da 100644
--- a/.github/workflows/publish-dev-assets.yml
+++ b/.github/workflows/publish-dev-assets.yml
@@ -17,7 +17,7 @@ jobs:
     environment: azure-publish
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
       - name: Checkout
diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml
index 17b49127c..e4d81f984 100644
--- a/.github/workflows/publish-package.yml
+++ b/.github/workflows/publish-package.yml
@@ -16,7 +16,7 @@ jobs:
       contents: read
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
       - name: Checkout
diff --git a/.github/workflows/publish-sample.yml b/.github/workflows/publish-sample.yml
index 3dfd19456..91cd14a4a 100644
--- a/.github/workflows/publish-sample.yml
+++ b/.github/workflows/publish-sample.yml
@@ -19,7 +19,7 @@ jobs:
       packages: write
     steps:            
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/quick-start.yml b/.github/workflows/quick-start.yml
index 930f9a343..f6739f243 100644
--- a/.github/workflows/quick-start.yml
+++ b/.github/workflows/quick-start.yml
@@ -30,7 +30,7 @@ jobs:
         KUBERNETES_VERSION: ["1.29.2"]
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 85e0f217d..ab898be3f 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -16,7 +16,7 @@ jobs:
       contents: write
     steps:
     - name: Harden Runner
-      uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+      uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
       with:
         egress-policy: audit
 
diff --git a/.github/workflows/run-full-validation.yml b/.github/workflows/run-full-validation.yml
index 6f4892a30..f6d03c15b 100644
--- a/.github/workflows/run-full-validation.yml
+++ b/.github/workflows/run-full-validation.yml
@@ -58,7 +58,7 @@ jobs:
     environment: azure-test
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/scan-vulns.yaml b/.github/workflows/scan-vulns.yaml
index 66e274256..105eed160 100644
--- a/.github/workflows/scan-vulns.yaml
+++ b/.github/workflows/scan-vulns.yaml
@@ -23,7 +23,7 @@ jobs:
     timeout-minutes: 15
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
@@ -39,7 +39,7 @@ jobs:
     timeout-minutes: 15
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index 63d2cc90c..2180ee329 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -30,7 +30,7 @@ jobs:
     
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
diff --git a/.github/workflows/sync-gh-pages.yml b/.github/workflows/sync-gh-pages.yml
index 0837d5cdf..9af80879f 100644
--- a/.github/workflows/sync-gh-pages.yml
+++ b/.github/workflows/sync-gh-pages.yml
@@ -17,7 +17,7 @@ jobs:
       repository-projects: write
     steps:
       - name: Harden Runner
-        uses: step-security/harden-runner@446798f8213ac2e75931c1b0769676d927801858 # v2.10.0
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 

From b32db85b4bc3f76d5d63de9c23d6d6a46559be09 Mon Sep 17 00:00:00 2001
From: Josh Duffney <jduffney@microsoft.com>
Date: Thu, 12 Sep 2024 08:37:08 -0500
Subject: [PATCH 8/8] fix: missing status update in KMP controller (#1761)

---
 .github/workflows/build-pr.yml                |  16 +-
 .github/workflows/cache-cleanup.yml           |   6 +-
 .github/workflows/clean-dev-package.yml       |  16 +-
 .github/workflows/codeql.yml                  |   7 +-
 .github/workflows/e2e-aks.yml                 |  12 +-
 .github/workflows/e2e-cli.yml                 |  15 +-
 .github/workflows/e2e-k8s.yml                 |  12 +-
 .github/workflows/golangci-lint.yml           |   2 +-
 .github/workflows/high-availability.yml       |   2 +-
 .github/workflows/pr-to-main.yml              |   2 +-
 .github/workflows/publish-charts.yml          |   2 +-
 .github/workflows/publish-cosign-sample.yml   |  10 +-
 .github/workflows/publish-dev-assets.yml      |   8 +-
 .github/workflows/publish-sample.yml          |  18 +-
 .github/workflows/release.yml                 |  72 +--
 .github/workflows/run-full-validation.yml     |   8 +-
 .github/workflows/scan-vulns.yaml             |   2 +-
 .github/workflows/scorecards.yml              |   6 +-
 .github/workflows/sync-gh-pages.yml           |   8 +-
 .../keymanagementprovider_controller.go       | 131 ++++-
 .../keymanagementprovider_controller_test.go  | 537 +++++++++++++++---
 .../keymanagementprovider_controller.go       | 132 ++++-
 .../keymanagementprovider_controller_test.go  | 517 ++++++++++++++---
 pkg/keymanagementprovider/mocks/client.go     |  41 +-
 pkg/keymanagementprovider/mocks/factory.go    |  12 +-
 pkg/keymanagementprovider/mocks/types.go      |  22 +-
 pkg/keymanagementprovider/refresh/factory.go  |  16 +-
 .../refresh/factory_test.go                   |  14 +-
 .../refresh/kubeRefresh.go                    | 164 ++----
 .../refresh/kubeRefreshNamespaced.go          | 211 -------
 .../refresh/kubeRefreshNamespaced_test.go     | 378 ------------
 .../refresh/kubeRefresh_test.go               | 435 +++++---------
 pkg/keymanagementprovider/refresh/refresh.go  |  16 +-
 33 files changed, 1538 insertions(+), 1312 deletions(-)
 delete mode 100644 pkg/keymanagementprovider/refresh/kubeRefreshNamespaced.go
 delete mode 100644 pkg/keymanagementprovider/refresh/kubeRefreshNamespaced_test.go

diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml
index c2a31ba42..804ea6a88 100644
--- a/.github/workflows/build-pr.yml
+++ b/.github/workflows/build-pr.yml
@@ -15,7 +15,7 @@ jobs:
     uses: ./.github/workflows/e2e-cli.yml
     secrets:
       CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
-   
+
   call_test_e2e_basic:
     name: "run e2e on basic matrix"
     if: ${{ ! (contains(github.event.pull_request.labels.*.name, 'safe to test') || github.event_name == 'workflow_dispatch') }}
@@ -26,7 +26,7 @@ jobs:
       matrix:
         KUBERNETES_VERSION: ["1.29.2"]
         GATEKEEPER_VERSION: ["3.17.0"]
-    uses: ./.github/workflows/e2e-k8s.yml 
+    uses: ./.github/workflows/e2e-k8s.yml
     with:
       k8s_version: ${{ matrix.KUBERNETES_VERSION }}
       gatekeeper_version: ${{ matrix.GATEKEEPER_VERSION }}
@@ -39,10 +39,10 @@ jobs:
       matrix:
         KUBERNETES_VERSION: ["1.28.12", "1.29.2"]
         GATEKEEPER_VERSION: ["3.15.0", "3.16.0", "3.17.0"]
-    uses: ./.github/workflows/e2e-k8s.yml 
+    uses: ./.github/workflows/e2e-k8s.yml
     with:
       k8s_version: ${{ matrix.KUBERNETES_VERSION }}
-      gatekeeper_version: ${{ matrix.GATEKEEPER_VERSION }} 
+      gatekeeper_version: ${{ matrix.GATEKEEPER_VERSION }}
 
   build_test_aks_e2e_conditional:
     name: "Build and run e2e Test on AKS with conditions"
@@ -60,9 +60,9 @@ jobs:
       k8s_version: ${{ matrix.KUBERNETES_VERSION }}
       gatekeeper_version: ${{ matrix.GATEKEEPER_VERSION }}
     secrets: inherit
-  
+
   aks-test-cleanup:
-    needs: ['build_test_aks_e2e_conditional']
+    needs: ["build_test_aks_e2e_conditional"]
     runs-on: ubuntu-latest
     permissions:
       id-token: write
@@ -79,7 +79,7 @@ jobs:
       - name: Set up Go 1.22
         uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
         with:
-          go-version: '1.22'
+          go-version: "1.22"
 
       - name: Az CLI login
         uses: azure/login@6c251865b4e6290e7b78be643ea2d005bc51f69a # v2.1.1
@@ -90,4 +90,4 @@ jobs:
 
       - name: clean up
         run: |
-          make e2e-cleanup AZURE_SUBSCRIPTION_ID=${{ secrets.AZURE_SUBSCRIPTION_ID }}
\ No newline at end of file
+          make e2e-cleanup AZURE_SUBSCRIPTION_ID=${{ secrets.AZURE_SUBSCRIPTION_ID }}
diff --git a/.github/workflows/cache-cleanup.yml b/.github/workflows/cache-cleanup.yml
index a248774bf..46042f7f1 100644
--- a/.github/workflows/cache-cleanup.yml
+++ b/.github/workflows/cache-cleanup.yml
@@ -10,7 +10,7 @@ permissions:
 jobs:
   cleanup:
     runs-on: ubuntu-latest
-    steps:      
+    steps:
       - name: Harden Runner
         uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
@@ -19,7 +19,7 @@ jobs:
       - name: Cleanup
         run: |
           gh extension install actions/gh-actions-cache
-          
+
           echo "Fetching list of cache key"
           cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 )
 
@@ -34,4 +34,4 @@ jobs:
         env:
           GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           REPO: ${{ github.repository }}
-          BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
\ No newline at end of file
+          BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
diff --git a/.github/workflows/clean-dev-package.yml b/.github/workflows/clean-dev-package.yml
index e355094ca..0a53bd8d0 100644
--- a/.github/workflows/clean-dev-package.yml
+++ b/.github/workflows/clean-dev-package.yml
@@ -10,7 +10,7 @@ jobs:
   cleanup-packages:
     runs-on: ubuntu-latest
     permissions:
-        packages: write
+      packages: write
     steps:
       - name: Harden Runner
         uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
@@ -19,15 +19,15 @@ jobs:
 
       - name: Clean up ratify-crds-dev
         uses: actions/delete-package-versions@e5bc658cc4c965c472efe991f8beea3981499c55 # v5.0.0
-        with: 
-          package-name: 'ratify-crds-dev'
-          package-type: 'container'
+        with:
+          package-name: "ratify-crds-dev"
+          package-type: "container"
           min-versions-to-keep: 7
           delete-only-pre-release-versions: "true"
       - name: Clean up ratify-dev
         uses: actions/delete-package-versions@e5bc658cc4c965c472efe991f8beea3981499c55 # v5.0.0
-        with: 
-          package-name: 'ratify-dev'
-          package-type: 'container'
+        with:
+          package-name: "ratify-dev"
+          package-type: "container"
           min-versions-to-keep: 7
-          delete-only-pre-release-versions: "true"
\ No newline at end of file
+          delete-only-pre-release-versions: "true"
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 4d15ab240..fe0ac8345 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -1,19 +1,18 @@
-
 name: "CodeQL Scan"
 
 on:
   push:
-    branches: 
+    branches:
       - main
       - dev
       - 1.0.0*
   pull_request:
-    branches: 
+    branches:
       - main
       - dev
       - 1.0.0*
   schedule:
-    - cron: '30 1 * * 0'
+    - cron: "30 1 * * 0"
   workflow_dispatch:
 
 permissions: read-all
diff --git a/.github/workflows/e2e-aks.yml b/.github/workflows/e2e-aks.yml
index 90799a297..f6a2c1f9d 100644
--- a/.github/workflows/e2e-aks.yml
+++ b/.github/workflows/e2e-aks.yml
@@ -7,14 +7,14 @@ on:
   workflow_call:
     inputs:
       k8s_version:
-        description: 'Kubernetes version'
+        description: "Kubernetes version"
         required: true
-        default: '1.29.2'
+        default: "1.29.2"
         type: string
       gatekeeper_version:
-        description: 'Gatekeeper version'
+        description: "Gatekeeper version"
         required: true
-        default: '3.17.0'
+        default: "3.17.0"
         type: string
 
 jobs:
@@ -37,7 +37,7 @@ jobs:
       - name: Set up Go 1.22
         uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
         with:
-          go-version: '1.22'
+          go-version: "1.22"
       - name: Az CLI login
         uses: azure/login@6c251865b4e6290e7b78be643ea2d005bc51f69a # v2.1.1
         with:
@@ -69,4 +69,4 @@ jobs:
         with:
           name: e2e-logs-aks-${{ inputs.k8s_version }}-${{ inputs.gatekeeper_version }}
           path: |
-            logs-*.json
\ No newline at end of file
+            logs-*.json
diff --git a/.github/workflows/e2e-cli.yml b/.github/workflows/e2e-cli.yml
index 895d77f26..67038445c 100644
--- a/.github/workflows/e2e-cli.yml
+++ b/.github/workflows/e2e-cli.yml
@@ -29,8 +29,7 @@ jobs:
         uses: apache/skywalking-eyes/dependency@cd7b195c51fd3d6ad52afceb760719ddc6b3ee91
         with:
           config: .github/licenserc.yml
-          flags:
-            --weak-compatible=true
+          flags: --weak-compatible=true
   build:
     runs-on: ubuntu-latest
     steps:
@@ -89,8 +88,8 @@ jobs:
         with:
           token: ${{ secrets.CODECOV_TOKEN }}
   markdown-link-check:
-      runs-on: ubuntu-latest
-      steps:
+    runs-on: ubuntu-latest
+    steps:
       - name: Harden Runner
         uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
@@ -103,7 +102,7 @@ jobs:
       - name: Run link check
         uses: gaurav-nelson/github-action-markdown-link-check@d53a906aa6b22b8979d33bc86170567e619495ec #3.10.3
         with:
-          use-quiet-mode: 'no'
-          use-verbose-mode: 'yes'
-          config-file: '.github/workflows/markdown.links.config.json'
-          folder-path: 'docs/'
\ No newline at end of file
+          use-quiet-mode: "no"
+          use-verbose-mode: "yes"
+          config-file: ".github/workflows/markdown.links.config.json"
+          folder-path: "docs/"
diff --git a/.github/workflows/e2e-k8s.yml b/.github/workflows/e2e-k8s.yml
index 22eaa69fc..717ff937c 100644
--- a/.github/workflows/e2e-k8s.yml
+++ b/.github/workflows/e2e-k8s.yml
@@ -7,14 +7,14 @@ on:
   workflow_call:
     inputs:
       k8s_version:
-        description: 'Kubernetes version'
+        description: "Kubernetes version"
         required: true
-        default: '1.29.2'
+        default: "1.29.2"
         type: string
       gatekeeper_version:
-        description: 'Gatekeeper version'
+        description: "Gatekeeper version"
         required: true
-        default: '3.17.0'
+        default: "3.17.0"
         type: string
 
 jobs:
@@ -35,7 +35,7 @@ jobs:
       - name: Set up Go 1.22
         uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
         with:
-          go-version: '1.22'
+          go-version: "1.22"
 
       - name: Bootstrap e2e
         run: |
@@ -70,4 +70,4 @@ jobs:
         with:
           name: e2e-logs-${{ inputs.k8s_version }}-${{ inputs.gatekeeper_version }}
           path: |
-            logs-*.json
\ No newline at end of file
+            logs-*.json
diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml
index 769e06009..cb827af40 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -21,7 +21,7 @@ jobs:
 
       - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
         with:
-          go-version: '1.22'
+          go-version: "1.22"
       - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
       - name: golangci-lint
         uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6.1.0
diff --git a/.github/workflows/high-availability.yml b/.github/workflows/high-availability.yml
index af3ec3b2f..631f9bb6f 100644
--- a/.github/workflows/high-availability.yml
+++ b/.github/workflows/high-availability.yml
@@ -39,7 +39,7 @@ jobs:
       - name: Set up Go 1.22
         uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
         with:
-          go-version: '1.22'
+          go-version: "1.22"
 
       - name: Bootstrap e2e
         run: |
diff --git a/.github/workflows/pr-to-main.yml b/.github/workflows/pr-to-main.yml
index 909d7b24c..5fcefe211 100644
--- a/.github/workflows/pr-to-main.yml
+++ b/.github/workflows/pr-to-main.yml
@@ -2,7 +2,7 @@ name: pr_to_main
 
 on:
   schedule:
-    - cron: '30 8 * * 0'  # early morning (08:30 UTC) every Sunday
+    - cron: "30 8 * * 0" # early morning (08:30 UTC) every Sunday
   workflow_dispatch:
 
 permissions:
diff --git a/.github/workflows/publish-charts.yml b/.github/workflows/publish-charts.yml
index 44b774b5e..850838750 100644
--- a/.github/workflows/publish-charts.yml
+++ b/.github/workflows/publish-charts.yml
@@ -21,4 +21,4 @@ jobs:
       - name: Publish Helm charts
         uses: stefanprodan/helm-gh-pages@0ad2bb377311d61ac04ad9eb6f252fb68e207260 # v1.7.0
         with:
-          token: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
+          token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/publish-cosign-sample.yml b/.github/workflows/publish-cosign-sample.yml
index 2dd20426f..566c27885 100644
--- a/.github/workflows/publish-cosign-sample.yml
+++ b/.github/workflows/publish-cosign-sample.yml
@@ -1,11 +1,11 @@
 name: publish-cosign-sample
 
-on: 
+on:
   workflow_dispatch:
-   
+
 env:
   REGISTRY: ghcr.io
-  
+
 permissions:
   contents: read
 
@@ -18,7 +18,7 @@ jobs:
       contents: write
       packages: write
       id-token: write
-    steps:            
+    steps:
       - name: Harden Runner
         uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
@@ -28,7 +28,7 @@ jobs:
         uses: sigstore/cosign-installer@4959ce089c160fddf62f7b42464195ba1a56d382 # v3.6.0
 
       - name: Get repo
-        run: |          
+        run: |
           echo "REPOSITORY=${{ env.REGISTRY }}/${{ github.repository }}" >> $GITHUB_ENV
 
       - name: Write signing key to disk
diff --git a/.github/workflows/publish-dev-assets.yml b/.github/workflows/publish-dev-assets.yml
index 0bc23c8da..c64a243e8 100644
--- a/.github/workflows/publish-dev-assets.yml
+++ b/.github/workflows/publish-dev-assets.yml
@@ -2,7 +2,7 @@ name: publish-dev-assets
 
 on:
   schedule:
-    - cron: '30 8 * * 0'  # early morning (08:30 UTC) every Sunday
+    - cron: "30 8 * * 0" # early morning (08:30 UTC) every Sunday
   workflow_dispatch:
 
 permissions: read-all
@@ -108,11 +108,11 @@ jobs:
         run: |
           sed -i '/^  repository:/c\  repository: ghcr.io/ratify-project/ratify-dev' charts/ratify/values.yaml
           sed -i '/^  crdRepository:/c\  crdRepository: ghcr.io/ratify-project/ratify-crds-dev' charts/ratify/values.yaml
-          sed -i '/^  tag:/c\  tag: ${{ steps.prepare.outputs.version }}' charts/ratify/values.yaml 
+          sed -i '/^  tag:/c\  tag: ${{ steps.prepare.outputs.version }}' charts/ratify/values.yaml
       - name: helm package
         run: |
-            helm package ./charts/ratify --version ${{ steps.prepare.outputs.semversion }}
-            helm package ./charts/ratify --version ${{ steps.prepare.outputs.semversionrolling }}
+          helm package ./charts/ratify --version ${{ steps.prepare.outputs.semversion }}
+          helm package ./charts/ratify --version ${{ steps.prepare.outputs.semversionrolling }}
       - name: helm push
         run: |
           helm push ratify-${{ steps.prepare.outputs.semversion }}.tgz oci://${{ steps.prepare.outputs.chartrepo }}
diff --git a/.github/workflows/publish-sample.yml b/.github/workflows/publish-sample.yml
index 91cd14a4a..52981797d 100644
--- a/.github/workflows/publish-sample.yml
+++ b/.github/workflows/publish-sample.yml
@@ -1,11 +1,11 @@
 name: publish-sample
 
-on: 
- workflow_dispatch:
+on:
+  workflow_dispatch:
 
 env:
   REGISTRY: ghcr.io
-  
+
 permissions:
   contents: read
 
@@ -17,14 +17,14 @@ jobs:
     permissions:
       contents: write
       packages: write
-    steps:            
+    steps:
       - name: Harden Runner
         uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
           egress-policy: audit
 
       - name: Get repo
-        run: |          
+        run: |
           echo "REPOSITORY=${{ env.REGISTRY }}/${{ github.repository }}" >> $GITHUB_ENV
 
       - name: Log in to the GHCR
@@ -35,9 +35,7 @@ jobs:
           password: ${{ secrets.GITHUB_TOKEN }}
 
       - name: Copy signed sample test image
-        run: 
-          oras cp -r wabbitnetworks.azurecr.io/ratify/notary-image:signed ${REPOSITORY}/notary-image:signed
+        run: oras cp -r wabbitnetworks.azurecr.io/ratify/notary-image:signed ${REPOSITORY}/notary-image:signed
 
-      - name: Copy unsigned sample test image 
-        run: 
-          oras cp wabbitnetworks.azurecr.io/ratify/notary-image:unsigned ${REPOSITORY}/notary-image:unsigned
+      - name: Copy unsigned sample test image
+        run: oras cp wabbitnetworks.azurecr.io/ratify/notary-image:unsigned ${REPOSITORY}/notary-image:unsigned
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ab898be3f..e261c1bd6 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -3,7 +3,7 @@ name: Release Ratify
 on:
   push:
     tags:
-      - 'v*'
+      - "v*"
   workflow_dispatch:
 
 permissions: read-all
@@ -15,41 +15,41 @@ jobs:
     permissions:
       contents: write
     steps:
-    - name: Harden Runner
-      uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
-      with:
-        egress-policy: audit
-
-    - name: Checkout
-      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag=3.0.2
-      with:
+      - name: Harden Runner
+        uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
+        with:
+          egress-policy: audit
+
+      - name: Checkout
+        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag=3.0.2
+        with:
           fetch-depth: 0
-    
-    - name: Install Syft
-      uses: anchore/sbom-action/download-syft@61119d458adab75f756bc0b9e4bde25725f86a7a # v0.17.2
-          
-    - name: Set up Go
-      uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
-      with:
-        go-version: '1.22'
-
-    - name: Goreleaser
-      id: goreleaser
-      uses: goreleaser/goreleaser-action@286f3b13b1b49da4ac219696163fb8c1c93e1200 # v6.0.0
-      with:
-        version: '2.0.1'
-        args: release --clean
-      env:
+
+      - name: Install Syft
+        uses: anchore/sbom-action/download-syft@61119d458adab75f756bc0b9e4bde25725f86a7a # v0.17.2
+
+      - name: Set up Go
+        uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
+        with:
+          go-version: "1.22"
+
+      - name: Goreleaser
+        id: goreleaser
+        uses: goreleaser/goreleaser-action@286f3b13b1b49da4ac219696163fb8c1c93e1200 # v6.0.0
+        with:
+          version: "2.0.1"
+          args: release --clean
+        env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 
-    - name: Generate SBOM
-      run: |
-        curl -Lo $RUNNER_TEMP/sbom-tool https://github.com/microsoft/sbom-tool/releases/latest/download/sbom-tool-linux-x64
-        chmod +x $RUNNER_TEMP/sbom-tool
-        $RUNNER_TEMP/sbom-tool generate -b . -bc . -pn ratify -pv $GITHUB_REF_NAME -ps Microsoft -nsb https://microsoft.com -V Verbose
-
-    - name: Upload a Build Artifact
-      uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # tag=v4.4.0
-      with:
-        name: SBOM SPDX files
-        path: _manifest/spdx_2.2/**
+      - name: Generate SBOM
+        run: |
+          curl -Lo $RUNNER_TEMP/sbom-tool https://github.com/microsoft/sbom-tool/releases/latest/download/sbom-tool-linux-x64
+          chmod +x $RUNNER_TEMP/sbom-tool
+          $RUNNER_TEMP/sbom-tool generate -b . -bc . -pn ratify -pv $GITHUB_REF_NAME -ps Microsoft -nsb https://microsoft.com -V Verbose
+
+      - name: Upload a Build Artifact
+        uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # tag=v4.4.0
+        with:
+          name: SBOM SPDX files
+          path: _manifest/spdx_2.2/**
diff --git a/.github/workflows/run-full-validation.yml b/.github/workflows/run-full-validation.yml
index f6d03c15b..3f2464cbc 100644
--- a/.github/workflows/run-full-validation.yml
+++ b/.github/workflows/run-full-validation.yml
@@ -28,7 +28,7 @@ jobs:
       matrix:
         KUBERNETES_VERSION: ["1.28.12", "1.29.2"]
         GATEKEEPER_VERSION: ["3.15.0", "3.16.0", "3.17.0"]
-    uses: ./.github/workflows/e2e-k8s.yml 
+    uses: ./.github/workflows/e2e-k8s.yml
     with:
       k8s_version: ${{ matrix.KUBERNETES_VERSION }}
       gatekeeper_version: ${{ matrix.GATEKEEPER_VERSION }}
@@ -50,7 +50,7 @@ jobs:
     secrets: inherit
 
   aks-test-cleanup:
-    needs: ['build_test_aks_e2e']
+    needs: ["build_test_aks_e2e"]
     runs-on: ubuntu-latest
     permissions:
       id-token: write
@@ -67,7 +67,7 @@ jobs:
       - name: Set up Go 1.22
         uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
         with:
-          go-version: '1.22'
+          go-version: "1.22"
 
       - name: Az CLI login
         uses: azure/login@6c251865b4e6290e7b78be643ea2d005bc51f69a # v2.1.1
@@ -78,4 +78,4 @@ jobs:
 
       - name: clean up
         run: |
-          make e2e-cleanup AZURE_SUBSCRIPTION_ID=${{ secrets.AZURE_SUBSCRIPTION_ID }}
\ No newline at end of file
+          make e2e-cleanup AZURE_SUBSCRIPTION_ID=${{ secrets.AZURE_SUBSCRIPTION_ID }}
diff --git a/.github/workflows/scan-vulns.yaml b/.github/workflows/scan-vulns.yaml
index 105eed160..aed9bba20 100644
--- a/.github/workflows/scan-vulns.yaml
+++ b/.github/workflows/scan-vulns.yaml
@@ -11,7 +11,7 @@ on:
       - "library/**"
       - "**.md"
   schedule:
-    - cron: '30 8 * * 0'  # early morning (08:30 UTC) every Sunday
+    - cron: "30 8 * * 0" # early morning (08:30 UTC) every Sunday
   workflow_dispatch:
 
 permissions: read-all
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index 2180ee329..96efefe42 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -3,7 +3,7 @@ on:
   branch_protection_rule:
   schedule:
     # Weekly on Saturdays.
-    - cron: '30 1 * * 6'
+    - cron: "30 1 * * 6"
   push:
     branches:
       - main
@@ -27,7 +27,7 @@ jobs:
       id-token: write
       actions: read
       contents: read
-    
+
     steps:
       - name: Harden Runner
         uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
@@ -53,7 +53,7 @@ jobs:
           name: SARIF file
           path: results.sarif
           retention-days: 5
-      
+
       - name: "Upload to code-scanning"
         uses: github/codeql-action/upload-sarif@4dd16135b69a43b6c8efb853346f8437d92d3c93 # tag=v3.26.6
         with:
diff --git a/.github/workflows/sync-gh-pages.yml b/.github/workflows/sync-gh-pages.yml
index 9af80879f..8c584c7e7 100644
--- a/.github/workflows/sync-gh-pages.yml
+++ b/.github/workflows/sync-gh-pages.yml
@@ -2,9 +2,9 @@ name: Sync GH Pages
 on:
   push:
     branches:
-    - main
+      - main
     paths:
-    - library/**
+      - library/**
 
 permissions: read-all
 
@@ -26,5 +26,5 @@ jobs:
         with:
           github_token: ${{ github.token }}
           source_ref: ${{ github.ref }}
-          target_branch: 'gh-pages'
-          commit_message_template: '[Automated] Merged {source_ref} into target {target_branch}'
\ No newline at end of file
+          target_branch: "gh-pages"
+          commit_message_template: "[Automated] Merged {source_ref} into target {target_branch}"
diff --git a/pkg/controllers/clusterresource/keymanagementprovider_controller.go b/pkg/controllers/clusterresource/keymanagementprovider_controller.go
index 93dda9806..afb53a904 100644
--- a/pkg/controllers/clusterresource/keymanagementprovider_controller.go
+++ b/pkg/controllers/clusterresource/keymanagementprovider_controller.go
@@ -18,11 +18,19 @@ package clusterresource
 
 import (
 	"context"
+	"encoding/json"
 	"fmt"
 
+	re "github.com/ratify-project/ratify/errors"
+	"github.com/ratify-project/ratify/internal/constants"
+	cutils "github.com/ratify-project/ratify/pkg/controllers/utils"
+	kmp "github.com/ratify-project/ratify/pkg/keymanagementprovider"
 	_ "github.com/ratify-project/ratify/pkg/keymanagementprovider/azurekeyvault" // register azure key vault key management provider
 	_ "github.com/ratify-project/ratify/pkg/keymanagementprovider/inline"        // register inline key management provider
 	"github.com/ratify-project/ratify/pkg/keymanagementprovider/refresh"
+	"github.com/sirupsen/logrus"
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
@@ -37,20 +45,91 @@ type KeyManagementProviderReconciler struct {
 	Scheme *runtime.Scheme
 }
 
-func (r *KeyManagementProviderReconciler) ReconcileWithConfig(ctx context.Context, config map[string]interface{}) (ctrl.Result, error) {
-	refresher, err := refresh.CreateRefresherFromConfig(config)
-	if err != nil {
+func (r *KeyManagementProviderReconciler) ReconcileWithType(ctx context.Context, req ctrl.Request, refresherType string) (ctrl.Result, error) {
+	logger := logrus.WithContext(ctx)
+
+	var keyManagementProvider configv1beta1.KeyManagementProvider
+
+	resource := req.Name
+
+	logger.Infof("reconciling cluster key management provider '%v'", resource)
+
+	if err := r.Get(ctx, req.NamespacedName, &keyManagementProvider); err != nil {
+		if apierrors.IsNotFound(err) {
+			logger.Infof("deletion detected, removing key management provider %v", resource)
+			kmp.DeleteResourceFromMap(resource)
+		} else {
+			logger.Error(err, "unable to fetch key management provider")
+		}
+
+		return ctrl.Result{}, client.IgnoreNotFound(err)
+	}
+
+	lastFetchedTime := metav1.Now()
+
+	// get certificate store list to check if certificate store is configured
+	// TODO: remove check in v2.0.0+
+	var certificateStoreList configv1beta1.CertificateStoreList
+	if err := r.List(ctx, &certificateStoreList); err != nil {
+		logger.Error(err, "unable to list certificate stores")
 		return ctrl.Result{}, err
 	}
+
+	if len(certificateStoreList.Items) > 0 {
+		// Note: for backwards compatibility in upgrade scenarios, Ratify will only log a warning statement.
+		logger.Warn("Certificate Store already exists. Key management provider and certificate store should not be configured together. Please migrate to key management provider and delete certificate store.")
+	}
+
+	provider, err := cutils.SpecToKeyManagementProvider(keyManagementProvider.Spec.Parameters.Raw, keyManagementProvider.Spec.Type)
+	if err != nil {
+		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail("Failed to create key management provider from CR")
+
+		kmp.SetCertificateError(resource, kmpErr)
+		kmp.SetKeyError(resource, kmpErr)
+		writeKMProviderStatus(ctx, r, &keyManagementProvider, logger, false, &kmpErr, lastFetchedTime, nil)
+		return ctrl.Result{}, kmpErr
+	}
+
+	refresherConfig := refresh.RefresherConfig{
+		RefresherType:           refresherType,
+		Provider:                provider,
+		ProviderType:            keyManagementProvider.Spec.Type,
+		ProviderRefreshInterval: keyManagementProvider.Spec.RefreshInterval,
+		Resource:                resource,
+	}
+
+	refresher, err := refresh.CreateRefresherFromConfig(refresherConfig)
+	if err != nil {
+		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail("Failed to create refresher from config")
+		kmp.SetCertificateError(resource, kmpErr)
+		kmp.SetKeyError(resource, kmpErr)
+		writeKMProviderStatus(ctx, r, &keyManagementProvider, logger, false, &kmpErr, lastFetchedTime, nil)
+		return ctrl.Result{}, kmpErr
+	}
+
 	err = refresher.Refresh(ctx)
 	if err != nil {
-		return ctrl.Result{}, err
+		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail("Failed to refresh key management provider")
+		writeKMProviderStatus(ctx, r, &keyManagementProvider, logger, false, &kmpErr, lastFetchedTime, nil)
+		return ctrl.Result{}, kmpErr
 	}
 
 	result, ok := refresher.GetResult().(ctrl.Result)
 	if !ok {
+		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail("Failed to get result from refresher")
+		writeKMProviderStatus(ctx, r, &keyManagementProvider, logger, false, &kmpErr, lastFetchedTime, nil)
 		return ctrl.Result{}, fmt.Errorf("unexpected type returned from GetResult: %T", refresher.GetResult())
 	}
+
+	status, ok := refresher.GetStatus().(kmp.KeyManagementProviderStatus)
+	if !ok {
+		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail("Failed to get status from refresher")
+		writeKMProviderStatus(ctx, r, &keyManagementProvider, logger, false, &kmpErr, lastFetchedTime, nil)
+		return ctrl.Result{}, fmt.Errorf("unexpected type returned from GetStatus: %T", refresher.GetStatus())
+	}
+
+	writeKMProviderStatus(ctx, r, &keyManagementProvider, logger, true, nil, lastFetchedTime, status)
+
 	return result, nil
 }
 
@@ -58,12 +137,7 @@ func (r *KeyManagementProviderReconciler) ReconcileWithConfig(ctx context.Contex
 // +kubebuilder:rbac:groups=config.ratify.deislabs.io,resources=keymanagementproviders/status,verbs=get;update;patch
 // +kubebuilder:rbac:groups=config.ratify.deislabs.io,resources=keymanagementproviders/finalizers,verbs=update
 func (r *KeyManagementProviderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
-	refresherConfig := map[string]interface{}{
-		"type":    refresh.KubeRefresherType,
-		"client":  r.Client,
-		"request": req,
-	}
-	return r.ReconcileWithConfig(ctx, refresherConfig)
+	return r.ReconcileWithType(ctx, req, refresh.KubeRefresherType)
 }
 
 // SetupWithManager sets up the controller with the Manager.
@@ -77,3 +151,40 @@ func (r *KeyManagementProviderReconciler) SetupWithManager(mgr ctrl.Manager) err
 		For(&configv1beta1.KeyManagementProvider{}).WithEventFilter(pred).
 		Complete(r)
 }
+
+func writeKMProviderStatus(ctx context.Context, r client.StatusClient, keyManagementProvider *configv1beta1.KeyManagementProvider, logger *logrus.Entry, isSuccess bool, err *re.Error, operationTime metav1.Time, kmProviderStatus kmp.KeyManagementProviderStatus) {
+	if isSuccess {
+		updateKMProviderSuccessStatus(keyManagementProvider, &operationTime, kmProviderStatus)
+	} else {
+		updateKMProviderErrorStatus(keyManagementProvider, err, &operationTime)
+	}
+	if statusErr := r.Status().Update(ctx, keyManagementProvider); statusErr != nil {
+		logger.Error(statusErr, ",unable to update key management provider error status")
+	}
+}
+
+// updateKMProviderErrorStatus updates the key management provider status with error, brief error and last fetched time
+func updateKMProviderErrorStatus(keyManagementProvider *configv1beta1.KeyManagementProvider, err *re.Error, operationTime *metav1.Time) {
+	keyManagementProvider.Status.IsSuccess = false
+	keyManagementProvider.Status.Error = err.Error()
+	keyManagementProvider.Status.BriefError = err.GetConciseError(constants.MaxBriefErrLength)
+	keyManagementProvider.Status.LastFetchedTime = operationTime
+}
+
+// updateKMProviderSuccessStatus updates the key management provider status if status argument is non nil
+// Success status includes last fetched time and other provider-specific properties
+func updateKMProviderSuccessStatus(keyManagementProvider *configv1beta1.KeyManagementProvider, lastOperationTime *metav1.Time, kmProviderStatus kmp.KeyManagementProviderStatus) {
+	keyManagementProvider.Status.IsSuccess = true
+	keyManagementProvider.Status.Error = ""
+	keyManagementProvider.Status.BriefError = ""
+	keyManagementProvider.Status.LastFetchedTime = lastOperationTime
+
+	if kmProviderStatus != nil {
+		jsonString, _ := json.Marshal(kmProviderStatus)
+
+		raw := runtime.RawExtension{
+			Raw: jsonString,
+		}
+		keyManagementProvider.Status.Properties = raw
+	}
+}
diff --git a/pkg/controllers/clusterresource/keymanagementprovider_controller_test.go b/pkg/controllers/clusterresource/keymanagementprovider_controller_test.go
index d4129e2c6..60254eeef 100644
--- a/pkg/controllers/clusterresource/keymanagementprovider_controller_test.go
+++ b/pkg/controllers/clusterresource/keymanagementprovider_controller_test.go
@@ -18,82 +18,357 @@ package clusterresource
 import (
 	"context"
 	"errors"
+	"fmt"
 	"reflect"
 	"testing"
 
-	"github.com/ratify-project/ratify/pkg/keymanagementprovider/refresh"
+	configv1beta1 "github.com/ratify-project/ratify/api/v1beta1"
+	"github.com/ratify-project/ratify/pkg/keymanagementprovider"
+	"github.com/ratify-project/ratify/pkg/keymanagementprovider/mocks"
 	test "github.com/ratify-project/ratify/pkg/utils"
+	"github.com/sirupsen/logrus"
+
+	re "github.com/ratify-project/ratify/errors"
+	kmp "github.com/ratify-project/ratify/pkg/keymanagementprovider"
+	"github.com/ratify-project/ratify/pkg/keymanagementprovider/refresh"
+
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apimachinery/pkg/types"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 )
 
-func TestKeyManagementProviderReconciler_ReconcileWithConfig(t *testing.T) {
+func init() {
+	refresh.Register("mockRefresher", &MockRefresher{})
+}
+
+type MockRefresher struct {
+	Result       ctrl.Result
+	RefreshError bool
+	ResultError  bool
+	StatusError  bool
+	Status       kmp.KeyManagementProviderStatus
+}
+
+func (mr *MockRefresher) Refresh(_ context.Context) error {
+	if mr.RefreshError {
+		return errors.New("error from refresh")
+	}
+	return nil
+}
+
+func (mr *MockRefresher) GetResult() interface{} {
+	if mr.ResultError {
+		return errors.New("error from result")
+	}
+	return mr.Result
+}
+
+func (mr *MockRefresher) GetStatus() interface{} {
+	if mr.StatusError {
+		return errors.New("error from status")
+	}
+	return mr.Status
+}
+
+func (mr *MockRefresher) Create(config refresh.RefresherConfig) (refresh.Refresher, error) {
+	if config.Resource == "refreshError" {
+		return &MockRefresher{
+			RefreshError: true,
+		}, nil
+	}
+	if config.Resource == "resultError" {
+		return &MockRefresher{
+			ResultError: true,
+		}, nil
+	}
+	if config.Resource == "statusError" {
+		return &MockRefresher{
+			StatusError: true,
+		}, nil
+	}
+	return &MockRefresher{}, nil
+}
+
+func TestKeyManagementProviderReconciler_ReconcileWithType(t *testing.T) {
 	tests := []struct {
-		name              string
-		refresherType     string
-		createConfigError bool
-		refreshError      bool
-		expectedError     bool
+		name           string
+		clientGetFunc  func(_ context.Context, key types.NamespacedName, obj client.Object) error
+		clientListFunc func(_ context.Context, list client.ObjectList) error
+		resourceName   string
+		refresherType  string
+		expectedResult ctrl.Result
+		expectedError  bool
 	}{
 		{
-			name:              "Successful Reconcile",
-			refresherType:     "mockRefresher",
-			createConfigError: false,
-			refreshError:      false,
-			expectedError:     false,
+			// TODO: Add SetLogger to internal/logger/logger.go to compare log messages
+			// https://maxchadwick.xyz/blog/testing-log-output-in-go-logrus
+			name: "api is not found",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, _ client.Object) error {
+				resource := schema.GroupResource{
+					Group:    "",     // Use an empty string for core resources (like Pod)
+					Resource: "pods", // Resource type, e.g., "pods" for Pod resources
+				}
+				return apierrors.NewNotFound(resource, "test")
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			refresherType:  "mockRefresher",
+			expectedResult: ctrl.Result{},
+			expectedError:  false,
+		},
+		{
+			name: "unable to fetch key management provider",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, _ client.Object) error {
+				return fmt.Errorf("unable to fetch key management provider")
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			refresherType:  "mockRefresher",
+			expectedResult: ctrl.Result{},
+			expectedError:  false,
+		},
+		{
+			name: "unable to list certificate stores",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, _ client.Object) error {
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return fmt.Errorf("unable to list certificate stores")
+			},
+			refresherType:  "mockRefresher",
+			expectedResult: ctrl.Result{},
+			expectedError:  true,
+		},
+		{
+			name: "certificate store already exists",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.KeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				getKMP.Spec = configv1beta1.KeyManagementProviderSpec{
+					Type: "inline",
+					Parameters: runtime.RawExtension{
+						Raw: []byte(`{"type": "inline", "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"}`),
+					},
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, list client.ObjectList) error {
+				certStoreList, ok := list.(*configv1beta1.CertificateStoreList)
+				if !ok {
+					return errors.New("expected CertificateStoreList")
+				}
+
+				certStoreList.Items = []configv1beta1.CertificateStore{
+					{
+						ObjectMeta: metav1.ObjectMeta{
+							Name: "test",
+						},
+					},
+				}
+				return nil
+			},
+			refresherType:  "mockRefresher",
+			expectedResult: ctrl.Result{},
+			expectedError:  false,
+		},
+		{
+			name: "cutils.SpecToKeyManagementProvider failed",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.KeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			refresherType:  "mockRefresher",
+			expectedResult: ctrl.Result{},
+			expectedError:  true,
+		},
+		{
+			name: "refresh.CreateRefresherFromConfig failed",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.KeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				getKMP.Spec = configv1beta1.KeyManagementProviderSpec{
+					Type: "inline",
+					Parameters: runtime.RawExtension{
+						Raw: []byte(`{"type": "inline", "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"}`),
+					},
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			refresherType:  "invalidRefresher",
+			expectedResult: ctrl.Result{},
+			expectedError:  true,
+		},
+		{
+			name: "refresh.Refresh failed",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.KeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				getKMP.Spec = configv1beta1.KeyManagementProviderSpec{
+					Type: "inline",
+					Parameters: runtime.RawExtension{
+						Raw: []byte(`{"type": "inline", "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"}`),
+					},
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			resourceName:   "refreshError",
+			refresherType:  "mockRefresher",
+			expectedResult: ctrl.Result{},
+			expectedError:  true,
 		},
 		{
-			name:              "Refresher Error",
-			refresherType:     "mockRefresher",
-			createConfigError: false,
-			refreshError:      true,
-			expectedError:     true,
+			name: "refresher.GetResult failed",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.KeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				getKMP.Spec = configv1beta1.KeyManagementProviderSpec{
+					Type: "inline",
+					Parameters: runtime.RawExtension{
+						Raw: []byte(`{"type": "inline", "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"}`),
+					},
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			resourceName:   "resultError",
+			refresherType:  "mockRefresher",
+			expectedResult: ctrl.Result{},
+			expectedError:  true,
 		},
 		{
-			name:              "Invalid Refresher Type",
-			refresherType:     "invalidRefresher",
-			createConfigError: true,
-			refreshError:      false,
-			expectedError:     true,
+			name: "refresher.GetStatus failed",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.KeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				getKMP.Spec = configv1beta1.KeyManagementProviderSpec{
+					Type: "inline",
+					Parameters: runtime.RawExtension{
+						Raw: []byte(`{"type": "inline", "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"}`),
+					},
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			resourceName:   "statusError",
+			refresherType:  "mockRefresher",
+			expectedResult: ctrl.Result{},
+			expectedError:  true,
+		},
+		{
+			name: "successfully reconciled",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.KeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				getKMP.Spec = configv1beta1.KeyManagementProviderSpec{
+					Type: "inline",
+					Parameters: runtime.RawExtension{
+						Raw: []byte(`{"type": "inline", "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"}`),
+					},
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			refresherType:  "mockRefresher",
+			expectedResult: ctrl.Result{},
+			expectedError:  false,
 		},
 	}
+
 	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			req := ctrl.Request{
-				NamespacedName: client.ObjectKey{
-					Name:      "fake-name",
-					Namespace: "fake-namespace",
-				},
-			}
-			scheme, _ := test.CreateScheme()
-			client := fake.NewClientBuilder().WithScheme(scheme).Build()
+		fmt.Println(tt.name)
+		mockClient := mocks.TestClient{
+			GetFunc:  tt.clientGetFunc,
+			ListFunc: tt.clientListFunc,
+		}
+		req := ctrl.Request{
+			NamespacedName: client.ObjectKey{
+				Name:      tt.resourceName,
+				Namespace: "test",
+			},
+		}
+		scheme, _ := test.CreateScheme()
 
-			r := &KeyManagementProviderReconciler{
-				Client: client,
-				Scheme: runtime.NewScheme(),
-			}
+		r := &KeyManagementProviderReconciler{
+			Client: &mockClient,
+			Scheme: scheme,
+		}
 
-			refresherConfig := map[string]interface{}{
-				"type":              tt.refresherType,
-				"client":            client,
-				"request":           req,
-				"createConfigError": tt.createConfigError,
-				"refreshError":      tt.refreshError,
-				"shouldError":       tt.expectedError,
-			}
+		result, err := r.ReconcileWithType(context.Background(), req, tt.refresherType)
 
-			_, err := r.ReconcileWithConfig(context.TODO(), refresherConfig)
-			if tt.expectedError && err == nil {
-				t.Errorf("Expected error, got nil")
-			}
-			if !tt.expectedError && err != nil {
-				t.Errorf("Expected no error, got %v", err)
-			}
-		})
+		if !reflect.DeepEqual(result, tt.expectedResult) {
+			t.Fatalf("Expected result %v, got %v", tt.expectedResult, result)
+		}
+		if tt.expectedError && err == nil {
+			t.Fatalf("Expected error, got nil")
+		}
 	}
 }
+
 func TestKeyManagementProviderReconciler_Reconcile(t *testing.T) {
 	req := ctrl.Request{
 		NamespacedName: client.ObjectKey{
@@ -124,36 +399,150 @@ func TestKeyManagementProviderReconciler_Reconcile(t *testing.T) {
 	}
 }
 
-type MockRefresher struct {
-	Results           ctrl.Result
-	CreateConfigError bool
-	RefreshError      bool
-	ShouldError       bool
-}
+// TestUpdateErrorStatus tests the updateErrorStatus method
+func TestKMProviderUpdateErrorStatus(t *testing.T) {
+	var parametersString = "{\"certs\":{\"name\":\"certName\"}}"
+	var kmProviderStatus = []byte(parametersString)
 
-func (mr *MockRefresher) Refresh(_ context.Context) error {
-	if mr.RefreshError {
-		return errors.New("refresh error")
+	status := configv1beta1.KeyManagementProviderStatus{
+		IsSuccess: true,
+		Properties: runtime.RawExtension{
+			Raw: kmProviderStatus,
+		},
+	}
+	keyManagementProvider := configv1beta1.KeyManagementProvider{
+		Status: status,
+	}
+	expectedErr := re.ErrorCodeUnknown.WithDetail("it's a long error from unit test")
+	lastFetchedTime := metav1.Now()
+	updateKMProviderErrorStatus(&keyManagementProvider, &expectedErr, &lastFetchedTime)
+
+	if keyManagementProvider.Status.IsSuccess != false {
+		t.Fatalf("Unexpected error, expected isSuccess to be false , actual %+v", keyManagementProvider.Status.IsSuccess)
+	}
+
+	if keyManagementProvider.Status.Error != expectedErr.Error() {
+		t.Fatalf("Unexpected error string, expected %+v, got %+v", expectedErr, keyManagementProvider.Status.Error)
+	}
+	if keyManagementProvider.Status.BriefError != expectedErr.GetConciseError(150) {
+		t.Fatalf("Unexpected error string, expected %+v, got %+v", expectedErr.GetConciseError(150), keyManagementProvider.Status.Error)
+	}
+
+	//make sure properties of last cached cert was not overridden
+	if len(keyManagementProvider.Status.Properties.Raw) == 0 {
+		t.Fatalf("Unexpected properties,  expected %+v, got %+v", parametersString, string(keyManagementProvider.Status.Properties.Raw))
 	}
-	return nil
 }
 
-func (mr *MockRefresher) GetResult() interface{} {
-	return ctrl.Result{}
+// TestKMProviderUpdateSuccessStatus tests the updateSuccessStatus method
+func TestKMProviderUpdateSuccessStatus(t *testing.T) {
+	kmProviderStatus := keymanagementprovider.KeyManagementProviderStatus{}
+	properties := map[string]string{}
+	properties["Name"] = "wabbit"
+	properties["Version"] = "ABC"
+
+	kmProviderStatus["Certificates"] = properties
+
+	lastFetchedTime := metav1.Now()
+
+	status := configv1beta1.KeyManagementProviderStatus{
+		IsSuccess: false,
+		Error:     "error from last operation",
+	}
+	keyManagementProvider := configv1beta1.KeyManagementProvider{
+		Status: status,
+	}
+
+	updateKMProviderSuccessStatus(&keyManagementProvider, &lastFetchedTime, kmProviderStatus)
+
+	if keyManagementProvider.Status.IsSuccess != true {
+		t.Fatalf("Expected isSuccess to be true , actual %+v", keyManagementProvider.Status.IsSuccess)
+	}
+
+	if keyManagementProvider.Status.Error != "" {
+		t.Fatalf("Unexpected error string, actual %+v", keyManagementProvider.Status.Error)
+	}
+
+	//make sure properties of last cached cert was updated
+	if len(keyManagementProvider.Status.Properties.Raw) == 0 {
+		t.Fatalf("Properties should not be empty")
+	}
 }
 
-func (mr *MockRefresher) Create(config map[string]interface{}) (refresh.Refresher, error) {
-	createConfigError := config["createConfigError"].(bool)
-	refreshError := config["refreshError"].(bool)
-	if createConfigError {
-		return nil, errors.New("create error")
+// TestKMProviderUpdateSuccessStatus tests the updateSuccessStatus method with empty properties
+func TestKMProviderUpdateSuccessStatus_emptyProperties(t *testing.T) {
+	lastFetchedTime := metav1.Now()
+	status := configv1beta1.KeyManagementProviderStatus{
+		IsSuccess: false,
+		Error:     "error from last operation",
+	}
+	keyManagementProvider := configv1beta1.KeyManagementProvider{
+		Status: status,
+	}
+
+	updateKMProviderSuccessStatus(&keyManagementProvider, &lastFetchedTime, nil)
+
+	if keyManagementProvider.Status.IsSuccess != true {
+		t.Fatalf("Expected isSuccess to be true , actual %+v", keyManagementProvider.Status.IsSuccess)
+	}
+
+	if keyManagementProvider.Status.Error != "" {
+		t.Fatalf("Unexpected error string, actual %+v", keyManagementProvider.Status.Error)
+	}
+
+	//make sure properties of last cached cert was updated
+	if len(keyManagementProvider.Status.Properties.Raw) != 0 {
+		t.Fatalf("Properties should be empty")
 	}
-	return &MockRefresher{
-		CreateConfigError: createConfigError,
-		RefreshError:      refreshError,
-	}, nil
 }
+func TestWriteKMProviderStatus(t *testing.T) {
+	logger := logrus.WithContext(context.Background())
+	lastFetchedTime := metav1.Now()
+	testCases := []struct {
+		name              string
+		isSuccess         bool
+		kmProvider        *configv1beta1.KeyManagementProvider
+		errString         string
+		expectedErrString string
+		reconciler        client.StatusClient
+	}{
+		{
+			name:       "success status",
+			isSuccess:  true,
+			errString:  "",
+			kmProvider: &configv1beta1.KeyManagementProvider{},
+			reconciler: &test.MockStatusClient{},
+		},
+		{
+			name:              "error status",
+			isSuccess:         false,
+			kmProvider:        &configv1beta1.KeyManagementProvider{},
+			errString:         "a long error string that exceeds the max length of 150 characters",
+			expectedErrString: "UNKNOWN: a long error string that exceeds the max length of 150 characters",
+			reconciler:        &test.MockStatusClient{},
+		},
+		{
+			name:       "status update failed",
+			isSuccess:  true,
+			kmProvider: &configv1beta1.KeyManagementProvider{},
+			reconciler: &test.MockStatusClient{
+				UpdateFailed: true,
+			},
+		},
+	}
 
-func init() {
-	refresh.Register("mockRefresher", &MockRefresher{})
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			err := re.ErrorCodeUnknown.WithDetail(tc.errString)
+			writeKMProviderStatus(context.Background(), tc.reconciler, tc.kmProvider, logger, tc.isSuccess, &err, lastFetchedTime, nil)
+
+			if tc.kmProvider.Status.IsSuccess != tc.isSuccess {
+				t.Fatalf("Expected isSuccess to be: %+v, actual: %+v", tc.isSuccess, tc.kmProvider.Status.IsSuccess)
+			}
+
+			if tc.kmProvider.Status.Error != tc.expectedErrString {
+				t.Fatalf("Expected Error to be: %+v, actual: %+v", tc.expectedErrString, tc.kmProvider.Status.Error)
+			}
+		})
+	}
 }
diff --git a/pkg/controllers/namespaceresource/keymanagementprovider_controller.go b/pkg/controllers/namespaceresource/keymanagementprovider_controller.go
index ba439a254..2bbdd0b29 100644
--- a/pkg/controllers/namespaceresource/keymanagementprovider_controller.go
+++ b/pkg/controllers/namespaceresource/keymanagementprovider_controller.go
@@ -18,11 +18,18 @@ package namespaceresource
 
 import (
 	"context"
-	"fmt"
+	"encoding/json"
 
+	re "github.com/ratify-project/ratify/errors"
+	"github.com/ratify-project/ratify/internal/constants"
+	cutils "github.com/ratify-project/ratify/pkg/controllers/utils"
+	kmp "github.com/ratify-project/ratify/pkg/keymanagementprovider"
 	_ "github.com/ratify-project/ratify/pkg/keymanagementprovider/azurekeyvault" // register azure key vault key management provider
 	_ "github.com/ratify-project/ratify/pkg/keymanagementprovider/inline"        // register inline key management provider
 	"github.com/ratify-project/ratify/pkg/keymanagementprovider/refresh"
+	"github.com/sirupsen/logrus"
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
@@ -37,20 +44,89 @@ type KeyManagementProviderReconciler struct {
 	Scheme *runtime.Scheme
 }
 
-func (r *KeyManagementProviderReconciler) ReconcileWithConfig(ctx context.Context, config map[string]interface{}) (ctrl.Result, error) {
-	refresher, err := refresh.CreateRefresherFromConfig(config)
-	if err != nil {
+func (r *KeyManagementProviderReconciler) ReconcileWithType(ctx context.Context, req ctrl.Request, refresherType string) (ctrl.Result, error) {
+	logger := logrus.WithContext(ctx)
+
+	var resource = req.NamespacedName.String()
+	var keyManagementProvider configv1beta1.NamespacedKeyManagementProvider
+
+	logger.Infof("reconciling cluster key management provider '%v'", resource)
+
+	if err := r.Get(ctx, req.NamespacedName, &keyManagementProvider); err != nil {
+		if apierrors.IsNotFound(err) {
+			logger.Infof("deletion detected, removing key management provider %v", resource)
+			kmp.DeleteResourceFromMap(resource)
+		} else {
+			logger.Error(err, "unable to fetch key management provider")
+		}
+
+		return ctrl.Result{}, client.IgnoreNotFound(err)
+	}
+
+	lastFetchedTime := metav1.Now()
+	isFetchSuccessful := false
+
+	// get certificate store list to check if certificate store is configured
+	// TODO: remove check in v2.0.0+
+	var certificateStoreList configv1beta1.CertificateStoreList
+	if err := r.List(ctx, &certificateStoreList); err != nil {
+		logger.Error(err, "unable to list certificate stores")
 		return ctrl.Result{}, err
 	}
+
+	if len(certificateStoreList.Items) > 0 {
+		// Note: for backwards compatibility in upgrade scenarios, Ratify will only log a warning statement.
+		logger.Warn("Certificate Store already exists. Key management provider and certificate store should not be configured together. Please migrate to key management provider and delete certificate store.")
+	}
+
+	provider, err := cutils.SpecToKeyManagementProvider(keyManagementProvider.Spec.Parameters.Raw, keyManagementProvider.Spec.Type)
+	if err != nil {
+		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail("Failed to create key management provider from CR")
+
+		kmp.SetCertificateError(resource, err)
+		kmp.SetKeyError(resource, err)
+		writeKMProviderStatusNamespaced(ctx, r, &keyManagementProvider, logger, isFetchSuccessful, &kmpErr, lastFetchedTime, nil)
+		return ctrl.Result{}, kmpErr
+	}
+
+	refresherConfig := refresh.RefresherConfig{
+		RefresherType:           refresherType,
+		Provider:                provider,
+		ProviderType:            keyManagementProvider.Spec.Type,
+		ProviderRefreshInterval: keyManagementProvider.Spec.RefreshInterval,
+		Resource:                resource,
+	}
+
+	refresher, err := refresh.CreateRefresherFromConfig(refresherConfig)
+	if err != nil {
+		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail("Failed to create refresher from config")
+		writeKMProviderStatusNamespaced(ctx, r, &keyManagementProvider, logger, isFetchSuccessful, &kmpErr, lastFetchedTime, nil)
+		return ctrl.Result{}, kmpErr
+	}
+
 	err = refresher.Refresh(ctx)
 	if err != nil {
-		return ctrl.Result{}, err
+		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail("Failed to refresh key management provider")
+		writeKMProviderStatusNamespaced(ctx, r, &keyManagementProvider, logger, isFetchSuccessful, &kmpErr, lastFetchedTime, nil)
+		return ctrl.Result{}, kmpErr
 	}
 
 	result, ok := refresher.GetResult().(ctrl.Result)
 	if !ok {
-		return ctrl.Result{}, fmt.Errorf("unexpected type returned from GetResult: %T", refresher.GetResult())
+		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail("Failed to get result from refresher")
+		writeKMProviderStatusNamespaced(ctx, r, &keyManagementProvider, logger, isFetchSuccessful, &kmpErr, lastFetchedTime, nil)
+		return ctrl.Result{}, kmpErr
+	}
+
+	status, ok := refresher.GetStatus().(kmp.KeyManagementProviderStatus)
+	if !ok {
+		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail("Failed to get status from refresher")
+		writeKMProviderStatusNamespaced(ctx, r, &keyManagementProvider, logger, isFetchSuccessful, &kmpErr, lastFetchedTime, nil)
+		return ctrl.Result{}, &kmpErr
 	}
+
+	writeKMProviderStatusNamespaced(ctx, r, &keyManagementProvider, logger, true, nil, lastFetchedTime, status)
+
 	return result, nil
 }
 
@@ -58,12 +134,7 @@ func (r *KeyManagementProviderReconciler) ReconcileWithConfig(ctx context.Contex
 // +kubebuilder:rbac:groups=config.ratify.deislabs.io,resources=namespacedkeymanagementproviders/status,verbs=get;update;patch
 // +kubebuilder:rbac:groups=config.ratify.deislabs.io,resources=namespacedkeymanagementproviders/finalizers,verbs=update
 func (r *KeyManagementProviderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
-	refresherConfig := map[string]interface{}{
-		"type":    refresh.KubeRefresherNamespacedType,
-		"client":  r.Client,
-		"request": req,
-	}
-	return r.ReconcileWithConfig(ctx, refresherConfig)
+	return r.ReconcileWithType(ctx, req, refresh.KubeRefresherType)
 }
 
 // SetupWithManager sets up the controller with the Manager.
@@ -77,3 +148,40 @@ func (r *KeyManagementProviderReconciler) SetupWithManager(mgr ctrl.Manager) err
 		For(&configv1beta1.NamespacedKeyManagementProvider{}).WithEventFilter(pred).
 		Complete(r)
 }
+
+// writeKMProviderStatusNamespaced updates the status of the key management provider resource
+func writeKMProviderStatusNamespaced(ctx context.Context, r client.StatusClient, keyManagementProvider *configv1beta1.NamespacedKeyManagementProvider, logger *logrus.Entry, isSuccess bool, err *re.Error, operationTime metav1.Time, kmProviderStatus kmp.KeyManagementProviderStatus) {
+	if isSuccess {
+		updateKMProviderSuccessStatusNamespaced(keyManagementProvider, &operationTime, kmProviderStatus)
+	} else {
+		updateKMProviderErrorStatusNamespaced(keyManagementProvider, err, &operationTime)
+	}
+	if statusErr := r.Status().Update(ctx, keyManagementProvider); statusErr != nil {
+		logger.Error(statusErr, ",unable to update key management provider error status")
+	}
+}
+
+// updateKMProviderErrorStatusNamespaced updates the key management provider status with error, brief error and last fetched time
+func updateKMProviderErrorStatusNamespaced(keyManagementProvider *configv1beta1.NamespacedKeyManagementProvider, err *re.Error, operationTime *metav1.Time) {
+	keyManagementProvider.Status.IsSuccess = false
+	keyManagementProvider.Status.Error = err.Error()
+	keyManagementProvider.Status.BriefError = err.GetConciseError(constants.MaxBriefErrLength)
+	keyManagementProvider.Status.LastFetchedTime = operationTime
+}
+
+// Success status includes last fetched time and other provider-specific properties
+func updateKMProviderSuccessStatusNamespaced(keyManagementProvider *configv1beta1.NamespacedKeyManagementProvider, lastOperationTime *metav1.Time, kmProviderStatus kmp.KeyManagementProviderStatus) {
+	keyManagementProvider.Status.IsSuccess = true
+	keyManagementProvider.Status.Error = ""
+	keyManagementProvider.Status.BriefError = ""
+	keyManagementProvider.Status.LastFetchedTime = lastOperationTime
+
+	if kmProviderStatus != nil {
+		jsonString, _ := json.Marshal(kmProviderStatus)
+
+		raw := runtime.RawExtension{
+			Raw: jsonString,
+		}
+		keyManagementProvider.Status.Properties = raw
+	}
+}
diff --git a/pkg/controllers/namespaceresource/keymanagementprovider_controller_test.go b/pkg/controllers/namespaceresource/keymanagementprovider_controller_test.go
index 7e4717a8e..d934754b8 100644
--- a/pkg/controllers/namespaceresource/keymanagementprovider_controller_test.go
+++ b/pkg/controllers/namespaceresource/keymanagementprovider_controller_test.go
@@ -18,80 +18,358 @@ package namespaceresource
 import (
 	"context"
 	"errors"
+	"fmt"
 	"reflect"
 	"testing"
 
+	configv1beta1 "github.com/ratify-project/ratify/api/v1beta1"
+	re "github.com/ratify-project/ratify/errors"
+	"github.com/ratify-project/ratify/pkg/keymanagementprovider"
+	kmp "github.com/ratify-project/ratify/pkg/keymanagementprovider"
+	"github.com/ratify-project/ratify/pkg/keymanagementprovider/mocks"
 	"github.com/ratify-project/ratify/pkg/keymanagementprovider/refresh"
 	test "github.com/ratify-project/ratify/pkg/utils"
+	"github.com/sirupsen/logrus"
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apimachinery/pkg/types"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 )
 
-func TestKeyManagementProviderReconciler_ReconcileWithConfig(t *testing.T) {
+func init() {
+	refresh.Register("mockRefresher", &MockRefresher{})
+}
+
+type MockRefresher struct {
+	Result       ctrl.Result
+	RefreshError bool
+	ResultError  bool
+	StatusError  bool
+	Status       kmp.KeyManagementProviderStatus
+}
+
+func (mr *MockRefresher) Refresh(_ context.Context) error {
+	if mr.RefreshError {
+		return errors.New("error from refresh")
+	}
+	return nil
+}
+
+func (mr *MockRefresher) GetResult() interface{} {
+	if mr.ResultError {
+		return errors.New("error from result")
+	}
+	return mr.Result
+}
+
+func (mr *MockRefresher) GetStatus() interface{} {
+	if mr.StatusError {
+		return errors.New("error from status")
+	}
+	return mr.Status
+}
+
+func (mr *MockRefresher) Create(config refresh.RefresherConfig) (refresh.Refresher, error) {
+	if config.Resource == "refreshError/test" {
+		return &MockRefresher{
+			RefreshError: true,
+		}, nil
+	}
+	if config.Resource == "resultError/test" {
+		return &MockRefresher{
+			ResultError: true,
+		}, nil
+	}
+	if config.Resource == "statusError/test" {
+		return &MockRefresher{
+			StatusError: true,
+		}, nil
+	}
+	return &MockRefresher{}, nil
+}
+func TestKeyManagementProviderReconciler_ReconcileWithType(t *testing.T) {
 	tests := []struct {
 		name              string
+		clientGetFunc     func(_ context.Context, key types.NamespacedName, obj client.Object) error
+		clientListFunc    func(_ context.Context, list client.ObjectList) error
+		resourceNamespace string
 		refresherType     string
-		createConfigError bool
-		refreshError      bool
+		expectedResult    ctrl.Result
 		expectedError     bool
 	}{
 		{
-			name:              "Successful Reconcile",
+			// TODO: Add SetLogger to internal/logger/logger.go to compare log messages
+			// https://maxchadwick.xyz/blog/testing-log-output-in-go-logrus
+			name: "api is not found",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, _ client.Object) error {
+				resource := schema.GroupResource{
+					Group:    "",     // Use an empty string for core resources (like Pod)
+					Resource: "pods", // Resource type, e.g., "pods" for Pod resources
+				}
+				return apierrors.NewNotFound(resource, "test")
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			resourceNamespace: "test",
+			refresherType:     "mockRefresher",
+			expectedResult:    ctrl.Result{},
+			expectedError:     false,
+		},
+		{
+			name: "unable to fetch key management provider",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, _ client.Object) error {
+				return fmt.Errorf("unable to fetch key management provider")
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			resourceNamespace: "test",
 			refresherType:     "mockRefresher",
-			createConfigError: false,
-			refreshError:      false,
+			expectedResult:    ctrl.Result{},
 			expectedError:     false,
 		},
 		{
-			name:              "Refresher Error",
+			name: "unable to list certificate stores",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, _ client.Object) error {
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return fmt.Errorf("unable to list certificate stores")
+			},
+			resourceNamespace: "test",
 			refresherType:     "mockRefresher",
-			createConfigError: false,
-			refreshError:      true,
+			expectedResult:    ctrl.Result{},
 			expectedError:     true,
 		},
 		{
-			name:              "Invalid Refresher Type",
+			name: "certificate store already exists",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.NamespacedKeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				getKMP.Spec = configv1beta1.NamespacedKeyManagementProviderSpec{
+					Type: "inline",
+					Parameters: runtime.RawExtension{
+						Raw: []byte(`{"type": "inline", "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"}`),
+					},
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, list client.ObjectList) error {
+				certStoreList, ok := list.(*configv1beta1.CertificateStoreList)
+				if !ok {
+					return errors.New("expected CertificateStoreList")
+				}
+
+				certStoreList.Items = []configv1beta1.CertificateStore{
+					{
+						ObjectMeta: metav1.ObjectMeta{
+							Name: "test",
+						},
+					},
+				}
+				return nil
+			},
+			resourceNamespace: "test",
+			refresherType:     "mockRefresher",
+			expectedResult:    ctrl.Result{},
+			expectedError:     false,
+		},
+		{
+			name: "cutils.SpecToKeyManagementProvider failed",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.NamespacedKeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			resourceNamespace: "test",
+			refresherType:     "mockRefresher",
+			expectedResult:    ctrl.Result{},
+			expectedError:     true,
+		},
+		{
+			name: "refresh.CreateRefresherFromConfig failed",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.NamespacedKeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				getKMP.Spec = configv1beta1.NamespacedKeyManagementProviderSpec{
+					Type: "inline",
+					Parameters: runtime.RawExtension{
+						Raw: []byte(`{"type": "inline", "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"}`),
+					},
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			resourceNamespace: "test",
 			refresherType:     "invalidRefresher",
-			createConfigError: true,
-			refreshError:      false,
+			expectedResult:    ctrl.Result{},
+			expectedError:     true,
+		},
+		{
+			name: "refresh.Refresh failed",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.NamespacedKeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				getKMP.Spec = configv1beta1.NamespacedKeyManagementProviderSpec{
+					Type: "inline",
+					Parameters: runtime.RawExtension{
+						Raw: []byte(`{"type": "inline", "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"}`),
+					},
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			resourceNamespace: "refreshError",
+			refresherType:     "mockRefresher",
+			expectedResult:    ctrl.Result{},
+			expectedError:     true,
+		},
+		{
+			name: "refresher.GetResult failed",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.NamespacedKeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				getKMP.Spec = configv1beta1.NamespacedKeyManagementProviderSpec{
+					Type: "inline",
+					Parameters: runtime.RawExtension{
+						Raw: []byte(`{"type": "inline", "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"}`),
+					},
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			resourceNamespace: "resultError",
+			refresherType:     "mockRefresher",
+			expectedResult:    ctrl.Result{},
+			expectedError:     true,
+		},
+		{
+			name: "refresher.GetStatus failed",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.NamespacedKeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				getKMP.Spec = configv1beta1.NamespacedKeyManagementProviderSpec{
+					Type: "inline",
+					Parameters: runtime.RawExtension{
+						Raw: []byte(`{"type": "inline", "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"}`),
+					},
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			resourceNamespace: "statusError",
+			refresherType:     "mockRefresher",
+			expectedResult:    ctrl.Result{},
 			expectedError:     true,
 		},
+		{
+			name: "successfully reconciled",
+			clientGetFunc: func(_ context.Context, _ types.NamespacedName, obj client.Object) error {
+				getKMP, ok := obj.(*configv1beta1.NamespacedKeyManagementProvider)
+				if !ok {
+					return errors.New("expected KeyManagementProvider")
+				}
+				getKMP.ObjectMeta = metav1.ObjectMeta{
+					Namespace: "test",
+					Name:      "test",
+				}
+				getKMP.Spec = configv1beta1.NamespacedKeyManagementProviderSpec{
+					Type: "inline",
+					Parameters: runtime.RawExtension{
+						Raw: []byte(`{"type": "inline", "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"}`),
+					},
+				}
+				return nil
+			},
+			clientListFunc: func(_ context.Context, _ client.ObjectList) error {
+				return nil
+			},
+			resourceNamespace: "test",
+			refresherType:     "mockRefresher",
+			expectedResult:    ctrl.Result{},
+			expectedError:     false,
+		},
 	}
+
 	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			req := ctrl.Request{
-				NamespacedName: client.ObjectKey{
-					Name:      "fake-name",
-					Namespace: "fake-namespace",
-				},
-			}
-			scheme, _ := test.CreateScheme()
-			client := fake.NewClientBuilder().WithScheme(scheme).Build()
+		fmt.Println(tt.name)
+		mockClient := mocks.TestClient{
+			GetFunc:  tt.clientGetFunc,
+			ListFunc: tt.clientListFunc,
+		}
+		req := ctrl.Request{
+			NamespacedName: client.ObjectKey{
+				Name:      "test",
+				Namespace: tt.resourceNamespace,
+			},
+		}
+		scheme, _ := test.CreateScheme()
 
-			r := &KeyManagementProviderReconciler{
-				Client: client,
-				Scheme: runtime.NewScheme(),
-			}
+		r := &KeyManagementProviderReconciler{
+			Client: &mockClient,
+			Scheme: scheme,
+		}
 
-			refresherConfig := map[string]interface{}{
-				"type":              tt.refresherType,
-				"client":            client,
-				"request":           req,
-				"createConfigError": tt.createConfigError,
-				"refreshError":      tt.refreshError,
-				"shouldError":       tt.expectedError,
-			}
+		result, err := r.ReconcileWithType(context.Background(), req, tt.refresherType)
 
-			_, err := r.ReconcileWithConfig(context.TODO(), refresherConfig)
-			if tt.expectedError && err == nil {
-				t.Errorf("Expected error, got nil")
-			}
-			if !tt.expectedError && err != nil {
-				t.Errorf("Expected no error, got %v", err)
-			}
-		})
+		if !reflect.DeepEqual(result, tt.expectedResult) {
+			t.Fatalf("Expected result %v, got %v", tt.expectedResult, result)
+		}
+		if tt.expectedError && err == nil {
+			t.Fatalf("Expected error, got nil")
+		}
 	}
 }
 
@@ -124,37 +402,148 @@ func TestKeyManagementProviderReconciler_Reconcile(t *testing.T) {
 		t.Errorf("Expected result %v, got %v", expectedResult, result)
 	}
 }
+func TestKMProviderUpdateErrorStatusNamespaced(t *testing.T) {
+	var parametersString = "{\"certs\":{\"name\":\"certName\"}}"
+	var kmProviderStatus = []byte(parametersString)
 
-type MockRefresher struct {
-	Results           ctrl.Result
-	CreateConfigError bool
-	RefreshError      bool
-	ShouldError       bool
-}
+	status := configv1beta1.NamespacedKeyManagementProviderStatus{
+		IsSuccess: true,
+		Properties: runtime.RawExtension{
+			Raw: kmProviderStatus,
+		},
+	}
+	keyManagementProvider := configv1beta1.NamespacedKeyManagementProvider{
+		Status: status,
+	}
+	expectedErr := re.ErrorCodeUnknown.WithDetail("it's a long error from unit test")
+	lastFetchedTime := metav1.Now()
+	updateKMProviderErrorStatusNamespaced(&keyManagementProvider, &expectedErr, &lastFetchedTime)
 
-func (mr *MockRefresher) Refresh(_ context.Context) error {
-	if mr.RefreshError {
-		return errors.New("refresh error")
+	if keyManagementProvider.Status.IsSuccess != false {
+		t.Fatalf("Unexpected error, expected isSuccess to be false , actual %+v", keyManagementProvider.Status.IsSuccess)
+	}
+
+	if keyManagementProvider.Status.Error != expectedErr.Error() {
+		t.Fatalf("Unexpected error string, expected %+v, got %+v", expectedErr, keyManagementProvider.Status.Error)
+	}
+	if keyManagementProvider.Status.BriefError != expectedErr.GetConciseError(150) {
+		t.Fatalf("Unexpected error string, expected %+v, got %+v", expectedErr.GetConciseError(150), keyManagementProvider.Status.Error)
+	}
+
+	//make sure properties of last cached cert was not overridden
+	if len(keyManagementProvider.Status.Properties.Raw) == 0 {
+		t.Fatalf("Unexpected properties,  expected %+v, got %+v", parametersString, string(keyManagementProvider.Status.Properties.Raw))
 	}
-	return nil
 }
 
-func (mr *MockRefresher) GetResult() interface{} {
-	return ctrl.Result{}
+func TestKMProviderUpdateSuccessStatusNamespaced(t *testing.T) {
+	kmProviderStatus := keymanagementprovider.KeyManagementProviderStatus{}
+	properties := map[string]string{}
+	properties["Name"] = "wabbit"
+	properties["Version"] = "ABC"
+
+	kmProviderStatus["Certificates"] = properties
+
+	lastFetchedTime := metav1.Now()
+
+	status := configv1beta1.NamespacedKeyManagementProviderStatus{
+		IsSuccess: false,
+		Error:     "error from last operation",
+	}
+	keyManagementProvider := configv1beta1.NamespacedKeyManagementProvider{
+		Status: status,
+	}
+
+	updateKMProviderSuccessStatusNamespaced(&keyManagementProvider, &lastFetchedTime, kmProviderStatus)
+
+	if keyManagementProvider.Status.IsSuccess != true {
+		t.Fatalf("Expected isSuccess to be true , actual %+v", keyManagementProvider.Status.IsSuccess)
+	}
+
+	if keyManagementProvider.Status.Error != "" {
+		t.Fatalf("Unexpected error string, actual %+v", keyManagementProvider.Status.Error)
+	}
+
+	//make sure properties of last cached cert was updated
+	if len(keyManagementProvider.Status.Properties.Raw) == 0 {
+		t.Fatalf("Properties should not be empty")
+	}
 }
 
-func (mr *MockRefresher) Create(config map[string]interface{}) (refresh.Refresher, error) {
-	createConfigError := config["shouldError"].(bool)
-	refreshError := config["refreshError"].(bool)
-	if createConfigError {
-		return nil, errors.New("create error")
+func TestKMProviderUpdateSuccessStatusNamespaced_emptyProperties(t *testing.T) {
+	lastFetchedTime := metav1.Now()
+	status := configv1beta1.NamespacedKeyManagementProviderStatus{
+		IsSuccess: false,
+		Error:     "error from last operation",
+	}
+	keyManagementProvider := configv1beta1.NamespacedKeyManagementProvider{
+		Status: status,
+	}
+
+	updateKMProviderSuccessStatusNamespaced(&keyManagementProvider, &lastFetchedTime, nil)
+
+	if keyManagementProvider.Status.IsSuccess != true {
+		t.Fatalf("Expected isSuccess to be true , actual %+v", keyManagementProvider.Status.IsSuccess)
+	}
+
+	if keyManagementProvider.Status.Error != "" {
+		t.Fatalf("Unexpected error string, actual %+v", keyManagementProvider.Status.Error)
+	}
+
+	//make sure properties of last cached cert was updated
+	if len(keyManagementProvider.Status.Properties.Raw) != 0 {
+		t.Fatalf("Properties should be empty")
 	}
-	return &MockRefresher{
-		CreateConfigError: createConfigError,
-		RefreshError:      refreshError,
-	}, nil
 }
 
-func init() {
-	refresh.Register("mockRefresher", &MockRefresher{})
+func TestWriteKMProviderStatusNamespaced(t *testing.T) {
+	logger := logrus.WithContext(context.Background())
+	lastFetchedTime := metav1.Now()
+	testCases := []struct {
+		name              string
+		isSuccess         bool
+		kmProvider        *configv1beta1.NamespacedKeyManagementProvider
+		errString         string
+		expectedErrString string
+		reconciler        client.StatusClient
+	}{
+		{
+			name:       "success status",
+			isSuccess:  true,
+			errString:  "",
+			kmProvider: &configv1beta1.NamespacedKeyManagementProvider{},
+			reconciler: &test.MockStatusClient{},
+		},
+		{
+			name:              "error status",
+			isSuccess:         false,
+			kmProvider:        &configv1beta1.NamespacedKeyManagementProvider{},
+			errString:         "a long error string that exceeds the max length of 30 characters",
+			expectedErrString: "UNKNOWN: a long error string that exceeds the max length of 30 characters",
+			reconciler:        &test.MockStatusClient{},
+		},
+		{
+			name:       "status update failed",
+			isSuccess:  true,
+			kmProvider: &configv1beta1.NamespacedKeyManagementProvider{},
+			reconciler: &test.MockStatusClient{
+				UpdateFailed: true,
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			err := re.ErrorCodeUnknown.WithDetail(tc.errString)
+			writeKMProviderStatusNamespaced(context.Background(), tc.reconciler, tc.kmProvider, logger, tc.isSuccess, &err, lastFetchedTime, nil)
+
+			if tc.kmProvider.Status.IsSuccess != tc.isSuccess {
+				t.Fatalf("Expected isSuccess to be %+v , actual %+v", tc.isSuccess, tc.kmProvider.Status.IsSuccess)
+			}
+
+			if tc.kmProvider.Status.Error != tc.expectedErrString {
+				t.Fatalf("Expected Error to be %+v , actual %+v", tc.expectedErrString, tc.kmProvider.Status.Error)
+			}
+		})
+	}
 }
diff --git a/pkg/keymanagementprovider/mocks/client.go b/pkg/keymanagementprovider/mocks/client.go
index f24c19029..4d651ce92 100644
--- a/pkg/keymanagementprovider/mocks/client.go
+++ b/pkg/keymanagementprovider/mocks/client.go
@@ -17,7 +17,7 @@ package mocks
 
 import (
 	"context"
-	"fmt"
+	"errors"
 
 	"k8s.io/apimachinery/pkg/types"
 	"sigs.k8s.io/controller-runtime/pkg/client"
@@ -25,8 +25,43 @@ import (
 
 type TestClient struct {
 	client.Client
+	GetFunc  func(ctx context.Context, key types.NamespacedName, obj client.Object) error
+	ListFunc func(ctx context.Context, list client.ObjectList) error
 }
 
-func (m TestClient) Get(_ context.Context, _ types.NamespacedName, _ client.Object, _ ...client.GetOption) error {
-	return fmt.Errorf("error")
+func (m TestClient) Get(_ context.Context, key types.NamespacedName, obj client.Object, _ ...client.GetOption) error {
+	if m.GetFunc != nil {
+		return m.GetFunc(context.Background(), key, obj)
+	}
+	return nil
+}
+
+func (m TestClient) List(_ context.Context, list client.ObjectList, _ ...client.ListOption) error {
+	if m.ListFunc != nil {
+		return m.ListFunc(context.Background(), list)
+	}
+	return nil
+}
+
+type mockSubResourceWriter struct {
+	updateFailed bool
+}
+
+func (m *TestClient) Status() client.StatusWriter {
+	return &mockSubResourceWriter{updateFailed: false}
+}
+
+func (m *mockSubResourceWriter) Create(_ context.Context, _ client.Object, _ client.Object, _ ...client.SubResourceCreateOption) error {
+	return nil
+}
+
+func (m *mockSubResourceWriter) Patch(_ context.Context, _ client.Object, _ client.Patch, _ ...client.SubResourcePatchOption) error {
+	return nil
+}
+
+func (m *mockSubResourceWriter) Update(_ context.Context, _ client.Object, _ ...client.SubResourceUpdateOption) error {
+	if m.updateFailed {
+		return errors.New("update failed")
+	}
+	return nil
 }
diff --git a/pkg/keymanagementprovider/mocks/factory.go b/pkg/keymanagementprovider/mocks/factory.go
index 0230582e2..15a0e0d7d 100644
--- a/pkg/keymanagementprovider/mocks/factory.go
+++ b/pkg/keymanagementprovider/mocks/factory.go
@@ -16,6 +16,7 @@ limitations under the License.
 package mocks
 
 import (
+	"context"
 	"crypto"
 	"crypto/x509"
 
@@ -24,10 +25,19 @@ import (
 )
 
 type TestKeyManagementProviderFactory struct {
+	GetCertsFunc      func(ctx context.Context) (map[keymanagementprovider.KMPMapKey][]*x509.Certificate, keymanagementprovider.KeyManagementProviderStatus, error)
+	GetKeysFunc       func(ctx context.Context) (map[keymanagementprovider.KMPMapKey]crypto.PublicKey, keymanagementprovider.KeyManagementProviderStatus, error)
+	IsRefreshableFunc func() bool
 }
 
 func (f *TestKeyManagementProviderFactory) Create(_ string, _ config.KeyManagementProviderConfig, _ string) (keymanagementprovider.KeyManagementProvider, error) {
 	var certMap map[keymanagementprovider.KMPMapKey][]*x509.Certificate
 	var keyMap map[keymanagementprovider.KMPMapKey]crypto.PublicKey
-	return &TestKeyManagementProvider{certificates: certMap, keys: keyMap}, nil
+	return &TestKeyManagementProvider{
+		certificates:        certMap,
+		keys:                keyMap,
+		GetCertificatesFunc: f.GetCertsFunc,
+		GetKeysFunc:         f.GetKeysFunc,
+		IsRefreshableFunc:   f.IsRefreshableFunc,
+	}, nil
 }
diff --git a/pkg/keymanagementprovider/mocks/types.go b/pkg/keymanagementprovider/mocks/types.go
index 246de21ba..5cfa21645 100644
--- a/pkg/keymanagementprovider/mocks/types.go
+++ b/pkg/keymanagementprovider/mocks/types.go
@@ -24,20 +24,32 @@ import (
 )
 
 type TestKeyManagementProvider struct {
-	certificates map[keymanagementprovider.KMPMapKey][]*x509.Certificate
-	keys         map[keymanagementprovider.KMPMapKey]crypto.PublicKey
-	status       keymanagementprovider.KeyManagementProviderStatus
-	err          error
+	certificates        map[keymanagementprovider.KMPMapKey][]*x509.Certificate
+	keys                map[keymanagementprovider.KMPMapKey]crypto.PublicKey
+	status              keymanagementprovider.KeyManagementProviderStatus
+	err                 error
+	GetCertificatesFunc func(ctx context.Context) (map[keymanagementprovider.KMPMapKey][]*x509.Certificate, keymanagementprovider.KeyManagementProviderStatus, error)
+	GetKeysFunc         func(ctx context.Context) (map[keymanagementprovider.KMPMapKey]crypto.PublicKey, keymanagementprovider.KeyManagementProviderStatus, error)
+	IsRefreshableFunc   func() bool
 }
 
 func (c *TestKeyManagementProvider) GetCertificates(_ context.Context) (map[keymanagementprovider.KMPMapKey][]*x509.Certificate, keymanagementprovider.KeyManagementProviderStatus, error) {
+	if c.GetCertificatesFunc != nil {
+		return c.GetCertificatesFunc(context.Background())
+	}
 	return c.certificates, c.status, c.err
 }
 
 func (c *TestKeyManagementProvider) GetKeys(_ context.Context) (map[keymanagementprovider.KMPMapKey]crypto.PublicKey, keymanagementprovider.KeyManagementProviderStatus, error) {
+	if c.GetKeysFunc != nil {
+		return c.GetKeysFunc(context.Background())
+	}
 	return c.keys, c.status, c.err
 }
 
 func (c *TestKeyManagementProvider) IsRefreshable() bool {
-	return true
+	if c.IsRefreshableFunc != nil {
+		return c.IsRefreshableFunc()
+	}
+	return false
 }
diff --git a/pkg/keymanagementprovider/refresh/factory.go b/pkg/keymanagementprovider/refresh/factory.go
index 186951c16..eed41e119 100644
--- a/pkg/keymanagementprovider/refresh/factory.go
+++ b/pkg/keymanagementprovider/refresh/factory.go
@@ -21,7 +21,8 @@ var refresherFactories = make(map[string]RefresherFactory)
 
 type RefresherFactory interface {
 	// Create creates a new instance of the refresher using the provided configuration
-	Create(config map[string]interface{}) (Refresher, error)
+	// Create(config map[string]interface{}) (Refresher, error)
+	Create(config RefresherConfig) (Refresher, error)
 }
 
 // Refresher is an interface that defines methods to be implemented by a each refresher
@@ -37,17 +38,10 @@ func Register(name string, factory RefresherFactory) {
 }
 
 // CreateRefresherFromConfig creates a new instance of the refresher using the provided configuration
-func CreateRefresherFromConfig(refresherConfig map[string]interface{}) (Refresher, error) {
-	refresherType, ok := refresherConfig["type"].(string)
+func CreateRefresherFromConfig(refresherConfig RefresherConfig) (Refresher, error) {
+	factory, ok := refresherFactories[refresherConfig.RefresherType]
 	if !ok {
-		return nil, fmt.Errorf("refresher type is not a string")
-	}
-	if !ok || refresherType == "" {
-		return nil, fmt.Errorf("refresher type cannot be empty")
-	}
-	factory, ok := refresherFactories[refresherType]
-	if !ok {
-		return nil, fmt.Errorf("refresher factory with name %s not found", refresherType)
+		return nil, fmt.Errorf("refresher factory with name %s not found", refresherConfig.RefresherType)
 	}
 	return factory.Create(refresherConfig)
 }
diff --git a/pkg/keymanagementprovider/refresh/factory_test.go b/pkg/keymanagementprovider/refresh/factory_test.go
index a4a267cc2..e8762a444 100644
--- a/pkg/keymanagementprovider/refresh/factory_test.go
+++ b/pkg/keymanagementprovider/refresh/factory_test.go
@@ -22,7 +22,7 @@ import (
 
 type MockRefresher struct{}
 
-func (f *MockRefresher) Create(_ map[string]interface{}) (Refresher, error) {
+func (f *MockRefresher) Create(_ RefresherConfig) (Refresher, error) {
 	return &MockRefresher{}, nil
 }
 
@@ -34,10 +34,14 @@ func (f *MockRefresher) GetResult() interface{} {
 	return nil
 }
 
+func (f *MockRefresher) GetStatus() interface{} {
+	return nil
+}
+
 func TestRefreshFactory_Create(t *testing.T) {
 	Register("mockRefresher", &MockRefresher{})
-	refresherConfig := map[string]interface{}{
-		"type": "mockRefresher",
+	refresherConfig := RefresherConfig{
+		RefresherType: "mockRefresher",
 	}
 	factory := refresherFactories["mockRefresher"]
 	refresher, err := factory.Create(refresherConfig)
@@ -104,8 +108,8 @@ func TestCreateRefresherFromConfig(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			refresherConfig := map[string]interface{}{
-				"type": tt.refresherType,
+			refresherConfig := RefresherConfig{
+				RefresherType: tt.refresherType,
 			}
 			_, err := CreateRefresherFromConfig(refresherConfig)
 			if tt.expectedError && err == nil {
diff --git a/pkg/keymanagementprovider/refresh/kubeRefresh.go b/pkg/keymanagementprovider/refresh/kubeRefresh.go
index acd967e0d..895cb7d8d 100644
--- a/pkg/keymanagementprovider/refresh/kubeRefresh.go
+++ b/pkg/keymanagementprovider/refresh/kubeRefresh.go
@@ -18,28 +18,23 @@ package refresh
 
 import (
 	"context"
-	"encoding/json"
 	"fmt"
 	"maps"
 	"time"
 
-	configv1beta1 "github.com/ratify-project/ratify/api/v1beta1"
 	re "github.com/ratify-project/ratify/errors"
-	"github.com/ratify-project/ratify/internal/constants"
-	cutils "github.com/ratify-project/ratify/pkg/controllers/utils"
 	kmp "github.com/ratify-project/ratify/pkg/keymanagementprovider"
 	"github.com/sirupsen/logrus"
-	apierrors "k8s.io/apimachinery/pkg/api/errors"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
 	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 type KubeRefresher struct {
-	client.Client
-	Request ctrl.Request
-	Result  ctrl.Result
+	Provider                kmp.KeyManagementProvider
+	ProviderType            string
+	ProviderRefreshInterval string
+	Resource                string
+	Result                  ctrl.Result
+	Status                  kmp.KeyManagementProviderStatus
 }
 
 // Register registers the kubeRefresher factory
@@ -51,99 +46,45 @@ func init() {
 func (kr *KubeRefresher) Refresh(ctx context.Context) error {
 	logger := logrus.WithContext(ctx)
 
-	var resource = kr.Request.Name
-	var keyManagementProvider configv1beta1.KeyManagementProvider
-
-	logger.Infof("reconciling cluster key management provider '%v'", resource)
-
-	if err := kr.Get(ctx, kr.Request.NamespacedName, &keyManagementProvider); err != nil {
-		if apierrors.IsNotFound(err) {
-			logger.Infof("deletion detected, removing key management provider %v", resource)
-			kmp.DeleteResourceFromMap(resource)
-		} else {
-			logger.Error(err, "unable to fetch key management provider")
-		}
-
-		kr.Result = ctrl.Result{}
-
-		return client.IgnoreNotFound(err)
-	}
-
-	lastFetchedTime := metav1.Now()
-	isFetchSuccessful := false
-
-	// get certificate store list to check if certificate store is configured
-	// TODO: remove check in v2.0.0+
-	var certificateStoreList configv1beta1.CertificateStoreList
-	if err := kr.List(ctx, &certificateStoreList); err != nil {
-		logger.Error(err, "unable to list certificate stores")
-		kr.Result = ctrl.Result{}
-		return err
-	}
-
-	if len(certificateStoreList.Items) > 0 {
-		// Note: for backwards compatibility in upgrade scenarios, Ratify will only log a warning statement.
-		logger.Warn("Certificate Store already exists. Key management provider and certificate store should not be configured together. Please migrate to key management provider and delete certificate store.")
-	}
-
-	provider, err := cutils.SpecToKeyManagementProvider(keyManagementProvider.Spec.Parameters.Raw, keyManagementProvider.Spec.Type)
-	if err != nil {
-		kmpErr := re.ErrorCodePluginInitFailure.WithError(err).WithDetail("Failed to create key management provider from CR")
-
-		kmp.SetCertificateError(resource, kmpErr)
-		kmp.SetKeyError(resource, kmpErr)
-		writeKMProviderStatus(ctx, kr, &keyManagementProvider, logger, isFetchSuccessful, &kmpErr, lastFetchedTime, nil)
-		kr.Request = ctrl.Request{}
-		return kmpErr
-	}
-
 	// fetch certificates and store in map
-	certificates, certAttributes, err := provider.GetCertificates(ctx)
+	certificates, certAttributes, err := kr.Provider.GetCertificates(ctx)
 	if err != nil {
-		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail(fmt.Sprintf("Unable to fetch certificates from key management provider [%s] of type [%s]", resource, keyManagementProvider.Spec.Type))
-
-		kmp.SetCertificateError(resource, err)
-		writeKMProviderStatus(ctx, kr, &keyManagementProvider, logger, isFetchSuccessful, &kmpErr, lastFetchedTime, nil)
-		kr.Request = ctrl.Request{}
+		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail(fmt.Sprintf("Unable to fetch certificates from key management provider [%s] of type [%s]", kr.Resource, kr.ProviderType))
+		kmp.SetCertificateError(kr.Resource, err)
 		return kmpErr
 	}
 
 	// fetch keys and store in map
-	keys, keyAttributes, err := provider.GetKeys(ctx)
+	keys, keyAttributes, err := kr.Provider.GetKeys(ctx)
 	if err != nil {
-		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail(fmt.Sprintf("Unable to fetch keys from key management provider [%s] of type [%s]", resource, keyManagementProvider.Spec.Type))
-
-		kmp.SetKeyError(resource, kmpErr)
-		writeKMProviderStatus(ctx, kr, &keyManagementProvider, logger, isFetchSuccessful, &kmpErr, lastFetchedTime, nil)
-		kr.Request = ctrl.Request{}
+		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail(fmt.Sprintf("Unable to fetch keys from key management provider [%s] of type [%s]", kr.Resource, kr.ProviderType))
+		kmp.SetKeyError(kr.Resource, err)
 		return kmpErr
 	}
-	kmp.SaveSecrets(resource, keyManagementProvider.Spec.Type, keys, certificates)
+
+	kmp.SaveSecrets(kr.Resource, kr.ProviderType, keys, certificates)
 	// merge certificates and keys status into one
 	maps.Copy(keyAttributes, certAttributes)
-	isFetchSuccessful = true
-	writeKMProviderStatus(ctx, kr, &keyManagementProvider, logger, isFetchSuccessful, nil, lastFetchedTime, keyAttributes)
+	kr.Status = keyAttributes
 
-	logger.Infof("%v certificate(s) & %v key(s) fetched for key management provider %v", len(certificates), len(keys), resource)
+	logger.Infof("%v certificate(s) & %v key(s) fetched for key management provider %v", len(certificates), len(keys), kr.Resource)
 
-	// returning empty result and no error to indicate we’ve successfully reconciled this object
+	// Resource is not refreshable, returning empty result and no error to indicate we’ve successfully reconciled this object
 	// will not reconcile again unless resource is recreated
-	if !provider.IsRefreshable() {
-		kr.Request = ctrl.Request{}
+	if !kr.Provider.IsRefreshable() {
 		return nil
 	}
 
 	// if interval is not set, disable refresh
-	if keyManagementProvider.Spec.RefreshInterval == "" {
-		kr.Result = ctrl.Result{}
+	if kr.ProviderRefreshInterval == "" {
 		return nil
 	}
+
 	// resource is refreshable, requeue after interval
-	intervalDuration, err := time.ParseDuration(keyManagementProvider.Spec.RefreshInterval)
+	intervalDuration, err := time.ParseDuration(kr.ProviderRefreshInterval)
 	if err != nil {
-		logger.Error(err, "unable to parse interval duration")
-		kr.Result = ctrl.Result{}
-		return err
+		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail(fmt.Sprintf("Unable to parse interval duration for key management provider [%s] of type [%s]", kr.Resource, kr.ProviderType))
+		return kmpErr
 	}
 
 	logger.Info("Reconciled KeyManagementProvider", "intervalDuration", intervalDuration)
@@ -157,57 +98,16 @@ func (kr *KubeRefresher) GetResult() interface{} {
 	return kr.Result
 }
 
-// Create creates a new KubeRefresher instance
-func (kr *KubeRefresher) Create(config map[string]interface{}) (Refresher, error) {
-	client, ok := config["client"].(client.Client)
-	if !ok {
-		return nil, fmt.Errorf("client is required in config")
-	}
-
-	request, ok := config["request"].(ctrl.Request)
-	if !ok {
-		return nil, fmt.Errorf("request is required in config")
-	}
+func (kr *KubeRefresher) GetStatus() interface{} {
+	return kr.Status
+}
 
+// Create creates a new KubeRefresher instance
+func (kr *KubeRefresher) Create(config RefresherConfig) (Refresher, error) {
 	return &KubeRefresher{
-		Client:  client,
-		Request: request,
+		Provider:                config.Provider,
+		ProviderType:            config.ProviderType,
+		ProviderRefreshInterval: config.ProviderRefreshInterval,
+		Resource:                config.Resource,
 	}, nil
 }
-
-func writeKMProviderStatus(ctx context.Context, r client.StatusClient, keyManagementProvider *configv1beta1.KeyManagementProvider, logger *logrus.Entry, isSuccess bool, err *re.Error, operationTime metav1.Time, kmProviderStatus kmp.KeyManagementProviderStatus) {
-	if isSuccess {
-		updateKMProviderSuccessStatus(keyManagementProvider, &operationTime, kmProviderStatus)
-	} else {
-		updateKMProviderErrorStatus(keyManagementProvider, err, &operationTime)
-	}
-	if statusErr := r.Status().Update(ctx, keyManagementProvider); statusErr != nil {
-		logger.Error(statusErr, ",unable to update key management provider error status")
-	}
-}
-
-// updateKMProviderErrorStatus updates the key management provider status with error, brief error and last fetched time
-func updateKMProviderErrorStatus(keyManagementProvider *configv1beta1.KeyManagementProvider, err *re.Error, operationTime *metav1.Time) {
-	keyManagementProvider.Status.IsSuccess = false
-	keyManagementProvider.Status.Error = err.Error()
-	keyManagementProvider.Status.BriefError = err.GetConciseError(constants.MaxBriefErrLength)
-	keyManagementProvider.Status.LastFetchedTime = operationTime
-}
-
-// updateKMProviderSuccessStatus updates the key management provider status if status argument is non nil
-// Success status includes last fetched time and other provider-specific properties
-func updateKMProviderSuccessStatus(keyManagementProvider *configv1beta1.KeyManagementProvider, lastOperationTime *metav1.Time, kmProviderStatus kmp.KeyManagementProviderStatus) {
-	keyManagementProvider.Status.IsSuccess = true
-	keyManagementProvider.Status.Error = ""
-	keyManagementProvider.Status.BriefError = ""
-	keyManagementProvider.Status.LastFetchedTime = lastOperationTime
-
-	if kmProviderStatus != nil {
-		jsonString, _ := json.Marshal(kmProviderStatus)
-
-		raw := runtime.RawExtension{
-			Raw: jsonString,
-		}
-		keyManagementProvider.Status.Properties = raw
-	}
-}
diff --git a/pkg/keymanagementprovider/refresh/kubeRefreshNamespaced.go b/pkg/keymanagementprovider/refresh/kubeRefreshNamespaced.go
deleted file mode 100644
index 8bd4ade20..000000000
--- a/pkg/keymanagementprovider/refresh/kubeRefreshNamespaced.go
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
-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 refresh
-
-import (
-	"context"
-	"encoding/json"
-	"fmt"
-	"maps"
-	"time"
-
-	configv1beta1 "github.com/ratify-project/ratify/api/v1beta1"
-	re "github.com/ratify-project/ratify/errors"
-	"github.com/ratify-project/ratify/internal/constants"
-	cutils "github.com/ratify-project/ratify/pkg/controllers/utils"
-	kmp "github.com/ratify-project/ratify/pkg/keymanagementprovider"
-	"github.com/sirupsen/logrus"
-	apierrors "k8s.io/apimachinery/pkg/api/errors"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-type KubeRefresherNamespaced struct {
-	client.Client
-	Request ctrl.Request
-	Result  ctrl.Result
-}
-
-// Register registers the kubeRefresherNamespaced factory
-func init() {
-	Register(KubeRefresherNamespacedType, &KubeRefresherNamespaced{})
-}
-
-// Refresh the certificates/keys for the key management provider by calling the GetCertificates and GetKeys methods
-func (kr *KubeRefresherNamespaced) Refresh(ctx context.Context) error {
-	logger := logrus.WithContext(ctx)
-
-	var resource = kr.Request.NamespacedName.String()
-	var keyManagementProvider configv1beta1.NamespacedKeyManagementProvider
-
-	logger.Infof("reconciling namespaced key management provider '%v'", resource)
-
-	if err := kr.Get(ctx, kr.Request.NamespacedName, &keyManagementProvider); err != nil {
-		if apierrors.IsNotFound(err) {
-			logger.Infof("deletion detected, removing key management provider %v", resource)
-			kmp.DeleteResourceFromMap(resource)
-		} else {
-			logger.Error(err, "unable to fetch key management provider")
-		}
-
-		kr.Result = ctrl.Result{}
-
-		return client.IgnoreNotFound(err)
-	}
-
-	lastFetchedTime := metav1.Now()
-	isFetchSuccessful := false
-
-	// get certificate store list to check if certificate store is configured
-	// TODO: remove check in v2.0.0+
-	var certificateStoreList configv1beta1.CertificateStoreList
-	if err := kr.List(ctx, &certificateStoreList); err != nil {
-		logger.Error(err, "unable to list certificate stores")
-		kr.Result = ctrl.Result{}
-		return err
-	}
-	// if certificate store is configured, return error. Only one of certificate store and key management provider can be configured
-	if len(certificateStoreList.Items) > 0 {
-		// Note: for backwards compatibility in upgrade scenarios, Ratify will only log a warning statement.
-		logger.Warn("Certificate Store already exists. Key management provider and certificate store should not be configured together. Please migrate to key management provider and delete certificate store.")
-	}
-
-	provider, err := cutils.SpecToKeyManagementProvider(keyManagementProvider.Spec.Parameters.Raw, keyManagementProvider.Spec.Type)
-	if err != nil {
-		kmpErr := re.ErrorCodePluginInitFailure.WithError(err).WithDetail("Failed to create key management provider from CR")
-
-		kmp.SetCertificateError(resource, kmpErr)
-		kmp.SetKeyError(resource, kmpErr)
-		writeKMProviderStatusNamespaced(ctx, kr, &keyManagementProvider, logger, isFetchSuccessful, &kmpErr, lastFetchedTime, nil)
-		kr.Result = ctrl.Result{}
-		return kmpErr
-	}
-
-	// fetch certificates and store in map
-	certificates, certAttributes, err := provider.GetCertificates(ctx)
-	if err != nil {
-		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail(fmt.Sprintf("Unable to fetch certificates from key management provider: %s of type: %s", resource, keyManagementProvider.Spec.Type))
-
-		kmp.SetCertificateError(resource, kmpErr)
-		writeKMProviderStatusNamespaced(ctx, kr, &keyManagementProvider, logger, isFetchSuccessful, &kmpErr, lastFetchedTime, nil)
-		kr.Result = ctrl.Result{}
-		return kmpErr
-	}
-
-	// fetch keys and store in map
-	keys, keyAttributes, err := provider.GetKeys(ctx)
-	if err != nil {
-		kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail(fmt.Sprintf("Unable to fetch keys from key management provider: %s of type: %s", resource, keyManagementProvider.Spec.Type))
-
-		kmp.SetKeyError(resource, kmpErr)
-		writeKMProviderStatusNamespaced(ctx, kr, &keyManagementProvider, logger, isFetchSuccessful, &kmpErr, lastFetchedTime, nil)
-		kr.Result = ctrl.Result{}
-		return kmpErr
-	}
-	kmp.SaveSecrets(resource, keyManagementProvider.Spec.Type, keys, certificates)
-	// merge certificates and keys status into one
-	maps.Copy(keyAttributes, certAttributes)
-	isFetchSuccessful = true
-	writeKMProviderStatusNamespaced(ctx, kr, &keyManagementProvider, logger, isFetchSuccessful, nil, lastFetchedTime, keyAttributes)
-
-	logger.Infof("%v certificate(s) & %v key(s) fetched for key management provider %v", len(certificates), len(keys), resource)
-
-	if !provider.IsRefreshable() {
-		kr.Result = ctrl.Result{}
-		return nil
-	}
-
-	// if interval is not set, disable refresh
-	if keyManagementProvider.Spec.RefreshInterval == "" {
-		kr.Result = ctrl.Result{}
-		return nil
-	}
-
-	intervalDuration, err := time.ParseDuration(keyManagementProvider.Spec.RefreshInterval)
-	if err != nil {
-		logger.Error(err, "unable to parse interval duration")
-		kr.Result = ctrl.Result{}
-		return err
-	}
-
-	logger.Info("Reconciled KeyManagementProvider", "intervalDuration", intervalDuration)
-	kr.Result = ctrl.Result{RequeueAfter: intervalDuration}
-
-	return nil
-}
-
-// GetResult returns the result of the refresh as ctrl.Result
-func (kr *KubeRefresherNamespaced) GetResult() interface{} {
-	return kr.Result
-}
-
-// Create creates a new instance of KubeRefresherNamespaced
-func (kr *KubeRefresherNamespaced) Create(config map[string]interface{}) (Refresher, error) {
-	client, ok := config["client"].(client.Client)
-	if !ok {
-		return nil, fmt.Errorf("client is required in config")
-	}
-
-	request, ok := config["request"].(ctrl.Request)
-	if !ok {
-		return nil, fmt.Errorf("request is required in config")
-	}
-
-	return &KubeRefresherNamespaced{
-		Client:  client,
-		Request: request,
-	}, nil
-}
-
-// writeKMProviderStatus updates the status of the key management provider resource
-func writeKMProviderStatusNamespaced(ctx context.Context, r client.StatusClient, keyManagementProvider *configv1beta1.NamespacedKeyManagementProvider, logger *logrus.Entry, isSuccess bool, err *re.Error, operationTime metav1.Time, kmProviderStatus kmp.KeyManagementProviderStatus) {
-	if isSuccess {
-		updateKMProviderSuccessStatusNamespaced(keyManagementProvider, &operationTime, kmProviderStatus)
-	} else {
-		updateKMProviderErrorStatusNamespaced(keyManagementProvider, err, &operationTime)
-	}
-	if statusErr := r.Status().Update(ctx, keyManagementProvider); statusErr != nil {
-		logger.Error(statusErr, ",unable to update key management provider error status")
-	}
-}
-
-// updateKMProviderErrorStatus updates the key management provider status with error, brief error and last fetched time
-func updateKMProviderErrorStatusNamespaced(keyManagementProvider *configv1beta1.NamespacedKeyManagementProvider, err *re.Error, operationTime *metav1.Time) {
-	keyManagementProvider.Status.IsSuccess = false
-	keyManagementProvider.Status.Error = err.Error()
-	keyManagementProvider.Status.BriefError = err.GetConciseError(constants.MaxBriefErrLength)
-	keyManagementProvider.Status.LastFetchedTime = operationTime
-}
-
-// updateKMProviderSuccessStatus updates the key management provider status if status argument is non nil
-// Success status includes last fetched time and other provider-specific properties
-func updateKMProviderSuccessStatusNamespaced(keyManagementProvider *configv1beta1.NamespacedKeyManagementProvider, lastOperationTime *metav1.Time, kmProviderStatus kmp.KeyManagementProviderStatus) {
-	keyManagementProvider.Status.IsSuccess = true
-	keyManagementProvider.Status.Error = ""
-	keyManagementProvider.Status.BriefError = ""
-	keyManagementProvider.Status.LastFetchedTime = lastOperationTime
-
-	if kmProviderStatus != nil {
-		jsonString, _ := json.Marshal(kmProviderStatus)
-
-		raw := runtime.RawExtension{
-			Raw: jsonString,
-		}
-		keyManagementProvider.Status.Properties = raw
-	}
-}
diff --git a/pkg/keymanagementprovider/refresh/kubeRefreshNamespaced_test.go b/pkg/keymanagementprovider/refresh/kubeRefreshNamespaced_test.go
deleted file mode 100644
index 944f54884..000000000
--- a/pkg/keymanagementprovider/refresh/kubeRefreshNamespaced_test.go
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
-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 refresh
-
-import (
-	"context"
-	"reflect"
-	"testing"
-	"time"
-
-	configv1beta1 "github.com/ratify-project/ratify/api/v1beta1"
-	re "github.com/ratify-project/ratify/errors"
-	"github.com/ratify-project/ratify/pkg/keymanagementprovider"
-	"github.com/ratify-project/ratify/pkg/keymanagementprovider/mocks"
-	test "github.com/ratify-project/ratify/pkg/utils"
-	"github.com/sirupsen/logrus"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/client/fake"
-)
-
-func TestKubeRefresherNamespaced_Refresh(t *testing.T) {
-	tests := []struct {
-		name           string
-		provider       *configv1beta1.NamespacedKeyManagementProvider
-		request        ctrl.Request
-		mockClient     bool
-		expectedResult ctrl.Result
-		expectedError  bool
-	}{
-		{
-			name: "Non-refreshable",
-			provider: &configv1beta1.NamespacedKeyManagementProvider{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-				Spec: configv1beta1.NamespacedKeyManagementProviderSpec{
-					Type: "inline",
-					Parameters: runtime.RawExtension{
-						Raw: []byte(`{"type": "inline", "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"}`),
-					},
-				},
-			},
-			request: ctrl.Request{
-				NamespacedName: client.ObjectKey{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-			},
-			expectedResult: ctrl.Result{},
-			expectedError:  false,
-		},
-		{
-			name: "Disabled",
-			provider: &configv1beta1.NamespacedKeyManagementProvider{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-				Spec: configv1beta1.NamespacedKeyManagementProviderSpec{
-					Type:            "test-kmp",
-					RefreshInterval: "",
-					Parameters: runtime.RawExtension{
-						Raw: []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
-					},
-				},
-			},
-			request: ctrl.Request{
-				NamespacedName: client.ObjectKey{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-			},
-			expectedResult: ctrl.Result{},
-			expectedError:  false,
-		},
-		{
-			name: "Refreshable",
-			provider: &configv1beta1.NamespacedKeyManagementProvider{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-				Spec: configv1beta1.NamespacedKeyManagementProviderSpec{
-					Type:            "test-kmp",
-					RefreshInterval: "1m",
-					Parameters: runtime.RawExtension{
-						Raw: []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
-					},
-				},
-			},
-			request: ctrl.Request{
-				NamespacedName: client.ObjectKey{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-			},
-			expectedResult: ctrl.Result{RequeueAfter: time.Minute},
-			expectedError:  false,
-		},
-		{
-			name: "Invalid Interval",
-			provider: &configv1beta1.NamespacedKeyManagementProvider{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-				Spec: configv1beta1.NamespacedKeyManagementProviderSpec{
-					Type:            "",
-					RefreshInterval: "1mm",
-					Parameters: runtime.RawExtension{
-						Raw: []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
-					},
-				},
-			},
-			request: ctrl.Request{
-				NamespacedName: client.ObjectKey{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-			},
-			expectedResult: ctrl.Result{},
-			expectedError:  true,
-		},
-		{
-			name: "IsNotFound",
-			provider: &configv1beta1.NamespacedKeyManagementProvider{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-				Spec: configv1beta1.NamespacedKeyManagementProviderSpec{
-					Type:            "",
-					RefreshInterval: "",
-					Parameters: runtime.RawExtension{
-						Raw: []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
-					},
-				},
-			},
-			expectedResult: ctrl.Result{},
-			expectedError:  false,
-		},
-		{
-			name:          "UnableToFetchKMP",
-			mockClient:    true,
-			expectedError: true,
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var client client.Client
-
-			if tt.mockClient {
-				client = mocks.TestClient{}
-			} else {
-				scheme, _ := test.CreateScheme()
-				client = fake.NewClientBuilder().WithScheme(scheme).WithObjects(tt.provider).Build()
-			}
-
-			kr := &KubeRefresherNamespaced{
-				Client:  client,
-				Request: tt.request,
-			}
-			err := kr.Refresh(context.Background())
-			result := kr.GetResult()
-			if !reflect.DeepEqual(result, tt.expectedResult) {
-				t.Fatalf("Expected nil but got %v with error %v", result, err)
-			}
-			if tt.expectedError && err == nil {
-				t.Fatalf("Expected error but got nil")
-			}
-		})
-	}
-}
-
-func TestKubeRefresherNamespaced_Create(t *testing.T) {
-	tests := []struct {
-		name          string
-		config        map[string]interface{}
-		expectedError bool
-	}{
-		{
-			name: "Success",
-			config: map[string]interface{}{
-				"client":  &mocks.TestClient{},
-				"request": ctrl.Request{},
-			},
-			expectedError: false,
-		},
-		{
-			name: "ClientMissing",
-			config: map[string]interface{}{
-				"request": ctrl.Request{},
-			},
-			expectedError: true,
-		},
-		{
-			name: "RequestMissing",
-			config: map[string]interface{}{
-				"client": &mocks.TestClient{},
-			},
-			expectedError: true,
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			kr := &KubeRefresherNamespaced{}
-			_, err := kr.Create(tt.config)
-			if tt.expectedError && err == nil {
-				t.Fatalf("Expected error but got nil")
-			}
-		})
-	}
-}
-
-func TestKMProviderUpdateErrorStatusNamespaced(t *testing.T) {
-	var parametersString = "{\"certs\":{\"name\":\"certName\"}}"
-	var kmProviderStatus = []byte(parametersString)
-
-	status := configv1beta1.NamespacedKeyManagementProviderStatus{
-		IsSuccess: true,
-		Properties: runtime.RawExtension{
-			Raw: kmProviderStatus,
-		},
-	}
-	keyManagementProvider := configv1beta1.NamespacedKeyManagementProvider{
-		Status: status,
-	}
-	expectedErr := re.ErrorCodeUnknown.WithDetail("it's a long error from unit test")
-	lastFetchedTime := metav1.Now()
-	updateKMProviderErrorStatusNamespaced(&keyManagementProvider, &expectedErr, &lastFetchedTime)
-
-	if keyManagementProvider.Status.IsSuccess != false {
-		t.Fatalf("Unexpected error, expected isSuccess to be false , actual %+v", keyManagementProvider.Status.IsSuccess)
-	}
-
-	if keyManagementProvider.Status.Error != expectedErr.Error() {
-		t.Fatalf("Unexpected error string, expected %+v, got %+v", expectedErr, keyManagementProvider.Status.Error)
-	}
-	if keyManagementProvider.Status.BriefError != expectedErr.GetConciseError(150) {
-		t.Fatalf("Unexpected error string, expected %+v, got %+v", expectedErr.GetConciseError(150), keyManagementProvider.Status.Error)
-	}
-
-	//make sure properties of last cached cert was not overridden
-	if len(keyManagementProvider.Status.Properties.Raw) == 0 {
-		t.Fatalf("Unexpected properties,  expected %+v, got %+v", parametersString, string(keyManagementProvider.Status.Properties.Raw))
-	}
-}
-
-func TestKMProviderUpdateSuccessStatusNamespaced(t *testing.T) {
-	kmProviderStatus := keymanagementprovider.KeyManagementProviderStatus{}
-	properties := map[string]string{}
-	properties["Name"] = "wabbit"
-	properties["Version"] = "ABC"
-
-	kmProviderStatus["Certificates"] = properties
-
-	lastFetchedTime := metav1.Now()
-
-	status := configv1beta1.NamespacedKeyManagementProviderStatus{
-		IsSuccess: false,
-		Error:     "error from last operation",
-	}
-	keyManagementProvider := configv1beta1.NamespacedKeyManagementProvider{
-		Status: status,
-	}
-
-	updateKMProviderSuccessStatusNamespaced(&keyManagementProvider, &lastFetchedTime, kmProviderStatus)
-
-	if keyManagementProvider.Status.IsSuccess != true {
-		t.Fatalf("Expected isSuccess to be true , actual %+v", keyManagementProvider.Status.IsSuccess)
-	}
-
-	if keyManagementProvider.Status.Error != "" {
-		t.Fatalf("Unexpected error string, actual %+v", keyManagementProvider.Status.Error)
-	}
-
-	//make sure properties of last cached cert was updated
-	if len(keyManagementProvider.Status.Properties.Raw) == 0 {
-		t.Fatalf("Properties should not be empty")
-	}
-}
-
-func TestKMProviderUpdateSuccessStatusNamespaced_emptyProperties(t *testing.T) {
-	lastFetchedTime := metav1.Now()
-	status := configv1beta1.NamespacedKeyManagementProviderStatus{
-		IsSuccess: false,
-		Error:     "error from last operation",
-	}
-	keyManagementProvider := configv1beta1.NamespacedKeyManagementProvider{
-		Status: status,
-	}
-
-	updateKMProviderSuccessStatusNamespaced(&keyManagementProvider, &lastFetchedTime, nil)
-
-	if keyManagementProvider.Status.IsSuccess != true {
-		t.Fatalf("Expected isSuccess to be true , actual %+v", keyManagementProvider.Status.IsSuccess)
-	}
-
-	if keyManagementProvider.Status.Error != "" {
-		t.Fatalf("Unexpected error string, actual %+v", keyManagementProvider.Status.Error)
-	}
-
-	//make sure properties of last cached cert was updated
-	if len(keyManagementProvider.Status.Properties.Raw) != 0 {
-		t.Fatalf("Properties should be empty")
-	}
-}
-
-func TestWriteKMProviderStatusNamespaced(t *testing.T) {
-	logger := logrus.WithContext(context.Background())
-	lastFetchedTime := metav1.Now()
-	testCases := []struct {
-		name              string
-		isSuccess         bool
-		kmProvider        *configv1beta1.NamespacedKeyManagementProvider
-		errString         string
-		expectedErrString string
-		reconciler        client.StatusClient
-	}{
-		{
-			name:       "success status",
-			isSuccess:  true,
-			errString:  "",
-			kmProvider: &configv1beta1.NamespacedKeyManagementProvider{},
-			reconciler: &test.MockStatusClient{},
-		},
-		{
-			name:              "error status",
-			isSuccess:         false,
-			kmProvider:        &configv1beta1.NamespacedKeyManagementProvider{},
-			errString:         "a long error string that exceeds the max length of 30 characters",
-			expectedErrString: "UNKNOWN: a long error string that exceeds the max length of 30 characters",
-			reconciler:        &test.MockStatusClient{},
-		},
-		{
-			name:       "status update failed",
-			isSuccess:  true,
-			kmProvider: &configv1beta1.NamespacedKeyManagementProvider{},
-			reconciler: &test.MockStatusClient{
-				UpdateFailed: true,
-			},
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			err := re.ErrorCodeUnknown.WithDetail(tc.errString)
-			writeKMProviderStatusNamespaced(context.Background(), tc.reconciler, tc.kmProvider, logger, tc.isSuccess, &err, lastFetchedTime, nil)
-
-			if tc.kmProvider.Status.IsSuccess != tc.isSuccess {
-				t.Fatalf("Expected isSuccess to be %+v , actual %+v", tc.isSuccess, tc.kmProvider.Status.IsSuccess)
-			}
-
-			if tc.kmProvider.Status.Error != tc.expectedErrString {
-				t.Fatalf("Expected Error to be %+v , actual %+v", tc.expectedErrString, tc.kmProvider.Status.Error)
-			}
-		})
-	}
-}
diff --git a/pkg/keymanagementprovider/refresh/kubeRefresh_test.go b/pkg/keymanagementprovider/refresh/kubeRefresh_test.go
index 29319abcd..9875098b8 100644
--- a/pkg/keymanagementprovider/refresh/kubeRefresh_test.go
+++ b/pkg/keymanagementprovider/refresh/kubeRefresh_test.go
@@ -18,168 +18,120 @@ package refresh
 
 import (
 	"context"
+	"crypto"
+	"crypto/x509"
+	"errors"
 	"reflect"
 	"testing"
 	"time"
 
-	configv1beta1 "github.com/ratify-project/ratify/api/v1beta1"
-	re "github.com/ratify-project/ratify/errors"
 	"github.com/ratify-project/ratify/pkg/keymanagementprovider"
+	"github.com/ratify-project/ratify/pkg/keymanagementprovider/config"
 	_ "github.com/ratify-project/ratify/pkg/keymanagementprovider/inline"
-	"github.com/ratify-project/ratify/pkg/keymanagementprovider/mocks"
-	test "github.com/ratify-project/ratify/pkg/utils"
-	"github.com/sirupsen/logrus"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
+	mock "github.com/ratify-project/ratify/pkg/keymanagementprovider/mocks"
 	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 )
 
 func TestKubeRefresher_Refresh(t *testing.T) {
 	tests := []struct {
-		name           string
-		provider       *configv1beta1.KeyManagementProvider
-		request        ctrl.Request
-		mockClient     bool
-		expectedResult ctrl.Result
-		expectedError  bool
+		name                    string
+		providerRawParameters   []byte
+		providerType            string
+		providerRefreshInterval string
+		GetCertsFunc            func(_ context.Context) (map[keymanagementprovider.KMPMapKey][]*x509.Certificate, keymanagementprovider.KeyManagementProviderStatus, error)
+		GetKeysFunc             func(_ context.Context) (map[keymanagementprovider.KMPMapKey]crypto.PublicKey, keymanagementprovider.KeyManagementProviderStatus, error)
+		IsRefreshableFunc       func() bool
+		expectedResult          ctrl.Result
+		expectedError           bool
 	}{
 		{
-			name: "Non-refreshable",
-			provider: &configv1beta1.KeyManagementProvider{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-				Spec: configv1beta1.KeyManagementProviderSpec{
-					Type: "inline",
-					Parameters: runtime.RawExtension{
-						Raw: []byte(`{"type": "inline", "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"}`),
-					},
-				},
-			},
-			request: ctrl.Request{
-				NamespacedName: client.ObjectKey{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-			},
-			expectedResult: ctrl.Result{},
-			expectedError:  false,
+			name:                  "Non-refreshable",
+			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 },
+			expectedResult:        ctrl.Result{},
+			expectedError:         false,
 		},
 		{
-			name: "Disabled",
-			provider: &configv1beta1.KeyManagementProvider{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-				Spec: configv1beta1.KeyManagementProviderSpec{
-					Type:            "test-kmp",
-					RefreshInterval: "",
-					Parameters: runtime.RawExtension{
-						Raw: []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
-					},
-				},
-			},
-			request: ctrl.Request{
-				NamespacedName: client.ObjectKey{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-			},
-			expectedResult: ctrl.Result{},
-			expectedError:  false,
+			name:                    "Disabled",
+			providerRawParameters:   []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
+			providerType:            "test-kmp",
+			providerRefreshInterval: "",
+			IsRefreshableFunc:       func() bool { return true },
+			expectedResult:          ctrl.Result{},
+			expectedError:           false,
 		},
 		{
-			name: "Refreshable",
-			provider: &configv1beta1.KeyManagementProvider{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-				Spec: configv1beta1.KeyManagementProviderSpec{
-					Type:            "test-kmp",
-					RefreshInterval: "1m",
-					Parameters: runtime.RawExtension{
-						Raw: []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
-					},
-				},
-			},
-			request: ctrl.Request{
-				NamespacedName: client.ObjectKey{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-			},
-			expectedResult: ctrl.Result{RequeueAfter: time.Minute},
-			expectedError:  false,
+			name:                    "Refreshable",
+			providerRawParameters:   []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
+			providerType:            "test-kmp",
+			providerRefreshInterval: "1m",
+			IsRefreshableFunc:       func() bool { return true },
+			expectedResult:          ctrl.Result{RequeueAfter: time.Minute},
+			expectedError:           false,
 		},
 		{
-			name: "Invalid Interval",
-			provider: &configv1beta1.KeyManagementProvider{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-				Spec: configv1beta1.KeyManagementProviderSpec{
-					Type:            "",
-					RefreshInterval: "1mm",
-					Parameters: runtime.RawExtension{
-						Raw: []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
-					},
-				},
-			},
-			request: ctrl.Request{
-				NamespacedName: client.ObjectKey{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-			},
-			expectedResult: ctrl.Result{},
-			expectedError:  true,
+			name:                    "Invalid Interval",
+			providerRawParameters:   []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
+			providerType:            "test-kmp",
+			providerRefreshInterval: "1mm",
+			IsRefreshableFunc:       func() bool { return true },
+			expectedResult:          ctrl.Result{},
+			expectedError:           true,
 		},
 		{
-			name: "IsNotFound",
-			provider: &configv1beta1.KeyManagementProvider{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "",
-					Name:      "kmpName",
-				},
-				Spec: configv1beta1.KeyManagementProviderSpec{
-					Type:            "",
-					RefreshInterval: "",
-					Parameters: runtime.RawExtension{
-						Raw: []byte(`{"vaultURI": "https://yourkeyvault.vault.azure.net/", "certificates": [{"name": "cert1", "version": "1"}], "tenantID": "yourtenantID", "clientID": "yourclientID"}`),
-					},
-				},
+			name: "Error Fetching Certificates",
+			GetCertsFunc: func(_ context.Context) (map[keymanagementprovider.KMPMapKey][]*x509.Certificate, keymanagementprovider.KeyManagementProviderStatus, error) {
+				// Example behavior: Return an error
+				return nil, nil, errors.New("test error")
 			},
-			expectedResult: ctrl.Result{},
-			expectedError:  false,
+			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 },
+			expectedError:         true,
 		},
 		{
-			name:          "UnableToFetchKMP",
-			mockClient:    true,
-			expectedError: true,
+			name: "Error Fetching Keys",
+			GetKeysFunc: func(_ context.Context) (map[keymanagementprovider.KMPMapKey]crypto.PublicKey, keymanagementprovider.KeyManagementProviderStatus, error) {
+				// Example behavior: Return an error
+				return nil, nil, errors.New("test error")
+			},
+			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 },
+			expectedError:         true,
 		},
 	}
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			var client client.Client
-
-			if tt.mockClient {
-				client = mocks.TestClient{}
+			var factory mock.TestKeyManagementProviderFactory
+
+			if tt.GetCertsFunc != nil {
+				factory = mock.TestKeyManagementProviderFactory{
+					GetCertsFunc:      tt.GetCertsFunc,
+					IsRefreshableFunc: tt.IsRefreshableFunc,
+				}
+			} else if tt.GetKeysFunc != nil {
+				factory = mock.TestKeyManagementProviderFactory{
+					GetKeysFunc:       tt.GetKeysFunc,
+					IsRefreshableFunc: tt.IsRefreshableFunc,
+				}
 			} else {
-				scheme, _ := test.CreateScheme()
-				client = fake.NewClientBuilder().WithScheme(scheme).WithObjects(tt.provider).Build()
+				factory = mock.TestKeyManagementProviderFactory{
+					IsRefreshableFunc: tt.IsRefreshableFunc,
+				}
 			}
 
+			provider, _ := factory.Create("", config.KeyManagementProviderConfig{}, "")
+
 			kr := &KubeRefresher{
-				Client:  client,
-				Request: tt.request,
+				Provider:                provider,
+				ProviderType:            tt.providerType,
+				ProviderRefreshInterval: tt.providerRefreshInterval,
+				Resource:                "kmpname",
 			}
+
 			err := kr.Refresh(context.Background())
 			result := kr.GetResult()
 			if !reflect.DeepEqual(result, tt.expectedResult) {
@@ -192,190 +144,93 @@ func TestKubeRefresher_Refresh(t *testing.T) {
 	}
 }
 
-func TestKubeRefresher_Create(t *testing.T) {
-	tests := []struct {
-		name          string
-		config        map[string]interface{}
-		expectedError bool
-	}{
-		{
-			name: "Success",
-			config: map[string]interface{}{
-				"client":  &mocks.TestClient{},
-				"request": ctrl.Request{},
-			},
-			expectedError: false,
-		},
-		{
-			name: "ClientMissing",
-			config: map[string]interface{}{
-				"request": ctrl.Request{},
-			},
-			expectedError: true,
-		},
-		{
-			name: "RequestMissing",
-			config: map[string]interface{}{
-				"client": &mocks.TestClient{},
-			},
-			expectedError: true,
-		},
+func TestKubeRefresher_GetResult(t *testing.T) {
+	kr := &KubeRefresher{
+		Result: ctrl.Result{RequeueAfter: time.Minute},
 	}
 
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			kr := &KubeRefresher{}
-			_, err := kr.Create(tt.config)
-			if tt.expectedError && err == nil {
-				t.Fatalf("Expected error but got nil")
-			}
-		})
-	}
-}
+	result := kr.GetResult()
+	expectedResult := ctrl.Result{RequeueAfter: time.Minute}
 
-func TestKMProviderUpdateErrorStatus(t *testing.T) {
-	var parametersString = "{\"certs\":{\"name\":\"certName\"}}"
-	var kmProviderStatus = []byte(parametersString)
-
-	status := configv1beta1.KeyManagementProviderStatus{
-		IsSuccess: true,
-		Properties: runtime.RawExtension{
-			Raw: kmProviderStatus,
-		},
-	}
-	keyManagementProvider := configv1beta1.KeyManagementProvider{
-		Status: status,
-	}
-	expectedErr := re.ErrorCodeUnknown.WithDetail("it's a long error from unit test")
-	lastFetchedTime := metav1.Now()
-	updateKMProviderErrorStatus(&keyManagementProvider, &expectedErr, &lastFetchedTime)
-
-	if keyManagementProvider.Status.IsSuccess != false {
-		t.Fatalf("Unexpected error, expected isSuccess to be false , actual %+v", keyManagementProvider.Status.IsSuccess)
-	}
-
-	if keyManagementProvider.Status.Error != expectedErr.Error() {
-		t.Fatalf("Unexpected error string, expected %+v, got %+v", expectedErr, keyManagementProvider.Status.Error)
-	}
-	if keyManagementProvider.Status.BriefError != expectedErr.GetConciseError(150) {
-		t.Fatalf("Unexpected error string, expected %+v, got %+v", expectedErr.GetConciseError(150), keyManagementProvider.Status.Error)
-	}
-
-	//make sure properties of last cached cert was not overridden
-	if len(keyManagementProvider.Status.Properties.Raw) == 0 {
-		t.Fatalf("Unexpected properties,  expected %+v, got %+v", parametersString, string(keyManagementProvider.Status.Properties.Raw))
+	if !reflect.DeepEqual(result, expectedResult) {
+		t.Fatalf("Expected result %v, but got %v", expectedResult, result)
 	}
 }
-
-// TestKMProviderUpdateSuccessStatus tests the updateSuccessStatus method
-func TestKMProviderUpdateSuccessStatus(t *testing.T) {
-	kmProviderStatus := keymanagementprovider.KeyManagementProviderStatus{}
-	properties := map[string]string{}
-	properties["Name"] = "wabbit"
-	properties["Version"] = "ABC"
-
-	kmProviderStatus["Certificates"] = properties
-
-	lastFetchedTime := metav1.Now()
-
-	status := configv1beta1.KeyManagementProviderStatus{
-		IsSuccess: false,
-		Error:     "error from last operation",
-	}
-	keyManagementProvider := configv1beta1.KeyManagementProvider{
-		Status: status,
-	}
-
-	updateKMProviderSuccessStatus(&keyManagementProvider, &lastFetchedTime, kmProviderStatus)
-
-	if keyManagementProvider.Status.IsSuccess != true {
-		t.Fatalf("Expected isSuccess to be true , actual %+v", keyManagementProvider.Status.IsSuccess)
-	}
-
-	if keyManagementProvider.Status.Error != "" {
-		t.Fatalf("Unexpected error string, actual %+v", keyManagementProvider.Status.Error)
-	}
-
-	//make sure properties of last cached cert was updated
-	if len(keyManagementProvider.Status.Properties.Raw) == 0 {
-		t.Fatalf("Properties should not be empty")
-	}
-}
-
-// TestKMProviderUpdateSuccessStatus tests the updateSuccessStatus method with empty properties
-func TestKMProviderUpdateSuccessStatus_emptyProperties(t *testing.T) {
-	lastFetchedTime := metav1.Now()
-	status := configv1beta1.KeyManagementProviderStatus{
-		IsSuccess: false,
-		Error:     "error from last operation",
-	}
-	keyManagementProvider := configv1beta1.KeyManagementProvider{
-		Status: status,
-	}
-
-	updateKMProviderSuccessStatus(&keyManagementProvider, &lastFetchedTime, nil)
-
-	if keyManagementProvider.Status.IsSuccess != true {
-		t.Fatalf("Expected isSuccess to be true , actual %+v", keyManagementProvider.Status.IsSuccess)
+func TestKubeRefresher_GetStatus(t *testing.T) {
+	kr := &KubeRefresher{
+		Status: keymanagementprovider.KeyManagementProviderStatus{
+			"attribute1": "value1",
+			"attribute2": "value2",
+		},
 	}
 
-	if keyManagementProvider.Status.Error != "" {
-		t.Fatalf("Unexpected error string, actual %+v", keyManagementProvider.Status.Error)
+	status := kr.GetStatus()
+	expectedStatus := keymanagementprovider.KeyManagementProviderStatus{
+		"attribute1": "value1",
+		"attribute2": "value2",
 	}
 
-	//make sure properties of last cached cert was updated
-	if len(keyManagementProvider.Status.Properties.Raw) != 0 {
-		t.Fatalf("Properties should be empty")
+	if !reflect.DeepEqual(status, expectedStatus) {
+		t.Fatalf("Expected status %v, but got %v", expectedStatus, status)
 	}
 }
-
-func TestWriteKMProviderStatus(t *testing.T) {
-	logger := logrus.WithContext(context.Background())
-	lastFetchedTime := metav1.Now()
-	testCases := []struct {
-		name              string
-		isSuccess         bool
-		kmProvider        *configv1beta1.KeyManagementProvider
-		errString         string
-		expectedErrString string
-		reconciler        client.StatusClient
+func TestKubeRefresher_Create(t *testing.T) {
+	tests := []struct {
+		name                    string
+		config                  RefresherConfig
+		expectedProviderType    string
+		expectedRefreshInterval string
+		expectedResource        string
 	}{
 		{
-			name:       "success status",
-			isSuccess:  true,
-			errString:  "",
-			kmProvider: &configv1beta1.KeyManagementProvider{},
-			reconciler: &test.MockStatusClient{},
-		},
-		{
-			name:              "error status",
-			isSuccess:         false,
-			kmProvider:        &configv1beta1.KeyManagementProvider{},
-			errString:         "a long error string that exceeds the max length of 150 characters",
-			expectedErrString: "UNKNOWN: a long error string that exceeds the max length of 150 characters",
-			reconciler:        &test.MockStatusClient{},
+			name: "Valid Config",
+			config: RefresherConfig{
+				Provider:                &mock.TestKeyManagementProvider{},
+				ProviderType:            "test-kmp",
+				ProviderRefreshInterval: "1m",
+				Resource:                "test-resource",
+			},
+			expectedProviderType:    "test-kmp",
+			expectedRefreshInterval: "1m",
+			expectedResource:        "test-resource",
 		},
 		{
-			name:       "status update failed",
-			isSuccess:  true,
-			kmProvider: &configv1beta1.KeyManagementProvider{},
-			reconciler: &test.MockStatusClient{
-				UpdateFailed: true,
+			name: "Empty Config",
+			config: RefresherConfig{
+				Provider:                nil,
+				ProviderType:            "",
+				ProviderRefreshInterval: "",
+				Resource:                "",
 			},
+			expectedProviderType:    "",
+			expectedRefreshInterval: "",
+			expectedResource:        "",
 		},
 	}
 
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			err := re.ErrorCodeUnknown.WithDetail(tc.errString)
-			writeKMProviderStatus(context.Background(), tc.reconciler, tc.kmProvider, logger, tc.isSuccess, &err, lastFetchedTime, nil)
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			kr := &KubeRefresher{}
+			refresher, err := kr.Create(tt.config)
+			if err != nil {
+				t.Fatalf("Expected no error, but got %v", err)
+			}
+
+			kubeRefresher, ok := refresher.(*KubeRefresher)
+			if !ok {
+				t.Fatalf("Expected KubeRefresher type, but got %T", refresher)
+			}
+
+			if kubeRefresher.ProviderType != tt.expectedProviderType {
+				t.Fatalf("Expected ProviderType %v, but got %v", tt.expectedProviderType, kubeRefresher.ProviderType)
+			}
 
-			if tc.kmProvider.Status.IsSuccess != tc.isSuccess {
-				t.Fatalf("Expected isSuccess to be: %+v, actual: %+v", tc.isSuccess, tc.kmProvider.Status.IsSuccess)
+			if kubeRefresher.ProviderRefreshInterval != tt.expectedRefreshInterval {
+				t.Fatalf("Expected ProviderRefreshInterval %v, but got %v", tt.expectedRefreshInterval, kubeRefresher.ProviderRefreshInterval)
 			}
 
-			if tc.kmProvider.Status.Error != tc.expectedErrString {
-				t.Fatalf("Expected Error to be: %+v, actual: %+v", tc.expectedErrString, tc.kmProvider.Status.Error)
+			if kubeRefresher.Resource != tt.expectedResource {
+				t.Fatalf("Expected Resource %v, but got %v", tt.expectedResource, kubeRefresher.Resource)
 			}
 		})
 	}
diff --git a/pkg/keymanagementprovider/refresh/refresh.go b/pkg/keymanagementprovider/refresh/refresh.go
index 78e32b12d..36e05e243 100644
--- a/pkg/keymanagementprovider/refresh/refresh.go
+++ b/pkg/keymanagementprovider/refresh/refresh.go
@@ -18,11 +18,12 @@ package refresh
 
 import (
 	"context"
+
+	"github.com/ratify-project/ratify/pkg/keymanagementprovider"
 )
 
 const (
-	KubeRefresherType           = "kubeRefresher"
-	KubeRefresherNamespacedType = "kubeRefresherNamespaced"
+	KubeRefresherType = "kubeRefresher"
 )
 
 // Refresher is an interface that defines methods to be implemented by a each refresher
@@ -31,4 +32,15 @@ type Refresher interface {
 	Refresh(ctx context.Context) error
 	// GetResult is a method that returns the result of the refresh
 	GetResult() interface{}
+	// GetStatus is a method that returns the status of the refresh
+	GetStatus() interface{}
+}
+
+// RefresherConfig is a struct that holds the configuration for a refresher
+type RefresherConfig struct {
+	RefresherType           string                                      // RefresherType is the type of the refresher
+	Provider                keymanagementprovider.KeyManagementProvider // Provider is the key management provider
+	ProviderType            string                                      // ProviderType is the type of the provider
+	ProviderRefreshInterval string                                      // ProviderRefreshInterval is the refresh interval for the provider
+	Resource                string                                      // Resource is the resource to be refreshed
 }