Repository: deislabs/ratify
Pull request #433 (2022-11-18 07:13:49)

feat: integrate notation-go rc.1
# Description

Integrate with notation-go rc.1
1. Add trustpolicy.json
2. Use the new constructor to create verifer.
3. Use the new verify API to verify signature.
4. Bump up oras to rc.4 as well to use the new Referrers API.
5. Add unit tests.

Notes: oras rc.4 will only support oci artifact instead of oras artifact. So the original image `wabbitnetworks.azurecr.io/test/net-monitor:signed` is no longer valid. Currently ACR on Dogfood supports the oci artifacts, the prod ACR will support it by early Dec. So the pipeline check will keep failing until ACR fully supports it.

Fixes https://github.com/deislabs/ratify/issues/274

## Type of change

Please delete options that are not relevant.

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update

# How Has This Been Tested?

- [ ] Manually tested commandline and add-on with notation-go.
- [ ] Tested the e2e pipeline test with dogfood ACR.

# Checklist:

- [ ] Does the affected code have corresponding tests?
- [ ] Are the changes documented, not just with inline documentation, but also with conceptual documentation such as an overview of a new feature, or task-based documentation like a tutorial? Consider if this change should be announced on your project blog.
- [ ] Does this introduce breaking changes that would require an announcement or bumping the major version?
- [ ] Do all new files have appropriate license header?


akashsinghal: Do we need to be concerned about watching for the truststore file changing? Similar to how we have file watcher on the ratify config. 
susanshi: > > Do we need to be concerned about watching for the truststore file changing? Similar to how we have file watcher on the ratify config. (Probably not a blocker for this in any case)
> 
> Good point! I added notes to [GetCertificates](https://github.com/deislabs/ratify/pull/433/files#diff-797b69ea269228c0253bef67febe9fd6228c4a266023f4eb2ce8868a45401ab3R80). The notary verify API would invoke this method for each signature verification. So updates to certificates would be watched automatically. But it might have some impact on the verification performance. If it does slow down the workflow, I'll make certificates pre-loaded and watched.

@akashsinghal , @binbin-li , what is the user experience if users need to update trust policy.json?
susanshi: Adding a link to the integration design doc : https://hackmd.io/4794vaJ2RAevQ1xk7zkXcA?view#How-does-Ratify-handle-the-Repository-object
binbin-li: > > > Do we need to be concerned about watching for the truststore file changing? Similar to how we have file watcher on the ratify config. (Probably not a blocker for this in any case)
> > 
> > 
> > Good point! I added notes to [GetCertificates](https://github.com/deislabs/ratify/pull/433/files#diff-797b69ea269228c0253bef67febe9fd6228c4a266023f4eb2ce8868a45401ab3R80). The notary verify API would invoke this method for each signature verification. So updates to certificates would be watched automatically. But it might have some impact on the verification performance. If it does slow down the workflow, I'll make certificates pre-loaded and watched.
> 
> @akashsinghal , @binbin-li , what is the user experience if users need to update trust policy.json?

Currently users have to update the policy config and restart the pod. In the next stage, there might be 2 options as far as I know.
1. We could convert it to a CRD, and Ratify would update/recreate notary verifier once it's updated. btw, we could add a watcher to the json file to support updates as CommandLine.
2. TrustPolicy might be migrated to Ratify config.json under the notary verifier plugin config. 
binbin-li: > * you can use a skip command in test.bat so e2e failure won't block PR merge. similar to ps://github.com/deislabs/ratify/blob/main/test/bats/test.bats#L46

Thanks for suggestion! Already updated it.
> * Update the Notary verify samples to align with latest notary,  docs https://github.com/deislabs/ratify/blob/main/docs/examples/ratify-verify-azure-cmd.md#discover--verify-using-ratify
>   It will be great to include a link to trust policy spec for further reading.

Updated the doc to reflect the new workflow.
> * Are there any user scenarios where there could be ambiguity as we have multiple levels of policy configuration?
>   e.g. if trust policy only specified certain repository for validation, ratify might not be returning a validation report for every image verification in passthrough mode.
>   Are there any scenraios we should point out in docs? We can create new doc, or notes to existing policy docs.
>   https://github.com/deislabs/ratify/blob/efb309692c331db1352811a254770d0970ae3e21/docs/developer/providers.md#policy-providers
>   https://github.com/deislabs/ratify/blob/efb309692c331db1352811a254770d0970ae3e21/docs/reference/gatekeeper-policy-authoring.md

Good question. Your example might not be an issue here. If there is no trust policy applies to a given repo, then notary will return an error saying the policy is missing so that users would configure it later.
But there does exist a case which might confuse users. i.e. if we set the verification level in trust policy to any value except `strict`, then the overall result might be a success even though underlying verification failed.
I'll add to the policy doc, thanks for calling it out!


binbin-li: > Actually @binbin-li this was my same question too as @susanshi points out. My mistake as I meant trust policy. Right now if it's changed this will require the ratify pod to restart for this to take effect?

You're right. I plan to make another PR to address it since it requires refactoring on verifier plugin. And this PR is aiming to unblock the notation rc.1 integration which might be a bit large to include this refactoring.

Patch:
diff --git a/charts/ratify/templates/configmap.yaml b/charts/ratify/templates/configmap.yaml
index 458428c..04205b9 100644
--- a/charts/ratify/templates/configmap.yaml
+++ b/charts/ratify/templates/configmap.yaml
@@ -59,8 +59,9 @@ data:
                 "name":"notaryv2",
                 "artifactTypes" : "application/vnd.cncf.notary.v2.signature",
                 "verificationCerts": [
-                    "/usr/local/ratify-certs/notary"
-                  ]
+                  "/usr/local/ratify-certs/notary/truststore"
+                  ],
+                "trustPolicy": "/usr/local/ratify-certs/notary/trustpolicy.json"
             {{- if .Values.cosign.enabled }}
             },
             {
@@ -71,4 +72,26 @@ data:
             }
           ]
       }
+    }
+
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ include "ratify.fullname" . }}-notation-policy
+data:
+  trustpolicy.json: |
+    {
+      "version": "1.0",
+      "trustPolicies": [
+        {
+          "name": "default",
+          "registryScopes": [ "*" ],
+          "signatureVerification": {
+            "level" : "strict" 
+          },
+          "trustStores": ["ca:certs"],
+          "trustedIdentities": ["*"]
+        }
+      ]
     }
\ No newline at end of file
diff --git a/charts/ratify/templates/deployment.yaml b/charts/ratify/templates/deployment.yaml
index 02accea..05e3644 100644
--- a/charts/ratify/templates/deployment.yaml
+++ b/charts/ratify/templates/deployment.yaml
@@ -52,7 +52,7 @@ spec:
           ports:
             - containerPort: 6001
           volumeMounts:
-            - mountPath: "/usr/local/ratify-certs/notary"
+            - mountPath: "/usr/local/ratify-certs/notary/truststore"
             {{- if .Values.akvCertConfig.enabled }}
               name: cert-from-akv
             {{- else }}
@@ -64,6 +64,9 @@ spec:
               name: cosign-certs
               readOnly: true
             {{- end }}
+            - mountPath: "/usr/local/ratify-certs/notary"
+              name: notation-trust-policy
+              readOnly: true
             - mountPath: "/usr/local/ratify"
               name: config
               readOnly: true
@@ -129,6 +132,9 @@ spec:
         - name: config
           configMap:
             name: {{ include "ratify.fullname" . }}-configuration
+        - name: notation-trust-policy
+          configMap:
+            name: {{ include "ratify.fullname" . }}-notation-policy
         {{- if and (.Values.provider.tls.cabundle) (or (eq .Values.provider.auth "tls") (eq .Values.provider.auth "mtls")) }}
         - name: tls
           secret:
diff --git a/charts/ratify/templates/verifier.yaml b/charts/ratify/templates/verifier.yaml
index 63cc591..78df1ae 100644
--- a/charts/ratify/templates/verifier.yaml
+++ b/charts/ratify/templates/verifier.yaml
@@ -6,8 +6,9 @@ spec:
   name: notaryv2
   artifactTypes: application/vnd.cncf.notary.v2.signature
   parameters:
-    verificationCerts: 
-    - /usr/local/ratify-certs/notary
+    verificationCerts:
+    - /usr/local/ratify-certs/notary/truststore
+    trustPolicy: /usr/local/ratify-certs/notary/trustpolicy.json
 ---
 {{- if .Values.cosign.enabled }}
 apiVersion: config.ratify.deislabs.io/v1alpha1
diff --git a/config/samples/config_v1alpha1_verifier_notary.yaml b/config/samples/config_v1alpha1_verifier_notary.yaml
index 5acaaa9..74bff82 100644
--- a/config/samples/config_v1alpha1_verifier_notary.yaml
+++ b/config/samples/config_v1alpha1_verifier_notary.yaml
@@ -6,6 +6,7 @@ spec:
   name: notaryv2
   artifactTypes: application/vnd.cncf.notary.v2.signature
   parameters:
-    verificationCerts: 
-    - /usr/local/ratify-certs/notary
+    verificationCerts:
+    - /usr/local/ratify-certs/notary/truststore
+    trustPolicy: /usr/local/ratify-certs/notary/trustpolicy.json
      
\ No newline at end of file
diff --git a/docs/examples/ratify-verify-azure-cmd.md b/docs/examples/ratify-verify-azure-cmd.md
index e48324c..e4e8d02 100644
--- a/docs/examples/ratify-verify-azure-cmd.md
+++ b/docs/examples/ratify-verify-azure-cmd.md
@@ -17,14 +17,14 @@ mkdir -p ~/bin && cp ./notation ~/bin
 
 ### ORAS
 
-Install ORAS 0.15.0 on a Linux machine. You can refer to the [ORAS installation guide](https://oras.land/cli/) for details.
+Install ORAS 0.16.0 on a Linux machine. You can refer to the [ORAS installation guide](https://oras.land/cli/) for details.
 
 ```bash
 # Download the ORAS binary
-curl -LO https://github.com/oras-project/oras/releases/download/v0.15.0/oras_0.15.0_linux_amd64.tar.gz
+curl -LO https://github.com/oras-project/oras/releases/download/v0.16.0/oras_0.16.0_linux_amd64.tar.gz
 # Create a folder to extract the ORAS binary
 mkdir -p oras-install/
-tar -zxf oras_0.15.0_*.tar.gz -C oras-install/
+tar -zxf oras_0.16.0_*.tar.gz -C oras-install/
 # Copy the Notation CLI to your bin directory
 mv oras-install/oras /usr/local/bin/
 ```
@@ -89,16 +89,41 @@ docker push $IMAGE
 # Generate a test certificate
 notation cert generate-test --default "wabbit-networks.io"
 ```
-4. Sign the image
+4. Create a trustpolicy.json under `~/.config/notation/` for notary verifier.
+
+Trust Policy reference: https://github.com/notaryproject/notaryproject/blob/main/specs/trust-store-trust-policy.md#trust-policy
+```json
+{
+    "version": "1.0",
+    "trustPolicies": [
+        {
+            "name": "default",
+            "registryScopes": [
+                "*"
+            ],
+            "signatureVerification": {
+                "level": "strict"
+            },
+            "trustStores": [
+                "ca:certs"
+            ],
+            "trustedIdentities": [
+                "*"
+            ]
+        }
+    ]
+}
+```
+5. Sign the image[Notation Sign command only works in the next rc.1 release version]
 ```bash
 notation sign $IMAGE
 ```
-5.  List the signatures with notation
+6.  List the signatures with notation
 ```bash
 # List the signatures
 notation list $IMAGE
 ```
-> You can repeat step 4-5 to create multiple signatures to the image.
+> You can repeat step 5-6 to create multiple signatures to the image.
 
 ### Discover & Verify using Ratify
 
@@ -131,11 +156,11 @@ cat <<EOF > ~/.ratify/config.json
                 "name":"notaryv2",
                 "artifactTypes" : "application/vnd.cncf.notary.v2.signature",
                 "verificationCerts": [
-                    "~/.config/notation/localkeys/wabbit-networks.io.crt"
-                  ]
+                    "~/.config/notation/truststore/x509/ca/wabbit-networks.io/wabbit-networks.io.crt"
+                ],
+                "trustPolicy": "~/.config/notation/trustpolicy.json"
             }
         ]
-        
     }
 }
 EOF
diff --git a/docs/reference/gatekeeper-policy-authoring.md b/docs/reference/gatekeeper-policy-authoring.md
index af06323..5be2d36 100644
--- a/docs/reference/gatekeeper-policy-authoring.md
+++ b/docs/reference/gatekeeper-policy-authoring.md
@@ -165,6 +165,18 @@ verifier includes the Issuer and SubjectName from the certificate as an extensio
 Currently, the best way to determine the extension fields for a verifier is to
 check the source for that verifier.
 
+When Ratify is verifying against a notation signature, there might be ambiguity
+in the verifierReport from notary verifier. Notary verifier introduces 
+a [trust policy](https://github.com/notaryproject/notaryproject/blob/main/specs/trust-store-trust-policy.md#trust-policy) component in the rc.1 release. Users 
+could control the verification level and scopes applied to specified artifact. There 
+could be 2 scenarios needed to pay attention:
+
+1. If Ratify is running in passthrough execution mode, but users forgot to set up scopes 
+for some repositories/artifacts. Then the verification result from notary verifier will be an error saying the policy is missing.
+2. If users set the verification level in trust policy to any value except `strict`,
+then the notary verification result might be a success even though some underlying
+validation failed. Check the verification level provided in notation for more information: [Signature Verification Level](https://github.com/notaryproject/notaryproject/blob/main/specs/trust-store-trust-policy.md#signature-verification-details)
+
 ## Sample Rego Policy
 Let's look at a Ratify policy from the library in more detail. Below is the
 rego from the `notaryv2issuervalidation` policy:
diff --git a/go.mod b/go.mod
index 3ed95ef..54203cf 100644
--- a/go.mod
+++ b/go.mod
@@ -17,8 +17,8 @@ require (
 	github.com/golang/protobuf v1.5.2
 	github.com/google/go-containerregistry v0.12.1
 	github.com/gorilla/mux v1.8.0
-	github.com/notaryproject/notation-core-go v0.1.0-alpha.4
-	github.com/notaryproject/notation-go v0.11.0-alpha.4
+	github.com/notaryproject/notation-core-go v0.2.0-beta.1
+	github.com/notaryproject/notation-go v0.12.0-beta.1.0.20221117032523-ed3112236845
 	github.com/open-policy-agent/frameworks/constraint v0.0.0-20220627162905-95c012350402
 	github.com/opencontainers/go-digest v1.0.0
 	github.com/opencontainers/image-spec v1.1.0-rc2
@@ -36,7 +36,13 @@ require (
 	k8s.io/api v0.24.8
 	k8s.io/apimachinery v0.24.8
 	k8s.io/client-go v0.24.8
-	oras.land/oras-go/v2 v2.0.0-rc.3
+	oras.land/oras-go/v2 v2.0.0-rc.4
+)
+
+require (
+	github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
+	github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
+	github.com/go-ldap/ldap/v3 v3.4.4 // indirect
 )
 
 require (
@@ -147,7 +153,6 @@ require (
 	github.com/oklog/ulid v1.3.1 // indirect
 	github.com/olekukonko/tablewriter v0.0.5 // indirect
 	github.com/open-policy-agent/opa v0.44.0 // indirect
-	github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86 // indirect
 	github.com/opentracing/opentracing-go v1.2.0 // indirect
 	github.com/pelletier/go-toml v1.9.5 // indirect
 	github.com/pelletier/go-toml/v2 v2.0.5 // indirect
diff --git a/go.sum b/go.sum
index 7bdaa34..69775ba 100644
--- a/go.sum
+++ b/go.sum
@@ -95,6 +95,8 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z
 github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
 github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
 github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU=
+github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
 github.com/AzureAD/microsoft-authentication-library-for-go v0.5.3 h1:TsFCaaF5tR4XN8b4zLVl/J4qMb0nf80Q4CXcpXDNJDY=
 github.com/AzureAD/microsoft-authentication-library-for-go v0.5.3/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4=
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
@@ -300,6 +302,8 @@ github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49P
 github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
+github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
+github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
 github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
 github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@@ -308,6 +312,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
 github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
+github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs=
+github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
 github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
@@ -717,10 +723,10 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nightlyone/lockfile v1.0.0/go.mod h1:rywoIealpdNse2r832aiD9jRk8ErCatROs6LzC841CI=
 github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=
-github.com/notaryproject/notation-core-go v0.1.0-alpha.4 h1:0OhA2PjwT0TAouHOrU4K+8H9YM6E/e4/ocoq+JiHeOw=
-github.com/notaryproject/notation-core-go v0.1.0-alpha.4/go.mod h1:s8DZptmN1rZS0tBLTPt/w+d4o6eAcGWTYYJlXaJhQ4U=
-github.com/notaryproject/notation-go v0.11.0-alpha.4 h1:PNptLtrhW0jyw10hUWU+KNzvzeuBBZmg+/1IUaGYE10=
-github.com/notaryproject/notation-go v0.11.0-alpha.4/go.mod h1:4xYTcW4wfsXkXw3piUA53uSW82RwdXyipSEtiiRVrCw=
+github.com/notaryproject/notation-core-go v0.2.0-beta.1 h1:8tFxNycWCcPLti9ZYST5kjkX2wMXtX9YPvMjiBAQ1tA=
+github.com/notaryproject/notation-core-go v0.2.0-beta.1/go.mod h1:s8DZptmN1rZS0tBLTPt/w+d4o6eAcGWTYYJlXaJhQ4U=
+github.com/notaryproject/notation-go v0.12.0-beta.1.0.20221117032523-ed3112236845 h1:UTN71vcdcPYXXVNUe5ph6XUayWc0WmjFuZK8smbX3gA=
+github.com/notaryproject/notation-go v0.12.0-beta.1.0.20221117032523-ed3112236845/go.mod h1:FSKeaMPAyxt5OpfCX3TK1RC3HHFBwFrNkwcBtyfU8x8=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
@@ -746,8 +752,6 @@ github.com/open-policy-agent/frameworks/constraint v0.0.0-20220627162905-95c0123
 github.com/open-policy-agent/frameworks/constraint v0.0.0-20220627162905-95c012350402/go.mod h1:Ct6YrxaLT9c28X7yv+GtDEKapG/EbI29ZsAO9oWs9Vg=
 github.com/open-policy-agent/opa v0.44.0 h1:sEZthsrWBqIN+ShTMJ0Hcz6a3GkYsY4FaB2S/ou2hZk=
 github.com/open-policy-agent/opa v0.44.0/go.mod h1:YpJaFIk5pq89n/k72c1lVvfvR5uopdJft2tMg1CW/yU=
-github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86 h1:Oumw+lPnO8qNLTY2mrqPJZMoGExLi/0h/DdikoLTXVU=
-github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86/go.mod h1:aA4vdXRS8E1TG7pLZOz85InHi3BiPdErh8IpJN6E0x4=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
 github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034=
@@ -1727,8 +1731,8 @@ k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
 k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc=
 k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
-oras.land/oras-go/v2 v2.0.0-rc.3 h1:O4GeIwJ9Ge7rbCkqa/M7DLrL55ww+ZEc+Rhc63OYitU=
-oras.land/oras-go/v2 v2.0.0-rc.3/go.mod h1:PrY+cCglzK/DrQoJUtxbYVbL94ZHecVS3eJR01RglpE=
+oras.land/oras-go/v2 v2.0.0-rc.4 h1:hg/R2znUQ1+qd43gRmL16VeX1GIZ8hQlLalBjYhhKSk=
+oras.land/oras-go/v2 v2.0.0-rc.4/go.mod h1:YGHvWBGuqRlZgUyXUIoKsR3lcuCOb3DAtG0SEsEw1iY=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
diff --git a/pkg/controllers/verifier_controller.go b/pkg/controllers/verifier_controller.go
index b24723a..12025f6 100644
--- a/pkg/controllers/verifier_controller.go
+++ b/pkg/controllers/verifier_controller.go
@@ -102,7 +102,7 @@ func verifierAddOrReplace(spec configv1alpha1.VerifierSpec, objectName string) e
 	verifierConfigVersion := "1.0.0" // TODO: move default values to defaulting webhook in the future #413
 	if spec.Address == "" {
 		spec.Address = config.GetDefaultPluginPath()
-		verifierLogger.Info(fmt.Sprintf("Address was empty, setting to default path %v", spec.Address))
+		verifierLogger.Info(fmt.Sprintf("Address was empty, setting to default path: %v", spec.Address))
 	}
 	verifierReference, err := vf.CreateVerifierFromConfig(verifierConfig, verifierConfigVersion, []string{spec.Address})
 
diff --git a/pkg/referrerstore/oras/oras.go b/pkg/referrerstore/oras/oras.go
index eb4fcce..b8b0d38 100644
--- a/pkg/referrerstore/oras/oras.go
+++ b/pkg/referrerstore/oras/oras.go
@@ -46,7 +46,6 @@ import (
 	_ "github.com/deislabs/ratify/pkg/referrerstore/oras/authprovider/aws"
 	_ "github.com/deislabs/ratify/pkg/referrerstore/oras/authprovider/azure"
 	"github.com/opencontainers/go-digest"
-	artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
 	"github.com/sirupsen/logrus"
 )
 
@@ -171,8 +170,8 @@ func (store *orasStore) ListReferrers(ctx context.Context, subjectReference comm
 
 	// find all referrers referencing subject descriptor
 	artifactTypeFilter := ""
-	var referrerDescriptors []artifactspec.Descriptor
-	if err := repository.Referrers(ctx, resolvedSubjectDesc.Descriptor, artifactTypeFilter, func(referrers []artifactspec.Descriptor) error {
+	var referrerDescriptors []oci.Descriptor
+	if err := repository.Referrers(ctx, resolvedSubjectDesc.Descriptor, artifactTypeFilter, func(referrers []oci.Descriptor) error {
 		referrerDescriptors = append(referrerDescriptors, referrers...)
 		return nil
 	}); err != nil && !errors.Is(err, errdef.ErrNotFound) {
@@ -185,7 +184,7 @@ func (store *orasStore) ListReferrers(ctx context.Context, subjectReference comm
 	// convert artifact descriptors to oci descriptor with artifact type
 	var referrers []ocispecs.ReferenceDescriptor
 	for _, referrer := range referrerDescriptors {
-		referrers = append(referrers, ArtifactDescriptorToReferenceDescriptor(referrer))
+		referrers = append(referrers, OciDescriptorToReferenceDescriptor(referrer))
 	}
 
 	if store.config.CosignEnabled {
diff --git a/pkg/referrerstore/oras/utils.go b/pkg/referrerstore/oras/utils.go
index f15b8a6..f5328ec 100644
--- a/pkg/referrerstore/oras/utils.go
+++ b/pkg/referrerstore/oras/utils.go
@@ -16,11 +16,12 @@ limitations under the License.
 package oras
 
 import (
+	"regexp"
+	"strings"
+
 	"github.com/deislabs/ratify/pkg/ocispecs"
 	oci "github.com/opencontainers/image-spec/specs-go/v1"
 	artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
-	"regexp"
-	"strings"
 )
 
 // Detect the loopback IP (127.0.0.1)
@@ -47,16 +48,10 @@ func isInsecureRegistry(registry string, config *OrasStoreConf) bool {
 	return false
 }
 
-func ArtifactDescriptorToReferenceDescriptor(artifactDescriptor artifactspec.Descriptor) ocispecs.ReferenceDescriptor {
+func OciDescriptorToReferenceDescriptor(ociDescriptor oci.Descriptor) ocispecs.ReferenceDescriptor {
 	return ocispecs.ReferenceDescriptor{
-		Descriptor: oci.Descriptor{
-			MediaType:   artifactDescriptor.MediaType,
-			Digest:      artifactDescriptor.Digest,
-			Size:        artifactDescriptor.Size,
-			URLs:        artifactDescriptor.URLs,
-			Annotations: artifactDescriptor.Annotations,
-		},
-		ArtifactType: artifactDescriptor.ArtifactType,
+		Descriptor:   ociDescriptor,
+		ArtifactType: ociDescriptor.ArtifactType,
 	}
 }
 
diff --git a/pkg/verifier/notaryv2/notaryv2.go b/pkg/verifier/notaryv2/notaryv2.go
index 5a8f88e..996e129 100644
--- a/pkg/verifier/notaryv2/notaryv2.go
+++ b/pkg/verifier/notaryv2/notaryv2.go
@@ -19,8 +19,8 @@ import (
 	"context"
 	"crypto/x509"
 	"encoding/json"
-	"errors"
 	"fmt"
+	"os"
 	paths "path/filepath"
 	"strings"
 
@@ -38,21 +38,27 @@ import (
 	_ "github.com/notaryproject/notation-core-go/signature/cose"
 	_ "github.com/notaryproject/notation-core-go/signature/jws"
 	"github.com/notaryproject/notation-go"
-	"github.com/notaryproject/notation-go/crypto/jwsutil"
-	"github.com/notaryproject/notation-go/signature"
+	notaryVerifier "github.com/notaryproject/notation-go/verifier"
+	"github.com/notaryproject/notation-go/verifier/trustpolicy"
+	"github.com/notaryproject/notation-go/verifier/truststore"
 	oci "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 const (
 	verifierName    = "notaryv2"
-	defaultCertPath = "ratify-certs/notary"
+	defaultCertPath = "ratify-certs/notary/truststore"
 )
 
 // NotaryV2VerifierConfig describes the configuration of notation verifier
 type NotaryV2VerifierConfig struct {
-	Name              string   `json:"name"`
-	ArtifactTypes     string   `json:"artifactTypes"`
+	Name          string `json:"name"`
+	ArtifactTypes string `json:"artifactTypes"`
+
+	// VerificationCerts is array of directories containing certificates.
 	VerificationCerts []string `json:"verificationCerts"`
+
+	// TrustPolicy is the path to the trustpolicy.json.
+	TrustPolicy string `json:"trustPolicy"`
 }
 
 type notaryV2Verifier struct {
@@ -60,35 +66,47 @@ type notaryV2Verifier struct {
 	notationVerifier *notation.Verifier
 }
 
+type trustStore struct {
+	certPaths []string
+}
+
 type notaryv2VerifierFactory struct{}
 
 func init() {
 	factory.Register(verifierName, &notaryv2VerifierFactory{})
 }
 
-func (f *notaryv2VerifierFactory) Create(version string, verifierConfig config.VerifierConfig) (verifier.ReferenceVerifier, error) {
-	conf := NotaryV2VerifierConfig{}
+// trustStore implements GetCertificates API of X509TrustStore interface: [https://pkg.go.dev/github.com/notaryproject/notation-go@v0.12.0-beta.1.0.20221117143817-2573c88a5f62/verifier/truststore#X509TrustStore]
+// Note: this api gets invoked when Ratify calls verify API, so the certificates
+// will be loaded for each signature verification.
+func (s trustStore) GetCertificates(ctx context.Context, storeType truststore.Type, namedStore string) ([]*x509.Certificate, error) {
+	certs := make([]*x509.Certificate, 0)
+	for _, path := range s.certPaths {
+		bundledCerts, err := utils.GetCertificatesFromPath(path)
+		if err != nil {
+			return nil, err
+		}
+		certs = append(certs, bundledCerts...)
+	}
+	return certs, nil
+}
 
-	verifierConfigBytes, err := json.Marshal(verifierConfig)
+func (f *notaryv2VerifierFactory) Create(version string, verifierConfig config.VerifierConfig) (verifier.ReferenceVerifier, error) {
+	conf, err := parseVerifierConfig(verifierConfig)
 	if err != nil {
 		return nil, err
 	}
 
-	if err := json.Unmarshal(verifierConfigBytes, &conf); err != nil {
-		return nil, fmt.Errorf("failed to parse config for the input: %v", err)
-	}
-
-	defaultDir := paths.Join(homedir.Get(), ratifyconfig.ConfigFileDir, defaultCertPath)
-	conf.VerificationCerts = append(conf.VerificationCerts, defaultDir)
-
-	artifactTypes := strings.Split(conf.ArtifactTypes, ",")
-
-	verfiyService, err := getVerifierService(conf.VerificationCerts...)
+	verfiyService, err := getVerifierService(conf)
 	if err != nil {
 		return nil, err
 	}
 
-	return &notaryV2Verifier{artifactTypes: artifactTypes, notationVerifier: &verfiyService}, nil
+	artifactTypes := strings.Split(conf.ArtifactTypes, ",")
+	return &notaryV2Verifier{
+		artifactTypes:    artifactTypes,
+		notationVerifier: &verfiyService,
+	}, nil
 }
 
 func (v *notaryV2Verifier) Name() string {
@@ -110,56 +128,36 @@ func (v *notaryV2Verifier) Verify(ctx context.Context,
 	store referrerstore.ReferrerStore,
 	executor executor.Executor) (verifier.VerifierResult, error) {
 
-	// TODO get the subject descriptor
-	desc := oci.Descriptor{
-		Digest: subjectReference.Digest,
-	}
-
 	extensions := make(map[string]string)
 
-	referenceManifest, err := store.GetReferenceManifest(ctx, subjectReference, referenceDescriptor)
+	subjectDesc, err := store.GetSubjectDescriptor(ctx, subjectReference)
+	if err != nil {
+		return verifier.VerifierResult{IsSuccess: false}, fmt.Errorf("failed to resolve subject: %+v, err: %v", subjectReference, err)
+	}
 
+	referenceManifest, err := store.GetReferenceManifest(ctx, subjectReference, referenceDescriptor)
 	if err != nil {
-		return verifier.VerifierResult{IsSuccess: false}, err
+		return verifier.VerifierResult{IsSuccess: false}, fmt.Errorf("failed to get reference manifest for reference: %s, err: %v", subjectReference.Original, err)
 	}
 
 	for _, blobDesc := range referenceManifest.Blobs {
 		refBlob, err := store.GetBlobContent(ctx, subjectReference, blobDesc.Digest)
 		if err != nil {
-			return verifier.VerifierResult{IsSuccess: false}, err
+			return verifier.VerifierResult{IsSuccess: false}, fmt.Errorf("failed to get blob content of digest: %s, err: %v", blobDesc.Digest, err)
 		}
 
-		cert, err := getCert(refBlob)
+		// TODO: notary verify API only accepts digested reference now.
+		// Pass in tagged reference instead once notation-go supports it.
+		subjectRef := fmt.Sprintf("%s@%s", subjectReference.Path, subjectReference.Digest.String())
+		outcome, err := v.verifySignature(ctx, subjectRef, blobDesc.MediaType, subjectDesc.Descriptor, refBlob)
 		if err != nil {
-			return verifier.VerifierResult{
-				Subject:   subjectReference.String(),
-				IsSuccess: false,
-				Name:      verifierName,
-				Message:   "error getting extension data from root cert",
-			}, err
+			return verifier.VerifierResult{IsSuccess: false, Extensions: extensions}, fmt.Errorf("failed to verify signature, err: %v", err)
 		}
+
+		// Note: notary verifier already validates certificate chain is not empty.
+		cert := outcome.EnvelopeContent.SignerInfo.CertificateChain[0]
 		extensions["Issuer"] = cert.Issuer.String()
 		extensions["SN"] = cert.Subject.String()
-
-		opts := notation.VerifyOptions{
-			SignatureMediaType: blobDesc.MediaType,
-		}
-
-		vdesc, err := (*v.notationVerifier).Verify(context.Background(), refBlob, opts)
-		if err != nil {
-			fmt.Printf("err: %v\n", err)
-			return verifier.VerifierResult{IsSuccess: false, Extensions: extensions}, err
-		}
-
-		// TODO get the subject descriptor and verify all the properties other than digest.
-		if desc.Digest != vdesc.Digest {
-			return verifier.VerifierResult{
-				Subject:    subjectReference.String(),
-				Name:       verifierName,
-				IsSuccess:  false,
-				Message:    fmt.Sprintf("verification failure: digest mismatch: %v: %v", desc.Digest, vdesc.Digest),
-				Extensions: extensions}, nil
-		}
 	}
 
 	return verifier.VerifierResult{
@@ -170,51 +168,61 @@ func (v *notaryV2Verifier) Verify(ctx context.Context,
 	}, nil
 }
 
-// This function is borrowed internals from the notation-go jws verifier
-// https://github.com/notaryproject/notation-go/blob/main/signature/jws/verifier.go
-func getCert(refBlob []byte) (*x509.Certificate, error) {
-	var envelope jwsutil.Envelope
-	if err := json.Unmarshal(refBlob, &envelope); err != nil {
+func getVerifierService(conf *NotaryV2VerifierConfig) (notation.Verifier, error) {
+	policyDoc, err := loadPolicyDocument(conf.TrustPolicy)
+	if err != nil {
 		return nil, err
 	}
-	if len(envelope.Signatures) != 1 {
-		return nil, errors.New("single signature envelope expected")
-	}
-	sig := envelope.Open()
 
-	var header struct {
-		TimeStampToken []byte   `json:"timestamp,omitempty"`
-		CertChain      [][]byte `json:"x5c,omitempty"`
+	store := &trustStore{
+		certPaths: conf.VerificationCerts,
 	}
-	if err := json.Unmarshal(sig.Unprotected, &header); err != nil {
+
+	return notaryVerifier.New(policyDoc, store, nil)
+}
+
+// loadPolicyDocument is brorrowd from notation-go [https://github.com/notaryproject/notation-go/blob/75b3248459d677d2a6abcae3dd880775f4456271/verification/helpers.go#L15]
+func loadPolicyDocument(policyPath string) (*trustpolicy.Document, error) {
+	policyDocument := &trustpolicy.Document{}
+	jsonFile, err := os.ReadFile(policyPath)
+	if err != nil {
 		return nil, err
 	}
-	if len(header.CertChain) == 0 {
-		return nil, errors.New("signer certificates not found")
+
+	if err := json.Unmarshal(jsonFile, &policyDocument); err != nil {
+		return nil, err
 	}
 
-	cert, err := x509.ParseCertificate(header.CertChain[0])
-	if err != nil {
+	if err := policyDocument.Validate(); err != nil {
 		return nil, err
 	}
 
-	return cert, nil
+	return policyDocument, nil
 }
 
-func getVerifierService(certPaths ...string) (notation.Verifier, error) {
-	certs := make([]*x509.Certificate, 0)
-	for _, path := range certPaths {
+func (v *notaryV2Verifier) verifySignature(ctx context.Context, subjectRef, mediaType string, subjectDesc oci.Descriptor, refBlob []byte) (*notation.VerificationOutcome, error) {
+	opts := notation.VerifyOptions{
+		SignatureMediaType: mediaType,
+		ArtifactReference:  subjectRef,
+	}
 
-		bundledCerts, err := utils.GetCertificatesFromPath(path)
+	return (*v.notationVerifier).Verify(ctx, subjectDesc, refBlob, opts)
+}
 
-		if err != nil {
-			return nil, err
-		}
+func parseVerifierConfig(verifierConfig config.VerifierConfig) (*NotaryV2VerifierConfig, error) {
+	conf := &NotaryV2VerifierConfig{}
 
-		certs = append(certs, bundledCerts...)
+	verifierConfigBytes, err := json.Marshal(verifierConfig)
+	if err != nil {
+		return nil, err
 	}
 
-	verifier := signature.NewVerifier()
-	verifier.TrustedCerts = certs
-	return verifier, nil
+	if err := json.Unmarshal(verifierConfigBytes, &conf); err != nil {
+		return nil, fmt.Errorf("failed to unmarshal to notaryV2VerifierConfig from： %+v, err: %v", verifierConfig, err)
+	}
+
+	defaultCertsDir := paths.Join(homedir.Get(), ratifyconfig.ConfigFileDir, defaultCertPath)
+	conf.VerificationCerts = append(conf.VerificationCerts, defaultCertsDir)
+
+	return conf, nil
 }


Test patch:
diff --git a/pkg/verifier/notaryv2/notaryv2_test.go b/pkg/verifier/notaryv2/notaryv2_test.go
new file mode 100644
index 0000000..0ca6a48
--- /dev/null
+++ b/pkg/verifier/notaryv2/notaryv2_test.go
@@ -0,0 +1,420 @@
+package notaryv2
+
+import (
+	"context"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"fmt"
+	paths "path/filepath"
+	"reflect"
+	"testing"
+	"time"
+
+	ratifyconfig "github.com/deislabs/ratify/config"
+	"github.com/deislabs/ratify/pkg/common"
+	e "github.com/deislabs/ratify/pkg/executor"
+	"github.com/deislabs/ratify/pkg/executor/types"
+	"github.com/deislabs/ratify/pkg/homedir"
+	"github.com/deislabs/ratify/pkg/ocispecs"
+	"github.com/deislabs/ratify/pkg/referrerstore"
+	"github.com/deislabs/ratify/pkg/referrerstore/config"
+	"github.com/deislabs/ratify/pkg/verifier"
+	sig "github.com/notaryproject/notation-core-go/signature"
+	"github.com/notaryproject/notation-go"
+	"github.com/notaryproject/notation-go/verifier/trustpolicy"
+	"github.com/opencontainers/go-digest"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+const (
+	testArtifactType1 = "testArtifactType1"
+	testArtifactType2 = "testArtifactType2"
+	test              = "test"
+	testPath          = "/test/path"
+	testMediaType     = "testMediaType"
+	testVersion       = "1.0"
+	testDigest        = "sha256:123456"
+	testDigest2       = "sha256:234567"
+	invalidDigest     = "invalidDigest"
+)
+
+var (
+	failedResult = verifier.VerifierResult{IsSuccess: false}
+	testOutcome  = &notation.VerificationOutcome{
+		EnvelopeContent: &sig.EnvelopeContent{
+			SignerInfo: sig.SignerInfo{
+				CertificateChain: []*x509.Certificate{
+					{Issuer: pkix.Name{}, Subject: pkix.Name{}},
+				},
+			},
+		},
+	}
+	testRefBlob  = []byte("test")
+	testRefBlob2 = []byte("test2")
+	testDesc1    = ocispec.Descriptor{}
+	validPolicy  = &trustpolicy.Document{
+		Version: "1.0",
+		TrustPolicies: []trustpolicy.TrustPolicy{
+			{
+				Name:                  "default",
+				RegistryScopes:        []string{"*"},
+				SignatureVerification: trustpolicy.SignatureVerification{VerificationLevel: "strict"},
+				TrustStores:           []string{"ca:certs"},
+				TrustedIdentities:     []string{"*"},
+			},
+		},
+	}
+	validRef = common.Reference{
+		Original: "testRegistry/repo:v1",
+		Digest:   testDigest,
+	}
+	validRef2 = common.Reference{
+		Original: "testRegistry/repo:v2",
+		Digest:   testDigest2,
+	}
+	invalidRef = common.Reference{
+		Original: "invalid",
+	}
+	testExecutor                         = &mockExecutor{}
+	testNotaryVerifier notation.Verifier = mockNotaryVerifier{}
+	validBlobDesc                        = ocispec.Descriptor{
+		Digest: testDigest,
+	}
+	validBlobDesc2 = ocispec.Descriptor{
+		Digest: testDigest2,
+	}
+	invalidBlobDesc = ocispec.Descriptor{
+		Digest: invalidDigest,
+	}
+	defaultCertDir = paths.Join(homedir.Get(), ratifyconfig.ConfigFileDir, defaultCertPath)
+)
+
+type mockNotaryVerifier struct{}
+
+func (v mockNotaryVerifier) Verify(ctx context.Context, desc ocispec.Descriptor, signature []byte, opts notation.VerifyOptions) (*notation.VerificationOutcome, error) {
+	if reflect.DeepEqual(signature, testRefBlob2) {
+		return nil, fmt.Errorf("failed verification")
+	}
+	return testOutcome, nil
+}
+
+type mockStore struct {
+	refBlob  []byte
+	manifest ocispecs.ReferenceManifest
+}
+
+func (s mockStore) Name() string {
+	return test
+}
+
+func (s mockStore) ListReferrers(ctx context.Context, subjectReference common.Reference, artifactTypes []string, nextToken string, subjectDesc *ocispecs.SubjectDescriptor) (referrerstore.ListReferrersResult, error) {
+	return referrerstore.ListReferrersResult{}, nil
+}
+
+func (s mockStore) GetBlobContent(ctx context.Context, subjectReference common.Reference, digest digest.Digest) ([]byte, error) {
+	if s.refBlob == nil {
+		return nil, fmt.Errorf("invalid blob")
+	}
+	return s.refBlob, nil
+}
+
+func (s mockStore) GetReferenceManifest(ctx context.Context, subjectReference common.Reference, referenceDesc ocispecs.ReferenceDescriptor) (ocispecs.ReferenceManifest, error) {
+	if len(s.manifest.Blobs) == 0 {
+		return s.manifest, fmt.Errorf("invalid reference")
+	}
+	return s.manifest, nil
+}
+
+func (s mockStore) GetConfig() *config.StoreConfig {
+	return nil
+}
+
+func (s mockStore) GetSubjectDescriptor(ctx context.Context, subjectReference common.Reference) (*ocispecs.SubjectDescriptor, error) {
+	return &ocispecs.SubjectDescriptor{
+		Descriptor: ocispec.Descriptor{},
+	}, nil
+}
+
+type mockExecutor struct{}
+
+func (e mockExecutor) VerifySubject(ctx context.Context, verifyParameters e.VerifyParameters) (types.VerifyResult, error) {
+	return types.VerifyResult{}, nil
+}
+
+func (e mockExecutor) GetVerifyRequestTimeout() time.Duration {
+	return time.Hour
+}
+
+func TestName(t *testing.T) {
+	v := &notaryV2Verifier{}
+	name := v.Name()
+
+	if name != "notaryv2" {
+		t.Fatalf("expect name: notaryv2, got: %s", name)
+	}
+}
+
+func TestCanVerify(t *testing.T) {
+	tests := []struct {
+		name              string
+		artifactTypes     []string
+		referenceArtifact string
+		expect            bool
+	}{
+		{
+			name:              "wildcard pattern",
+			artifactTypes:     []string{"*"},
+			referenceArtifact: testArtifactType1,
+			expect:            true,
+		},
+		{
+			name:              "type unmatched",
+			artifactTypes:     []string{testArtifactType2},
+			referenceArtifact: testArtifactType1,
+			expect:            false,
+		},
+		{
+			name:              "type matched",
+			artifactTypes:     []string{testArtifactType1},
+			referenceArtifact: testArtifactType1,
+			expect:            true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			v := &notaryV2Verifier{
+				artifactTypes: tt.artifactTypes,
+			}
+			desc := ocispecs.ReferenceDescriptor{
+				ArtifactType: tt.referenceArtifact,
+			}
+
+			got := v.CanVerify(context.Background(), desc)
+			if got != tt.expect {
+				t.Fatalf("Expect: %v, got: %v", tt.expect, got)
+			}
+		})
+	}
+}
+
+func TestParseVerifierConfig(t *testing.T) {
+	tests := []struct {
+		name      string
+		configMap map[string]interface{}
+		expectErr bool
+		expect    *NotaryV2VerifierConfig
+	}{
+		{
+			name: "failed unmarshalling to notary config",
+			configMap: map[string]interface{}{
+				"name": []string{test},
+			},
+			expectErr: true,
+			expect:    nil,
+		},
+		{
+			name: "sucessfully parsed with default cert directory",
+			configMap: map[string]interface{}{
+				"name": test,
+			},
+			expectErr: false,
+			expect: &NotaryV2VerifierConfig{
+				Name:              test,
+				VerificationCerts: []string{defaultCertDir},
+			},
+		},
+		{
+			name: "successfully parsed with specified cert directory",
+			configMap: map[string]interface{}{
+				"name":              test,
+				"verificationCerts": []string{testPath},
+			},
+			expectErr: false,
+			expect: &NotaryV2VerifierConfig{
+				Name:              test,
+				VerificationCerts: []string{testPath, defaultCertDir},
+			},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			notaryConfig, err := parseVerifierConfig(tt.configMap)
+
+			if (err != nil) != tt.expectErr {
+				t.Errorf("error = %v, expectErr = %v", err, tt.expectErr)
+			}
+			if !reflect.DeepEqual(notaryConfig, tt.expect) {
+				t.Errorf("expect %+v, got %+v", tt.expect, notaryConfig)
+			}
+		})
+	}
+}
+
+func TestVerifySignature(t *testing.T) {
+	v := &notaryV2Verifier{
+		notationVerifier: &testNotaryVerifier,
+	}
+
+	outcome, err := v.verifySignature(context.Background(), testArtifactType1, testMediaType, testDesc1, testRefBlob)
+	if err != nil {
+		t.Errorf("got unexpected error: %v", err)
+	}
+	if !reflect.DeepEqual(outcome, testOutcome) {
+		t.Fatalf("expect outcome: %v, got: %v", outcome, testOutcome)
+	}
+}
+
+func TestLoadPolicyDocument(t *testing.T) {
+	tests := []struct {
+		name      string
+		path      string
+		expect    *trustpolicy.Document
+		expectErr bool
+	}{
+		{
+			name:      "not existent path",
+			path:      "./nonexistent.json",
+			expect:    nil,
+			expectErr: true,
+		},
+		{
+			name:      "invalid json file",
+			path:      "../../../test/testdata/invalid_json.json",
+			expect:    nil,
+			expectErr: true,
+		},
+		{
+			name:      "invalid policy document",
+			path:      "../../../test/testdata/invalid_trust_policy.json",
+			expect:    nil,
+			expectErr: true,
+		},
+		{
+			name:      "invalid policy document",
+			path:      "../../../test/testdata/valid_trust_policy.json",
+			expect:    validPolicy,
+			expectErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			policy, err := loadPolicyDocument(tt.path)
+
+			if (err != nil) != tt.expectErr {
+				t.Fatalf("error = %v, expectErr = %v", err, tt.expectErr)
+			}
+			if !reflect.DeepEqual(policy, tt.expect) {
+				t.Fatalf("expect %+v, got %+v", tt.expect, policy)
+			}
+		})
+	}
+}
+
+func TestCreate(t *testing.T) {
+	tests := []struct {
+		name      string
+		configMap map[string]interface{}
+		expect    verifier.ReferenceVerifier
+		expectErr bool
+	}{
+		{
+			name: "failed parsing verifier config",
+			configMap: map[string]interface{}{
+				"name": []string{test},
+			},
+			expectErr: true,
+		},
+		{
+			name: "failed loading policy",
+			configMap: map[string]interface{}{
+				"name":        test,
+				"trustPolicy": "./nonexistent.json",
+			},
+			expectErr: true,
+		},
+		{
+			name: "created verifier successfully",
+			configMap: map[string]interface{}{
+				"name":        test,
+				"trustPolicy": "../../../test/testdata/valid_trust_policy.json",
+			},
+			expectErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			f := &notaryv2VerifierFactory{}
+			_, err := f.Create(testVersion, tt.configMap)
+
+			if (err != nil) != tt.expectErr {
+				t.Fatalf("error = %v, expectErr = %v", err, tt.expectErr)
+			}
+		})
+	}
+}
+
+func TestVerify(t *testing.T) {
+	tests := []struct {
+		name      string
+		expect    verifier.VerifierResult
+		ref       common.Reference
+		manifest  ocispecs.ReferenceManifest
+		refBlob   []byte
+		expectErr bool
+	}{
+		{
+			name:      "failed getting manifest",
+			ref: invalidRef,
+			refBlob: []byte(""),
+			manifest: ocispecs.ReferenceManifest{},
+			expect:    failedResult,
+			expectErr: true,
+		},
+		{
+			name:    "failed verifying signature",
+			ref:     validRef2,
+			refBlob: testRefBlob2,
+			manifest: ocispecs.ReferenceManifest{
+				Blobs: []ocispec.Descriptor{validBlobDesc2},
+			},
+			expect:    failedResult,
+			expectErr: true,
+		},
+		{
+			name: "verified successfully",
+			ref: validRef,
+			refBlob: testRefBlob,
+			manifest: ocispecs.ReferenceManifest{
+				Blobs: []ocispec.Descriptor{validBlobDesc},
+			},
+			expect: verifier.VerifierResult{IsSuccess: true},
+			expectErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			v := &notaryV2Verifier{
+				notationVerifier: &testNotaryVerifier,
+			}
+
+			store := &mockStore{
+				refBlob:  tt.refBlob,
+				manifest: tt.manifest,
+			}
+
+			result, err := v.Verify(context.Background(), tt.ref, ocispecs.ReferenceDescriptor{}, store, testExecutor)
+
+			if (err != nil) != tt.expectErr {
+				t.Fatalf("error = %v, expectErr = %v", err, tt.expectErr)
+			}
+			if result.IsSuccess != tt.expect.IsSuccess {
+				t.Fatalf("expect %+v, got %+v", tt.expect, result)
+			}
+		})
+	}
+}
diff --git a/test/bats/test.bats b/test/bats/test.bats
index 09bf74f..38692c9 100644
--- a/test/bats/test.bats
+++ b/test/bats/test.bats
@@ -7,6 +7,7 @@ WAIT_TIME=60
 SLEEP_TIME=1
 
 @test "quick start test" {
+    skip "Skipping test for now as ACR does not support OCI artifacts which is required by Notary Verifier"
     run kubectl apply -f ./library/default/template.yaml
     assert_success
     sleep 5
@@ -23,6 +24,7 @@ SLEEP_TIME=1
 }
 
 @test "validate crd add, replace and delete" {     
+    skip "Skipping test for now as ACR does not support OCI artifacts which is required by Notary Verifier"
     echo "adding license checker, delete notary verifier and validate deployment fails due to missing notary verifier"
     run kubectl apply -f ./config/samples/config_v1alpha1_verifier_licensechecker.yaml
     assert_success
diff --git a/test/testdata/invalid_json.json b/test/testdata/invalid_json.json
new file mode 100644
index 0000000..81750b9
--- /dev/null
+++ b/test/testdata/invalid_json.json
@@ -0,0 +1,1 @@
+{
\ No newline at end of file
diff --git a/test/testdata/invalid_trust_policy.json b/test/testdata/invalid_trust_policy.json
new file mode 100644
index 0000000..90fa5e8
--- /dev/null
+++ b/test/testdata/invalid_trust_policy.json
@@ -0,0 +1,3 @@
+{
+    "version": "1.0"
+}
\ No newline at end of file
diff --git a/test/testdata/valid_trust_policy.json b/test/testdata/valid_trust_policy.json
new file mode 100644
index 0000000..5d64d7a
--- /dev/null
+++ b/test/testdata/valid_trust_policy.json
@@ -0,0 +1,20 @@
+{
+    "version": "1.0",
+    "trustPolicies": [
+        {
+            "name": "default",
+            "registryScopes": [
+                "*"
+            ],
+            "signatureVerification": {
+                "level": "strict"
+            },
+            "trustStores": [
+                "ca:certs"
+            ],
+            "trustedIdentities": [
+                "*"
+            ]
+        }
+    ]
+}
\ No newline at end of file