Repository: deislabs/ratify
Pull request #172 (2022-04-26 22:33:10)

Review policy
Adding review policy for Ratify

sajayantony: Great to see this and multiple repos adopting this - 

Patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index fc48e3f..0d19041 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -37,13 +37,6 @@ The Ratify project is composed of the following main components:
 
 If you'd like to start contributing to Ratify, you can search for issues tagged as "good first issue" [here](https://github.com/deislabs/ratify/labels/good%20first%20issue).
 
-### Ratify Code
-
-* Ensure that an issue has been created to track the feature enhancement or bug that is being fixed.
-* In the PR description, make sure you've included "Fixes #{issue_number}" e.g. "Fixes #242" so that GitHub knows to link it to an issue.
-* To avoid multiple contributors working on the same issue, please add a comment to the issue to let us know you plan to work on it.
-* If a significant amount of design is required, please include a proposal in the issue and wait for approval before working on code. If there's anything you're not sure about, please feel free to discuss this in the issue. We'd much rather all be on the same page at the start, so that there's less chance that drastic changes will be needed when your pull request is reviewed.
-
 ### Plugins
 
 If you'd like to contribute to the collection of plugins:
diff --git a/README.md b/README.md
index 09115d8..e3919d8 100644
--- a/README.md
+++ b/README.md
@@ -45,13 +45,11 @@ NOTE: `validatingWebhookTimeoutSeconds` increased from 3 to 7 so all Ratify oper
 - Deploy ratify and a `demo` constraint on gatekeeper
 
 ```bash
-git clone https://github.com/deislabs/ratify.git
-cd ratify
-
+helm repo add ratify https://deislabs.github.io/ratify
 helm install ratify \
-    ./charts/ratify --atomic
+    ratify/ratify --atomic
 
-kubectl apply -f ./charts/ratify-gatekeeper/templates/constraint.yaml
+kubectl apply -f https://deislabs.github.io/ratify/charts/ratify-gatekeeper/templates/constraint.yaml
 ```
 
 Once the installation is completed, you can test the deployment of an image that is signed using Notary V2 solution.
@@ -81,7 +79,7 @@ You just validated the container images in your k8s cluster!
 - Uninstall Ratify
 
 ```bash=
-kubectl delete -f ./charts/ratify-gatekeeper/templates/constraint.yaml
+kubectl delete -f https://deislabs.github.io/ratify/charts/ratify-gatekeeper/templates/constraint.yaml
 helm delete ratify
 kubectl delete namespace demo
 ```
diff --git a/REVIEWING.md b/REVIEWING.md
new file mode 100644
index 0000000..86fbb1b
--- /dev/null
+++ b/REVIEWING.md
@@ -0,0 +1,74 @@
+# Reviewing Guide
+
+This document covers who may review pull requests for this project, and provides guidance on how to perform code reviews that meet our community standards and code of conduct. All reviewers must read this document and agree to follow the project review guidelines. Reviewers who do not follow these guidelines may have their privileges revoked.
+
+## Attribution
+
+The reviewing guide was created using content and verbiage from [CNCF reviewing guide]( https://contribute.cncf.io/maintainers/github/templates/recommended/reviewing/)
+
+## Values
+
+All reviewers must abide by the [Code of Conduct](CODE_OF_CONDUCT.md) and are also protected by it. A reviewer should not tolerate poor behavior and is encouraged to report any behavior that violates the Code of Conduct. All of our values listed above are distilled from our Code of Conduct.
+
+Below are concrete examples of how it applies to code review specifically:
+
+### Inclusion
+
+Be welcoming and inclusive. You should proactively ensure that the author is successful. While any particular pull request may not ultimately be merged, overall we want people to have a great experience and be willing to contribute again. Answer the questions they didn't know to ask or offer concrete help when they appear stuck.
+
+### Sustainability
+
+Avoid burnout by enforcing healthy boundaries. Here are some examples of how a reviewer is encouraged to act to take care of themselves:
+
+* Authors should meet baseline expectations when submitting a pull request, such as writing tests.
+* If your availability changes, you can step down from a pull request and have someone else assigned.
+* If interactions with an author are not following code of conduct, close the PR and raise it up with your Code of Conduct committee or point of contact. It's not your job to coax people into behaving.
+
+### Trust
+
+Be trustworthy. During a review, your actions both build and help maintain the trust that the community has placed in this project. Below are examples of ways that we build trust:
+
+* **Transparency** - If a pull request won't be merged, clearly say why and close it. If a pull request won't be reviewed for a while, let the author know so they can set expectations and understand why it's blocked.
+* **Integrity** - Put the project's best interests ahead of personal relationships or company affiliations when deciding if a change should be merged.
+* **Stability** - Only merge when the change won't negatively impact project stability. It can be tempting to merge a pull request that doesn't meet our quality standards, for example when the review has been delayed, or because we are trying to deliver new features quickly, but regressions can significantly hurt trust in our project.
+
+## Process
+
+### PR Lifecycle
+
+#### 1. PR creation
+
+* Ensure that an issue has been created to track the feature enhancement or bug that is being fixed.
+* In the PR description, make sure you've included "Fixes #{issue_number}" e.g. "Fixes #242" so that GitHub knows to link it to an issue.
+* To avoid multiple contributors working on the same issue, please add a comment to the issue to let us know you plan to work on it.
+* If a significant amount of design is required, please include a proposal in the issue and wait for approval before working on code. If there's anything you're not sure about, please feel free to discuss this in the issue. We'd much rather all be on the same page at the start, so that there's less chance that drastic changes will be needed when your pull request is reviewed.
+
+#### 2. Reviewing/Discussion
+
+* Everyone is encouraged to participate in code reviews.
+* It is best to get approval from contributors with knowledge about the code paths being modified. You can identify an appropriate reviewer by looking through the file history to find frequent contributor. Contributors can not be directly added as reviews but can be notified via a comment.
+* When you provide feedback, make it clear if the change must be made for the pull request to be approved, or if it is just a suggestion. Mark suggestions with `nit`.
+* If your code review has had no activity for 7 days, a maintainer should assist in reassigning the review.  If a maintainer has not updated your review, please reach out to @project maintainers.
+* Reviewers are welcome to suggest changes through [applying a suggested change](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/incorporating-feedback-in-your-pull-request#applying-a-suggested-change) workflow.
+
+#### 3. Merge or close
+
+* Maintainers are responsible for handling final approval and merging of pull requests. Contributors can approve pull requests and provide input.
+* Maintainers can merge their own pull requests after being approved by other maintainers.
+
+## Checklist
+
+Below are a set of common questions that apply to all pull requests:
+
+- [ ] Does the affected code have corresponding tests?
+- [ ] Are the changes documented, not just with inline documentation, but also with conceptual documentation such as an overview of a new feature, or task-based documentation like a tutorial? Consider if this change should be announced on your project blog.
+- [ ] Does this introduce breaking changes that would require an announcement or bumping the major version?
+- [ ] Does all new files have appropriate license header?
+
+## Reading List
+
+Reviewers are encouraged to read the following articles for help with common reviewer tasks:
+
+* [The Art of Closing: How to closing an unfinished or rejected pull request](https://blog.jessfraz.com/post/the-art-of-closing/)
+* [Kindness and Code Reviews: Improving the Way We Give Feedback](https://product.voxmedia.com/2018/8/21/17549400/kindness-and-code-reviews-improving-the-way-we-give-feedback)
+* [Code Review Guidelines for Humans: Examples of good and back feedback](https://phauer.com/2018/code-review-guidelines/#code-reviews-guidelines-for-the-reviewer)
diff --git a/charts/ratify/templates/configmap.yaml b/charts/ratify/templates/configmap.yaml
index c4a1bf8..7c61b74 100644
--- a/charts/ratify/templates/configmap.yaml
+++ b/charts/ratify/templates/configmap.yaml
@@ -33,10 +33,13 @@ data:
         ]
       },
       "policies": {
-          "version": "1.0.0",
-          "artifactVerificationPolicies": {
-              "application/vnd.cncf.notary.v2.signature": "any"
-          }
+        "version": "1.0.0",
+        "plugin": {
+            "name": "configPolicy",
+            "artifactVerificationPolicies": {
+                "application/vnd.cncf.notary.v2.signature": "all"
+            }
+        }
       },
       "verifiers": {
           "version": "1.0.0",
diff --git a/cmd/ratify/cmd/serve.go b/cmd/ratify/cmd/serve.go
index 070b03d..5621492 100644
--- a/cmd/ratify/cmd/serve.go
+++ b/cmd/ratify/cmd/serve.go
@@ -21,7 +21,7 @@ import (
 	"github.com/deislabs/ratify/config"
 	"github.com/deislabs/ratify/httpserver"
 	ef "github.com/deislabs/ratify/pkg/executor/core"
-	pf "github.com/deislabs/ratify/pkg/policyprovider/configpolicy"
+	pf "github.com/deislabs/ratify/pkg/policyprovider/factory"
 	sf "github.com/deislabs/ratify/pkg/referrerstore/factory"
 	vf "github.com/deislabs/ratify/pkg/verifier/factory"
 	"github.com/sirupsen/logrus"
@@ -80,7 +80,7 @@ func serve(opts serveCmdOptions) error {
 
 	logrus.Infof("verifiers successfully created. number of verifiers %d", len(verifiers))
 
-	policyEnforcer, err := pf.CreatePolicyEnforcerFromConfig(cf.PoliciesConfig)
+	policyEnforcer, err := pf.CreatePolicyProviderFromConfig(cf.PoliciesConfig)
 
 	if err != nil {
 		return err
diff --git a/cmd/ratify/cmd/verify.go b/cmd/ratify/cmd/verify.go
index b9bd1b5..d528085 100644
--- a/cmd/ratify/cmd/verify.go
+++ b/cmd/ratify/cmd/verify.go
@@ -22,7 +22,7 @@ import (
 	"github.com/deislabs/ratify/config"
 	e "github.com/deislabs/ratify/pkg/executor"
 	ef "github.com/deislabs/ratify/pkg/executor/core"
-	pf "github.com/deislabs/ratify/pkg/policyprovider/configpolicy"
+	pf "github.com/deislabs/ratify/pkg/policyprovider/factory"
 	sf "github.com/deislabs/ratify/pkg/referrerstore/factory"
 	vf "github.com/deislabs/ratify/pkg/verifier/factory"
 	"github.com/spf13/cobra"
@@ -90,7 +90,7 @@ func verify(opts verifyCmdOptions) error {
 		return err
 	}
 
-	policyEnforcer, err := pf.CreatePolicyEnforcerFromConfig(cf.PoliciesConfig)
+	policyEnforcer, err := pf.CreatePolicyProviderFromConfig(cf.PoliciesConfig)
 
 	if err != nil {
 		return err
diff --git a/cmd/ratify/main.go b/cmd/ratify/main.go
index caa8019..0c1f716 100644
--- a/cmd/ratify/main.go
+++ b/cmd/ratify/main.go
@@ -19,6 +19,7 @@ import (
 	"os"
 
 	"github.com/deislabs/ratify/cmd/ratify/cmd"
+	_ "github.com/deislabs/ratify/pkg/policyprovider/configpolicy"
 	_ "github.com/deislabs/ratify/pkg/referrerstore/oras"
 	_ "github.com/deislabs/ratify/pkg/verifier/notaryv2"
 )
diff --git a/config/config.json b/config/config.json
index 477631c..28623b7 100644
--- a/config/config.json
+++ b/config/config.json
@@ -9,10 +9,11 @@
     },
     "policies": {
         "version": "1.0.0",
-        "artifactVerificationPolicies": {
-            "application/vnd.cncf.notary.v2": "any",
-            "org.example.sbom.v0": "all",
-            "application/vnd.ratify.spdx.v0": "any"
+        "plugin": {
+            "name": "configPolicy",
+            "artifactVerificationPolicies": {
+                "application/vnd.cncf.notary.v2.signature": "any"
+            }
         }
     },
     "verifiers": {
diff --git a/docs/executor.md b/docs/executor.md
new file mode 100644
index 0000000..a691269
--- /dev/null
+++ b/docs/executor.md
@@ -0,0 +1,25 @@
+# Executor
+
+The executor is the 'glue' that links all Ratify plugin-based components such as the verifiers, referrer stores, and policy providers. The executor handles all components of the verification process once a subject verification request is received either via CLI or server.
+
+
+## Execution Steps
+
+- Executor's `VerifySubject` function is invoked with a string reference to a subject to be verified.
+- Subject string is parsed and extracted into a subject reference
+- Find the subject descriptor associated with reference
+    - Check each of the referrer stores configured and invoke `GetSubjectDescriptor` method until descriptor is successfully resolved and returned
+- Iterate through each referrer store configured
+    - For each store, get the list of reference descriptors for the subject from that store. (use continuation token if provided to retrieve all references)
+    - Iterate through each reference descriptor found
+        - Use policy provider's `VerifyNeeded` method to determine if subject with reference artifact should be verified based on configured policy
+        - If verification is required, perform verification:
+            - For each of the configured verifiers, check if the verifier can verify the reference artifact type
+                - Invoke the verifier plugin's `Verify` method to perform verification
+                - Return the `VerifyResult` containing `VerifierReport`, which has metadata such as the subject reference, verifier name, artifact type, and success status for the report. 
+        - add the verifier reports returned by subject verification to a list of reports
+        - if the verification result for that reference artifact was false, invoke the policy provider to determine if executor should continue to verify subsequent reference artifacts.
+- After iterating through all stores, if there are no verifier reports generated, then we assume we failed to retrieve verifiable reference artifacts and error.
+- Invoke the policy provider to determine the final overall success to return.
+- Return a `VerifyResult` with final determined outcome from policy provider and the list of verifier reports.
+
diff --git a/docs/policy-provider.md b/docs/policy-provider.md
new file mode 100644
index 0000000..1af1caa
--- /dev/null
+++ b/docs/policy-provider.md
@@ -0,0 +1,94 @@
+# Policy Providers
+
+Ratify implements an extensible policy provider interface allowing for different policy providers to be created and registered. The policy provider to be used is determined by the policy plugin specified in the `policies` section of the configuration. 
+
+Currently, Ratify supports a Configuration based Policy Provider named `configPolicy`.
+
+
+## How is the Policy Provider used in Ratify execution?
+
+The executor is the "glue" that links all Ratify plugin-based components such as the verifiers, referrer stores, and policy providers. The policy provider is primarily invoked for each reference artifact discovered AFTER a configured verifier is found that can be used to verify that particular artifacy type. If a reference artifact is found that does not have a corresponding verifier configured that can perform verification, the executor will ignore this artifact. As a result, this unverifiable artifact will NOT influence the final overall verification success determined by the policy provider. 
+## Config Policy Provider
+
+```
+...
+"policies": {
+    "version": "1.0.0",
+    "plugin": {
+        "name": "configPolicy",
+        "artifactVerificationPolicies": {
+            "application/vnd.cncf.notary.v2.signature": "any"
+        }
+    }
+},
+...
+```
+
+- The `name` field is REQUIRED and MUST match the name of the registered policy provider
+- `artifactVerificationPolicies`: map of artifact type to policy; each entry in the map's policy must be satisfied for Ratify to return true.
+    - `any`: policy that REQUIRES at least one artifact of specified type to verify to `true` 
+    - `all`: policy that REQUIRES all artifacts of specified type to verify to `true``
+- Default policy:
+    - The `default` policy applies to unspecified artifact types. The `default` policy is set to `all`. Thus, all unspecified artifact types must have all successful verification results for an overall success result.
+    - The `default` policy can be overriden to `any` in the map:
+        
+        ```
+        ...
+        "policies": {
+            "version": "1.0.0",
+            "plugin": {
+                "name": "configPolicy",
+                "artifactVerificationPolicies": {
+                    "default": "any"
+                }
+            }
+        },
+        ...
+        ```
+### Examples:
+
+- Require all reference artifacts associated with subject image to be verify successfully:
+    ```
+    ...
+    "policies": {
+        "version": "1.0.0",
+        "plugin": {
+            "name": "configPolicy"
+        }
+    },
+    ...
+    ```
+- Require at least one reference artifact of the same type to verify succesfully. (relaxes the default policy to 'any'):
+    ```
+    ...
+    "policies": {
+        "version": "1.0.0",
+        "plugin": {
+            "name": "configPolicy",
+            "artifactVerificationPolicies": {
+                "default": "any"
+            }
+        }
+    },
+    ...
+    ```
+- For a specific artifact type, relax requirement so only one success is needed for artifacts of that type:
+    ```
+    ...
+    "policies": {
+        "version": "1.0.0",
+        "plugin": {
+            "name": "configPolicy",
+            "artifactVerificationPolicies": {
+                "application/vnd.cncf.notary.v2.signature": "any"
+            }
+        }
+    },
+    ...
+    ```
+
+## Notational Conventions
+
+The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as described in [RFC 2119](http://tools.ietf.org/html/rfc2119).
+
+The key words "unspecified", "undefined", and "implementation-defined" are to be interpreted as described in the [rationale for the C99 standard](http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf#page=18).
\ No newline at end of file
diff --git a/pkg/executor/core/executor.go b/pkg/executor/core/executor.go
index e2f3f99..ffb1100 100644
--- a/pkg/executor/core/executor.go
+++ b/pkg/executor/core/executor.go
@@ -82,10 +82,6 @@ func (executor Executor) verifySubjectInternal(ctx context.Context, verifyParame
 	subjectReference.Digest = desc.Digest
 
 	var verifierReports []interface{}
-	anyVerifySuccess := map[string]bool{}
-	for _, referenceType := range verifyParameters.ReferenceTypes {
-		anyVerifySuccess[referenceType] = false
-	}
 
 	for _, referrerStore := range executor.ReferrerStores {
 		var continuationToken string
@@ -95,6 +91,7 @@ func (executor Executor) verifySubjectInternal(ctx context.Context, verifyParame
 				return types.VerifyResult{}, err
 			}
 			continuationToken = referrersResult.NextToken
+
 			for _, reference := range referrersResult.Referrers {
 
 				if executor.PolicyEnforcer.VerifyNeeded(ctx, subjectReference, reference) {
@@ -106,8 +103,6 @@ func (executor Executor) verifySubjectInternal(ctx context.Context, verifyParame
 						if !executor.PolicyEnforcer.ContinueVerifyOnFailure(ctx, subjectReference, reference, result) {
 							return result, nil
 						}
-					} else {
-						anyVerifySuccess[reference.ArtifactType] = true
 					}
 				}
 			}
@@ -121,13 +116,7 @@ func (executor Executor) verifySubjectInternal(ctx context.Context, verifyParame
 		return types.VerifyResult{}, ReferrersNotFound
 	}
 
-	overallVerifySuccess := true
-	for _, referenceType := range verifyParameters.ReferenceTypes {
-		if anyVerifySuccess[referenceType] == false {
-			overallVerifySuccess = false
-			break
-		}
-	}
+	overallVerifySuccess := executor.PolicyEnforcer.OverallVerifyResult(ctx, verifierReports)
 
 	return types.VerifyResult{IsSuccess: overallVerifySuccess, VerifierReports: verifierReports}, nil
 }
@@ -146,6 +135,7 @@ func (ex Executor) verifyReference(ctx context.Context, subjectRef common.Refere
 					Results:   []string{fmt.Sprintf("an error thrown by the verifier %v", err)}}
 			}
 
+			verifyResult.ArtifactType = referenceDesc.ArtifactType
 			verifyResults = append(verifyResults, verifyResult)
 			isSuccess = verifyResult.IsSuccess
 			break
diff --git a/pkg/policyprovider/api.go b/pkg/policyprovider/api.go
index b565997..dfdc512 100644
--- a/pkg/policyprovider/api.go
+++ b/pkg/policyprovider/api.go
@@ -29,7 +29,9 @@ type PolicyProvider interface {
 	VerifyNeeded(ctx context.Context, subjectReference common.Reference, referenceDesc ocispecs.ReferenceDescriptor) bool
 	// ContinueVerifyOnFailure determines if the given error can be ignored and verification can be continued.
 	ContinueVerifyOnFailure(ctx context.Context, subjectReference common.Reference, referenceDesc ocispecs.ReferenceDescriptor, partialVerifyResult types.VerifyResult) bool
-	// ErrorToVerifyResult determines the final outcome of verification that is constructed using the results from
-	// individual verifications or other errors that occurred during the workflow
+	// ErrorToVerifyResult converts an error to a properly formatted verify result
 	ErrorToVerifyResult(ctx context.Context, subjectRefString string, verifyError error) types.VerifyResult
+	// OverallVerifyResult determines the final outcome of verification that is constructed using the results from
+	// individual verifications
+	OverallVerifyResult(ctx context.Context, verifierReports []interface{}) bool
 }
diff --git a/pkg/policyprovider/config/config.go b/pkg/policyprovider/config/config.go
index f87d5ac..d2b7014 100644
--- a/pkg/policyprovider/config/config.go
+++ b/pkg/policyprovider/config/config.go
@@ -15,10 +15,11 @@ limitations under the License.
 
 package config
 
-import "github.com/deislabs/ratify/pkg/policyprovider/types"
+// PolicyPluginConfig represents the configuration of a policy plugin
+type PolicyPluginConfig map[string]interface{}
 
 // PoliciesConfig describes policies that are defined in the configuration
 type PoliciesConfig struct {
-	Version                      string                                    `json:"version,omitempty"`
-	ArtifactVerificationPolicies map[string]types.ArtifactTypeVerifyPolicy `json:"artifactVerificationPolicies,omitempty"`
+	Version      string             `json:"version,omitempty"`
+	PolicyPlugin PolicyPluginConfig `json:"plugin"`
 }
diff --git a/pkg/policyprovider/configpolicy/configpolicy.go b/pkg/policyprovider/configpolicy/configpolicy.go
index a4efd0a..be91179 100644
--- a/pkg/policyprovider/configpolicy/configpolicy.go
+++ b/pkg/policyprovider/configpolicy/configpolicy.go
@@ -13,10 +13,11 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package config
+package configpolicy
 
 import (
 	"context"
+	"encoding/json"
 	"fmt"
 
 	"github.com/deislabs/ratify/pkg/common"
@@ -24,6 +25,7 @@ import (
 	"github.com/deislabs/ratify/pkg/ocispecs"
 	"github.com/deislabs/ratify/pkg/policyprovider"
 	"github.com/deislabs/ratify/pkg/policyprovider/config"
+	pf "github.com/deislabs/ratify/pkg/policyprovider/factory"
 	vt "github.com/deislabs/ratify/pkg/policyprovider/types"
 	"github.com/deislabs/ratify/pkg/verifier"
 )
@@ -33,29 +35,56 @@ type PolicyEnforcer struct {
 	ArtifactTypePolicies map[string]vt.ArtifactTypeVerifyPolicy
 }
 
-// CreatePolicyEnforcerFromConfig creates a policy enforcer from the given configuration
-func CreatePolicyEnforcerFromConfig(policiesConfig config.PoliciesConfig) (policyprovider.PolicyProvider, error) {
+type configPolicyEnforcerConf struct {
+	Name                         string                                 `json:"name"`
+	ArtifactVerificationPolicies map[string]vt.ArtifactTypeVerifyPolicy `json:"artifactVerificationPolicies,omitempty"`
+}
+
+const defaultPolicyName string = "default"
+
+type configPolicyFactory struct{}
+
+// init calls Register for our config policy provider
+func init() {
+	pf.Register("configPolicy", &configPolicyFactory{})
+}
+
+// Create initializes a new policy provider based on the provider selected in config
+func (f *configPolicyFactory) Create(policyConfig config.PolicyPluginConfig) (policyprovider.PolicyProvider, error) {
 	policyEnforcer := PolicyEnforcer{}
-	if policiesConfig.ArtifactVerificationPolicies == nil {
+
+	conf := configPolicyEnforcerConf{}
+	policyProviderConfigBytes, err := json.Marshal(policyConfig)
+	if err != nil {
+		return nil, fmt.Errorf("failed to marshal policy config: %v", err)
+	}
+
+	if err := json.Unmarshal(policyProviderConfigBytes, &conf); err != nil {
+		return nil, fmt.Errorf("failed to parse policy provider configuration: %v", err)
+	}
+
+	if conf.ArtifactVerificationPolicies == nil {
 		policyEnforcer.ArtifactTypePolicies = map[string]vt.ArtifactTypeVerifyPolicy{}
 	} else {
-		policyEnforcer.ArtifactTypePolicies = policiesConfig.ArtifactVerificationPolicies
+		policyEnforcer.ArtifactTypePolicies = conf.ArtifactVerificationPolicies
 	}
-	if policyEnforcer.ArtifactTypePolicies["default"] == "" {
-		policyEnforcer.ArtifactTypePolicies["default"] = vt.AnyVerifySuccess
+	if policyEnforcer.ArtifactTypePolicies[defaultPolicyName] == "" {
+		policyEnforcer.ArtifactTypePolicies[defaultPolicyName] = vt.AllVerifySuccess
 	}
 	return &policyEnforcer, nil
 }
 
+// VerifyNeeded determines if the given subject/reference artifact should be verified
 func (enforcer PolicyEnforcer) VerifyNeeded(ctx context.Context, subjectReference common.Reference, referenceDesc ocispecs.ReferenceDescriptor) bool {
 	return true
 }
 
+// ContinueVerifyOnFailure determines if the given error can be ignored and verification can be continued.
 func (enforcer PolicyEnforcer) ContinueVerifyOnFailure(ctx context.Context, subjectReference common.Reference, referenceDesc ocispecs.ReferenceDescriptor, partialVerifyResult types.VerifyResult) bool {
 	artifactType := referenceDesc.ArtifactType
 	policy := enforcer.ArtifactTypePolicies[artifactType]
 	if policy == "" {
-		policy = enforcer.ArtifactTypePolicies["default"]
+		policy = enforcer.ArtifactTypePolicies[defaultPolicyName]
 	}
 	if policy == vt.AnyVerifySuccess {
 		return true
@@ -64,6 +93,7 @@ func (enforcer PolicyEnforcer) ContinueVerifyOnFailure(ctx context.Context, subj
 	}
 }
 
+// ErrorToVerifyResult converts an error to a properly formatted verify result
 func (enforcer PolicyEnforcer) ErrorToVerifyResult(ctx context.Context, subjectRefString string, verifyError error) types.VerifyResult {
 	errorReport := verifier.VerifierResult{
 		Subject:   subjectRefString,
@@ -74,3 +104,54 @@ func (enforcer PolicyEnforcer) ErrorToVerifyResult(ctx context.Context, subjectR
 	reports = append(reports, errorReport)
 	return types.VerifyResult{IsSuccess: false, VerifierReports: reports}
 }
+
+// OverallVerifyResult determines the final outcome of verification that is constructed using the results from
+// individual verifications
+func (enforcer PolicyEnforcer) OverallVerifyResult(ctx context.Context, verifierReports []interface{}) bool {
+	if len(verifierReports) <= 0 {
+		return false
+	}
+
+	// use boolean map to track if each artifact type policy constraint is satisfied
+	verifySuccess := map[string]bool{}
+	for artifactType := range enforcer.ArtifactTypePolicies {
+		// add all policies except for default
+		if artifactType != defaultPolicyName {
+			verifySuccess[artifactType] = false
+		}
+	}
+
+	for _, report := range verifierReports {
+		castedReport := report.(verifier.VerifierResult)
+		// extract the policy for the artifact type of the verified artifact if specified
+		policyType, ok := enforcer.ArtifactTypePolicies[castedReport.ArtifactType]
+		// if artifact type policy not specified, set policy to be default policy and add artifact type to success map
+		if !ok {
+			policyType = enforcer.ArtifactTypePolicies[defaultPolicyName]
+			// set the artifact type success field in map to false to start
+			verifySuccess[castedReport.ArtifactType] = false
+			// add the unspecified artifact type to the enforcer's artifact type map
+			enforcer.ArtifactTypePolicies[castedReport.ArtifactType] = policyType
+		}
+
+		if policyType == vt.AnyVerifySuccess && castedReport.IsSuccess {
+			// if policy is 'any' and report is successful
+			verifySuccess[castedReport.ArtifactType] = true
+		} else if policyType == vt.AllVerifySuccess {
+			// if policy is 'all'
+			if !castedReport.IsSuccess {
+				// return false after first failure
+				return false
+			}
+			verifySuccess[castedReport.ArtifactType] = true
+		}
+	}
+
+	// all booleans in map must be true for overall success to be true
+	for artifactType := range verifySuccess {
+		if !verifySuccess[artifactType] {
+			return false
+		}
+	}
+	return true
+}
diff --git a/pkg/policyprovider/factory/factory.go b/pkg/policyprovider/factory/factory.go
new file mode 100644
index 0000000..bddd4f5
--- /dev/null
+++ b/pkg/policyprovider/factory/factory.go
@@ -0,0 +1,73 @@
+/*
+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 factory
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/deislabs/ratify/pkg/policyprovider"
+	"github.com/deislabs/ratify/pkg/policyprovider/config"
+	"github.com/deislabs/ratify/pkg/verifier/types"
+	"github.com/sirupsen/logrus"
+)
+
+var builtInPolicyProviders = make(map[string]PolicyFactory)
+
+// PolicyFactory is an interface that defines methods to create a policy provider
+type PolicyFactory interface {
+	Create(policyConfig config.PolicyPluginConfig) (policyprovider.PolicyProvider, error)
+}
+
+// Register adds the factory to the built in providers map
+func Register(name string, factory PolicyFactory) {
+	if factory == nil {
+		panic("policy factory cannot be nil")
+	}
+	_, registered := builtInPolicyProviders[name]
+	if registered {
+		panic(fmt.Sprintf("policy factory named %s already registered", name))
+	}
+
+	builtInPolicyProviders[name] = factory
+}
+
+// CreatePolicyProvidersFromConfig creates a policy provider from the provided configuration
+func CreatePolicyProviderFromConfig(policyConfig config.PoliciesConfig) (policyprovider.PolicyProvider, error) {
+	if policyConfig.PolicyPlugin == nil {
+		return nil, errors.New("policy provider config must be specified")
+	}
+
+	policyProviderName, ok := policyConfig.PolicyPlugin[types.Name]
+	if !ok {
+		return nil, fmt.Errorf("failed to find policy provider name in the policy config with key %s", "name")
+	}
+
+	providerNameStr := fmt.Sprintf("%s", policyProviderName)
+
+	policyFactory, ok := builtInPolicyProviders[providerNameStr]
+	if !ok {
+		return nil, fmt.Errorf("failed to find registered policy provider with name %s", policyProviderName)
+	}
+
+	policyProvider, err := policyFactory.Create(policyConfig.PolicyPlugin)
+	if err != nil {
+		return nil, fmt.Errorf("failed to Create policy provider: %v", err)
+	}
+
+	logrus.Infof("selected policy provider: %s", providerNameStr)
+	return policyProvider, nil
+}
diff --git a/pkg/policyprovider/mocks/types.go b/pkg/policyprovider/mocks/types.go
new file mode 100644
index 0000000..b178aba
--- /dev/null
+++ b/pkg/policyprovider/mocks/types.go
@@ -0,0 +1,50 @@
+/*
+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 mocks
+
+import (
+	"context"
+
+	"github.com/deislabs/ratify/pkg/common"
+	"github.com/deislabs/ratify/pkg/executor/types"
+	"github.com/deislabs/ratify/pkg/ocispecs"
+	"github.com/deislabs/ratify/pkg/verifier"
+)
+
+type TestPolicyProvider struct{}
+
+func (p *TestPolicyProvider) VerifyNeeded(ctx context.Context, subjectReference common.Reference, referenceDesc ocispecs.ReferenceDescriptor) bool {
+	return true
+}
+
+func (p *TestPolicyProvider) ContinueVerifyOnFailure(ctx context.Context, subjectReference common.Reference, referenceDesc ocispecs.ReferenceDescriptor, partialVerifyResult types.VerifyResult) bool {
+	return true
+}
+
+func (p *TestPolicyProvider) ErrorToVerifyResult(ctx context.Context, subjectRefString string, verifyError error) types.VerifyResult {
+	errorReport := verifier.VerifierResult{
+		Subject:   subjectRefString,
+		IsSuccess: false,
+		Results:   []string{"this a test"},
+	}
+	var reports []interface{}
+	reports = append(reports, errorReport)
+	return types.VerifyResult{IsSuccess: false, VerifierReports: reports}
+}
+
+func (p *TestPolicyProvider) OverallVerifyResult(ctx context.Context, verifierReports []interface{}) bool {
+	return true
+}
diff --git a/pkg/policyprovider/types/types.go b/pkg/policyprovider/types/types.go
index 6707ac3..8749bec 100644
--- a/pkg/policyprovider/types/types.go
+++ b/pkg/policyprovider/types/types.go
@@ -20,5 +20,5 @@ type ArtifactTypeVerifyPolicy string
 
 const (
 	AnyVerifySuccess ArtifactTypeVerifyPolicy = "any"
-	AllVerifySuccess                          = "all"
+	AllVerifySuccess ArtifactTypeVerifyPolicy = "all"
 )
diff --git a/pkg/verifier/api.go b/pkg/verifier/api.go
index f2a6add..6f2ece5 100644
--- a/pkg/verifier/api.go
+++ b/pkg/verifier/api.go
@@ -31,6 +31,7 @@ type VerifierResult struct {
 	Name          string           `json:"name,omitempty"`
 	Results       []string         `json:"results,omitempty"`
 	NestedResults []VerifierResult `json:"nestedResults,omitempty"`
+	ArtifactType  string           `json:"artifactType,omitempty"`
 }
 
 // ReferenceVerifier is an interface that defines methods to verify a reference for a subject
diff --git a/plugins/verifier/cosign/README.md b/plugins/verifier/cosign/README.md
index 8861e47..3e60577 100644
--- a/plugins/verifier/cosign/README.md
+++ b/plugins/verifier/cosign/README.md
@@ -5,6 +5,8 @@ This README outlines how this validation framework can be used to verify signatu
 ### Fallback in OCIRegistry store
 A configuration flag called ```cosign-enabled``` is introduced to the plugin configuration. If this flag is enabled, the ```ListReferrers``` API will attempt to query for the cosign signatures for a subject in addition to the references queried using ```referrers API```. All the cosign signatures are returned as the reference artifacts with the artifact type ```org.sigstore.cosign.v1``` This option will enable to verify cosign signatures against any registry including the onces that don't support the [notaryproject](https://github.com/notaryproject)'s ```referrers API```. 
 
+IMPORTANT NOTE: Cosign signatures cannot be verified from private registries. ```cosign-enabled``` flag should not be enabled for any private registry scenario even for non-cosign signature verifications.
+
 ### Configuration
 The only configuration that is needed for cosign verifier is the path to the public key that is used to verify the signature. This is specified using ```key``` property in the plugin config. Here is the sample ```ratify``` config with cosign verifier
 


Test patch:
diff --git a/httpserver/server_test.go b/httpserver/server_test.go
index 2ec14e7..84d2359 100644
--- a/httpserver/server_test.go
+++ b/httpserver/server_test.go
@@ -26,6 +26,7 @@ import (
 	"github.com/deislabs/ratify/pkg/executor/core"
 	"github.com/deislabs/ratify/pkg/ocispecs"
 	config "github.com/deislabs/ratify/pkg/policyprovider/configpolicy"
+	"github.com/deislabs/ratify/pkg/policyprovider/types"
 	"github.com/deislabs/ratify/pkg/referrerstore"
 	"github.com/deislabs/ratify/pkg/referrerstore/mocks"
 	"github.com/deislabs/ratify/pkg/verifier"
@@ -43,7 +44,10 @@ func TestServer_Timeout_Failed(t *testing.T) {
 		responseRecorder := httptest.NewRecorder()
 
 		testDigest := digest.FromString("test")
-		configPolicy := config.PolicyEnforcer{}
+		configPolicy := config.PolicyEnforcer{
+			ArtifactTypePolicies: map[string]types.ArtifactTypeVerifyPolicy{
+				"test-type1": types.AnyVerifySuccess,
+			}}
 		store := &mocks.TestStore{References: []ocispecs.ReferenceDescriptor{
 			{
 				ArtifactType: "test-type1",
diff --git a/pkg/executor/core/executor_test.go b/pkg/executor/core/executor_test.go
index 96a7cd1..0b54acb 100644
--- a/pkg/executor/core/executor_test.go
+++ b/pkg/executor/core/executor_test.go
@@ -22,6 +22,7 @@ import (
 	e "github.com/deislabs/ratify/pkg/executor"
 	"github.com/deislabs/ratify/pkg/ocispecs"
 	config "github.com/deislabs/ratify/pkg/policyprovider/configpolicy"
+	"github.com/deislabs/ratify/pkg/policyprovider/types"
 	"github.com/deislabs/ratify/pkg/referrerstore"
 	"github.com/deislabs/ratify/pkg/referrerstore/mocks"
 	"github.com/deislabs/ratify/pkg/verifier"
@@ -92,7 +93,10 @@ func TestVerifySubject_Verify_NoReferrers(t *testing.T) {
 
 func TestVerifySubject_CanVerify_ExpectedResults(t *testing.T) {
 	testDigest := digest.FromString("test")
-	configPolicy := config.PolicyEnforcer{}
+	configPolicy := config.PolicyEnforcer{
+		ArtifactTypePolicies: map[string]types.ArtifactTypeVerifyPolicy{
+			"test-type1": types.AnyVerifySuccess,
+		}}
 	store := &mocks.TestStore{References: []ocispecs.ReferenceDescriptor{
 		{
 			ArtifactType: "test-type1",
@@ -140,7 +144,10 @@ func TestVerifySubject_CanVerify_ExpectedResults(t *testing.T) {
 
 func TestVerifySubject_VerifyFailures_ExpectedResults(t *testing.T) {
 	testDigest := digest.FromString("test")
-	configPolicy := config.PolicyEnforcer{}
+	configPolicy := config.PolicyEnforcer{
+		ArtifactTypePolicies: map[string]types.ArtifactTypeVerifyPolicy{
+			"test-type1": types.AnyVerifySuccess,
+		}}
 	store := &mocks.TestStore{References: []ocispecs.ReferenceDescriptor{
 		{
 			ArtifactType: "test-type1",
@@ -184,15 +191,15 @@ func TestVerifySubject_VerifyFailures_ExpectedResults(t *testing.T) {
 	if result.IsSuccess {
 		t.Fatal("verification expected to fail")
 	}
-
-	if len(result.VerifierReports) != 1 {
-		t.Fatalf("verification expected to return single report but actual count %d", len(result.VerifierReports))
-	}
 }
 
 func TestVerifySubject_VerifySuccess_ExpectedResults(t *testing.T) {
 	testDigest := digest.FromString("test")
-	configPolicy := config.PolicyEnforcer{}
+	configPolicy := config.PolicyEnforcer{
+		ArtifactTypePolicies: map[string]types.ArtifactTypeVerifyPolicy{
+			"test-type1": types.AnyVerifySuccess,
+			"test-type2": types.AnyVerifySuccess,
+		}}
 	store := &mocks.TestStore{References: []ocispecs.ReferenceDescriptor{
 		{
 			ArtifactType: "test-type1",
diff --git a/pkg/policyprovider/configpolicy/configpolicy_test.go b/pkg/policyprovider/configpolicy/configpolicy_test.go
index 8002ad3..f23e656 100644
--- a/pkg/policyprovider/configpolicy/configpolicy_test.go
+++ b/pkg/policyprovider/configpolicy/configpolicy_test.go
@@ -13,30 +13,37 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package config
+package configpolicy
 
 import (
 	"context"
+	"testing"
+
 	"github.com/deislabs/ratify/pkg/common"
 	vt "github.com/deislabs/ratify/pkg/executor/types"
 	"github.com/deislabs/ratify/pkg/ocispecs"
 	pc "github.com/deislabs/ratify/pkg/policyprovider/config"
+	pf "github.com/deislabs/ratify/pkg/policyprovider/factory"
 	"github.com/deislabs/ratify/pkg/policyprovider/types"
+	vr "github.com/deislabs/ratify/pkg/verifier"
 	oci "github.com/opencontainers/image-spec/specs-go/v1"
-	"testing"
 )
 
 func TestPolicyEnforcer_ContinueVerifyOnFailure(t *testing.T) {
-	config := pc.PoliciesConfig{
-		Version: "1.0.0",
-		ArtifactVerificationPolicies: map[string]types.ArtifactTypeVerifyPolicy{
+	configPolicyConfig := map[string]interface{}{
+		"name": "configPolicy",
+		"artifactVerificationPolicies": map[string]types.ArtifactTypeVerifyPolicy{
 			"application/vnd.cncf.notary.v2": "any",
 			"org.example.sbom.v0":            "all",
 			"default":                        "any",
 		},
 	}
+	config := pc.PoliciesConfig{
+		Version:      "1.0.0",
+		PolicyPlugin: configPolicyConfig,
+	}
 
-	policyEnforcer, err := CreatePolicyEnforcerFromConfig(config)
+	policyEnforcer, err := pf.CreatePolicyProviderFromConfig(config)
 
 	if err != nil {
 		t.Fatalf("PolicyEnforcer should create from PoliciesConfig")
@@ -80,3 +87,221 @@ func TestPolicyEnforcer_ContinueVerifyOnFailure(t *testing.T) {
 		t.Fatalf("For artifact types without a policy the default policy should be followed")
 	}
 }
+
+func TestPolicyEnforcer_OverallVerifyResult(t *testing.T) {
+
+	testcases := []struct {
+		configPolicyConfig map[string]interface{}
+		verifierReports    []interface{}
+		output             bool
+	}{
+		{
+			// no artifact policies or verifier reports
+			configPolicyConfig: map[string]interface{}{
+				"name":                         "configPolicy",
+				"artifactVerificationPolicies": map[string]types.ArtifactTypeVerifyPolicy{},
+			},
+			verifierReports: []interface{}{},
+			output:          false,
+		},
+		{
+			// no artifact policies
+			configPolicyConfig: map[string]interface{}{
+				"name":                         "configPolicy",
+				"artifactVerificationPolicies": map[string]types.ArtifactTypeVerifyPolicy{},
+			},
+			verifierReports: []interface{}{
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    false,
+					ArtifactType: "application/vnd.cncf.notary.v2",
+				},
+			},
+			output: false,
+		},
+		{
+			// no artifact policies but 1 verifier result is false
+			configPolicyConfig: map[string]interface{}{
+				"name":                         "configPolicy",
+				"artifactVerificationPolicies": map[string]types.ArtifactTypeVerifyPolicy{},
+			},
+			verifierReports: []interface{}{
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    true,
+					ArtifactType: "application/vnd.cncf.notary.v2",
+				},
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    false,
+					ArtifactType: "application/vnd.cncf.notary.v2",
+				},
+			},
+			output: false,
+		},
+		{
+			// no artifact policies but default relaxed to 'any' and 1 verifier result is false
+			configPolicyConfig: map[string]interface{}{
+				"name": "configPolicy",
+				"artifactVerificationPolicies": map[string]types.ArtifactTypeVerifyPolicy{
+					"default": "any",
+				},
+			},
+			verifierReports: []interface{}{
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    true,
+					ArtifactType: "application/vnd.cncf.notary.v2",
+				},
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    false,
+					ArtifactType: "application/vnd.cncf.notary.v2",
+				},
+			},
+			output: true,
+		},
+		{
+			// any notary artifact policy but no artifact verifier reports
+			configPolicyConfig: map[string]interface{}{
+				"name": "configPolicy",
+				"artifactVerificationPolicies": map[string]types.ArtifactTypeVerifyPolicy{
+					"application/vnd.cncf.notary.v2": "any",
+				},
+			},
+			verifierReports: []interface{}{},
+			output:          false,
+		},
+		{
+			// any notary artifact policy and only 1 notary report is true
+			configPolicyConfig: map[string]interface{}{
+				"name": "configPolicy",
+				"artifactVerificationPolicies": map[string]types.ArtifactTypeVerifyPolicy{
+					"application/vnd.cncf.notary.v2": "any",
+				},
+			},
+			verifierReports: []interface{}{
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    true,
+					ArtifactType: "application/vnd.cncf.notary.v2",
+				},
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    false,
+					ArtifactType: "application/vnd.cncf.notary.v2",
+				},
+			},
+			output: true,
+		},
+		{
+			// all notary artifact policy but only 1 notary report is true
+			configPolicyConfig: map[string]interface{}{
+				"name": "configPolicy",
+				"artifactVerificationPolicies": map[string]types.ArtifactTypeVerifyPolicy{
+					"application/vnd.cncf.notary.v2": "all",
+				},
+			},
+			verifierReports: []interface{}{
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    true,
+					ArtifactType: "application/vnd.cncf.notary.v2",
+				},
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    false,
+					ArtifactType: "application/vnd.cncf.notary.v2",
+				},
+			},
+			output: false,
+		},
+		{
+			// all notary artifact policy and both notary reports are true
+			configPolicyConfig: map[string]interface{}{
+				"name": "configPolicy",
+				"artifactVerificationPolicies": map[string]types.ArtifactTypeVerifyPolicy{
+					"application/vnd.cncf.notary.v2": "all",
+				},
+			},
+			verifierReports: []interface{}{
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    true,
+					ArtifactType: "application/vnd.cncf.notary.v2",
+				},
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    true,
+					ArtifactType: "application/vnd.cncf.notary.v2",
+				},
+			},
+			output: true,
+		},
+		{
+			// any notary artifact policy, any sbom artifact policy and notary report is true and sbom is false
+			configPolicyConfig: map[string]interface{}{
+				"name": "configPolicy",
+				"artifactVerificationPolicies": map[string]types.ArtifactTypeVerifyPolicy{
+					"application/vnd.cncf.notary.v2": "any",
+					"org.example.sbom.v0":            "any",
+				},
+			},
+			verifierReports: []interface{}{
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    true,
+					ArtifactType: "application/vnd.cncf.notary.v2",
+				},
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    false,
+					ArtifactType: "org.example.sbom.v0",
+				},
+			},
+			output: false,
+		},
+		{
+			// any notary artifact policy, all sbom artifact policy, and both notary and sbom are true
+			configPolicyConfig: map[string]interface{}{
+				"name": "configPolicy",
+				"artifactVerificationPolicies": map[string]types.ArtifactTypeVerifyPolicy{
+					"application/vnd.cncf.notary.v2": "any",
+					"org.example.sbom.v0":            "all",
+				},
+			},
+			verifierReports: []interface{}{
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    true,
+					ArtifactType: "application/vnd.cncf.notary.v2",
+				},
+				vr.VerifierResult{
+					Subject:      "",
+					IsSuccess:    true,
+					ArtifactType: "org.example.sbom.v0",
+				},
+			},
+			output: true,
+		},
+	}
+
+	ctx := context.Background()
+
+	for _, testcase := range testcases {
+		config := pc.PoliciesConfig{
+			Version:      "1.0.0",
+			PolicyPlugin: testcase.configPolicyConfig,
+		}
+
+		policyEnforcer, err := pf.CreatePolicyProviderFromConfig(config)
+		if err != nil {
+			t.Fatalf("PolicyEnforcer should create from PoliciesConfig")
+		}
+
+		overallVerifyResult := policyEnforcer.OverallVerifyResult(ctx, testcase.verifierReports)
+		if overallVerifyResult != testcase.output {
+			t.Fatalf("Expected %v from OverallVerifyResult but got %v", testcase.output, overallVerifyResult)
+		}
+	}
+}
diff --git a/pkg/policyprovider/factory/factory_test.go b/pkg/policyprovider/factory/factory_test.go
new file mode 100644
index 0000000..050870b
--- /dev/null
+++ b/pkg/policyprovider/factory/factory_test.go
@@ -0,0 +1,70 @@
+/*
+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 factory
+
+import (
+	"testing"
+
+	"github.com/deislabs/ratify/pkg/policyprovider"
+	"github.com/deislabs/ratify/pkg/policyprovider/config"
+	"github.com/deislabs/ratify/pkg/policyprovider/mocks"
+)
+
+type TestPolicyProviderFactory struct{}
+
+func (f *TestPolicyProviderFactory) Create(policyConfig config.PolicyPluginConfig) (policyprovider.PolicyProvider, error) {
+	return &mocks.TestPolicyProvider{}, nil
+}
+
+// Checks the correct registered policy provider is invoked based on config
+func TestCreatePolicyProvidersFromConfig_BuiltInPolicyProviders_ReturnsExpected(t *testing.T) {
+	builtInPolicyProviders = map[string]PolicyFactory{
+		"test-policyprovider": &TestPolicyProviderFactory{},
+	}
+
+	configPolicyConfig := map[string]interface{}{
+		"name": "test-policyprovider",
+	}
+	policyProviderConfig := config.PoliciesConfig{
+		Version:      "1.0.0",
+		PolicyPlugin: configPolicyConfig,
+	}
+
+	_, err := CreatePolicyProviderFromConfig(policyProviderConfig)
+	if err != nil {
+		t.Fatalf("create policy provider failed with err %v", err)
+	}
+}
+
+// Checks the auth provider creation fails if auth provider specified does not exist
+func TestCreatePolicyProvidersFromConfig_NonexistentPolicyProviders_ReturnsExpected(t *testing.T) {
+	builtInPolicyProviders = map[string]PolicyFactory{
+		"test-policyprovider": &TestPolicyProviderFactory{},
+	}
+
+	configPolicyConfig := map[string]interface{}{
+		"name": "test-nonexistent",
+	}
+	policyProviderConfig := config.PoliciesConfig{
+		Version:      "1.0.0",
+		PolicyPlugin: configPolicyConfig,
+	}
+
+	_, err := CreatePolicyProviderFromConfig(policyProviderConfig)
+	if err == nil {
+		t.Fatalf("create policy provider should have failed for non existent provider")
+	}
+}