Repository: cerbos/cerbos
Pull request #821 (2022-04-06 08:27:43)

chore: Add CheckResources API to Playground
Adds the `CheckResources` API introduced in #819 to the Playground.

Signed-off-by: Charith Ellawala <charith@cerbos.dev>


codecov-commenter: # [Codecov](https://codecov.io/gh/cerbos/cerbos/pull/821?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cerbos) Report
> Merging [#821](https://codecov.io/gh/cerbos/cerbos/pull/821?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cerbos) (fe91dd3) into [main](https://codecov.io/gh/cerbos/cerbos/commit/3d17855930bf334e851d3a754987fd89c09cfbe8?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cerbos) (3d17855) will **increase** coverage by `0.18%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/cerbos/cerbos/pull/821/graphs/tree.svg?width=650&height=150&src=pr&token=tGaxiUZUzL&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cerbos)](https://codecov.io/gh/cerbos/cerbos/pull/821?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cerbos)

```diff
@@            Coverage Diff             @@
##             main     #821      +/-   ##
==========================================
+ Coverage   54.40%   54.58%   +0.18%     
==========================================
  Files         100      100              
  Lines       10788    10788              
==========================================
+ Hits         5869     5889      +20     
+ Misses       4414     4396      -18     
+ Partials      505      503       -2     
```


| [Impacted Files](https://codecov.io/gh/cerbos/cerbos/pull/821?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cerbos) | Coverage Δ | |
|---|---|---|
| [internal/audit/local/badgerdb.go](https://codecov.io/gh/cerbos/cerbos/pull/821/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cerbos#diff-aW50ZXJuYWwvYXVkaXQvbG9jYWwvYmFkZ2VyZGIuZ28=) | `63.17% <0.00%> (-0.64%)` | :arrow_down: |
| [internal/engine/engine.go](https://codecov.io/gh/cerbos/cerbos/pull/821/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cerbos#diff-aW50ZXJuYWwvZW5naW5lL2VuZ2luZS5nbw==) | `69.97% <0.00%> (+0.80%)` | :arrow_up: |
| [internal/storage/index/builder.go](https://codecov.io/gh/cerbos/cerbos/pull/821/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cerbos#diff-aW50ZXJuYWwvc3RvcmFnZS9pbmRleC9idWlsZGVyLmdv) | `84.35% <0.00%> (+5.02%)` | :arrow_up: |
| [internal/compile/errors.go](https://codecov.io/gh/cerbos/cerbos/pull/821/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cerbos#diff-aW50ZXJuYWwvY29tcGlsZS9lcnJvcnMuZ28=) | `55.55% <0.00%> (+15.87%)` | :arrow_up: |


Patch:
diff --git a/.github/workflows/dependabot.yaml b/.github/workflows/dependabot.yaml
index f8216c5a..3bb62da6 100644
--- a/.github/workflows/dependabot.yaml
+++ b/.github/workflows/dependabot.yaml
@@ -13,7 +13,7 @@ jobs:
         with:
           ref: ${{ github.event.pull_request.head.ref }}
 
-      - uses: actions/setup-go@v2
+      - uses: actions/setup-go@v3
         with:
           go-version: 1.18.x
 
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 7205ca91..e88b5bca 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -10,7 +10,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Install Go
-        uses: actions/setup-go@v2
+        uses: actions/setup-go@v3
         with:
           go-version: 1.18.x
 
diff --git a/.github/workflows/snaphot.yaml b/.github/workflows/snaphot.yaml
index d2b4bad6..983648fb 100644
--- a/.github/workflows/snaphot.yaml
+++ b/.github/workflows/snaphot.yaml
@@ -12,7 +12,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Install Go
-        uses: actions/setup-go@v2
+        uses: actions/setup-go@v3
         with:
           go-version: 1.18.x
 
@@ -63,7 +63,7 @@ jobs:
         run: make test-all
 
       - name: Upload to CodeCov
-        uses: codecov/codecov-action@v2
+        uses: codecov/codecov-action@v3
         with:
           token: ${{ secrets.CODECOV_TOKEN }}
           files: "unit.cover,integration.cover"
diff --git a/.goreleaser.yml b/.goreleaser.yml
index 47a641fa..5bbffecf 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -159,9 +159,15 @@ release:
 
 changelog:
   sort: asc
-  filters:
-    exclude:
-      - '^ci:'
-      - '^chore'
-      - '^docs:'
-      - '^test:'
+  groups:
+    - title: Features
+      regexp: '^feat.+'
+      order: 5
+    - title: Enhancements
+      regexp: '^enhancement.+'
+      order: 10
+    - title: Bug fixes
+      regexp: '^fix.+'
+      order: 15
+    - title: Others
+      order: 20
diff --git a/api/genpb/cerbos/private/v1/hashpb_helpers.pb.go b/api/genpb/cerbos/private/v1/hashpb_helpers.pb.go
index ccecdc4a..4393776b 100644
--- a/api/genpb/cerbos/private/v1/hashpb_helpers.pb.go
+++ b/api/genpb/cerbos/private/v1/hashpb_helpers.pb.go
@@ -1891,6 +1891,11 @@ func cerbos_request_v1_PlaygroundProxyRequest_hashpb_sum(m *v12.PlaygroundProxyR
 					cerbos_request_v1_ResourcesQueryPlanRequest_hashpb_sum(t.ResourcesQueryPlan, hasher, ignore)
 				}
 
+			case *v12.PlaygroundProxyRequest_CheckResources:
+				if t.CheckResources != nil {
+					cerbos_request_v1_CheckResourcesRequest_hashpb_sum(t.CheckResources, hasher, ignore)
+				}
+
 			}
 		}
 	}
@@ -2425,6 +2430,11 @@ func cerbos_response_v1_PlaygroundProxyResponse_hashpb_sum(m *v13.PlaygroundProx
 					cerbos_response_v1_ResourcesQueryPlanResponse_hashpb_sum(t.ResourcesQueryPlan, hasher, ignore)
 				}
 
+			case *v13.PlaygroundProxyResponse_CheckResources:
+				if t.CheckResources != nil {
+					cerbos_response_v1_CheckResourcesResponse_hashpb_sum(t.CheckResources, hasher, ignore)
+				}
+
 			}
 		}
 	}
diff --git a/api/genpb/cerbos/request/v1/hashpb_helpers.pb.go b/api/genpb/cerbos/request/v1/hashpb_helpers.pb.go
index 74f28028..e3b220c2 100644
--- a/api/genpb/cerbos/request/v1/hashpb_helpers.pb.go
+++ b/api/genpb/cerbos/request/v1/hashpb_helpers.pb.go
@@ -872,6 +872,11 @@ func cerbos_request_v1_PlaygroundProxyRequest_hashpb_sum(m *PlaygroundProxyReque
 					cerbos_request_v1_ResourcesQueryPlanRequest_hashpb_sum(t.ResourcesQueryPlan, hasher, ignore)
 				}
 
+			case *PlaygroundProxyRequest_CheckResources:
+				if t.CheckResources != nil {
+					cerbos_request_v1_CheckResourcesRequest_hashpb_sum(t.CheckResources, hasher, ignore)
+				}
+
 			}
 		}
 	}
diff --git a/api/genpb/cerbos/request/v1/request.pb.go b/api/genpb/cerbos/request/v1/request.pb.go
index 60ce40d5..aaf4bed8 100644
--- a/api/genpb/cerbos/request/v1/request.pb.go
+++ b/api/genpb/cerbos/request/v1/request.pb.go
@@ -836,6 +836,7 @@ type PlaygroundProxyRequest struct {
 	//	*PlaygroundProxyRequest_CheckResourceSet
 	//	*PlaygroundProxyRequest_CheckResourceBatch
 	//	*PlaygroundProxyRequest_ResourcesQueryPlan
+	//	*PlaygroundProxyRequest_CheckResources
 	ProxyRequest isPlaygroundProxyRequest_ProxyRequest `protobuf_oneof:"proxy_request"`
 }
 
@@ -913,6 +914,13 @@ func (x *PlaygroundProxyRequest) GetResourcesQueryPlan() *ResourcesQueryPlanRequ
 	return nil
 }
 
+func (x *PlaygroundProxyRequest) GetCheckResources() *CheckResourcesRequest {
+	if x, ok := x.GetProxyRequest().(*PlaygroundProxyRequest_CheckResources); ok {
+		return x.CheckResources
+	}
+	return nil
+}
+
 type isPlaygroundProxyRequest_ProxyRequest interface {
 	isPlaygroundProxyRequest_ProxyRequest()
 }
@@ -929,12 +937,18 @@ type PlaygroundProxyRequest_ResourcesQueryPlan struct {
 	ResourcesQueryPlan *ResourcesQueryPlanRequest `protobuf:"bytes,5,opt,name=resources_query_plan,json=resourcesQueryPlan,proto3,oneof"`
 }
 
+type PlaygroundProxyRequest_CheckResources struct {
+	CheckResources *CheckResourcesRequest `protobuf:"bytes,6,opt,name=check_resources,json=checkResources,proto3,oneof"`
+}
+
 func (*PlaygroundProxyRequest_CheckResourceSet) isPlaygroundProxyRequest_ProxyRequest() {}
 
 func (*PlaygroundProxyRequest_CheckResourceBatch) isPlaygroundProxyRequest_ProxyRequest() {}
 
 func (*PlaygroundProxyRequest_ResourcesQueryPlan) isPlaygroundProxyRequest_ProxyRequest() {}
 
+func (*PlaygroundProxyRequest_CheckResources) isPlaygroundProxyRequest_ProxyRequest() {}
+
 type AddOrUpdatePolicyRequest struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -2100,7 +2114,7 @@ var file_cerbos_request_v1_request_proto_rawDesc = []byte{
 	0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x78, 0x44, 0x61, 0x74, 0x61, 0x52,
 	0x07, 0x61, 0x75, 0x78, 0x44, 0x61, 0x74, 0x61, 0x3a, 0x22, 0x92, 0x41, 0x1f, 0x0a, 0x1d, 0x32,
 	0x1b, 0x50, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x65, 0x76, 0x61, 0x6c,
-	0x75, 0x61, 0x74, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xec, 0x03, 0x0a,
+	0x75, 0x61, 0x74, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xc1, 0x04, 0x0a,
 	0x16, 0x50, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x72, 0x6f, 0x78, 0x79,
 	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x6c, 0x61, 0x79, 0x67,
 	0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
@@ -2128,149 +2142,155 @@ var file_cerbos_request_v1_request_proto_rawDesc = []byte{
 	0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x51, 0x75,
 	0x65, 0x72, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00,
 	0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x51, 0x75, 0x65, 0x72, 0x79,
-	0x50, 0x6c, 0x61, 0x6e, 0x3a, 0x1f, 0x92, 0x41, 0x1c, 0x0a, 0x1a, 0x32, 0x18, 0x50, 0x6c, 0x61,
-	0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x20, 0x72, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x14, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x72,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x03, 0xf8, 0x42, 0x01, 0x22, 0x9e, 0x01, 0x0a, 0x18,
-	0x41, 0x64, 0x64, 0x4f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63,
-	0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69,
-	0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x65, 0x72,
-	0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f,
-	0x6c, 0x69, 0x63, 0x79, 0x42, 0x2a, 0x92, 0x41, 0x19, 0x32, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x20,
-	0x6f, 0x66, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x2e, 0xa0, 0x01, 0x0a, 0xa8,
-	0x01, 0x01, 0xe2, 0x41, 0x01, 0x02, 0xfa, 0x42, 0x07, 0x92, 0x01, 0x04, 0x08, 0x01, 0x10, 0x0a,
-	0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x3a, 0x20, 0x92, 0x41, 0x1d, 0x0a,
-	0x1b, 0x32, 0x19, 0x41, 0x64, 0x64, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x70, 0x6f,
-	0x6c, 0x69, 0x63, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xa5, 0x07, 0x0a,
-	0x1a, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74,
-	0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x86, 0x01, 0x0a, 0x04,
-	0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x63, 0x65, 0x72,
-	0x62, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
-	0x69, 0x73, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x69,
-	0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4b, 0x69, 0x6e, 0x64, 0x42, 0x3e,
-	0x92, 0x41, 0x31, 0x32, 0x11, 0x4b, 0x69, 0x6e, 0x64, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x67,
-	0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0xf2, 0x02, 0x0b, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x41, 0x43,
-	0x43, 0x45, 0x53, 0x53, 0xf2, 0x02, 0x0d, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x44, 0x45, 0x43, 0x49,
-	0x53, 0x49, 0x4f, 0x4e, 0xfa, 0x42, 0x07, 0x82, 0x01, 0x04, 0x18, 0x01, 0x18, 0x02, 0x52, 0x04,
-	0x6b, 0x69, 0x6e, 0x64, 0x12, 0x44, 0x0a, 0x04, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x0d, 0x42, 0x2e, 0x92, 0x41, 0x23, 0x32, 0x0f, 0x4c, 0x61, 0x73, 0x74, 0x20, 0x4e, 0x20,
-	0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x8f,
-	0x40, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18,
-	0xe8, 0x07, 0x48, 0x00, 0x52, 0x04, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x53, 0x0a, 0x07, 0x62, 0x65,
-	0x74, 0x77, 0x65, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x63, 0x65,
-	0x72, 0x62, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e,
-	0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72,
-	0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52,
-	0x61, 0x6e, 0x67, 0x65, 0x48, 0x00, 0x52, 0x07, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x12,
-	0x59, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19,
-	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
-	0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x26, 0x92, 0x41, 0x23, 0x32, 0x21,
-	0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x20, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x20, 0x4e, 0x20,
-	0x68, 0x6f, 0x75, 0x72, 0x73, 0x2f, 0x6d, 0x69, 0x6e, 0x75, 0x74, 0x65, 0x73, 0x20, 0x61, 0x67,
-	0x6f, 0x48, 0x00, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12, 0x83, 0x01, 0x0a, 0x06, 0x6c,
-	0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x69, 0x92, 0x41, 0x37,
-	0x32, 0x0a, 0x42, 0x79, 0x20, 0x43, 0x61, 0x6c, 0x6c, 0x20, 0x49, 0x44, 0x8a, 0x01, 0x28, 0x5e,
-	0x5b, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45,
-	0x46, 0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54, 0x56, 0x57, 0x58, 0x59,
-	0x5a, 0x5d, 0x7b, 0x32, 0x36, 0x7d, 0x24, 0xfa, 0x42, 0x2c, 0x72, 0x2a, 0x32, 0x28, 0x5e, 0x5b,
-	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
-	0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54, 0x56, 0x57, 0x58, 0x59, 0x5a,
-	0x5d, 0x7b, 0x32, 0x36, 0x7d, 0x24, 0x48, 0x00, 0x52, 0x06, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70,
-	0x1a, 0xb0, 0x02, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x80,
-	0x01, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
-	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
-	0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x4e, 0x92, 0x41, 0x3d, 0x32,
-	0x1e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x20, 0x64, 0x61, 0x74, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x49,
-	0x53, 0x4f, 0x20, 0x38, 0x36, 0x30, 0x31, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x4a,
-	0x1b, 0x22, 0x32, 0x30, 0x32, 0x31, 0x2d, 0x30, 0x37, 0x2d, 0x30, 0x35, 0x54, 0x30, 0x37, 0x3a,
-	0x32, 0x37, 0x3a, 0x30, 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x22, 0xe2, 0x41, 0x01, 0x02,
-	0xfa, 0x42, 0x07, 0xb2, 0x01, 0x04, 0x08, 0x01, 0x38, 0x01, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72,
-	0x74, 0x12, 0x7a, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
-	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
-	0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x4c, 0x92, 0x41, 0x3b, 0x32,
-	0x1c, 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x53, 0x4f,
-	0x20, 0x38, 0x36, 0x30, 0x31, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x4a, 0x1b, 0x22,
-	0x32, 0x30, 0x32, 0x31, 0x2d, 0x30, 0x37, 0x2d, 0x30, 0x35, 0x54, 0x30, 0x37, 0x3a, 0x32, 0x37,
-	0x3a, 0x30, 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x22, 0xe2, 0x41, 0x01, 0x02, 0xfa, 0x42,
-	0x07, 0xb2, 0x01, 0x04, 0x08, 0x01, 0x38, 0x01, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x3a, 0x24, 0x92,
-	0x41, 0x21, 0x0a, 0x1f, 0x32, 0x1d, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x20, 0x62, 0x65,
-	0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x61, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x72, 0x61, 0x6e,
-	0x67, 0x65, 0x2e, 0x22, 0x40, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x10, 0x4b,
-	0x49, 0x4e, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
-	0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53,
-	0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x44, 0x45, 0x43, 0x49, 0x53,
-	0x49, 0x4f, 0x4e, 0x10, 0x02, 0x42, 0x0d, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12,
-	0x03, 0xf8, 0x42, 0x01, 0x22, 0x2f, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x6e,
-	0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x3a, 0x1a, 0x92, 0x41, 0x17, 0x0a, 0x15,
-	0x32, 0x13, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x72, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x33, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c,
-	0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x3a, 0x1c, 0x92, 0x41,
-	0x19, 0x0a, 0x17, 0x32, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69,
-	0x65, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x84, 0x02, 0x0a, 0x10, 0x47,
-	0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
-	0xd4, 0x01, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0xc3, 0x01, 0x92,
-	0x41, 0xa6, 0x01, 0x32, 0x87, 0x01, 0x46, 0x6f, 0x72, 0x20, 0x62, 0x6c, 0x6f, 0x62, 0x2c, 0x20,
-	0x64, 0x69, 0x73, 0x6b, 0x2c, 0x20, 0x67, 0x69, 0x74, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x73,
-	0x20, 0x75, 0x73, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x28,
-	0x3c, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x3e, 0x2e, 0x79, 0x61, 0x6d, 0x6c, 0x29,
-	0x2e, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x2c, 0x20, 0x70, 0x6f, 0x73,
-	0x74, 0x67, 0x72, 0x65, 0x73, 0x2c, 0x20, 0x73, 0x71, 0x6c, 0x69, 0x74, 0x65, 0x33, 0x20, 0x75,
-	0x73, 0x65, 0x20, 0x69, 0x64, 0x20, 0x28, 0x3c, 0x6b, 0x69, 0x6e, 0x64, 0x3e, 0x2e, 0x3c, 0x6e,
-	0x61, 0x6d, 0x65, 0x3e, 0x2e, 0x3c, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3e, 0x29, 0x20,
-	0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4a, 0x1a, 0x22,
-	0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x73, 0x61, 0x72, 0x61, 0x68, 0x2e,
-	0x76, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0xe2, 0x41, 0x01, 0x02, 0xfa, 0x42, 0x12,
-	0x92, 0x01, 0x0f, 0x08, 0x01, 0x10, 0x19, 0x18, 0x01, 0x22, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18,
-	0x80, 0x0a, 0x52, 0x02, 0x69, 0x64, 0x3a, 0x19, 0x92, 0x41, 0x16, 0x0a, 0x14, 0x32, 0x12, 0x47,
-	0x65, 0x74, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x22, 0x9b, 0x01, 0x0a, 0x18, 0x41, 0x64, 0x64, 0x4f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74,
-	0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5d,
-	0x0a, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
-	0x18, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e,
-	0x76, 0x31, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x42, 0x29, 0x92, 0x41, 0x18, 0x32, 0x10,
-	0x4c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x2e,
-	0xa0, 0x01, 0x0a, 0xa8, 0x01, 0x01, 0xe2, 0x41, 0x01, 0x02, 0xfa, 0x42, 0x07, 0x92, 0x01, 0x04,
-	0x08, 0x01, 0x10, 0x0a, 0x52, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x3a, 0x20, 0x92,
-	0x41, 0x1d, 0x0a, 0x1b, 0x32, 0x19, 0x41, 0x64, 0x64, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
-	0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22,
-	0x34, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x3a, 0x1e, 0x92, 0x41, 0x1b, 0x0a, 0x19, 0x32, 0x17, 0x4c, 0x69,
-	0x73, 0x74, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x20, 0x69, 0x64, 0x73, 0x20, 0x72, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x92, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68,
-	0x65, 0x6d, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x02, 0x69, 0x64,
-	0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x50, 0x92, 0x41, 0x34, 0x32, 0x20, 0x55, 0x6e, 0x69,
-	0x71, 0x75, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x66,
-	0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4a, 0x10, 0x22,
-	0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x6a, 0x73, 0x6f, 0x6e, 0x22, 0xe2,
-	0x41, 0x01, 0x02, 0xfa, 0x42, 0x12, 0x92, 0x01, 0x0f, 0x08, 0x01, 0x10, 0x19, 0x18, 0x01, 0x22,
-	0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x52, 0x02, 0x69, 0x64, 0x3a, 0x1c, 0x92, 0x41,
-	0x19, 0x0a, 0x17, 0x32, 0x15, 0x47, 0x65, 0x74, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x28,
-	0x73, 0x29, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x98, 0x01, 0x0a, 0x13, 0x44,
-	0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65,
-	0x73, 0x74, 0x12, 0x60, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x50,
-	0x92, 0x41, 0x34, 0x32, 0x20, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e,
-	0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
-	0x63, 0x68, 0x65, 0x6d, 0x61, 0x4a, 0x10, 0x22, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61,
-	0x6c, 0x2e, 0x6a, 0x73, 0x6f, 0x6e, 0x22, 0xe2, 0x41, 0x01, 0x02, 0xfa, 0x42, 0x12, 0x92, 0x01,
-	0x0f, 0x08, 0x01, 0x10, 0x19, 0x18, 0x01, 0x22, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01,
-	0x52, 0x02, 0x69, 0x64, 0x3a, 0x1f, 0x92, 0x41, 0x1c, 0x0a, 0x1a, 0x32, 0x18, 0x44, 0x65, 0x6c,
-	0x65, 0x74, 0x65, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x28, 0x73, 0x29, 0x20, 0x72, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x7a, 0x0a, 0x12, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53,
-	0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x47, 0x0a, 0x04, 0x77,
-	0x61, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x42, 0x33, 0x92, 0x41, 0x2c, 0x32, 0x2a,
-	0x57, 0x61, 0x69, 0x74, 0x20, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72,
-	0x65, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
-	0x20, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x73, 0xe2, 0x41, 0x01, 0x01, 0x52, 0x04,
-	0x77, 0x61, 0x69, 0x74, 0x3a, 0x1b, 0x92, 0x41, 0x18, 0x0a, 0x16, 0x32, 0x14, 0x52, 0x65, 0x6c,
-	0x6f, 0x61, 0x64, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x42, 0x73, 0x0a, 0x19, 0x64, 0x65, 0x76, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e,
-	0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5a, 0x3e,
-	0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x65, 0x72, 0x62, 0x6f,
-	0x73, 0x2f, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e,
-	0x70, 0x62, 0x2f, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x76, 0x31, 0xaa, 0x02,
-	0x15, 0x43, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x31, 0x2e, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x50, 0x6c, 0x61, 0x6e, 0x12, 0x53, 0x0a, 0x0f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x72, 0x65,
+	0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e,
+	0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76,
+	0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x63, 0x68, 0x65, 0x63, 0x6b,
+	0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x1f, 0x92, 0x41, 0x1c, 0x0a, 0x1a,
+	0x32, 0x18, 0x50, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f,
+	0x78, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x14, 0x0a, 0x0d, 0x70, 0x72,
+	0x6f, 0x78, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x03, 0xf8, 0x42, 0x01,
+	0x22, 0x9e, 0x01, 0x0a, 0x18, 0x41, 0x64, 0x64, 0x4f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
+	0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a,
+	0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x18, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
+	0x76, 0x31, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, 0x2a, 0x92, 0x41, 0x19, 0x32, 0x11,
+	0x4c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73,
+	0x2e, 0xa0, 0x01, 0x0a, 0xa8, 0x01, 0x01, 0xe2, 0x41, 0x01, 0x02, 0xfa, 0x42, 0x07, 0x92, 0x01,
+	0x04, 0x08, 0x01, 0x10, 0x0a, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x3a,
+	0x20, 0x92, 0x41, 0x1d, 0x0a, 0x1b, 0x32, 0x19, 0x41, 0x64, 0x64, 0x2f, 0x75, 0x70, 0x64, 0x61,
+	0x74, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x22, 0xa5, 0x07, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c,
+	0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x12, 0x86, 0x01, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
+	0x32, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f, 0x67,
+	0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4b,
+	0x69, 0x6e, 0x64, 0x42, 0x3e, 0x92, 0x41, 0x31, 0x32, 0x11, 0x4b, 0x69, 0x6e, 0x64, 0x20, 0x6f,
+	0x66, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0xf2, 0x02, 0x0b, 0x4b, 0x49,
+	0x4e, 0x44, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0xf2, 0x02, 0x0d, 0x4b, 0x49, 0x4e, 0x44,
+	0x5f, 0x44, 0x45, 0x43, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0xfa, 0x42, 0x07, 0x82, 0x01, 0x04, 0x18,
+	0x01, 0x18, 0x02, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x44, 0x0a, 0x04, 0x74, 0x61, 0x69,
+	0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x2e, 0x92, 0x41, 0x23, 0x32, 0x0f, 0x4c, 0x61,
+	0x73, 0x74, 0x20, 0x4e, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x59, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x40, 0x8f, 0x40, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0xfa,
+	0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x48, 0x00, 0x52, 0x04, 0x74, 0x61, 0x69, 0x6c, 0x12,
+	0x53, 0x0a, 0x07, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x37, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f,
+	0x67, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e,
+	0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x48, 0x00, 0x52, 0x07, 0x62, 0x65, 0x74,
+	0x77, 0x65, 0x65, 0x6e, 0x12, 0x59, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x26,
+	0x92, 0x41, 0x23, 0x32, 0x21, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x20, 0x73, 0x69, 0x6e,
+	0x63, 0x65, 0x20, 0x4e, 0x20, 0x68, 0x6f, 0x75, 0x72, 0x73, 0x2f, 0x6d, 0x69, 0x6e, 0x75, 0x74,
+	0x65, 0x73, 0x20, 0x61, 0x67, 0x6f, 0x48, 0x00, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12,
+	0x83, 0x01, 0x0a, 0x06, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
+	0x42, 0x69, 0x92, 0x41, 0x37, 0x32, 0x0a, 0x42, 0x79, 0x20, 0x43, 0x61, 0x6c, 0x6c, 0x20, 0x49,
+	0x44, 0x8a, 0x01, 0x28, 0x5e, 0x5b, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+	0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53,
+	0x54, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5d, 0x7b, 0x32, 0x36, 0x7d, 0x24, 0xfa, 0x42, 0x2c, 0x72,
+	0x2a, 0x32, 0x28, 0x5e, 0x5b, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41,
+	0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54,
+	0x56, 0x57, 0x58, 0x59, 0x5a, 0x5d, 0x7b, 0x32, 0x36, 0x7d, 0x24, 0x48, 0x00, 0x52, 0x06, 0x6c,
+	0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x1a, 0xb0, 0x02, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61,
+	0x6e, 0x67, 0x65, 0x12, 0x80, 0x01, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42,
+	0x4e, 0x92, 0x41, 0x3d, 0x32, 0x1e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x20, 0x64, 0x61, 0x74, 0x65,
+	0x20, 0x69, 0x6e, 0x20, 0x49, 0x53, 0x4f, 0x20, 0x38, 0x36, 0x30, 0x31, 0x20, 0x66, 0x6f, 0x72,
+	0x6d, 0x61, 0x74, 0x2e, 0x4a, 0x1b, 0x22, 0x32, 0x30, 0x32, 0x31, 0x2d, 0x30, 0x37, 0x2d, 0x30,
+	0x35, 0x54, 0x30, 0x37, 0x3a, 0x32, 0x37, 0x3a, 0x30, 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30,
+	0x22, 0xe2, 0x41, 0x01, 0x02, 0xfa, 0x42, 0x07, 0xb2, 0x01, 0x04, 0x08, 0x01, 0x38, 0x01, 0x52,
+	0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x7a, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42,
+	0x4c, 0x92, 0x41, 0x3b, 0x32, 0x1c, 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x65, 0x20, 0x69,
+	0x6e, 0x20, 0x49, 0x53, 0x4f, 0x20, 0x38, 0x36, 0x30, 0x31, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61,
+	0x74, 0x2e, 0x4a, 0x1b, 0x22, 0x32, 0x30, 0x32, 0x31, 0x2d, 0x30, 0x37, 0x2d, 0x30, 0x35, 0x54,
+	0x30, 0x37, 0x3a, 0x32, 0x37, 0x3a, 0x30, 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x22, 0xe2,
+	0x41, 0x01, 0x02, 0xfa, 0x42, 0x07, 0xb2, 0x01, 0x04, 0x08, 0x01, 0x38, 0x01, 0x52, 0x03, 0x65,
+	0x6e, 0x64, 0x3a, 0x24, 0x92, 0x41, 0x21, 0x0a, 0x1f, 0x32, 0x1d, 0x45, 0x6e, 0x74, 0x72, 0x69,
+	0x65, 0x73, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x61, 0x20, 0x74, 0x69, 0x6d,
+	0x65, 0x20, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x22, 0x40, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64,
+	0x12, 0x14, 0x0a, 0x10, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
+	0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x41,
+	0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x4b, 0x49, 0x4e, 0x44, 0x5f,
+	0x44, 0x45, 0x43, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x42, 0x0d, 0x0a, 0x06, 0x66, 0x69,
+	0x6c, 0x74, 0x65, 0x72, 0x12, 0x03, 0xf8, 0x42, 0x01, 0x22, 0x2f, 0x0a, 0x11, 0x53, 0x65, 0x72,
+	0x76, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x3a, 0x1a,
+	0x92, 0x41, 0x17, 0x0a, 0x15, 0x32, 0x13, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x69, 0x6e,
+	0x66, 0x6f, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x33, 0x0a, 0x13, 0x4c, 0x69,
+	0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x3a, 0x1c, 0x92, 0x41, 0x19, 0x0a, 0x17, 0x32, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x70,
+	0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22,
+	0x84, 0x02, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x12, 0xd4, 0x01, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28,
+	0x09, 0x42, 0xc3, 0x01, 0x92, 0x41, 0xa6, 0x01, 0x32, 0x87, 0x01, 0x46, 0x6f, 0x72, 0x20, 0x62,
+	0x6c, 0x6f, 0x62, 0x2c, 0x20, 0x64, 0x69, 0x73, 0x6b, 0x2c, 0x20, 0x67, 0x69, 0x74, 0x20, 0x73,
+	0x74, 0x6f, 0x72, 0x65, 0x73, 0x20, 0x75, 0x73, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x6e,
+	0x61, 0x6d, 0x65, 0x20, 0x28, 0x3c, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x3e, 0x2e,
+	0x79, 0x61, 0x6d, 0x6c, 0x29, 0x2e, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x6d, 0x79, 0x73, 0x71, 0x6c,
+	0x2c, 0x20, 0x70, 0x6f, 0x73, 0x74, 0x67, 0x72, 0x65, 0x73, 0x2c, 0x20, 0x73, 0x71, 0x6c, 0x69,
+	0x74, 0x65, 0x33, 0x20, 0x75, 0x73, 0x65, 0x20, 0x69, 0x64, 0x20, 0x28, 0x3c, 0x6b, 0x69, 0x6e,
+	0x64, 0x3e, 0x2e, 0x3c, 0x6e, 0x61, 0x6d, 0x65, 0x3e, 0x2e, 0x3c, 0x76, 0x65, 0x72, 0x73, 0x69,
+	0x6f, 0x6e, 0x3e, 0x29, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69,
+	0x63, 0x79, 0x4a, 0x1a, 0x22, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x73,
+	0x61, 0x72, 0x61, 0x68, 0x2e, 0x76, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0xe2, 0x41,
+	0x01, 0x02, 0xfa, 0x42, 0x12, 0x92, 0x01, 0x0f, 0x08, 0x01, 0x10, 0x19, 0x18, 0x01, 0x22, 0x07,
+	0x72, 0x05, 0x10, 0x01, 0x18, 0x80, 0x0a, 0x52, 0x02, 0x69, 0x64, 0x3a, 0x19, 0x92, 0x41, 0x16,
+	0x0a, 0x14, 0x32, 0x12, 0x47, 0x65, 0x74, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x72,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x9b, 0x01, 0x0a, 0x18, 0x41, 0x64, 0x64, 0x4f, 0x72,
+	0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x5d, 0x0a, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x01,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x73, 0x63,
+	0x68, 0x65, 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x42, 0x29,
+	0x92, 0x41, 0x18, 0x32, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x63, 0x68,
+	0x65, 0x6d, 0x61, 0x73, 0x2e, 0xa0, 0x01, 0x0a, 0xa8, 0x01, 0x01, 0xe2, 0x41, 0x01, 0x02, 0xfa,
+	0x42, 0x07, 0x92, 0x01, 0x04, 0x08, 0x01, 0x10, 0x0a, 0x52, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d,
+	0x61, 0x73, 0x3a, 0x20, 0x92, 0x41, 0x1d, 0x0a, 0x1b, 0x32, 0x19, 0x41, 0x64, 0x64, 0x2f, 0x75,
+	0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x20, 0x72, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x22, 0x34, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x3a, 0x1e, 0x92, 0x41, 0x1b, 0x0a,
+	0x19, 0x32, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x20, 0x69,
+	0x64, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x92, 0x01, 0x0a, 0x10, 0x47,
+	0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+	0x60, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x50, 0x92, 0x41, 0x34,
+	0x32, 0x20, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66,
+	0x69, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x4a, 0x10, 0x22, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x6a,
+	0x73, 0x6f, 0x6e, 0x22, 0xe2, 0x41, 0x01, 0x02, 0xfa, 0x42, 0x12, 0x92, 0x01, 0x0f, 0x08, 0x01,
+	0x10, 0x19, 0x18, 0x01, 0x22, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x52, 0x02, 0x69,
+	0x64, 0x3a, 0x1c, 0x92, 0x41, 0x19, 0x0a, 0x17, 0x32, 0x15, 0x47, 0x65, 0x74, 0x20, 0x73, 0x63,
+	0x68, 0x65, 0x6d, 0x61, 0x28, 0x73, 0x29, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22,
+	0x98, 0x01, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
+	0x03, 0x28, 0x09, 0x42, 0x50, 0x92, 0x41, 0x34, 0x32, 0x20, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65,
+	0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20,
+	0x74, 0x68, 0x65, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4a, 0x10, 0x22, 0x70, 0x72, 0x69,
+	0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x6a, 0x73, 0x6f, 0x6e, 0x22, 0xe2, 0x41, 0x01, 0x02,
+	0xfa, 0x42, 0x12, 0x92, 0x01, 0x0f, 0x08, 0x01, 0x10, 0x19, 0x18, 0x01, 0x22, 0x07, 0x72, 0x05,
+	0x10, 0x01, 0x18, 0xff, 0x01, 0x52, 0x02, 0x69, 0x64, 0x3a, 0x1f, 0x92, 0x41, 0x1c, 0x0a, 0x1a,
+	0x32, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x28,
+	0x73, 0x29, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x7a, 0x0a, 0x12, 0x52, 0x65,
+	0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x12, 0x47, 0x0a, 0x04, 0x77, 0x61, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x42, 0x33,
+	0x92, 0x41, 0x2c, 0x32, 0x2a, 0x57, 0x61, 0x69, 0x74, 0x20, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x20,
+	0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x72,
+	0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x73, 0xe2,
+	0x41, 0x01, 0x01, 0x52, 0x04, 0x77, 0x61, 0x69, 0x74, 0x3a, 0x1b, 0x92, 0x41, 0x18, 0x0a, 0x16,
+	0x32, 0x14, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x72,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x73, 0x0a, 0x19, 0x64, 0x65, 0x76, 0x2e, 0x63, 0x65,
+	0x72, 0x62, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x72, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+	0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2f, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2f, 0x61, 0x70,
+	0x69, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x62, 0x2f, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2f, 0x72,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x76, 0x31, 0xaa, 0x02, 0x15, 0x43, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69,
+	0x2e, 0x56, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x33,
 }
 
 var (
@@ -2352,22 +2372,23 @@ var file_cerbos_request_v1_request_proto_depIdxs = []int32{
 	2,  // 22: cerbos.request.v1.PlaygroundProxyRequest.check_resource_set:type_name -> cerbos.request.v1.CheckResourceSetRequest
 	5,  // 23: cerbos.request.v1.PlaygroundProxyRequest.check_resource_batch:type_name -> cerbos.request.v1.CheckResourceBatchRequest
 	1,  // 24: cerbos.request.v1.PlaygroundProxyRequest.resources_query_plan:type_name -> cerbos.request.v1.ResourcesQueryPlanRequest
-	32, // 25: cerbos.request.v1.AddOrUpdatePolicyRequest.policies:type_name -> cerbos.policy.v1.Policy
-	0,  // 26: cerbos.request.v1.ListAuditLogEntriesRequest.kind:type_name -> cerbos.request.v1.ListAuditLogEntriesRequest.Kind
-	28, // 27: cerbos.request.v1.ListAuditLogEntriesRequest.between:type_name -> cerbos.request.v1.ListAuditLogEntriesRequest.TimeRange
-	33, // 28: cerbos.request.v1.ListAuditLogEntriesRequest.since:type_name -> google.protobuf.Duration
-	34, // 29: cerbos.request.v1.AddOrUpdateSchemaRequest.schemas:type_name -> cerbos.schema.v1.Schema
-	4,  // 30: cerbos.request.v1.ResourceSet.InstancesEntry.value:type_name -> cerbos.request.v1.AttributesMap
-	35, // 31: cerbos.request.v1.AttributesMap.AttrEntry.value:type_name -> google.protobuf.Value
-	31, // 32: cerbos.request.v1.CheckResourceBatchRequest.BatchEntry.resource:type_name -> cerbos.engine.v1.Resource
-	31, // 33: cerbos.request.v1.CheckResourcesRequest.ResourceEntry.resource:type_name -> cerbos.engine.v1.Resource
-	36, // 34: cerbos.request.v1.ListAuditLogEntriesRequest.TimeRange.start:type_name -> google.protobuf.Timestamp
-	36, // 35: cerbos.request.v1.ListAuditLogEntriesRequest.TimeRange.end:type_name -> google.protobuf.Timestamp
-	36, // [36:36] is the sub-list for method output_type
-	36, // [36:36] is the sub-list for method input_type
-	36, // [36:36] is the sub-list for extension type_name
-	36, // [36:36] is the sub-list for extension extendee
-	0,  // [0:36] is the sub-list for field type_name
+	6,  // 25: cerbos.request.v1.PlaygroundProxyRequest.check_resources:type_name -> cerbos.request.v1.CheckResourcesRequest
+	32, // 26: cerbos.request.v1.AddOrUpdatePolicyRequest.policies:type_name -> cerbos.policy.v1.Policy
+	0,  // 27: cerbos.request.v1.ListAuditLogEntriesRequest.kind:type_name -> cerbos.request.v1.ListAuditLogEntriesRequest.Kind
+	28, // 28: cerbos.request.v1.ListAuditLogEntriesRequest.between:type_name -> cerbos.request.v1.ListAuditLogEntriesRequest.TimeRange
+	33, // 29: cerbos.request.v1.ListAuditLogEntriesRequest.since:type_name -> google.protobuf.Duration
+	34, // 30: cerbos.request.v1.AddOrUpdateSchemaRequest.schemas:type_name -> cerbos.schema.v1.Schema
+	4,  // 31: cerbos.request.v1.ResourceSet.InstancesEntry.value:type_name -> cerbos.request.v1.AttributesMap
+	35, // 32: cerbos.request.v1.AttributesMap.AttrEntry.value:type_name -> google.protobuf.Value
+	31, // 33: cerbos.request.v1.CheckResourceBatchRequest.BatchEntry.resource:type_name -> cerbos.engine.v1.Resource
+	31, // 34: cerbos.request.v1.CheckResourcesRequest.ResourceEntry.resource:type_name -> cerbos.engine.v1.Resource
+	36, // 35: cerbos.request.v1.ListAuditLogEntriesRequest.TimeRange.start:type_name -> google.protobuf.Timestamp
+	36, // 36: cerbos.request.v1.ListAuditLogEntriesRequest.TimeRange.end:type_name -> google.protobuf.Timestamp
+	37, // [37:37] is the sub-list for method output_type
+	37, // [37:37] is the sub-list for method input_type
+	37, // [37:37] is the sub-list for extension type_name
+	37, // [37:37] is the sub-list for extension extendee
+	0,  // [0:37] is the sub-list for field type_name
 }
 
 func init() { file_cerbos_request_v1_request_proto_init() }
@@ -2693,6 +2714,7 @@ func file_cerbos_request_v1_request_proto_init() {
 		(*PlaygroundProxyRequest_CheckResourceSet)(nil),
 		(*PlaygroundProxyRequest_CheckResourceBatch)(nil),
 		(*PlaygroundProxyRequest_ResourcesQueryPlan)(nil),
+		(*PlaygroundProxyRequest_CheckResources)(nil),
 	}
 	file_cerbos_request_v1_request_proto_msgTypes[13].OneofWrappers = []interface{}{
 		(*ListAuditLogEntriesRequest_Tail)(nil),
diff --git a/api/genpb/cerbos/request/v1/request.pb.validate.go b/api/genpb/cerbos/request/v1/request.pb.validate.go
index 560a3fb9..103f880a 100644
--- a/api/genpb/cerbos/request/v1/request.pb.validate.go
+++ b/api/genpb/cerbos/request/v1/request.pb.validate.go
@@ -2319,6 +2319,37 @@ func (m *PlaygroundProxyRequest) validate(all bool) error {
 			}
 		}
 
+	case *PlaygroundProxyRequest_CheckResources:
+
+		if all {
+			switch v := interface{}(m.GetCheckResources()).(type) {
+			case interface{ ValidateAll() error }:
+				if err := v.ValidateAll(); err != nil {
+					errors = append(errors, PlaygroundProxyRequestValidationError{
+						field:  "CheckResources",
+						reason: "embedded message failed validation",
+						cause:  err,
+					})
+				}
+			case interface{ Validate() error }:
+				if err := v.Validate(); err != nil {
+					errors = append(errors, PlaygroundProxyRequestValidationError{
+						field:  "CheckResources",
+						reason: "embedded message failed validation",
+						cause:  err,
+					})
+				}
+			}
+		} else if v, ok := interface{}(m.GetCheckResources()).(interface{ Validate() error }); ok {
+			if err := v.Validate(); err != nil {
+				return PlaygroundProxyRequestValidationError{
+					field:  "CheckResources",
+					reason: "embedded message failed validation",
+					cause:  err,
+				}
+			}
+		}
+
 	default:
 		err := PlaygroundProxyRequestValidationError{
 			field:  "ProxyRequest",
diff --git a/api/genpb/cerbos/request/v1/request_vtproto.pb.go b/api/genpb/cerbos/request/v1/request_vtproto.pb.go
index bfae3fbe..fa264b10 100644
--- a/api/genpb/cerbos/request/v1/request_vtproto.pb.go
+++ b/api/genpb/cerbos/request/v1/request_vtproto.pb.go
@@ -1163,6 +1163,25 @@ func (m *PlaygroundProxyRequest_ResourcesQueryPlan) MarshalToSizedBufferVT(dAtA
 	}
 	return len(dAtA) - i, nil
 }
+func (m *PlaygroundProxyRequest_CheckResources) MarshalToVT(dAtA []byte) (int, error) {
+	size := m.SizeVT()
+	return m.MarshalToSizedBufferVT(dAtA[:size])
+}
+
+func (m *PlaygroundProxyRequest_CheckResources) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	if m.CheckResources != nil {
+		size, err := m.CheckResources.MarshalToSizedBufferVT(dAtA[:i])
+		if err != nil {
+			return 0, err
+		}
+		i -= size
+		i = encodeVarint(dAtA, i, uint64(size))
+		i--
+		dAtA[i] = 0x32
+	}
+	return len(dAtA) - i, nil
+}
 func (m *AddOrUpdatePolicyRequest) MarshalVT() (dAtA []byte, err error) {
 	if m == nil {
 		return nil, nil
@@ -2261,6 +2280,18 @@ func (m *PlaygroundProxyRequest_ResourcesQueryPlan) SizeVT() (n int) {
 	}
 	return n
 }
+func (m *PlaygroundProxyRequest_CheckResources) SizeVT() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	if m.CheckResources != nil {
+		l = m.CheckResources.SizeVT()
+		n += 1 + l + sov(uint64(l))
+	}
+	return n
+}
 func (m *AddOrUpdatePolicyRequest) SizeVT() (n int) {
 	if m == nil {
 		return 0
@@ -5205,6 +5236,47 @@ func (m *PlaygroundProxyRequest) UnmarshalVT(dAtA []byte) error {
 				m.ProxyRequest = &PlaygroundProxyRequest_ResourcesQueryPlan{v}
 			}
 			iNdEx = postIndex
+		case 6:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field CheckResources", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflow
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLength
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLength
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if oneof, ok := m.ProxyRequest.(*PlaygroundProxyRequest_CheckResources); ok {
+				if err := oneof.CheckResources.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
+					return err
+				}
+			} else {
+				v := &CheckResourcesRequest{}
+				if err := v.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
+					return err
+				}
+				m.ProxyRequest = &PlaygroundProxyRequest_CheckResources{v}
+			}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skip(dAtA[iNdEx:])
diff --git a/api/genpb/cerbos/response/v1/hashpb_helpers.pb.go b/api/genpb/cerbos/response/v1/hashpb_helpers.pb.go
index 857e89b2..3d98eccd 100644
--- a/api/genpb/cerbos/response/v1/hashpb_helpers.pb.go
+++ b/api/genpb/cerbos/response/v1/hashpb_helpers.pb.go
@@ -1471,6 +1471,11 @@ func cerbos_response_v1_PlaygroundProxyResponse_hashpb_sum(m *PlaygroundProxyRes
 					cerbos_response_v1_ResourcesQueryPlanResponse_hashpb_sum(t.ResourcesQueryPlan, hasher, ignore)
 				}
 
+			case *PlaygroundProxyResponse_CheckResources:
+				if t.CheckResources != nil {
+					cerbos_response_v1_CheckResourcesResponse_hashpb_sum(t.CheckResources, hasher, ignore)
+				}
+
 			}
 		}
 	}
diff --git a/api/genpb/cerbos/response/v1/response.pb.go b/api/genpb/cerbos/response/v1/response.pb.go
index 8028b69b..460341bc 100644
--- a/api/genpb/cerbos/response/v1/response.pb.go
+++ b/api/genpb/cerbos/response/v1/response.pb.go
@@ -666,6 +666,7 @@ type PlaygroundProxyResponse struct {
 	//	*PlaygroundProxyResponse_CheckResourceSet
 	//	*PlaygroundProxyResponse_CheckResourceBatch
 	//	*PlaygroundProxyResponse_ResourcesQueryPlan
+	//	*PlaygroundProxyResponse_CheckResources
 	Outcome isPlaygroundProxyResponse_Outcome `protobuf_oneof:"outcome"`
 }
 
@@ -743,6 +744,13 @@ func (x *PlaygroundProxyResponse) GetResourcesQueryPlan() *ResourcesQueryPlanRes
 	return nil
 }
 
+func (x *PlaygroundProxyResponse) GetCheckResources() *CheckResourcesResponse {
+	if x, ok := x.GetOutcome().(*PlaygroundProxyResponse_CheckResources); ok {
+		return x.CheckResources
+	}
+	return nil
+}
+
 type isPlaygroundProxyResponse_Outcome interface {
 	isPlaygroundProxyResponse_Outcome()
 }
@@ -763,6 +771,10 @@ type PlaygroundProxyResponse_ResourcesQueryPlan struct {
 	ResourcesQueryPlan *ResourcesQueryPlanResponse `protobuf:"bytes,5,opt,name=resources_query_plan,json=resourcesQueryPlan,proto3,oneof"`
 }
 
+type PlaygroundProxyResponse_CheckResources struct {
+	CheckResources *CheckResourcesResponse `protobuf:"bytes,6,opt,name=check_resources,json=checkResources,proto3,oneof"`
+}
+
 func (*PlaygroundProxyResponse_Failure) isPlaygroundProxyResponse_Outcome() {}
 
 func (*PlaygroundProxyResponse_CheckResourceSet) isPlaygroundProxyResponse_Outcome() {}
@@ -771,6 +783,8 @@ func (*PlaygroundProxyResponse_CheckResourceBatch) isPlaygroundProxyResponse_Out
 
 func (*PlaygroundProxyResponse_ResourcesQueryPlan) isPlaygroundProxyResponse_Outcome() {}
 
+func (*PlaygroundProxyResponse_CheckResources) isPlaygroundProxyResponse_Outcome() {}
+
 type AddOrUpdatePolicyResponse struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -2844,7 +2858,7 @@ var file_cerbos_response_v1_response_proto_rawDesc = []byte{
 	0x3a, 0x23, 0x92, 0x41, 0x20, 0x0a, 0x1e, 0x32, 0x1c, 0x50, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f,
 	0x75, 0x6e, 0x64, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x72, 0x65, 0x73,
 	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65,
-	0x22, 0xd4, 0x03, 0x0a, 0x17, 0x50, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x50,
+	0x22, 0xab, 0x04, 0x0a, 0x17, 0x50, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x50,
 	0x72, 0x6f, 0x78, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d,
 	0x70, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
 	0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49,
@@ -2870,84 +2884,89 @@ var file_cerbos_response_v1_response_proto_rawDesc = []byte{
 	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
 	0x63, 0x65, 0x73, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70,
 	0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
-	0x73, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x3a, 0x20, 0x92, 0x41, 0x1d, 0x0a,
-	0x1b, 0x32, 0x19, 0x50, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x70, 0x72,
-	0x6f, 0x78, 0x79, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07,
-	0x6f, 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x22, 0x70, 0x0a, 0x19, 0x41, 0x64, 0x64, 0x4f, 0x72,
-	0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x07, 0x73,
-	0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x3a, 0x21, 0x92, 0x41, 0x1e, 0x0a, 0x1c, 0x32, 0x1a, 0x41,
-	0x64, 0x64, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
-	0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe0, 0x01, 0x0a, 0x1b, 0x4c, 0x69,
-	0x73, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65,
-	0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x10, 0x61, 0x63, 0x63,
-	0x65, 0x73, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x64,
-	0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x45,
-	0x6e, 0x74, 0x72, 0x79, 0x48, 0x00, 0x52, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f,
-	0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x51, 0x0a, 0x12, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69,
-	0x6f, 0x6e, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x64, 0x69,
-	0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x67,
-	0x45, 0x6e, 0x74, 0x72, 0x79, 0x48, 0x00, 0x52, 0x10, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f,
-	0x6e, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x3a, 0x18, 0x92, 0x41, 0x15, 0x0a, 0x13,
-	0x32, 0x11, 0x41, 0x75, 0x64, 0x69, 0x74, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x73, 0x74, 0x72, 0x65,
-	0x61, 0x6d, 0x2e, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x82, 0x01, 0x0a,
-	0x12, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a,
-	0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63,
-	0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64,
-	0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x69, 0x6c, 0x64,
-	0x44, 0x61, 0x74, 0x65, 0x3a, 0x1b, 0x92, 0x41, 0x18, 0x0a, 0x16, 0x32, 0x14, 0x53, 0x65, 0x72,
-	0x76, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x22, 0x6a, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65,
-	0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x6f, 0x6c,
-	0x69, 0x63, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x70,
-	0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49, 0x64, 0x73, 0x3a, 0x33, 0x92, 0x41, 0x30, 0x0a, 0x2e, 0x32,
-	0x2c, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65,
-	0x73, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20,
-	0x43, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x65, 0x0a,
-	0x11, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x12, 0x34, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01,
-	0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f,
-	0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08,
-	0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x3a, 0x1a, 0x92, 0x41, 0x17, 0x0a, 0x15, 0x32,
-	0x13, 0x47, 0x65, 0x74, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x72, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3e, 0x0a, 0x19, 0x41, 0x64, 0x64, 0x4f, 0x72, 0x55, 0x70, 0x64,
-	0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x3a, 0x21, 0x92, 0x41, 0x1e, 0x0a, 0x1c, 0x32, 0x1a, 0x41, 0x64, 0x64, 0x2f, 0x75, 0x70,
-	0x64, 0x61, 0x74, 0x65, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x20, 0x72, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x22, 0x55, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65,
-	0x6d, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73,
-	0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52,
-	0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x49, 0x64, 0x73, 0x3a, 0x1f, 0x92, 0x41, 0x1c, 0x0a,
-	0x1a, 0x32, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x20, 0x69,
-	0x64, 0x73, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x66, 0x0a, 0x11, 0x47,
-	0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
-	0x12, 0x32, 0x0a, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
-	0x0b, 0x32, 0x18, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d,
-	0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x07, 0x73, 0x63, 0x68,
-	0x65, 0x6d, 0x61, 0x73, 0x3a, 0x1d, 0x92, 0x41, 0x1a, 0x0a, 0x18, 0x32, 0x16, 0x47, 0x65, 0x74,
-	0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x28, 0x73, 0x29, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x22, 0x38, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x68,
-	0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x3a, 0x20, 0x92, 0x41, 0x1d,
-	0x0a, 0x1b, 0x32, 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d,
-	0x61, 0x28, 0x73, 0x29, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x0a,
-	0x13, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x3a, 0x1c, 0x92, 0x41, 0x19, 0x0a, 0x17, 0x32, 0x15, 0x52, 0x65, 0x6c,
-	0x6f, 0x61, 0x64, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x42, 0x77, 0x0a, 0x1a, 0x64, 0x65, 0x76, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73,
-	0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
-	0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x65, 0x72,
-	0x62, 0x6f, 0x73, 0x2f, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67,
-	0x65, 0x6e, 0x70, 0x62, 0x2f, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2f, 0x72, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
-	0x76, 0x31, 0xaa, 0x02, 0x16, 0x43, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e,
-	0x56, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x33,
+	0x73, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x12, 0x55, 0x0a, 0x0f, 0x63, 0x68,
+	0x65, 0x63, 0x6b, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x06, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65,
+	0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48,
+	0x00, 0x52, 0x0e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+	0x73, 0x3a, 0x20, 0x92, 0x41, 0x1d, 0x0a, 0x1b, 0x32, 0x19, 0x50, 0x6c, 0x61, 0x79, 0x67, 0x72,
+	0x6f, 0x75, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x22, 0x70,
+	0x0a, 0x19, 0x41, 0x64, 0x64, 0x4f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x6c,
+	0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x07, 0x73,
+	0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67,
+	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45,
+	0x6d, 0x70, 0x74, 0x79, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x3a, 0x21, 0x92,
+	0x41, 0x1e, 0x0a, 0x1c, 0x32, 0x1a, 0x41, 0x64, 0x64, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
+	0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x22, 0xe0, 0x01, 0x0a, 0x1b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f,
+	0x67, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x12, 0x4b, 0x0a, 0x10, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x65,
+	0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x65, 0x72,
+	0x62, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63,
+	0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x48, 0x00, 0x52, 0x0e, 0x61,
+	0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x51, 0x0a,
+	0x12, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x65, 0x6e,
+	0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x65, 0x72, 0x62,
+	0x6f, 0x73, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x69,
+	0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x48, 0x00, 0x52, 0x10,
+	0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x3a, 0x18, 0x92, 0x41, 0x15, 0x0a, 0x13, 0x32, 0x11, 0x41, 0x75, 0x64, 0x69, 0x74, 0x20, 0x6c,
+	0x6f, 0x67, 0x20, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x6e,
+	0x74, 0x72, 0x79, 0x22, 0x82, 0x01, 0x0a, 0x12, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x6e,
+	0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65,
+	0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72,
+	0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x1d, 0x0a, 0x0a,
+	0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x09, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x1b, 0x92, 0x41, 0x18,
+	0x0a, 0x16, 0x32, 0x14, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x20,
+	0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6a, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74,
+	0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49, 0x64, 0x73, 0x3a,
+	0x33, 0x92, 0x41, 0x30, 0x0a, 0x2e, 0x32, 0x2c, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20,
+	0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20,
+	0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x20, 0x73, 0x65,
+	0x72, 0x76, 0x65, 0x72, 0x22, 0x65, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63,
+	0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x08, 0x70, 0x6f, 0x6c,
+	0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x65,
+	0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x50,
+	0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x3a,
+	0x1a, 0x92, 0x41, 0x17, 0x0a, 0x15, 0x32, 0x13, 0x47, 0x65, 0x74, 0x20, 0x70, 0x6f, 0x6c, 0x69,
+	0x63, 0x79, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3e, 0x0a, 0x19, 0x41,
+	0x64, 0x64, 0x4f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x3a, 0x21, 0x92, 0x41, 0x1e, 0x0a, 0x1c, 0x32,
+	0x1a, 0x41, 0x64, 0x64, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x73, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x55, 0x0a, 0x13, 0x4c,
+	0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x69, 0x64, 0x73,
+	0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x49, 0x64,
+	0x73, 0x3a, 0x1f, 0x92, 0x41, 0x1c, 0x0a, 0x1a, 0x32, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x73,
+	0x63, 0x68, 0x65, 0x6d, 0x61, 0x20, 0x69, 0x64, 0x73, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x22, 0x66, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d,
+	0x61, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f,
+	0x73, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x52, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x3a, 0x1d, 0x92, 0x41, 0x1a,
+	0x0a, 0x18, 0x32, 0x16, 0x47, 0x65, 0x74, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x28, 0x73,
+	0x29, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x38, 0x0a, 0x14, 0x44, 0x65,
+	0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x3a, 0x20, 0x92, 0x41, 0x1d, 0x0a, 0x1b, 0x32, 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74,
+	0x65, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x28, 0x73, 0x29, 0x20, 0x72, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x0a, 0x13, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74,
+	0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x3a, 0x1c, 0x92, 0x41, 0x19,
+	0x0a, 0x17, 0x32, 0x15, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65,
+	0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x77, 0x0a, 0x1a, 0x64, 0x65, 0x76,
+	0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x72,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
+	0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2f, 0x63, 0x65, 0x72, 0x62, 0x6f,
+	0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x62, 0x2f, 0x63, 0x65, 0x72, 0x62,
+	0x6f, 0x73, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x72,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x76, 0x31, 0xaa, 0x02, 0x16, 0x43, 0x65, 0x72, 0x62,
+	0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -3036,42 +3055,43 @@ var file_cerbos_response_v1_response_proto_depIdxs = []int32{
 	2,  // 14: cerbos.response.v1.PlaygroundProxyResponse.check_resource_set:type_name -> cerbos.response.v1.CheckResourceSetResponse
 	3,  // 15: cerbos.response.v1.PlaygroundProxyResponse.check_resource_batch:type_name -> cerbos.response.v1.CheckResourceBatchResponse
 	1,  // 16: cerbos.response.v1.PlaygroundProxyResponse.resources_query_plan:type_name -> cerbos.response.v1.ResourcesQueryPlanResponse
-	43, // 17: cerbos.response.v1.AddOrUpdatePolicyResponse.success:type_name -> google.protobuf.Empty
-	45, // 18: cerbos.response.v1.ListAuditLogEntriesResponse.access_log_entry:type_name -> cerbos.audit.v1.AccessLogEntry
-	46, // 19: cerbos.response.v1.ListAuditLogEntriesResponse.decision_log_entry:type_name -> cerbos.audit.v1.DecisionLogEntry
-	47, // 20: cerbos.response.v1.GetPolicyResponse.policies:type_name -> cerbos.policy.v1.Policy
-	48, // 21: cerbos.response.v1.GetSchemaResponse.schemas:type_name -> cerbos.schema.v1.Schema
-	23, // 22: cerbos.response.v1.ResourcesQueryPlanResponse.Expression.operands:type_name -> cerbos.response.v1.ResourcesQueryPlanResponse.Expression.Operand
-	0,  // 23: cerbos.response.v1.ResourcesQueryPlanResponse.Filter.kind:type_name -> cerbos.response.v1.ResourcesQueryPlanResponse.Filter.Kind
-	23, // 24: cerbos.response.v1.ResourcesQueryPlanResponse.Filter.condition:type_name -> cerbos.response.v1.ResourcesQueryPlanResponse.Expression.Operand
-	49, // 25: cerbos.response.v1.ResourcesQueryPlanResponse.Expression.Operand.value:type_name -> google.protobuf.Value
-	20, // 26: cerbos.response.v1.ResourcesQueryPlanResponse.Expression.Operand.expression:type_name -> cerbos.response.v1.ResourcesQueryPlanResponse.Expression
-	27, // 27: cerbos.response.v1.CheckResourceSetResponse.ActionEffectMap.actions:type_name -> cerbos.response.v1.CheckResourceSetResponse.ActionEffectMap.ActionsEntry
-	50, // 28: cerbos.response.v1.CheckResourceSetResponse.ActionEffectMap.validation_errors:type_name -> cerbos.schema.v1.ValidationError
-	30, // 29: cerbos.response.v1.CheckResourceSetResponse.Meta.resource_instances:type_name -> cerbos.response.v1.CheckResourceSetResponse.Meta.ResourceInstancesEntry
-	24, // 30: cerbos.response.v1.CheckResourceSetResponse.ResourceInstancesEntry.value:type_name -> cerbos.response.v1.CheckResourceSetResponse.ActionEffectMap
-	51, // 31: cerbos.response.v1.CheckResourceSetResponse.ActionEffectMap.ActionsEntry.value:type_name -> cerbos.effect.v1.Effect
-	31, // 32: cerbos.response.v1.CheckResourceSetResponse.Meta.ActionMeta.actions:type_name -> cerbos.response.v1.CheckResourceSetResponse.Meta.ActionMeta.ActionsEntry
-	29, // 33: cerbos.response.v1.CheckResourceSetResponse.Meta.ResourceInstancesEntry.value:type_name -> cerbos.response.v1.CheckResourceSetResponse.Meta.ActionMeta
-	28, // 34: cerbos.response.v1.CheckResourceSetResponse.Meta.ActionMeta.ActionsEntry.value:type_name -> cerbos.response.v1.CheckResourceSetResponse.Meta.EffectMeta
-	33, // 35: cerbos.response.v1.CheckResourceBatchResponse.ActionEffectMap.actions:type_name -> cerbos.response.v1.CheckResourceBatchResponse.ActionEffectMap.ActionsEntry
-	50, // 36: cerbos.response.v1.CheckResourceBatchResponse.ActionEffectMap.validation_errors:type_name -> cerbos.schema.v1.ValidationError
-	51, // 37: cerbos.response.v1.CheckResourceBatchResponse.ActionEffectMap.ActionsEntry.value:type_name -> cerbos.effect.v1.Effect
-	35, // 38: cerbos.response.v1.CheckResourcesResponse.ResultEntry.resource:type_name -> cerbos.response.v1.CheckResourcesResponse.ResultEntry.Resource
-	37, // 39: cerbos.response.v1.CheckResourcesResponse.ResultEntry.actions:type_name -> cerbos.response.v1.CheckResourcesResponse.ResultEntry.ActionsEntry
-	50, // 40: cerbos.response.v1.CheckResourcesResponse.ResultEntry.validation_errors:type_name -> cerbos.schema.v1.ValidationError
-	36, // 41: cerbos.response.v1.CheckResourcesResponse.ResultEntry.meta:type_name -> cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta
-	39, // 42: cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta.actions:type_name -> cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta.ActionsEntry
-	51, // 43: cerbos.response.v1.CheckResourcesResponse.ResultEntry.ActionsEntry.value:type_name -> cerbos.effect.v1.Effect
-	38, // 44: cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta.ActionsEntry.value:type_name -> cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta.EffectMeta
-	51, // 45: cerbos.response.v1.PlaygroundEvaluateResponse.EvalResult.effect:type_name -> cerbos.effect.v1.Effect
-	50, // 46: cerbos.response.v1.PlaygroundEvaluateResponse.EvalResult.validation_errors:type_name -> cerbos.schema.v1.ValidationError
-	41, // 47: cerbos.response.v1.PlaygroundEvaluateResponse.EvalResultList.results:type_name -> cerbos.response.v1.PlaygroundEvaluateResponse.EvalResult
-	48, // [48:48] is the sub-list for method output_type
-	48, // [48:48] is the sub-list for method input_type
-	48, // [48:48] is the sub-list for extension type_name
-	48, // [48:48] is the sub-list for extension extendee
-	0,  // [0:48] is the sub-list for field type_name
+	4,  // 17: cerbos.response.v1.PlaygroundProxyResponse.check_resources:type_name -> cerbos.response.v1.CheckResourcesResponse
+	43, // 18: cerbos.response.v1.AddOrUpdatePolicyResponse.success:type_name -> google.protobuf.Empty
+	45, // 19: cerbos.response.v1.ListAuditLogEntriesResponse.access_log_entry:type_name -> cerbos.audit.v1.AccessLogEntry
+	46, // 20: cerbos.response.v1.ListAuditLogEntriesResponse.decision_log_entry:type_name -> cerbos.audit.v1.DecisionLogEntry
+	47, // 21: cerbos.response.v1.GetPolicyResponse.policies:type_name -> cerbos.policy.v1.Policy
+	48, // 22: cerbos.response.v1.GetSchemaResponse.schemas:type_name -> cerbos.schema.v1.Schema
+	23, // 23: cerbos.response.v1.ResourcesQueryPlanResponse.Expression.operands:type_name -> cerbos.response.v1.ResourcesQueryPlanResponse.Expression.Operand
+	0,  // 24: cerbos.response.v1.ResourcesQueryPlanResponse.Filter.kind:type_name -> cerbos.response.v1.ResourcesQueryPlanResponse.Filter.Kind
+	23, // 25: cerbos.response.v1.ResourcesQueryPlanResponse.Filter.condition:type_name -> cerbos.response.v1.ResourcesQueryPlanResponse.Expression.Operand
+	49, // 26: cerbos.response.v1.ResourcesQueryPlanResponse.Expression.Operand.value:type_name -> google.protobuf.Value
+	20, // 27: cerbos.response.v1.ResourcesQueryPlanResponse.Expression.Operand.expression:type_name -> cerbos.response.v1.ResourcesQueryPlanResponse.Expression
+	27, // 28: cerbos.response.v1.CheckResourceSetResponse.ActionEffectMap.actions:type_name -> cerbos.response.v1.CheckResourceSetResponse.ActionEffectMap.ActionsEntry
+	50, // 29: cerbos.response.v1.CheckResourceSetResponse.ActionEffectMap.validation_errors:type_name -> cerbos.schema.v1.ValidationError
+	30, // 30: cerbos.response.v1.CheckResourceSetResponse.Meta.resource_instances:type_name -> cerbos.response.v1.CheckResourceSetResponse.Meta.ResourceInstancesEntry
+	24, // 31: cerbos.response.v1.CheckResourceSetResponse.ResourceInstancesEntry.value:type_name -> cerbos.response.v1.CheckResourceSetResponse.ActionEffectMap
+	51, // 32: cerbos.response.v1.CheckResourceSetResponse.ActionEffectMap.ActionsEntry.value:type_name -> cerbos.effect.v1.Effect
+	31, // 33: cerbos.response.v1.CheckResourceSetResponse.Meta.ActionMeta.actions:type_name -> cerbos.response.v1.CheckResourceSetResponse.Meta.ActionMeta.ActionsEntry
+	29, // 34: cerbos.response.v1.CheckResourceSetResponse.Meta.ResourceInstancesEntry.value:type_name -> cerbos.response.v1.CheckResourceSetResponse.Meta.ActionMeta
+	28, // 35: cerbos.response.v1.CheckResourceSetResponse.Meta.ActionMeta.ActionsEntry.value:type_name -> cerbos.response.v1.CheckResourceSetResponse.Meta.EffectMeta
+	33, // 36: cerbos.response.v1.CheckResourceBatchResponse.ActionEffectMap.actions:type_name -> cerbos.response.v1.CheckResourceBatchResponse.ActionEffectMap.ActionsEntry
+	50, // 37: cerbos.response.v1.CheckResourceBatchResponse.ActionEffectMap.validation_errors:type_name -> cerbos.schema.v1.ValidationError
+	51, // 38: cerbos.response.v1.CheckResourceBatchResponse.ActionEffectMap.ActionsEntry.value:type_name -> cerbos.effect.v1.Effect
+	35, // 39: cerbos.response.v1.CheckResourcesResponse.ResultEntry.resource:type_name -> cerbos.response.v1.CheckResourcesResponse.ResultEntry.Resource
+	37, // 40: cerbos.response.v1.CheckResourcesResponse.ResultEntry.actions:type_name -> cerbos.response.v1.CheckResourcesResponse.ResultEntry.ActionsEntry
+	50, // 41: cerbos.response.v1.CheckResourcesResponse.ResultEntry.validation_errors:type_name -> cerbos.schema.v1.ValidationError
+	36, // 42: cerbos.response.v1.CheckResourcesResponse.ResultEntry.meta:type_name -> cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta
+	39, // 43: cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta.actions:type_name -> cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta.ActionsEntry
+	51, // 44: cerbos.response.v1.CheckResourcesResponse.ResultEntry.ActionsEntry.value:type_name -> cerbos.effect.v1.Effect
+	38, // 45: cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta.ActionsEntry.value:type_name -> cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta.EffectMeta
+	51, // 46: cerbos.response.v1.PlaygroundEvaluateResponse.EvalResult.effect:type_name -> cerbos.effect.v1.Effect
+	50, // 47: cerbos.response.v1.PlaygroundEvaluateResponse.EvalResult.validation_errors:type_name -> cerbos.schema.v1.ValidationError
+	41, // 48: cerbos.response.v1.PlaygroundEvaluateResponse.EvalResultList.results:type_name -> cerbos.response.v1.PlaygroundEvaluateResponse.EvalResult
+	49, // [49:49] is the sub-list for method output_type
+	49, // [49:49] is the sub-list for method input_type
+	49, // [49:49] is the sub-list for extension type_name
+	49, // [49:49] is the sub-list for extension extendee
+	0,  // [0:49] is the sub-list for field type_name
 }
 
 func init() { file_cerbos_response_v1_response_proto_init() }
@@ -3518,6 +3538,7 @@ func file_cerbos_response_v1_response_proto_init() {
 		(*PlaygroundProxyResponse_CheckResourceSet)(nil),
 		(*PlaygroundProxyResponse_CheckResourceBatch)(nil),
 		(*PlaygroundProxyResponse_ResourcesQueryPlan)(nil),
+		(*PlaygroundProxyResponse_CheckResources)(nil),
 	}
 	file_cerbos_response_v1_response_proto_msgTypes[10].OneofWrappers = []interface{}{
 		(*ListAuditLogEntriesResponse_AccessLogEntry)(nil),
diff --git a/api/genpb/cerbos/response/v1/response.pb.validate.go b/api/genpb/cerbos/response/v1/response.pb.validate.go
index a33c7518..6851ae4a 100644
--- a/api/genpb/cerbos/response/v1/response.pb.validate.go
+++ b/api/genpb/cerbos/response/v1/response.pb.validate.go
@@ -1458,6 +1458,37 @@ func (m *PlaygroundProxyResponse) validate(all bool) error {
 			}
 		}
 
+	case *PlaygroundProxyResponse_CheckResources:
+
+		if all {
+			switch v := interface{}(m.GetCheckResources()).(type) {
+			case interface{ ValidateAll() error }:
+				if err := v.ValidateAll(); err != nil {
+					errors = append(errors, PlaygroundProxyResponseValidationError{
+						field:  "CheckResources",
+						reason: "embedded message failed validation",
+						cause:  err,
+					})
+				}
+			case interface{ Validate() error }:
+				if err := v.Validate(); err != nil {
+					errors = append(errors, PlaygroundProxyResponseValidationError{
+						field:  "CheckResources",
+						reason: "embedded message failed validation",
+						cause:  err,
+					})
+				}
+			}
+		} else if v, ok := interface{}(m.GetCheckResources()).(interface{ Validate() error }); ok {
+			if err := v.Validate(); err != nil {
+				return PlaygroundProxyResponseValidationError{
+					field:  "CheckResources",
+					reason: "embedded message failed validation",
+					cause:  err,
+				}
+			}
+		}
+
 	}
 
 	if len(errors) > 0 {
diff --git a/api/genpb/cerbos/response/v1/response_vtproto.pb.go b/api/genpb/cerbos/response/v1/response_vtproto.pb.go
index 90d0dee9..48e5f050 100644
--- a/api/genpb/cerbos/response/v1/response_vtproto.pb.go
+++ b/api/genpb/cerbos/response/v1/response_vtproto.pb.go
@@ -1769,6 +1769,25 @@ func (m *PlaygroundProxyResponse_ResourcesQueryPlan) MarshalToSizedBufferVT(dAtA
 	}
 	return len(dAtA) - i, nil
 }
+func (m *PlaygroundProxyResponse_CheckResources) MarshalToVT(dAtA []byte) (int, error) {
+	size := m.SizeVT()
+	return m.MarshalToSizedBufferVT(dAtA[:size])
+}
+
+func (m *PlaygroundProxyResponse_CheckResources) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	if m.CheckResources != nil {
+		size, err := m.CheckResources.MarshalToSizedBufferVT(dAtA[:i])
+		if err != nil {
+			return 0, err
+		}
+		i -= size
+		i = encodeVarint(dAtA, i, uint64(size))
+		i--
+		dAtA[i] = 0x32
+	}
+	return len(dAtA) - i, nil
+}
 func (m *AddOrUpdatePolicyResponse) MarshalVT() (dAtA []byte, err error) {
 	if m == nil {
 		return nil, nil
@@ -3090,6 +3109,18 @@ func (m *PlaygroundProxyResponse_ResourcesQueryPlan) SizeVT() (n int) {
 	}
 	return n
 }
+func (m *PlaygroundProxyResponse_CheckResources) SizeVT() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	if m.CheckResources != nil {
+		l = m.CheckResources.SizeVT()
+		n += 1 + l + sov(uint64(l))
+	}
+	return n
+}
 func (m *AddOrUpdatePolicyResponse) SizeVT() (n int) {
 	if m == nil {
 		return 0
@@ -7545,6 +7576,47 @@ func (m *PlaygroundProxyResponse) UnmarshalVT(dAtA []byte) error {
 				m.Outcome = &PlaygroundProxyResponse_ResourcesQueryPlan{v}
 			}
 			iNdEx = postIndex
+		case 6:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field CheckResources", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflow
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLength
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLength
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if oneof, ok := m.Outcome.(*PlaygroundProxyResponse_CheckResources); ok {
+				if err := oneof.CheckResources.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
+					return err
+				}
+			} else {
+				v := &CheckResourcesResponse{}
+				if err := v.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
+					return err
+				}
+				m.Outcome = &PlaygroundProxyResponse_CheckResources{v}
+			}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skip(dAtA[iNdEx:])
diff --git a/api/public/cerbos/request/v1/request.proto b/api/public/cerbos/request/v1/request.proto
index 361f7dd2..2ab05b77 100644
--- a/api/public/cerbos/request/v1/request.proto
+++ b/api/public/cerbos/request/v1/request.proto
@@ -465,6 +465,7 @@ message PlaygroundProxyRequest {
     CheckResourceSetRequest check_resource_set = 3;
     CheckResourceBatchRequest check_resource_batch = 4;
     ResourcesQueryPlanRequest resources_query_plan = 5;
+    CheckResourcesRequest check_resources = 6;
   }
 }
 
diff --git a/api/public/cerbos/response/v1/response.proto b/api/public/cerbos/response/v1/response.proto
index 5c6b3a89..5035113a 100644
--- a/api/public/cerbos/response/v1/response.proto
+++ b/api/public/cerbos/response/v1/response.proto
@@ -377,6 +377,7 @@ message PlaygroundProxyResponse {
     CheckResourceSetResponse check_resource_set = 3;
     CheckResourceBatchResponse check_resource_batch = 4;
     ResourcesQueryPlanResponse resources_query_plan = 5;
+    CheckResourcesResponse check_resources = 6;
   }
 }
 
diff --git a/cmd/cerbos/repl/internal/cel.go b/cmd/cerbos/repl/internal/cel.go
index fa8ddcc4..544f8efa 100644
--- a/cmd/cerbos/repl/internal/cel.go
+++ b/cmd/cerbos/repl/internal/cel.go
@@ -6,11 +6,12 @@ package internal
 import (
 	"fmt"
 
-	enginev1 "github.com/cerbos/cerbos/api/genpb/cerbos/engine/v1"
-	"github.com/cerbos/cerbos/internal/conditions"
 	"github.com/google/cel-go/checker/decls"
 	"github.com/google/cel-go/common/types"
 	exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
+
+	enginev1 "github.com/cerbos/cerbos/api/genpb/cerbos/engine/v1"
+	"github.com/cerbos/cerbos/internal/conditions"
 )
 
 const lastResultVar = "_"
diff --git a/cmd/cerbos/repl/internal/directive.go b/cmd/cerbos/repl/internal/directive.go
index f0d5508e..9f81fb81 100644
--- a/cmd/cerbos/repl/internal/directive.go
+++ b/cmd/cerbos/repl/internal/directive.go
@@ -6,7 +6,7 @@ package internal
 import (
 	"fmt"
 
-	participle "github.com/alecthomas/participle/v2"
+	"github.com/alecthomas/participle/v2"
 	"github.com/alecthomas/participle/v2/lexer"
 )
 
@@ -14,6 +14,9 @@ func NewParser() (*participle.Parser, error) {
 	lex, err := lexer.New(lexer.Rules{
 		"Root": {
 			{Name: "Ident", Pattern: `[a-zA-Z]\w*(\.\w+)*`},
+			{Name: "#", Pattern: `#`},
+			{Name: "Int", Pattern: `[0-9]+`},
+			{Name: "Path", Pattern: `(?:((?:[\/]?)(?:[^\/]+\/)+)([^\/]+))`},
 			{Name: "Assign", Pattern: `=`, Action: lexer.Push("Assign")},
 			{Name: "Whitespace", Pattern: `\s+`},
 		},
@@ -38,14 +41,25 @@ func NewParser() (*participle.Parser, error) {
 
 //nolint:govet
 type REPLDirective struct {
-	Exit  bool          `parser:"@('q'|'quit'|'exit')"`
-	Reset bool          `parser:"| @'reset'"`
-	Vars  bool          `parser:"| @'vars'"`
-	Help  bool          `parser:"| @('h' | 'help')"`
-	Let   *LetDirective `parser:"| @@"`
+	Exit  bool           `parser:"@('q'|'quit'|'exit')"`
+	Reset bool           `parser:"| @'reset'"`
+	Vars  bool           `parser:"| @'vars'"`
+	Help  bool           `parser:"| @('h' | 'help')"`
+	Rules bool           `parser:"| @'rules'"`
+	Load  *LoadDirective `parser:"| @@"`
+	Exec  *ExecDirective `parser:"| @@"`
+	Let   *LetDirective  `parser:"| @@"`
 }
 
 type LetDirective struct {
 	Name string `parser:"'let' @Ident"`
 	Expr string `parser:"'=' @Any"`
 }
+
+type LoadDirective struct {
+	Path string `parser:"'load' @Path"`
+}
+
+type ExecDirective struct {
+	RuleID int `parser:"'exec' '#'@Int"`
+}
diff --git a/cmd/cerbos/repl/internal/eval.go b/cmd/cerbos/repl/internal/eval.go
new file mode 100644
index 00000000..db5dc847
--- /dev/null
+++ b/cmd/cerbos/repl/internal/eval.go
@@ -0,0 +1,82 @@
+// Copyright 2021-2022 Zenauth Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+package internal
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/pterm/pterm"
+
+	"github.com/cerbos/cerbos/internal/printer/colored"
+)
+
+var errEvalErrorPresent = errors.New("failed expression(s) present")
+
+type evalOutput struct {
+	tree  pterm.LeveledList
+	level int
+}
+
+func (eo *evalOutput) append(text string) {
+	eo.tree = append(eo.tree, pterm.LeveledListItem{Level: eo.level, Text: text})
+}
+
+func (eo *evalOutput) appendAndLevelUp(text string) {
+	eo.append(text)
+	eo.level++
+}
+
+func buildEvalOutput(e *eval) *evalOutput {
+	eo := &evalOutput{level: 0}
+	doBuildEvalOutput(eo, e)
+
+	return eo
+}
+
+func successText(success bool) string {
+	if success {
+		return colored.REPLSuccess("true")
+	}
+
+	return colored.REPLError("false")
+}
+
+func doBuildEvalOutput(eo *evalOutput, e *eval) {
+	switch e.evalType {
+	case evalTypeExpr:
+		eo.append(fmt.Sprintf("%s [%v]", colored.REPLExpr(e.expr), successText(e.success)))
+	case evalTypeAny, evalTypeAll, evalTypeNone:
+		eo.appendAndLevelUp(fmt.Sprintf("%s [%v]", e.evalType, successText(e.success)))
+		for _, ev := range e.evals {
+			doBuildEvalOutput(eo, ev)
+		}
+	}
+}
+
+type evalType string
+
+const (
+	evalTypeAll  evalType = "all"
+	evalTypeAny  evalType = "any"
+	evalTypeExpr evalType = "expr"
+	evalTypeNone evalType = "none"
+)
+
+type eval struct {
+	err      error
+	evalType evalType
+	expr     string
+	evals    []*eval
+	success  bool
+}
+
+func (e *eval) append(eval *eval) {
+	if eval.err != nil || !eval.success {
+		e.err = errEvalErrorPresent
+		e.success = false
+	}
+
+	e.evals = append(e.evals, eval)
+}
diff --git a/cmd/cerbos/repl/internal/help.txt b/cmd/cerbos/repl/internal/help.txt
index 9bdd6b24..e9199044 100644
--- a/cmd/cerbos/repl/internal/help.txt
+++ b/cmd/cerbos/repl/internal/help.txt
@@ -16,6 +16,9 @@ Directives are commands prefixed with a colon (":") character. The following dir
   :quit             | Exit the program
   :reset            | Clear all variables
   :vars             | View defined variables
+  :load             | Load rules from a policy
+  :rules            | View rules loaded from policies
+  :exec             | Execute rules loaded from policies
 
 ## Evaluating CEL conditions
 You can type in any valid CEL expression at the prompt to immediately evaluate it.
@@ -50,6 +53,23 @@ You can view the currently defined variables by using the :vars directive.
   :vars             | prints all defined variables
 
 
+## Load rules from a policy
+You can load rules from a Cerbos policy using the :load directive.
+
+  :load /policies/resource_policies/policy_01.yaml
+
+## View loaded rules
+You can view the currently loaded policy rules using the :rules directive. Each rule has an ID assigned by the REPL. You can use that ID in an :exec directive to execute the condition attached to that rule. 
+
+  :rules            | prints currently loaded policy rules
+
+## Execute rules
+
+You can execute a loaded rule using its ID. Use the :rules directive to view the IDs for rules.
+
+  :exec  #1           |  execute rule with ID #1
+
+
 ## Clear state
 You can destroy all variables and reset the REPL with the :reset directive.
 
diff --git a/cmd/cerbos/repl/internal/repl.go b/cmd/cerbos/repl/internal/repl.go
index 8cdea6a8..97e8e2f7 100644
--- a/cmd/cerbos/repl/internal/repl.go
+++ b/cmd/cerbos/repl/internal/repl.go
@@ -4,22 +4,17 @@
 package internal
 
 import (
+	_ "embed"
 	"encoding/json"
 	"errors"
 	"fmt"
 	"io"
+	"os"
 	"reflect"
 	"sort"
 	"strings"
 
-	_ "embed"
-
-	participle "github.com/alecthomas/participle/v2"
-	enginev1 "github.com/cerbos/cerbos/api/genpb/cerbos/engine/v1"
-	"github.com/cerbos/cerbos/internal/conditions"
-	"github.com/cerbos/cerbos/internal/outputcolor"
-	"github.com/cerbos/cerbos/internal/printer"
-	"github.com/cerbos/cerbos/internal/printer/colored"
+	"github.com/alecthomas/participle/v2"
 	"github.com/google/cel-go/cel"
 	"github.com/google/cel-go/checker/decls"
 	"github.com/google/cel-go/common"
@@ -27,9 +22,21 @@ import (
 	"github.com/google/cel-go/common/types/ref"
 	"github.com/google/cel-go/interpreter"
 	"github.com/peterh/liner"
+	"github.com/pterm/pterm"
 	exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
 	"google.golang.org/protobuf/encoding/protojson"
 	"google.golang.org/protobuf/proto"
+
+	enginev1 "github.com/cerbos/cerbos/api/genpb/cerbos/engine/v1"
+	policyv1 "github.com/cerbos/cerbos/api/genpb/cerbos/policy/v1"
+	runtimev1 "github.com/cerbos/cerbos/api/genpb/cerbos/runtime/v1"
+	"github.com/cerbos/cerbos/internal/compile"
+	"github.com/cerbos/cerbos/internal/conditions"
+	"github.com/cerbos/cerbos/internal/namer"
+	"github.com/cerbos/cerbos/internal/outputcolor"
+	"github.com/cerbos/cerbos/internal/policy"
+	"github.com/cerbos/cerbos/internal/printer"
+	"github.com/cerbos/cerbos/internal/printer/colored"
 )
 
 var (
@@ -49,16 +56,20 @@ const (
 	commentPrefix   = '#'
 	directivePrefix = ':'
 	prompt          = "-> "
+	rulePrefix      = "#"
 	secondaryPrompt = "> "
+	yamlIndent      = 2
 )
 
 type REPL struct {
-	vars     variables
-	decls    map[string]*exprpb.Decl
-	reader   *liner.State
-	parser   *participle.Parser
-	output   Output
-	toRefVal func(any) ref.Val
+	policyKey string
+	output    Output
+	vars      variables
+	decls     map[string]*exprpb.Decl
+	reader    *liner.State
+	parser    *participle.Parser
+	toRefVal  func(any) ref.Val
+	rules     []any
 }
 
 func NewREPL(reader *liner.State, output Output) (*REPL, error) {
@@ -158,12 +169,18 @@ func (r *REPL) processDirective(line string) error {
 		return r.showVars()
 	case directive.Help:
 		return r.help()
+	case directive.Rules:
+		return r.showRules()
 	case directive.Let != nil:
 		prefix, _, _ := strings.Cut(directive.Let.Name, ".")
 		if _, ok := specialVars[prefix]; ok {
 			return r.setSpecialVar(directive.Let.Name, directive.Let.Expr)
 		}
 		return r.processExpr(directive.Let.Name, directive.Let.Expr)
+	case directive.Load != nil:
+		return r.loadRulesFromPolicy(directive.Load.Path)
+	case directive.Exec != nil:
+		return r.execRule(directive.Exec.RuleID)
 	default:
 		return fmt.Errorf("unknown directive %q", line)
 	}
@@ -198,6 +215,23 @@ func (r *REPL) showVars() error {
 	return nil
 }
 
+func (r *REPL) showRules() error {
+	if r.rules == nil {
+		r.output.Println()
+		return nil
+	}
+
+	r.output.Print(fmt.Sprintf("Showing rules for the policy '%s'\n", colored.REPLPolicyName(r.policyKey)))
+	for idx, rule := range r.rules {
+		err := r.output.PrintRule(idx, rule)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
 func (r *REPL) setSpecialVar(name, value string) error {
 	switch name {
 	case lastResultVar:
@@ -318,6 +352,150 @@ func (r *REPL) evalExpr(expr string) (ref.Val, *exprpb.Type, error) {
 	return val, tpe, nil
 }
 
+func (r *REPL) loadRulesFromPolicy(path string) error {
+	f, err := os.Open(strings.Trim(path, " "))
+	if err != nil {
+		return fmt.Errorf("failed to open policy file at %s: %w", path, err)
+	}
+	defer f.Close()
+
+	p, err := policy.ReadPolicy(f)
+	if err != nil {
+		return fmt.Errorf("failed to read policy file: %w", err)
+	}
+
+	r.vars[conditions.CELVariablesIdent] = r.toRefVal(p.Variables)
+	r.vars[conditions.CELVariablesAbbrev] = r.toRefVal(p.Variables)
+
+	r.rules = nil
+	switch pt := p.PolicyType.(type) {
+	case *policyv1.Policy_ResourcePolicy:
+		for _, rule := range pt.ResourcePolicy.Rules {
+			if rule.Condition != nil && rule.Condition.Condition != nil {
+				_, ok := rule.Condition.Condition.(*policyv1.Condition_Match)
+				if !ok {
+					continue
+				}
+				r.rules = append(r.rules, rule)
+			}
+		}
+
+		r.policyKey = namer.PolicyKey(p)
+		r.output.Println(fmt.Sprintf("Resource policy '%s' loaded", colored.REPLPolicyName(namer.PolicyKey(p))))
+	case *policyv1.Policy_DerivedRoles:
+		for _, def := range pt.DerivedRoles.Definitions {
+			if def.Condition != nil {
+				r.rules = append(r.rules, def)
+			}
+		}
+
+		r.policyKey = namer.PolicyKey(p)
+		r.output.Println(fmt.Sprintf("Derived roles '%s' loaded", colored.REPLPolicyName(namer.PolicyKey(p))))
+	case *policyv1.Policy_PrincipalPolicy:
+		for _, rule := range pt.PrincipalPolicy.Rules {
+			for _, action := range rule.Actions {
+				if action.Condition != nil {
+					pr := &policyv1.PrincipalRule{
+						Resource: rule.Resource,
+						Actions: []*policyv1.PrincipalRule_Action{
+							action,
+						},
+					}
+					r.rules = append(r.rules, pr)
+				}
+			}
+		}
+
+		r.policyKey = namer.PolicyKey(p)
+		r.output.Println(fmt.Sprintf("Principal policy '%s' loaded", colored.REPLPolicyName(namer.PolicyKey(p))))
+	}
+
+	r.output.Println()
+	err = r.showRules()
+	if err != nil {
+		return fmt.Errorf("failed to display rules after loading a policy: %w", err)
+	}
+
+	return nil
+}
+
+func (r *REPL) execRule(id int) error {
+	if id >= len(r.rules) {
+		return fmt.Errorf("failed to find rule with id %d", id)
+	}
+
+	return r.evalCondition(id)
+}
+
+func (r *REPL) evalCondition(id int) error {
+	var cond *policyv1.Condition
+	switch rt := r.rules[id].(type) {
+	case *policyv1.ResourceRule:
+		cond = rt.Condition
+	case *policyv1.RoleDef:
+		cond = rt.Condition
+	case *policyv1.PrincipalRule:
+		cond = rt.Actions[0].Condition
+	}
+
+	condition, err := compile.Condition(cond)
+	if err != nil {
+		return fmt.Errorf("failed to compile condition: %w", err)
+	}
+
+	e := r.doEvalCondition(condition)
+	eo := buildEvalOutput(e)
+
+	err = pterm.DefaultTree.WithRoot(pterm.NewTreeFromLeveledList(eo.tree)).Render()
+	if err != nil {
+		return fmt.Errorf("failed to render tree: %w", err)
+	}
+
+	return nil
+}
+
+func (r *REPL) doEvalCondition(condition *runtimev1.Condition) *eval {
+	switch c := condition.Op.(type) {
+	case *runtimev1.Condition_Expr:
+		val, tpe, err := r.evalExpr(c.Expr.Original)
+		if err != nil {
+			return &eval{err: err, success: false, evalType: evalTypeExpr, evals: nil, expr: c.Expr.Original}
+		}
+
+		r.vars[lastResultVar] = val
+		r.decls[lastResultVar] = decls.NewVar(lastResultVar, tpe)
+
+		if success, ok := val.Value().(bool); ok {
+			return &eval{err: nil, success: success, evalType: evalTypeExpr, evals: nil, expr: c.Expr.Original}
+		}
+
+		return &eval{err: err, success: false, evalType: evalTypeExpr, evals: nil, expr: c.Expr.Original}
+	case *runtimev1.Condition_All:
+		eval := &eval{err: nil, success: true, evalType: evalTypeAll, evals: nil}
+		for _, expr := range c.All.GetExpr() {
+			e := r.doEvalCondition(expr)
+			eval.append(e)
+		}
+		return eval
+	case *runtimev1.Condition_Any:
+		eval := &eval{err: nil, success: true, evalType: evalTypeAny, evals: nil}
+		for _, expr := range c.Any.GetExpr() {
+			e := r.doEvalCondition(expr)
+			eval.append(e)
+		}
+		return eval
+	case *runtimev1.Condition_None:
+		eval := &eval{err: nil, success: true, evalType: evalTypeNone, evals: nil}
+		for _, expr := range c.None.GetExpr() {
+			e := r.doEvalCondition(expr)
+			eval.append(e)
+		}
+		return eval
+	}
+
+	return nil
+}
+
 func (r *REPL) mkEnv() (*cel.Env, error) {
 	decls := make([]*exprpb.Decl, len(r.decls))
 	i := 0
@@ -345,7 +523,9 @@ type Output interface {
 	Print(string, ...any)
 	Println(...any)
 	PrintResult(string, ref.Val)
+	PrintRule(int, any) error
 	PrintJSON(any)
+	PrintYAML(proto.Message, int)
 	PrintErr(string, error)
 }
 
@@ -366,6 +546,18 @@ func (po *PrinterOutput) Print(format string, args ...any) {
 	po.Println()
 }
 
+func (po *PrinterOutput) PrintRule(id int, rule any) error {
+	msg, ok := rule.(proto.Message)
+	if !ok {
+		return fmt.Errorf("failed to type assert rule with id: %s", fmt.Sprintf("%s%d", rulePrefix, id))
+	}
+
+	po.Println(fmt.Sprintf("[%s]", colored.REPLRule(fmt.Sprintf("%s%d", rulePrefix, id))))
+	po.PrintYAML(msg, yamlIndent)
+
+	return nil
+}
+
 func (po *PrinterOutput) PrintResult(name string, value ref.Val) {
 	po.Printf("%s = ", colored.REPLVar(name))
 
@@ -406,6 +598,13 @@ func (po *PrinterOutput) PrintJSON(obj any) {
 	po.Println()
 }
 
+func (po *PrinterOutput) PrintYAML(obj proto.Message, indent int) {
+	if err := po.Printer.PrintProtoYAML(obj, po.level, indent); err != nil {
+		po.Println("<...>")
+	}
+	po.Println()
+}
+
 func (po *PrinterOutput) PrintErr(msg string, err error) {
 	po.Println(colored.REPLError(fmt.Sprintf("Error: %s", msg)))
 	if err != nil {
diff --git a/cmd/cerbos/repl/repl.go b/cmd/cerbos/repl/repl.go
index 96b07d07..944dca91 100644
--- a/cmd/cerbos/repl/repl.go
+++ b/cmd/cerbos/repl/repl.go
@@ -6,20 +6,28 @@ package repl
 import (
 	"errors"
 	"fmt"
+	"io"
 	"os"
 	"path/filepath"
 
 	"github.com/adrg/xdg"
 	"github.com/alecthomas/kong"
-	"github.com/cerbos/cerbos/cmd/cerbos/repl/internal"
 	"github.com/peterh/liner"
+
+	"github.com/cerbos/cerbos/cmd/cerbos/repl/internal"
 )
 
 type Cmd struct {
 	History string `help:"Path to history file" type:"path"`
 }
 
+func (c *Cmd) clear(stdout io.Writer) {
+	fmt.Fprintf(stdout, "\033[H\033[2J")
+}
+
 func (c *Cmd) Run(k *kong.Kong) error {
+	c.clear(k.Stdout)
+
 	histFile := getHistoryFile(c.History)
 
 	reader := liner.NewLiner()
diff --git a/docs/modules/cli/pages/cerbos.adoc b/docs/modules/cli/pages/cerbos.adoc
index f731743a..e8c358d8 100644
--- a/docs/modules/cli/pages/cerbos.adoc
+++ b/docs/modules/cli/pages/cerbos.adoc
@@ -203,6 +203,41 @@ Type `:help` or `:h` to display help. Type `:quit`, `:q` or `:exit` to exit the
 
 TIP: Use the up/down arrow keys (or kbd:[Ctrl+P]/kbd:[Ctrl+N]) to navigate command history. Most of the standard line-editing commands such as kbd:[Ctrl+a], kbd:[Ctrl+h], kbd:[Ctrl+r] are supported as well. 
 
+You can load rules from a policies.
+
+[listing]
+----
+-> :load /policies/resource_policies/policy_01.yaml
+Resource policy 'resource.leave_request.v20210210' loaded
+
+-> :load /policies/derived_roles/derived_01.yaml
+Derived roles 'derived_roles.alpha' loaded
+----
+
+Type `:rules` to display the rules loaded from policies.
+
+Type `:exec` to execute the rules using the environment of the REPL.
+
+[listing]
+----
+-> :rules
+#0 (derived_roles)
+{
+  "name": "employee_that_owns_the_record",
+  "parentRoles": [
+    "employee"
+  ],
+  "condition": {
+    "match": {
+      "expr": "R.attr.owner == P.id"
+    }
+  }
+}
+
+-> :exec #0
+Executing: R.attr.owner == P.id
+_ = true
+----
 
 [#run]
 == `run` Command
diff --git a/docs/modules/policies/pages/compile.adoc b/docs/modules/policies/pages/compile.adoc
index 118a3b45..697fbb87 100644
--- a/docs/modules/policies/pages/compile.adoc
+++ b/docs/modules/policies/pages/compile.adoc
@@ -36,17 +36,17 @@ principals: <3>
       - user
 resources: <4>
   alicia_album:
+    id: XX125
     kind: album:object
     attr:
       owner: aliciaID
-      id: XX125
       public: false
       flagged: false
   bradley_album:
+    id: XX250
     kind: album:object
     attr:
       owner: bradleyID
-      id: XX250
       public: false
       flagged: false
 auxData: <5>
@@ -131,10 +131,10 @@ principals:
 ---
 resources:
   alicia_album:
+    id: XX125
     kind: "album:object"
     attr:
       owner: aliciaID
-      id: XX125
       public: false
       flagged: false
 ----
@@ -168,26 +168,26 @@ For example, the following definitions are equivalent:
 ----
 resources:
   alicias_album1:
+    id: "XX125"
     kind: "album:object"
     attr: 
       owner: "alicia"
-      id: "XX125"
       public: false
       flagged: false
 
   alicias_album2:
+    id: "XX525"
     kind: "album:object"
     attr: 
       owner: "alicia"
-      id: "XX525"
       public: false
       flagged: false
 
   alicias_album3:
+    id: "XX925"
     kind: "album:object"
     attr: 
       owner: "alicia"
-      id: "XX925"
       public: false
       flagged: false
 ----
@@ -196,24 +196,24 @@ resources:
 ----
 resources:
   alicias_album1:
+    id: "XX125"
     kind: "album:object"
     attr: &alicia_album_attr
       owner: "alicia"
-      id: "XX125"
       public: false
       flagged: false
 
   alicias_album2:
+    id: "XX525"
     kind: "album:object"
     attr:
       <<: *alicia_album_attr
-      id: "XX525"
 
   alicias_album3:
+    id: "XX925"
     kind: "album:object"
     attr:
       <<: *alicia_album_attr
-      id: "XX925"
 ----
 |===
 
diff --git a/docs/modules/releases/nav.adoc b/docs/modules/releases/nav.adoc
index 57ab9b06..ea6e480f 100644
--- a/docs/modules/releases/nav.adoc
+++ b/docs/modules/releases/nav.adoc
@@ -1,4 +1,5 @@
 .Release Notes
+* xref:v0.15.1.adoc[v0.15.1]
 * xref:v0.15.0.adoc[v0.15.0]
 * xref:v0.14.0.adoc[v0.14.0]
 * xref:v0.13.0.adoc[v0.13.0]
diff --git a/docs/modules/releases/pages/v0.15.1.adoc b/docs/modules/releases/pages/v0.15.1.adoc
new file mode 100644
index 00000000..bb080afa
--- /dev/null
+++ b/docs/modules/releases/pages/v0.15.1.adoc
@@ -0,0 +1,19 @@
+include::ROOT:partial$attributes.adoc[]
+
+[#v0.15.1]
+= Cerbos v0.15.1
+
+This is a small patch release to fix an issue with Git pulls when there are multiple branches present in the remote repo. See xref:v0.15.0.adoc[v0.15.0 release notes] for details about all the new features available in 0.15.x.
+
+
+
+== Changelog
+
+=== Bug Fixes
+
+* Use the branch name in git pull (link:https://github.com/cerbos/cerbos/pull/823[#823])
+
+=== Documentation
+
+* Fix ID attribute in testing docs (link:https://github.com/cerbos/cerbos/pull/822[#822])
+
diff --git a/go.mod b/go.mod
index a6f61e25..39676c8f 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,7 @@ require (
 	github.com/adrg/xdg v0.4.0
 	github.com/alecthomas/chroma v0.10.0
 	github.com/alecthomas/kong v0.5.0
-	github.com/alecthomas/participle/v2 v2.0.0-alpha7
+	github.com/alecthomas/participle/v2 v2.0.0-alpha8
 	github.com/aws/aws-sdk-go v1.43.31
 	github.com/bluele/gcache v0.0.2
 	github.com/cespare/xxhash v1.1.0
@@ -42,7 +42,7 @@ require (
 	github.com/jwalton/gchalk v1.3.0
 	github.com/jwalton/go-supportscolor v1.1.0
 	github.com/kavu/go_reuseport v1.5.0
-	github.com/lestrrat-go/jwx v1.2.21
+	github.com/lestrrat-go/jwx v1.2.22
 	github.com/mattn/go-isatty v0.0.14
 	github.com/minio/minio-go/v7 v7.0.23
 	github.com/oklog/ulid/v2 v2.0.2
@@ -62,12 +62,12 @@ require (
 	github.com/tidwall/sjson v1.2.4
 	go.elastic.co/ecszap v1.0.1
 	go.opencensus.io v0.23.0
-	go.opentelemetry.io/otel v1.6.1
+	go.opentelemetry.io/otel v1.6.3
 	go.opentelemetry.io/otel/bridge/opencensus v0.28.0
-	go.opentelemetry.io/otel/exporters/jaeger v1.6.1
-	go.opentelemetry.io/otel/sdk v1.6.1
-	go.opentelemetry.io/otel/trace v1.6.1
-	go.uber.org/automaxprocs v1.4.0
+	go.opentelemetry.io/otel/exporters/jaeger v1.6.3
+	go.opentelemetry.io/otel/sdk v1.6.3
+	go.opentelemetry.io/otel/trace v1.6.3
+	go.uber.org/automaxprocs v1.5.1
 	go.uber.org/config v1.4.0
 	go.uber.org/multierr v1.8.0
 	go.uber.org/zap v1.21.0
@@ -82,7 +82,7 @@ require (
 	gopkg.in/segmentio/analytics-go.v3 v3.1.0
 	gopkg.in/yaml.v2 v2.4.0
 	helm.sh/helm/v3 v3.8.1
-	modernc.org/sqlite v1.15.4
+	modernc.org/sqlite v1.16.0
 )
 
 require (
@@ -170,7 +170,7 @@ require (
 	github.com/klauspost/cpuid v1.3.1 // indirect
 	github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
 	github.com/lestrrat-go/blackmagic v1.0.0 // indirect
-	github.com/lestrrat-go/httpcc v1.0.0 // indirect
+	github.com/lestrrat-go/httpcc v1.0.1 // indirect
 	github.com/lestrrat-go/iter v1.0.1 // indirect
 	github.com/lestrrat-go/option v1.0.0 // indirect
 	github.com/lib/pq v1.10.4 // indirect
diff --git a/go.sum b/go.sum
index 0e3a9eb5..61a0035c 100644
--- a/go.sum
+++ b/go.sum
@@ -200,8 +200,8 @@ github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbf
 github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
 github.com/alecthomas/kong v0.5.0 h1:u8Kdw+eeml93qtMZ04iei0CFYve/WPcA5IFh+9wSskE=
 github.com/alecthomas/kong v0.5.0/go.mod h1:uzxf/HUh0tj43x1AyJROl3JT7SgsZ5m+icOv1csRhc0=
-github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c=
-github.com/alecthomas/participle/v2 v2.0.0-alpha7/go.mod h1:NumScqsC42o9x+dGj8/YqsIfhrIQjFEOFovxotbBirA=
+github.com/alecthomas/participle/v2 v2.0.0-alpha8 h1:X6nuChfgfQXNTE+ZdjTFSfnSNr8E07LSVLAqIIjtsGI=
+github.com/alecthomas/participle/v2 v2.0.0-alpha8/go.mod h1:NumScqsC42o9x+dGj8/YqsIfhrIQjFEOFovxotbBirA=
 github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
 github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142 h1:8Uy0oSf5co/NZXje7U1z8Mpep++QJOldL2hs/sBQf48=
 github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
@@ -1141,12 +1141,12 @@ github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf
 github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
 github.com/lestrrat-go/blackmagic v1.0.0 h1:XzdxDbuQTz0RZZEmdU7cnQxUtFUzgCSPq8RCz4BxIi4=
 github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ=
-github.com/lestrrat-go/httpcc v1.0.0 h1:FszVC6cKfDvBKcJv646+lkh4GydQg2Z29scgUfkOpYc=
-github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++0Gf8MBnAvE=
+github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
+github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
 github.com/lestrrat-go/iter v1.0.1 h1:q8faalr2dY6o8bV45uwrxq12bRa1ezKrB6oM9FUgN4A=
 github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc=
-github.com/lestrrat-go/jwx v1.2.21 h1:n+yG95UMm5ZFsDdvsZmui+bqat4Cj/di4ys6XbgSlE8=
-github.com/lestrrat-go/jwx v1.2.21/go.mod h1:9cfxnOH7G1gN75CaJP2hKGcxFEx5sPh1abRIA/ZJVh4=
+github.com/lestrrat-go/jwx v1.2.22 h1:bCxMokwHNuJHVxgANP4OBddXGtQ9Oy+6cqp4O2rW7DU=
+github.com/lestrrat-go/jwx v1.2.22/go.mod h1:sAXjRwzSvCN6soO4RLoWWm1bVPpb8iOuv0IYfH8OWd8=
 github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
 github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
 github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -1386,6 +1386,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
 github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
+github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
 github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
@@ -1660,12 +1661,12 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.2
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
 go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
 go.opentelemetry.io/otel v1.6.0/go.mod h1:bfJD2DZVw0LBxghOTlgnlI0CV3hLDu9XF/QKOUXMTQQ=
-go.opentelemetry.io/otel v1.6.1 h1:6r1YrcTenBvYa1x491d0GGpTVBsNECmrc/K6b+zDeis=
-go.opentelemetry.io/otel v1.6.1/go.mod h1:blzUabWHkX6LJewxvadmzafgh/wnvBSDBdOuwkAtrWQ=
+go.opentelemetry.io/otel v1.6.3 h1:FLOfo8f9JzFVFVyU+MSRJc2HdEAXQgm7pIv2uFKRSZE=
+go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI=
 go.opentelemetry.io/otel/bridge/opencensus v0.28.0 h1:FW1D3WQYwUVQHQkMUcMucI4A7hqlXaF0Yc2MYdsqBRA=
 go.opentelemetry.io/otel/bridge/opencensus v0.28.0/go.mod h1:DiAeRr5mifJcz09RCNAeF/ab1wTu7rlTljXcFG2LdB0=
-go.opentelemetry.io/otel/exporters/jaeger v1.6.1 h1:7xuwXr3qUWq48Chyuq+VvomV3KjXZLd5seQwg83s/sU=
-go.opentelemetry.io/otel/exporters/jaeger v1.6.1/go.mod h1:Cu6mKJ+LLTPuOBX830xM4wVKIsVpHSXa50uN7aAxraQ=
+go.opentelemetry.io/otel/exporters/jaeger v1.6.3 h1:7tvBU1Ydbzq080efuepYYqC1Pv3/vOFBgCSrxLb24d0=
+go.opentelemetry.io/otel/exporters/jaeger v1.6.3/go.mod h1:YgX3eZWbJzgrNyNHCK0otGreAMBTIAcObtZS2VRi6sU=
 go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
 go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
 go.opentelemetry.io/otel/metric v0.28.0 h1:o5YNh+jxACMODoAo1bI7OES0RUW4jAMae0Vgs2etWAQ=
@@ -1673,16 +1674,16 @@ go.opentelemetry.io/otel/metric v0.28.0/go.mod h1:TrzsfQAmQaB1PDcdhBauLMk7nyyg9h
 go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
 go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
 go.opentelemetry.io/otel/sdk v1.6.0/go.mod h1:PjLRUfDsoPy0zl7yrDGSUqjj43tL7rEtFdCEiGlxXRM=
-go.opentelemetry.io/otel/sdk v1.6.1 h1:ZmcNyMhcuAYIb/Nr6QhBPTMopMTbov/47wHt1gibkoY=
-go.opentelemetry.io/otel/sdk v1.6.1/go.mod h1:IVYrddmFZ+eJqu2k38qD3WezFR2pymCzm8tdxyh3R4E=
+go.opentelemetry.io/otel/sdk v1.6.3 h1:prSHYdwCQOX5DrsEzxowH3nLhoAzEBdZhvrR79scfLs=
+go.opentelemetry.io/otel/sdk v1.6.3/go.mod h1:A4iWF7HTXa+GWL/AaqESz28VuSBIcZ+0CV+IzJ5NMiQ=
 go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
 go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
 go.opentelemetry.io/otel/sdk/metric v0.28.0 h1:+1ndwHSiknwZtC8VmXM3xtMsd6kbFxtqti4qevn2J+o=
 go.opentelemetry.io/otel/sdk/metric v0.28.0/go.mod h1:DqJmT0ovBgoW6TJ8CAQyTnwxZPIp3KWtCiDDZ1uHAzU=
 go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
 go.opentelemetry.io/otel/trace v1.6.0/go.mod h1:qs7BrU5cZ8dXQHBGxHMOxwME/27YH2qEp4/+tZLLwJE=
-go.opentelemetry.io/otel/trace v1.6.1 h1:f8c93l5tboBYZna1nWk0W9DYyMzJXDWdZcJZ0Kb400U=
-go.opentelemetry.io/otel/trace v1.6.1/go.mod h1:RkFRM1m0puWIq10oxImnGEduNBzxiN7TXluRBtE+5j0=
+go.opentelemetry.io/otel/trace v1.6.3 h1:IqN4L+5b0mPNjdXIiZ90Ni4Bl5BRkDQywePLWemd9bc=
+go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -1692,8 +1693,8 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
 go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
-go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
-go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
+go.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk=
+go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU=
 go.uber.org/config v1.4.0 h1:upnMPpMm6WlbZtXoasNkK4f0FhxwS+W4Iqz5oNznehQ=
 go.uber.org/config v1.4.0/go.mod h1:aCyrMHmUAc/s2h9sv1koP84M9ZF/4K+g2oleyESO/Ig=
 go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
@@ -2657,8 +2658,8 @@ modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
 modernc.org/ql v1.0.0/go.mod h1:xGVyrLIatPcO2C1JvI/Co8c0sr6y91HKFNy4pt9JXEY=
 modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k=
 modernc.org/sqlite v1.10.6/go.mod h1:Z9FEjUtZP4qFEg6/SiADg9XCER7aYy9a/j7Pg9P7CPs=
-modernc.org/sqlite v1.15.4 h1:pr3EA3Rety3j1c/9pCyGAe5d3vjF6wQwusHdgGCjIqc=
-modernc.org/sqlite v1.15.4/go.mod h1:Jwe13ItpESZ+78K5WS6+AjXsUg+JvirsjN3iIDO4C8k=
+modernc.org/sqlite v1.16.0 h1:DdvOGaWN0y+X7t2L7RUD63gcwbVjYZjcBZnA68g44EI=
+modernc.org/sqlite v1.16.0/go.mod h1:Jwe13ItpESZ+78K5WS6+AjXsUg+JvirsjN3iIDO4C8k=
 modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
 modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
 modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
diff --git a/internal/printer/colored/colored.go b/internal/printer/colored/colored.go
index 57470c7f..a0936a0c 100644
--- a/internal/printer/colored/colored.go
+++ b/internal/printer/colored/colored.go
@@ -16,10 +16,13 @@ var (
 	Principal               = color.New(color.FgCyan).SprintFunc()
 	REPLCmd                 = color.New(color.FgYellow).SprintFunc()
 	REPLError               = color.New(color.FgRed).SprintFunc()
+	REPLExpr                = color.New(color.FgCyan).SprintFunc()
+	REPLPolicyName          = color.New(color.FgCyan).SprintFunc()
+	REPLRule                = color.New(color.FgCyan, color.Bold).SprintFunc()
+	REPLSuccess             = color.New(color.FgGreen).SprintFunc()
 	REPLVar                 = color.New(color.FgCyan).SprintFunc()
 	Resource                = color.New(color.FgBlue).SprintFunc()
 	SkippedTest             = color.New(color.FgHiWhite).SprintFunc()
-	SuccessfulTest          = color.New(color.FgGreen).SprintFunc()
 	Suite                   = color.New(color.FgBlue, color.Bold).SprintFunc()
 	Trace                   = color.New(color.FgHiWhite).SprintFunc()
 	TraceComponentKey       = color.New(color.FgBlue).SprintFunc()
diff --git a/internal/printer/printer.go b/internal/printer/printer.go
index 156e0516..dddd6595 100644
--- a/internal/printer/printer.go
+++ b/internal/printer/printer.go
@@ -8,17 +8,20 @@ import (
 	"encoding/json"
 	"fmt"
 	"io"
+	"strings"
 
 	"github.com/alecthomas/chroma"
 	"github.com/alecthomas/chroma/formatters"
 	"github.com/alecthomas/chroma/lexers"
 	"github.com/alecthomas/chroma/styles"
+	"github.com/ghodss/yaml"
+	"google.golang.org/protobuf/encoding/protojson"
+	"google.golang.org/protobuf/proto"
+
 	effectv1 "github.com/cerbos/cerbos/api/genpb/cerbos/effect/v1"
 	enginev1 "github.com/cerbos/cerbos/api/genpb/cerbos/engine/v1"
 	"github.com/cerbos/cerbos/internal/outputcolor"
 	"github.com/cerbos/cerbos/internal/printer/colored"
-	"google.golang.org/protobuf/encoding/protojson"
-	"google.golang.org/protobuf/proto"
 )
 
 func New(stdout, stderr io.Writer) *Printer {
@@ -85,6 +88,63 @@ func (p *Printer) PrintJSON(val any, colorLevel outputcolor.Level) error {
 	return nil
 }
 
+func (p *Printer) coloredYAML(data string, colorLevel outputcolor.Level) ([]byte, error) {
+	lexer := chroma.Coalesce(lexers.Get("yaml"))
+	if lexer == nil {
+		lexer = lexers.Fallback
+	}
+
+	var formatter chroma.Formatter
+	switch colorLevel {
+	case outputcolor.Basic:
+		formatter = formatters.TTY
+	case outputcolor.Ansi256:
+		formatter = formatters.TTY256
+	case outputcolor.Ansi16m:
+		formatter = formatters.TTY16m
+	default:
+		formatter = formatters.NoOp
+	}
+
+	iterator, err := lexer.Tokenise(nil, data)
+	if err != nil {
+		return nil, fmt.Errorf("failed to tokenise YAML: %w", err)
+	}
+
+	var yml bytes.Buffer
+	err = formatter.Format(&yml, styles.SolarizedDark256, iterator)
+	if err != nil {
+		return nil, fmt.Errorf("failed to format yaml: %w", err)
+	}
+
+	return yml.Bytes(), nil
+}
+
+func (p *Printer) PrintProtoYAML(message proto.Message, colorLevel outputcolor.Level, indent int) error {
+	data, err := protojson.MarshalOptions{Multiline: true}.Marshal(message)
+	if err != nil {
+		return fmt.Errorf("failed to encode JSON: %w", err)
+	}
+
+	yamlBytes, err := yaml.JSONToYAML(data)
+	if err != nil {
+		return fmt.Errorf("failed to convert data to YAML: %w", err)
+	}
+
+	if colorLevel.Enabled() {
+		yamlBytes, err = p.coloredYAML(string(yamlBytes), colorLevel)
+		if err != nil {
+			return err
+		}
+	}
+
+	for _, line := range strings.Split(strings.TrimSuffix(string(yamlBytes), "\n"), "\n") {
+		fmt.Fprintf(p.stdout, "%s%s\n", strings.Repeat("  ", indent), line)
+	}
+
+	return nil
+}
+
 func (p *Printer) PrintProtoJSON(message proto.Message, colorLevel outputcolor.Level) error {
 	data, err := protojson.MarshalOptions{Multiline: true}.Marshal(message)
 	if err != nil {
diff --git a/internal/storage/git/store.go b/internal/storage/git/store.go
index 5d073bf1..f6541c1b 100644
--- a/internal/storage/git/store.go
+++ b/internal/storage/git/store.go
@@ -259,7 +259,6 @@ func (s *Store) pullAndCompare(ctx context.Context) (object.Changes, error) {
 
 	branch := s.conf.getBranch()
 
-	s.log.Debugw("Pulling from remote", "branch", branch)
 	auth, err := s.conf.getAuth()
 	if err != nil {
 		return nil, fmt.Errorf("failed to create git auth credentials: %w", err)
@@ -267,13 +266,16 @@ func (s *Store) pullAndCompare(ctx context.Context) (object.Changes, error) {
 
 	// Now pull from remote
 	opts := &git.PullOptions{
-		Auth: auth,
+		Auth:          auth,
+		ReferenceName: plumbing.NewBranchReferenceName(branch),
+		SingleBranch:  true,
 	}
 
-	ctx, cancelFunc := s.conf.getOpCtx(ctx)
-	defer cancelFunc()
+	pullCtx, pullCancel := s.conf.getOpCtx(ctx)
+	defer pullCancel()
 
-	if err := wt.PullContext(ctx, opts); err != nil {
+	s.log.Debugw("Pulling from remote", "branch", branch)
+	if err := wt.PullContext(pullCtx, opts); err != nil {
 		if !errors.Is(err, git.NoErrAlreadyUpToDate) {
 			s.log.Errorw("Failed to pull from remote", "error", err)
 			return nil, fmt.Errorf("failed to pull from remote: %w", err)
diff --git a/internal/svc/playground_svc.go b/internal/svc/playground_svc.go
index 6bee2f00..ae2ef448 100644
--- a/internal/svc/playground_svc.go
+++ b/internal/svc/playground_svc.go
@@ -235,6 +235,19 @@ func (cs *CerbosPlaygroundService) PlaygroundProxy(ctx context.Context, req *req
 				ResourcesQueryPlan: resp,
 			},
 		}, nil
+	case *requestv1.PlaygroundProxyRequest_CheckResources:
+		resp, err := cerbosSvc.CheckResources(ctx, proxyReq.CheckResources)
+		if err != nil {
+			return nil, err
+		}
+
+		return &responsev1.PlaygroundProxyResponse{
+			PlaygroundId: req.PlaygroundId,
+			Outcome: &responsev1.PlaygroundProxyResponse_CheckResources{
+				CheckResources: resp,
+			},
+		}, nil
+
 	default:
 		log.Error(fmt.Sprintf("Unhandled playground proxy request type %T", proxyReq))
 		return nil, status.Error(codes.Unimplemented, "unknown request type")
diff --git a/schema/jsonschema/cerbos/request/v1/PlaygroundProxyRequest.schema.json b/schema/jsonschema/cerbos/request/v1/PlaygroundProxyRequest.schema.json
index 7c0a0e67..5ae8cc32 100644
--- a/schema/jsonschema/cerbos/request/v1/PlaygroundProxyRequest.schema.json
+++ b/schema/jsonschema/cerbos/request/v1/PlaygroundProxyRequest.schema.json
@@ -224,6 +224,59 @@
         }
       }
     },
+    "cerbos.request.v1.CheckResourcesRequest": {
+      "type": "object",
+      "required": [
+        "principal",
+        "resources"
+      ],
+      "additionalProperties": false,
+      "properties": {
+        "auxData": {
+          "$ref": "#/definitions/cerbos.request.v1.AuxData"
+        },
+        "includeMeta": {
+          "type": "boolean"
+        },
+        "principal": {
+          "$ref": "#/definitions/cerbos.engine.v1.Principal"
+        },
+        "requestId": {
+          "type": "string"
+        },
+        "resources": {
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/cerbos.request.v1.CheckResourcesRequest.ResourceEntry"
+          },
+          "maxItems": 20,
+          "minItems": 1
+        }
+      }
+    },
+    "cerbos.request.v1.CheckResourcesRequest.ResourceEntry": {
+      "type": "object",
+      "required": [
+        "actions",
+        "resource"
+      ],
+      "additionalProperties": false,
+      "properties": {
+        "actions": {
+          "type": "array",
+          "items": {
+            "type": "string",
+            "minLength": 1
+          },
+          "maxItems": 10,
+          "minItems": 1,
+          "uniqueItems": true
+        },
+        "resource": {
+          "$ref": "#/definitions/cerbos.engine.v1.Resource"
+        }
+      }
+    },
     "cerbos.request.v1.File": {
       "type": "object",
       "required": [
@@ -330,6 +383,9 @@
         "checkResourceSet": {
           "$ref": "#/definitions/cerbos.request.v1.CheckResourceSetRequest"
         },
+        "checkResources": {
+          "$ref": "#/definitions/cerbos.request.v1.CheckResourcesRequest"
+        },
         "files": {
           "type": "array",
           "items": {
@@ -365,6 +421,12 @@
           "required": [
             "resourcesQueryPlan"
           ]
+        },
+        {
+          "type": "object",
+          "required": [
+            "checkResources"
+          ]
         }
       ]
     }
diff --git a/schema/jsonschema/cerbos/response/v1/PlaygroundProxyResponse.schema.json b/schema/jsonschema/cerbos/response/v1/PlaygroundProxyResponse.schema.json
index cc8379b9..353deff8 100644
--- a/schema/jsonschema/cerbos/response/v1/PlaygroundProxyResponse.schema.json
+++ b/schema/jsonschema/cerbos/response/v1/PlaygroundProxyResponse.schema.json
@@ -125,6 +125,93 @@
         }
       }
     },
+    "cerbos.response.v1.CheckResourcesResponse": {
+      "type": "object",
+      "additionalProperties": false,
+      "properties": {
+        "requestId": {
+          "type": "string"
+        },
+        "results": {
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/cerbos.response.v1.CheckResourcesResponse.ResultEntry"
+          }
+        }
+      }
+    },
+    "cerbos.response.v1.CheckResourcesResponse.ResultEntry": {
+      "type": "object",
+      "additionalProperties": false,
+      "properties": {
+        "actions": {
+          "type": "object",
+          "additionalProperties": {
+            "$ref": "#/definitions/cerbos.effect.v1.Effect"
+          }
+        },
+        "meta": {
+          "$ref": "#/definitions/cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta"
+        },
+        "resource": {
+          "$ref": "#/definitions/cerbos.response.v1.CheckResourcesResponse.ResultEntry.Resource"
+        },
+        "validationErrors": {
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/cerbos.schema.v1.ValidationError"
+          }
+        }
+      }
+    },
+    "cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta": {
+      "type": "object",
+      "additionalProperties": false,
+      "properties": {
+        "actions": {
+          "type": "object",
+          "additionalProperties": {
+            "$ref": "#/definitions/cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta.EffectMeta"
+          }
+        },
+        "effectiveDerivedRoles": {
+          "type": "array",
+          "items": {
+            "type": "string"
+          }
+        }
+      }
+    },
+    "cerbos.response.v1.CheckResourcesResponse.ResultEntry.Meta.EffectMeta": {
+      "type": "object",
+      "additionalProperties": false,
+      "properties": {
+        "matchedPolicy": {
+          "type": "string"
+        },
+        "matchedScope": {
+          "type": "string"
+        }
+      }
+    },
+    "cerbos.response.v1.CheckResourcesResponse.ResultEntry.Resource": {
+      "type": "object",
+      "additionalProperties": false,
+      "properties": {
+        "id": {
+          "type": "string"
+        },
+        "kind": {
+          "type": "string"
+        },
+        "policyVersion": {
+          "type": "string"
+        },
+        "scope": {
+          "type": "string"
+        }
+      }
+    },
     "cerbos.response.v1.PlaygroundFailure": {
       "type": "object",
       "additionalProperties": false,
@@ -273,6 +360,9 @@
     "checkResourceSet": {
       "$ref": "#/definitions/cerbos.response.v1.CheckResourceSetResponse"
     },
+    "checkResources": {
+      "$ref": "#/definitions/cerbos.response.v1.CheckResourcesResponse"
+    },
     "failure": {
       "$ref": "#/definitions/cerbos.response.v1.PlaygroundFailure"
     },
diff --git a/schema/openapiv2/cerbos/svc/v1/svc.swagger.json b/schema/openapiv2/cerbos/svc/v1/svc.swagger.json
index 35fa7ced..6dcfc6a0 100644
--- a/schema/openapiv2/cerbos/svc/v1/svc.swagger.json
+++ b/schema/openapiv2/cerbos/svc/v1/svc.swagger.json
@@ -2410,6 +2410,9 @@
         },
         "resourcesQueryPlan": {
           "$ref": "#/definitions/cerbosrequestv1ResourcesQueryPlanRequest"
+        },
+        "checkResources": {
+          "$ref": "#/definitions/v1CheckResourcesRequest"
         }
       },
       "description": "Playground proxy request",
@@ -2434,6 +2437,9 @@
         },
         "resourcesQueryPlan": {
           "$ref": "#/definitions/v1ResourcesQueryPlanResponse"
+        },
+        "checkResources": {
+          "$ref": "#/definitions/v1CheckResourcesResponse"
         }
       },
       "description": "Playground proxy response"
diff --git a/tools/go.mod b/tools/go.mod
index 64d16280..a529a9b7 100644
--- a/tools/go.mod
+++ b/tools/go.mod
@@ -3,7 +3,7 @@ module github.com/cerbos/cerbos/tools
 go 1.18
 
 require (
-	github.com/bojand/ghz v0.106.1
+	github.com/bojand/ghz v0.108.0
 	github.com/bufbuild/buf v1.3.1
 	github.com/cerbos/protoc-gen-go-hashpb v0.1.0
 	github.com/envoyproxy/protoc-gen-validate v0.6.7
@@ -13,11 +13,11 @@ require (
 	github.com/goreleaser/goreleaser v1.7.0
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.0
 	github.com/planetscale/vtprotobuf v0.2.0
-	github.com/vektra/mockery/v2 v2.10.2
+	github.com/vektra/mockery/v2 v2.10.4
 	go.elastic.co/go-licence-detector v0.5.0
 	google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0
 	google.golang.org/protobuf v1.28.0
-	gotest.tools/gotestsum v1.7.0
+	gotest.tools/gotestsum v1.8.0
 )
 
 require (
diff --git a/tools/go.sum b/tools/go.sum
index e6210f9e..e3c2544b 100644
--- a/tools/go.sum
+++ b/tools/go.sum
@@ -295,8 +295,8 @@ github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4
 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
 github.com/blizzy78/varnamelen v0.7.0 h1:Y7LzPAysnU3YAabhqXkP9/G9/r7Ks9fUEvOjXoXStlY=
 github.com/blizzy78/varnamelen v0.7.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k=
-github.com/bojand/ghz v0.106.1 h1:u9RmtTVuPqk1Pg5s3dw3XxkNERmNDZRRpciTza4sOgU=
-github.com/bojand/ghz v0.106.1/go.mod h1:l3GXrJtJB3KbuhJ3Inr4Osu2fVwIEvJ5U69I2YA1h14=
+github.com/bojand/ghz v0.108.0 h1:rpLA8MKhF0FhrZx22ufTsMGBl4J99LJMKMl6RrW4ExM=
+github.com/bojand/ghz v0.108.0/go.mod h1:mAEf0dbMwX2vXQBIMPR0UUSlMyqJKvcH+lVJj2tYk/w=
 github.com/bojand/hri v1.1.0/go.mod h1:qwGosuHpNn1S0nyw/mExN0+WZrDf4bQyWjhWh51y3VY=
 github.com/bombsimon/wsl/v3 v3.1.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc=
 github.com/bombsimon/wsl/v3 v3.3.0 h1:Mka/+kRLoQJq7g2rggtgQsjuI/K5Efd87WX96EWFxjM=
@@ -1356,8 +1356,8 @@ github.com/valyala/fasthttp v1.15.1/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl
 github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
 github.com/valyala/quicktemplate v1.6.2/go.mod h1:mtEJpQtUiBV0SHhMX6RtiJtqxncgrfmjcUy5T68X8TM=
 github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
-github.com/vektra/mockery/v2 v2.10.2 h1:ISAFkB3rQS6Y3aDZzAKtDwgeyDknwNa1aBE3Zgx0h+I=
-github.com/vektra/mockery/v2 v2.10.2/go.mod h1:m/WO2UzWzqgVX3nvqpRQq70I4Z7jbSCRhdmkgtp+Ab4=
+github.com/vektra/mockery/v2 v2.10.4 h1:nMdsCKIS7ZdNTRNS/77Bx6Q/UbasGcfc3Nx7JO7HGTg=
+github.com/vektra/mockery/v2 v2.10.4/go.mod h1:m/WO2UzWzqgVX3nvqpRQq70I4Z7jbSCRhdmkgtp+Ab4=
 github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE=
 github.com/xanzy/go-gitlab v0.59.0 h1:fAr6rT/YIdfmBavYgI42+Op7yAAex2Y4xOfvbjN9hxQ=
 github.com/xanzy/go-gitlab v0.59.0/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM=
@@ -2101,8 +2101,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
 gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools/gotestsum v1.7.0 h1:RwpqwwFKBAa2h+F6pMEGpE707Edld0etUD3GhqqhDNc=
-gotest.tools/gotestsum v1.7.0/go.mod h1:V1m4Jw3eBerhI/A6qCxUE07RnCg7ACkKj9BYcAm09V8=
+gotest.tools/gotestsum v1.8.0 h1:ltj5KWhbQjt1Yx+IPBj0Dk2HVDUs9OlLmGC2JvivTMo=
+gotest.tools/gotestsum v1.8.0/go.mod h1:ctqdxBSCPv80kAFjYvFNpPntBrE5HAQnLiOKBGLmOBs=
 gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
 gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=


Test patch:
diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index cb733654..34bb4f10 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -10,7 +10,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Install Go
-        uses: actions/setup-go@v2
+        uses: actions/setup-go@v3
         with:
           go-version: 1.18.x
 
diff --git a/.github/workflows/pr-test.yaml b/.github/workflows/pr-test.yaml
index 2de5aada..5b7dde34 100644
--- a/.github/workflows/pr-test.yaml
+++ b/.github/workflows/pr-test.yaml
@@ -30,7 +30,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Install Go
-        uses: actions/setup-go@v2
+        uses: actions/setup-go@v3
         with:
           go-version: 1.18.x
 
@@ -65,7 +65,7 @@ jobs:
           CERBOS_DEBUG_ENGINE: "true"
 
       - name: Upload to CodeCov
-        uses: codecov/codecov-action@v2
+        uses: codecov/codecov-action@v3
         with:
           token: ${{ secrets.CODECOV_TOKEN }}
           files: "unit.cover,integration.cover"
@@ -93,7 +93,7 @@ jobs:
     steps:
       - uses: actions/checkout@v3
       - name: Install Go
-        uses: actions/setup-go@v2
+        uses: actions/setup-go@v3
         with:
           go-version: 1.18.x
       - name: golangci-lint
diff --git a/.github/workflows/test-matrix.yaml b/.github/workflows/test-matrix.yaml
index 8b8ce6c1..5bc39d65 100644
--- a/.github/workflows/test-matrix.yaml
+++ b/.github/workflows/test-matrix.yaml
@@ -12,7 +12,7 @@ jobs:
         os: [ubuntu-latest, macos-latest, windows-latest]
     steps:
       - name: Install Go
-        uses: actions/setup-go@v2
+        uses: actions/setup-go@v3
         with:
           go-version: 1.18.x
 
diff --git a/cmd/cerbos/repl/internal/repl_test.go b/cmd/cerbos/repl/internal/repl_test.go
index 0e58a19f..74f1bd2b 100644
--- a/cmd/cerbos/repl/internal/repl_test.go
+++ b/cmd/cerbos/repl/internal/repl_test.go
@@ -4,15 +4,24 @@
 package internal
 
 import (
+	"fmt"
+	"path/filepath"
 	"testing"
 
-	enginev1 "github.com/cerbos/cerbos/api/genpb/cerbos/engine/v1"
-	"github.com/cerbos/cerbos/internal/conditions"
 	"github.com/google/cel-go/common/types/ref"
 	"github.com/google/go-cmp/cmp"
 	"github.com/stretchr/testify/require"
+	"google.golang.org/protobuf/encoding/protojson"
+	"google.golang.org/protobuf/proto"
 	"google.golang.org/protobuf/testing/protocmp"
 	"google.golang.org/protobuf/types/known/structpb"
+
+	enginev1 "github.com/cerbos/cerbos/api/genpb/cerbos/engine/v1"
+	policyv1 "github.com/cerbos/cerbos/api/genpb/cerbos/policy/v1"
+	runtimev1 "github.com/cerbos/cerbos/api/genpb/cerbos/runtime/v1"
+	"github.com/cerbos/cerbos/internal/compile"
+	"github.com/cerbos/cerbos/internal/conditions"
+	"github.com/cerbos/cerbos/internal/test"
 )
 
 type DirectiveTest struct {
@@ -23,6 +32,12 @@ type DirectiveTest struct {
 
 func TestREPL(t *testing.T) {
 	toRefVal := conditions.StdEnv.TypeAdapter().NativeToValue
+	drPath := filepath.Join(test.PathToDir(t, "store"), "derived_roles", "derived_roles_01.yaml")
+	rpPath := filepath.Join(test.PathToDir(t, "store"), "resource_policies", "policy_01.yaml")
+	ppPath := filepath.Join(test.PathToDir(t, "store"), "principal_policies", "policy_01.yaml")
+	drConds := loadConditionsFromPolicy(t, drPath)
+	rpConds := loadConditionsFromPolicy(t, rpPath)
+	ppConds := loadConditionsFromPolicy(t, ppPath)
 
 	testCases := []struct {
 		name       string
@@ -258,6 +273,62 @@ func TestREPL(t *testing.T) {
 				},
 			},
 		},
+		{
+			name: "load_derived_roles",
+			directives: []DirectiveTest{
+				{
+					Directive: fmt.Sprintf(":load %s", drPath),
+					Check: func(t *testing.T, output *mockOutput) {
+						t.Helper()
+						for idx, r := range output.rules {
+							rd, ok := r.(*policyv1.RoleDef)
+							require.True(t, ok)
+							condition, err := compile.Condition(rd.Condition)
+							require.NoError(t, err)
+							require.JSONEq(t, protojson.Format(drConds[idx]), protojson.Format(condition))
+						}
+					},
+				},
+			},
+		},
+		{
+			name: "load_resource_policy",
+			directives: []DirectiveTest{
+				{
+					Directive: fmt.Sprintf(":load %s", rpPath),
+					Check: func(t *testing.T, output *mockOutput) {
+						t.Helper()
+						for idx, r := range output.rules {
+							rr, ok := r.(*policyv1.ResourceRule)
+							require.True(t, ok)
+							condition, err := compile.Condition(rr.Condition)
+							require.NoError(t, err)
+							require.JSONEq(t, protojson.Format(rpConds[idx]), protojson.Format(condition))
+						}
+					},
+				},
+			},
+		},
+		{
+			name: "load_principal_policy",
+			directives: []DirectiveTest{
+				{
+					Directive: fmt.Sprintf(":load %s", ppPath),
+					Check: func(t *testing.T, output *mockOutput) {
+						t.Helper()
+						for idx, r := range output.rules {
+							pr, ok := r.(*policyv1.PrincipalRule)
+							for _, action := range pr.Actions {
+								require.True(t, ok)
+								condition, err := compile.Condition(action.Condition)
+								require.NoError(t, err)
+								require.JSONEq(t, protojson.Format(ppConds[idx]), protojson.Format(condition))
+							}
+						}
+					},
+				},
+			},
+		},
 	}
 
 	for _, tc := range testCases {
@@ -287,8 +358,10 @@ type mockOutput struct {
 	msg        string
 	args       []any
 	jsonObj    any
+	yamlObj    any
 	resultName string
 	resultVal  ref.Val
+	rules      []any
 	err        error
 }
 
@@ -306,11 +379,58 @@ func (mo *mockOutput) PrintResult(name string, val ref.Val) {
 	mo.resultVal = val
 }
 
+func (mo *mockOutput) PrintRule(_ int, rule any) error {
+	mo.rules = append(mo.rules, rule)
+	return nil
+}
+
 func (mo *mockOutput) PrintJSON(obj any) {
 	mo.jsonObj = obj
 }
 
+func (mo *mockOutput) PrintYAML(obj proto.Message, _ int) {
+	mo.yamlObj = obj
+}
+
 func (mo *mockOutput) PrintErr(msg string, err error) {
 	mo.msg = msg
 	mo.err = err
 }
+
+func loadConditionsFromPolicy(t *testing.T, path string) []*runtimev1.Condition {
+	t.Helper()
+
+	p := test.LoadPolicy(t, path)
+
+	var conds []*runtimev1.Condition
+	switch pt := p.PolicyType.(type) {
+	case *policyv1.Policy_ResourcePolicy:
+		for _, rule := range pt.ResourcePolicy.Rules {
+			if rule.Condition != nil {
+				cond, err := compile.Condition(rule.Condition)
+				require.NoError(t, err)
+				conds = append(conds, cond)
+			}
+		}
+	case *policyv1.Policy_DerivedRoles:
+		for _, def := range pt.DerivedRoles.Definitions {
+			if def.Condition != nil {
+				cond, err := compile.Condition(def.Condition)
+				require.NoError(t, err)
+				conds = append(conds, cond)
+			}
+		}
+	case *policyv1.Policy_PrincipalPolicy:
+		for _, rule := range pt.PrincipalPolicy.Rules {
+			for _, action := range rule.Actions {
+				if action.Condition != nil {
+					cond, err := compile.Condition(action.Condition)
+					require.NoError(t, err)
+					conds = append(conds, cond)
+				}
+			}
+		}
+	}
+
+	return conds
+}
diff --git a/internal/test/mocks/Index.go b/internal/test/mocks/Index.go
index 7bbd1238..80f607ef 100644
--- a/internal/test/mocks/Index.go
+++ b/internal/test/mocks/Index.go
@@ -1,7 +1,7 @@
 // Copyright 2021-2022 Zenauth Ltd.
 // SPDX-License-Identifier: Apache-2.0
 
-// Code generated by mockery v2.10.2. DO NOT EDIT.
+// Code generated by mockery v2.10.4. DO NOT EDIT.
 
 package mocks
 
diff --git a/internal/test/mocks/Store.go b/internal/test/mocks/Store.go
index 292b8ef5..e58ad1d6 100644
--- a/internal/test/mocks/Store.go
+++ b/internal/test/mocks/Store.go
@@ -1,7 +1,7 @@
 // Copyright 2021-2022 Zenauth Ltd.
 // SPDX-License-Identifier: Apache-2.0
 
-// Code generated by mockery v2.10.2. DO NOT EDIT.
+// Code generated by mockery v2.10.4. DO NOT EDIT.
 
 package mocks
 
diff --git a/internal/test/testdata/server/playground/proxy/pgp_cr_case_00.yaml b/internal/test/testdata/server/playground/proxy/pgp_cr_case_00.yaml
new file mode 100644
index 00000000..a4e1082a
--- /dev/null
+++ b/internal/test/testdata/server/playground/proxy/pgp_cr_case_00.yaml
@@ -0,0 +1,149 @@
+---
+description: "Valid CheckResources request"
+wantStatus:
+  httpStatusCode: 200
+  grpcStatusCode: 0
+playgroundProxy:
+  input: {
+    "playgroundId": "test",
+    "files": [
+      {
+        "fileName": "derived_roles_01.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "derived_roles_02.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_02.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_01.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_02.yaml",
+        "contents": "{{ fileString `store/principal_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/principal.json",
+        "contents": "{{ fileString `store/_schemas/principal.json` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/leave_request.json",
+        "contents": "{{ fileString `store/_schemas/leave_request.json` | b64enc }}",
+      }
+    ],
+    "checkResources": {
+      "requestId": "test",
+      "principal": {
+        "id": "john",
+        "policyVersion": "20210210",
+        "roles": [
+          "employee"
+        ],
+        "attr": {
+          "department": "marketing",
+          "geography": "GB",
+          "team": "design"
+        }
+      },
+      "resources": [
+        {
+          "actions": [
+            "view:public",
+            "approve"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "policyVersion": "20210210",
+            "id": "XX125",
+            "attr": {
+              "department": "marketing",
+              "geography": "GB",
+              "id": "XX125",
+              "owner": "john",
+              "team": "design"
+            }
+          }
+        },
+        {
+          "actions": [
+            "view:public",
+            "approve"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "policyVersion": "20210210",
+            "id": "YY125",
+            "attr": {
+              "department": "engineering",
+              "geography": "GB",
+              "id": "YY125",
+              "owner": "jenny",
+              "team": "backend"
+            }
+          }
+        },
+        {
+          "actions": [
+            "view:public",
+            "delete",
+            "edit"
+          ],
+          "resource": {
+            "kind": "salary_record",
+            "policyVersion": "20210210",
+            "id": "YY525",
+            "attr": {
+              "department": "engineering",
+              "geography": "GB",
+              "id": "YY525",
+              "owner": "mark",
+              "team": "backend"
+            }
+          }
+        }
+      ]
+    }
+  }
+  wantResponse: {
+    "playgroundId": "test",
+    "checkResources": {
+      "requestId": "test",
+      "results": [
+        {
+          "resource": {
+            "id": "XX125",
+            "kind": "leave_request",
+            "policyVersion": "20210210"
+          },
+          "actions": {
+            "view:public": "EFFECT_ALLOW",
+            "approve": "EFFECT_DENY"
+          }
+        },
+        {
+          "resource": {
+            "id": "YY125",
+            "kind": "leave_request",
+            "policyVersion": "20210210"
+          },
+          "actions": {
+            "view:public": "EFFECT_ALLOW",
+            "approve": "EFFECT_DENY"
+          }
+        },
+        {
+          "resource": {
+            "id": "YY525",
+            "kind": "salary_record",
+            "policyVersion": "20210210"
+          },
+          "actions": {
+            "view:public": "EFFECT_DENY",
+            "delete": "EFFECT_DENY",
+            "edit": "EFFECT_DENY"
+          }
+        }
+      ]
+    }
+  }
diff --git a/internal/test/testdata/server/playground/proxy/pgp_cr_case_01.yaml b/internal/test/testdata/server/playground/proxy/pgp_cr_case_01.yaml
new file mode 100644
index 00000000..e578770e
--- /dev/null
+++ b/internal/test/testdata/server/playground/proxy/pgp_cr_case_01.yaml
@@ -0,0 +1,96 @@
+---
+description: "AuxData"
+wantStatus:
+  httpStatusCode: 200
+  grpcStatusCode: 0
+playgroundProxy:
+  input: {
+    "playgroundId": "test",
+    "files": [
+      {
+        "fileName": "derived_roles_01.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "derived_roles_02.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_02.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_01.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_02.yaml",
+        "contents": "{{ fileString `store/principal_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/principal.json",
+        "contents": "{{ fileString `store/_schemas/principal.json` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/leave_request.json",
+        "contents": "{{ fileString `store/_schemas/leave_request.json` | b64enc }}",
+      }
+    ],
+    "checkResources": {
+      "requestId": "test",
+      "principal": {
+        "id": "john",
+        "policyVersion": "20210210",
+        "roles": [
+          "employee"
+        ],
+        "attr": {
+          "department": "marketing",
+          "geography": "GB",
+          "team": "design"
+        }
+      },
+      "resources": [
+        {
+          "actions": [
+            "view:public",
+            "approve",
+            "defer"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "policyVersion": "20210210",
+            "id": "XX125",
+            "attr": {
+              "department": "marketing",
+              "geography": "GB",
+              "id": "XX125",
+              "owner": "john",
+              "team": "design"
+            }
+          }
+        }
+      ],
+      "auxData": {
+        "jwt": {
+          "token": "eyJhbGciOiJFUzM4NCIsImtpZCI6IjE5TGZaYXRFZGc4M1lOYzVyMjNndU1KcXJuND0iLCJ0eXAiOiJKV1QifQ.eyJhdWQiOlsiY2VyYm9zLWp3dC10ZXN0cyJdLCJjdXN0b21BcnJheSI6WyJBIiwiQiIsIkMiXSwiY3VzdG9tSW50Ijo0MiwiY3VzdG9tTWFwIjp7IkEiOiJBQSIsIkIiOiJCQiIsIkMiOiJDQyJ9LCJjdXN0b21TdHJpbmciOiJmb29iYXIiLCJleHAiOjE5NDk5MzQwMzksImlzcyI6ImNlcmJvcy10ZXN0LXN1aXRlIn0.WN_tOScSpd_EI-P5EI1YlagxEgExSfBjAtcrgcF6lyWj1lGpR_GKx9goZEp2p_t5AVWXN_bjz_sMUmJdJa4cVd55Qm1miR-FKu6oNRHnSEWdMFmnArwPw-YDJWfylLFX"
+        }
+      }
+    }
+  }
+  wantResponse: {
+    "playgroundId": "test",
+    "checkResources": {
+      "requestId": "test",
+      "results": [
+        {
+          "resource": {
+            "id": "XX125",
+            "kind": "leave_request",
+            "policyVersion": "20210210"
+          },
+          "actions": {
+            "view:public": "EFFECT_ALLOW",
+            "approve": "EFFECT_DENY",
+            "defer": "EFFECT_ALLOW"
+          }
+        }
+      ]
+    }
+  }
diff --git a/internal/test/testdata/server/playground/proxy/pgp_cr_case_02.yaml b/internal/test/testdata/server/playground/proxy/pgp_cr_case_02.yaml
new file mode 100644
index 00000000..95f8280b
--- /dev/null
+++ b/internal/test/testdata/server/playground/proxy/pgp_cr_case_02.yaml
@@ -0,0 +1,168 @@
+---
+description: "Validation errors"
+wantStatus:
+  httpStatusCode: 200
+  grpcStatusCode: 0
+playgroundProxy:
+  input: {
+    "playgroundId": "test",
+    "files": [
+      {
+        "fileName": "derived_roles_01.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "derived_roles_02.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_02.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_01.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_02.yaml",
+        "contents": "{{ fileString `store/principal_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/principal.json",
+        "contents": "{{ fileString `store/_schemas/principal.json` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/leave_request.json",
+        "contents": "{{ fileString `store/_schemas/leave_request.json` | b64enc }}",
+      }
+    ],
+    "checkResources": {
+      "requestId": "test",
+      "principal": {
+        "id": "john",
+        "policyVersion": "20210210",
+        "roles": [
+          "employee"
+        ],
+        "attr": {
+          "department": "accounting",
+          "geography": "GB",
+          "team": "design"
+        }
+      },
+      "resources": [
+        {
+          "actions": [
+            "view:public",
+            "approve"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "policyVersion": "20210210",
+            "id": "XX125",
+            "attr": {
+              "department": "accounting",
+              "geography": "GB",
+              "id": "XX125",
+              "owner": "john",
+              "team": "design"
+            }
+          }
+        },
+        {
+          "actions": [
+            "view:public",
+            "approve"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "policyVersion": "20210210",
+            "id": "YY125",
+            "attr": {
+              "department": "engineering",
+              "geography": "GB",
+              "id": "YY125",
+              "owner": "jenny",
+              "team": "backend"
+            }
+          }
+        },
+        {
+          "actions": [
+            "view:public",
+            "delete",
+            "edit"
+          ],
+          "resource": {
+            "kind": "salary_record",
+            "policyVersion": "20210210",
+            "id": "YY525",
+            "attr": {
+              "department": "engineering",
+              "geography": "GB",
+              "id": "YY525",
+              "owner": "mark",
+              "team": "backend"
+            }
+          }
+        }
+      ]
+    }
+  }
+  wantResponse: {
+    "playgroundId": "test",
+    "checkResources": {
+      "requestId": "test",
+      "results": [
+        {
+          "resource": {
+            "id": "XX125",
+            "kind": "leave_request",
+            "policyVersion": "20210210"
+          },
+          "actions": {
+            "view:public": "EFFECT_ALLOW",
+            "approve": "EFFECT_DENY"
+          },
+          "validationErrors": [
+            {
+              "path": "/department",
+              "message": "value must be one of \"marketing\", \"engineering\"",
+              "source": "SOURCE_PRINCIPAL"
+            },
+            {
+              "path": "/department",
+              "message": "value must be one of \"marketing\", \"engineering\"",
+              "source": "SOURCE_RESOURCE"
+            }
+          ]
+        },
+        {
+          "resource": {
+            "id": "YY125",
+            "kind": "leave_request",
+            "policyVersion": "20210210"
+          },
+          "actions": {
+            "view:public": "EFFECT_ALLOW",
+            "approve": "EFFECT_DENY"
+          },
+          "validationErrors": [
+            {
+              "path": "/department",
+              "message": "value must be one of \"marketing\", \"engineering\"",
+              "source": "SOURCE_PRINCIPAL"
+            }
+          ]
+        },
+        {
+          "resource": {
+            "id": "YY525",
+            "kind": "salary_record",
+            "policyVersion": "20210210"
+          },
+          "actions": {
+            "view:public": "EFFECT_DENY",
+            "delete": "EFFECT_DENY",
+            "edit": "EFFECT_DENY"
+          }
+        }
+      ]
+    }
+  }
diff --git a/internal/test/testdata/server/playground/proxy/pgp_cr_case_03.yaml b/internal/test/testdata/server/playground/proxy/pgp_cr_case_03.yaml
new file mode 100644
index 00000000..5287c97d
--- /dev/null
+++ b/internal/test/testdata/server/playground/proxy/pgp_cr_case_03.yaml
@@ -0,0 +1,191 @@
+---
+description: "Scoped policies"
+wantStatus:
+  httpStatusCode: 200
+  grpcStatusCode: 0
+playgroundProxy:
+  input: {
+    "playgroundId": "test",
+    "files": [
+      {
+        "fileName": "derived_roles_01.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "derived_roles_02.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_02.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_05.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_05.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_05_acme.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_05_acme.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_05_acme.hr.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_05_acme.hr.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_05_acme.hr.uk.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_05_acme.hr.uk.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/principal.json",
+        "contents": "{{ fileString `store/_schemas/principal.json` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/leave_request.json",
+        "contents": "{{ fileString `store/_schemas/leave_request.json` | b64enc }}",
+      }
+    ],
+    "checkResources": {
+      "requestId": "test",
+      "principal": {
+        "id": "john",
+        "scope": "acme.hr",
+        "roles": [
+          "employee"
+        ],
+        "attr": {
+          "department": "marketing",
+          "geography": "GB",
+          "team": "design",
+          "ip_address": "10.20.5.5"
+        }
+      },
+      "resources": [
+        {
+          "actions": [
+            "view:public",
+            "delete",
+            "create"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "scope": "acme.hr.uk",
+            "id": "XX125",
+            "attr": {
+              "department": "marketing",
+              "geography": "GB",
+              "id": "XX125",
+              "owner": "john",
+              "team": "design"
+            }
+          }
+        },
+        {
+          "actions": [
+            "view:public",
+            "delete",
+            "create"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "scope": "acme.hr",
+            "id": "XX225",
+            "attr": {
+              "department": "marketing",
+              "geography": "GB",
+              "id": "XX225",
+              "owner": "john",
+              "team": "design"
+            }
+          }
+        },
+        {
+          "actions": [
+            "view:public",
+            "approve"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "scope": "acme.hr.uk",
+            "id": "YY125",
+            "attr": {
+              "department": "engineering",
+              "geography": "GB",
+              "id": "YY125",
+              "owner": "jenny",
+              "team": "backend",
+            }
+          }
+        },
+        {
+          "actions": [
+            "view:public",
+            "delete",
+            "edit"
+          ],
+          "resource": {
+            "kind": "salary_record",
+            "policyVersion": "20210210",
+            "id": "YY525",
+            "attr": {
+              "department": "engineering",
+              "geography": "GB",
+              "id": "YY525",
+              "owner": "mark",
+              "team": "backend"
+            }
+          }
+        }
+      ]
+    }
+  }
+  wantResponse: {
+    "playgroundId": "test",
+    "checkResources": {
+      "requestId": "test",
+      "results": [
+        {
+          "resource": {
+            "id": "XX125",
+            "kind": "leave_request",
+            "scope": "acme.hr.uk"
+          },
+          "actions": {
+            "view:public": "EFFECT_ALLOW",
+            "delete": "EFFECT_ALLOW",
+            "create": "EFFECT_ALLOW"
+          }
+        },
+        {
+          "resource": {
+            "id": "XX225",
+            "kind": "leave_request",
+            "scope": "acme.hr"
+          },
+          "actions": {
+            "view:public": "EFFECT_ALLOW",
+            "delete": "EFFECT_DENY",
+            "create": "EFFECT_ALLOW"
+          }
+        },
+        {
+          "resource": {
+            "id": "YY125",
+            "kind": "leave_request",
+            "scope": "acme.hr.uk"
+          },
+          "actions": {
+            "view:public": "EFFECT_ALLOW",
+            "approve": "EFFECT_DENY"
+          }
+        },
+        {
+          "resource": {
+            "id": "YY525",
+            "kind": "salary_record",
+            "policyVersion": "20210210"
+          },
+          "actions": {
+            "view:public": "EFFECT_DENY",
+            "delete": "EFFECT_DENY",
+            "edit": "EFFECT_DENY"
+          }
+        }
+      ]
+    }
+  }
diff --git a/internal/test/testdata/server/playground/proxy/pgp_cr_case_04.yaml b/internal/test/testdata/server/playground/proxy/pgp_cr_case_04.yaml
new file mode 100644
index 00000000..a2c4807d
--- /dev/null
+++ b/internal/test/testdata/server/playground/proxy/pgp_cr_case_04.yaml
@@ -0,0 +1,242 @@
+---
+description: "Include meta"
+wantStatus:
+  httpStatusCode: 200
+  grpcStatusCode: 0
+playgroundProxy:
+  input: {
+    "playgroundId": "test",
+    "files": [
+      {
+        "fileName": "derived_roles_01.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "derived_roles_02.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_02.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_01.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_02.yaml",
+        "contents": "{{ fileString `store/principal_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_05.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_05.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_05_acme.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_05_acme.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_05_acme.hr.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_05_acme.hr.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_05_acme.hr.uk.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_05_acme.hr.uk.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/principal.json",
+        "contents": "{{ fileString `store/_schemas/principal.json` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/leave_request.json",
+        "contents": "{{ fileString `store/_schemas/leave_request.json` | b64enc }}",
+      }
+    ],
+    "checkResources": {
+      "requestId": "test",
+      "includeMeta": true,
+      "principal": {
+        "id": "john",
+        "policyVersion": "20210210",
+        "roles": [
+          "employee"
+        ],
+        "attr": {
+          "department": "marketing",
+          "geography": "GB",
+          "team": "design"
+        }
+      },
+      "resources": [
+        {
+          "actions": [
+            "view:public",
+            "approve"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "policyVersion": "20210210",
+            "id": "XX125",
+            "attr": {
+              "department": "marketing",
+              "geography": "GB",
+              "id": "XX125",
+              "owner": "john",
+              "team": "design"
+            }
+          }
+        },
+        {
+          "actions": [
+            "view:public",
+            "approve"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "policyVersion": "20210210",
+            "id": "YY125",
+            "attr": {
+              "department": "engineering",
+              "geography": "GB",
+              "id": "YY125",
+              "owner": "jenny",
+              "team": "backend"
+            }
+          }
+        },
+        {
+          "actions": [
+            "view:public",
+            "approve"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "scope": "acme.hr.uk",
+            "id": "YY225",
+            "attr": {
+              "department": "engineering",
+              "geography": "GB",
+              "id": "YY225",
+              "owner": "jenny",
+              "team": "backend",
+            }
+          }
+        },
+        {
+          "actions": [
+            "view:public",
+            "delete",
+            "edit"
+          ],
+          "resource": {
+            "kind": "salary_record",
+            "policyVersion": "20210210",
+            "id": "YY525",
+            "attr": {
+              "department": "engineering",
+              "geography": "GB",
+              "id": "YY525",
+              "owner": "mark",
+              "team": "backend"
+            }
+          }
+        }
+      ]
+    }
+  }
+  wantResponse: {
+    "playgroundId": "test",
+    "checkResources": {
+      "requestId": "test",
+      "results": [
+        {
+          "resource": {
+            "id": "XX125",
+            "kind": "leave_request",
+            "policyVersion": "20210210"
+          },
+          "actions": {
+            "view:public": "EFFECT_ALLOW",
+            "approve": "EFFECT_DENY"
+          },
+          "meta": {
+            "actions": {
+              "view:public": {
+                "matchedPolicy": "resource.leave_request.v20210210"
+              },
+              "approve": {
+                "matchedPolicy": "resource.leave_request.v20210210"
+              }
+            },
+            "effectiveDerivedRoles": ["employee_that_owns_the_record", "any_employee"]
+          }
+        },
+        {
+          "resource": {
+            "id": "YY125",
+            "kind": "leave_request",
+            "policyVersion": "20210210"
+          },
+          "actions": {
+            "view:public": "EFFECT_ALLOW",
+            "approve": "EFFECT_DENY"
+          },
+          "meta": {
+            "actions": {
+              "view:public": {
+                "matchedPolicy": "resource.leave_request.v20210210"
+              },
+              "approve": {
+                "matchedPolicy": "resource.leave_request.v20210210"
+              }
+            },
+            "effectiveDerivedRoles": ["any_employee"]
+          }
+        },
+        {
+          "resource": {
+            "id": "YY225",
+            "kind": "leave_request",
+            "scope": "acme.hr.uk"
+          },
+          "actions": {
+            "view:public": "EFFECT_ALLOW",
+            "approve": "EFFECT_DENY"
+          },
+          "meta": {
+            "actions": {
+              "view:public": {
+                "matchedPolicy": "resource.leave_request.vdefault/acme.hr.uk",
+                "matchedScope": "acme"
+              },
+              "approve": {
+                "matchedPolicy": "resource.leave_request.vdefault/acme.hr.uk"
+              }
+            },
+            "effectiveDerivedRoles": ["any_employee"]
+          }
+        },
+        {
+          "resource": {
+            "id": "YY525",
+            "kind": "salary_record",
+            "policyVersion": "20210210"
+          },
+          "actions": {
+            "view:public": "EFFECT_DENY",
+            "delete": "EFFECT_DENY",
+            "edit": "EFFECT_DENY"
+          },
+          "meta": {
+            "actions": {
+              "view:public": {
+                "matchedPolicy": "NO_MATCH"
+              },
+              "delete": {
+                "matchedPolicy": "NO_MATCH"
+              },
+              "edit": {
+                "matchedPolicy": "NO_MATCH"
+              }
+            }
+          }
+        }
+      ]
+    }
+  }
diff --git a/internal/test/testdata/server/playground/proxy/pgp_cr_case_05.yaml b/internal/test/testdata/server/playground/proxy/pgp_cr_case_05.yaml
new file mode 100644
index 00000000..bf2814a6
--- /dev/null
+++ b/internal/test/testdata/server/playground/proxy/pgp_cr_case_05.yaml
@@ -0,0 +1,143 @@
+---
+description: "Principal policy"
+wantStatus:
+  httpStatusCode: 200
+  grpcStatusCode: 0
+playgroundProxy:
+  input: {
+    "playgroundId": "test",
+    "files": [
+      {
+        "fileName": "derived_roles_01.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "derived_roles_02.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_02.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_01.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_02.yaml",
+        "contents": "{{ fileString `store/principal_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/principal.json",
+        "contents": "{{ fileString `store/_schemas/principal.json` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/leave_request.json",
+        "contents": "{{ fileString `store/_schemas/leave_request.json` | b64enc }}",
+      }
+    ],
+    "checkResources": {
+      "requestId": "test",
+      "includeMeta": true,
+      "principal": {
+        "id": "donald_duck",
+        "policyVersion": "20210210",
+        "roles": [
+          "employee",
+        ],
+        "attr": {
+          "department": "marketing",
+          "geography": "GB",
+          "team": "design",
+          "managed_geographies": "GB"
+        }
+      },
+      "resources": [
+        {
+          "actions": [
+            "view:public",
+            "approve"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "policyVersion": "20210210",
+            "id": "XX125",
+            "attr": {
+              "department": "marketing",
+              "geography": "GB",
+              "id": "XX125",
+              "owner": "john",
+              "team": "design"
+            }
+          }
+        },
+        {
+          "actions": [
+            "view:public",
+            "approve"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "policyVersion": "20210210",
+            "id": "YY125",
+            "attr": {
+              "department": "marketing",
+              "geography": "GB",
+              "id": "YY125",
+              "owner": "john",
+              "team": "design",
+              "status": "PENDING_APPROVAL",
+              "dev_record": true
+            }
+          }
+        }
+      ]
+    }
+  }
+  wantResponse: {
+    "playgroundId": "test",
+    "checkResources": {
+      "requestId": "test",
+      "results": [
+        {
+          "resource": {
+            "id": "XX125",
+            "kind": "leave_request",
+            "policyVersion": "20210210"
+          },
+          "actions": {
+            "view:public": "EFFECT_ALLOW",
+            "approve": "EFFECT_DENY"
+          },
+          "meta": {
+            "actions": {
+              "view:public": {
+                "matchedPolicy": "resource.leave_request.v20210210"
+              },
+              "approve": {
+                "matchedPolicy": "resource.leave_request.v20210210"
+              }
+            },
+            "effectiveDerivedRoles": ["any_employee"]
+          }
+        },
+        {
+          "resource": {
+            "id": "YY125",
+            "kind": "leave_request",
+            "policyVersion": "20210210"
+          },
+          "actions": {
+            "view:public": "EFFECT_ALLOW",
+            "approve": "EFFECT_ALLOW"
+          },
+          "meta": {
+            "actions": {
+              "view:public": {
+                "matchedPolicy": "principal.donald_duck.v20210210"
+              },
+              "approve": {
+                "matchedPolicy": "principal.donald_duck.v20210210"
+              }
+            }
+          }
+        }
+      ]
+    }
+  }
diff --git a/internal/test/testdata/server/playground/proxy/pgp_cr_invalid_case_00.yaml b/internal/test/testdata/server/playground/proxy/pgp_cr_invalid_case_00.yaml
new file mode 100644
index 00000000..25e476a4
--- /dev/null
+++ b/internal/test/testdata/server/playground/proxy/pgp_cr_invalid_case_00.yaml
@@ -0,0 +1,96 @@
+---
+description: "Missing principal"
+wantStatus:
+  httpStatusCode: 400
+  grpcStatusCode: 3
+wantError: true
+playgroundProxy:
+  input: {
+    "playgroundId": "test",
+    "files": [
+      {
+        "fileName": "derived_roles_01.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "derived_roles_02.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_02.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_05.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "principal.yaml",
+        "contents": "{{ fileString `store/principal_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/principal.json",
+        "contents": "{{ fileString `store/_schemas/principal.json` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/leave_request.json",
+        "contents": "{{ fileString `store/_schemas/leave_request.json` | b64enc }}",
+      }
+    ],
+    "checkResources": {
+      "requestId": "test",
+      "resources": [
+        {
+          "actions": [
+            "view:public",
+            "approve"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "policyVersion": "20210210",
+            "id": "XX125",
+            "attr": {
+              "department": "marketing",
+              "geography": "GB",
+              "id": "XX125",
+              "owner": "john",
+              "team": "design"
+            }
+          }
+        },
+        {
+          "actions": [
+            "view:public",
+            "approve"
+          ],
+          "resource": {
+            "kind": "leave_request",
+            "policyVersion": "20210210",
+            "id": "YY125",
+            "attr": {
+              "department": "engineering",
+              "geography": "GB",
+              "id": "YY125",
+              "owner": "jenny",
+              "team": "backend"
+            }
+          }
+        },
+        {
+          "actions": [
+            "view:public",
+            "delete",
+            "edit"
+          ],
+          "resource": {
+            "kind": "salary_record",
+            "policyVersion": "20210210",
+            "id": "YY525",
+            "attr": {
+              "department": "engineering",
+              "geography": "GB",
+              "id": "YY525",
+              "owner": "mark",
+              "team": "backend"
+            }
+          }
+        }
+      ]
+    }
+  }
diff --git a/internal/test/testdata/server/playground/proxy/pgp_cr_invalid_case_01.yaml b/internal/test/testdata/server/playground/proxy/pgp_cr_invalid_case_01.yaml
new file mode 100644
index 00000000..18c8ccd8
--- /dev/null
+++ b/internal/test/testdata/server/playground/proxy/pgp_cr_invalid_case_01.yaml
@@ -0,0 +1,67 @@
+---
+description: "Empty actions"
+wantStatus:
+  httpStatusCode: 400
+  grpcStatusCode: 3
+wantError: true
+playgroundProxy:
+  input: {
+    "playgroundId": "test",
+    "files": [
+      {
+        "fileName": "derived_roles_01.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "derived_roles_02.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_02.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_05.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "principal.yaml",
+        "contents": "{{ fileString `store/principal_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/principal.json",
+        "contents": "{{ fileString `store/_schemas/principal.json` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/leave_request.json",
+        "contents": "{{ fileString `store/_schemas/leave_request.json` | b64enc }}",
+      }
+    ],
+    "checkResources": {
+      "requestId": "test",
+      "principal": {
+        "id": "john",
+        "policyVersion": "20210210",
+        "roles": [
+          "employee"
+        ],
+        "attr": {
+          "department": "marketing",
+          "geography": "GB",
+          "team": "design"
+        }
+      },
+      "resources": [
+        {
+          "resource": {
+            "kind": "leave_request",
+            "policyVersion": "20210210",
+            "id": "XX125",
+            "attr": {
+              "department": "marketing",
+              "geography": "GB",
+              "id": "XX125",
+              "owner": "john",
+              "team": "design"
+            }
+          }
+        }
+      ]
+    }
+  }
diff --git a/internal/test/testdata/server/playground/proxy/pgp_cr_invalid_case_03.yaml b/internal/test/testdata/server/playground/proxy/pgp_cr_invalid_case_03.yaml
new file mode 100644
index 00000000..16015a4c
--- /dev/null
+++ b/internal/test/testdata/server/playground/proxy/pgp_cr_invalid_case_03.yaml
@@ -0,0 +1,51 @@
+---
+description: "Empty resources"
+wantStatus:
+  httpStatusCode: 400
+  grpcStatusCode: 3
+wantError: true
+playgroundProxy:
+  input: {
+    "playgroundId": "test",
+    "files": [
+      {
+        "fileName": "derived_roles_01.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "derived_roles_02.yaml",
+        "contents": "{{ fileString `store/derived_roles/derived_roles_02.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "policy_05.yaml",
+        "contents": "{{ fileString `store/resource_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "principal.yaml",
+        "contents": "{{ fileString `store/principal_policies/policy_01.yaml` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/principal.json",
+        "contents": "{{ fileString `store/_schemas/principal.json` | b64enc }}",
+      },
+      {
+        "fileName": "_schemas/leave_request.json",
+        "contents": "{{ fileString `store/_schemas/leave_request.json` | b64enc }}",
+      }
+    ],
+    "checkResources": {
+      "requestId": "test",
+      "principal": {
+        "id": "john",
+        "policyVersion": "20210210",
+        "roles": [
+          "employee"
+        ],
+        "attr": {
+          "department": "marketing",
+          "geography": "GB",
+          "team": "design"
+        }
+      }
+    }
+  }
diff --git a/internal/test/testdata/store/derived_roles/derived_roles_01.yaml b/internal/test/testdata/store/derived_roles/derived_roles_01.yaml
index 94395e12..dc75ea36 100644
--- a/internal/test/testdata/store/derived_roles/derived_roles_01.yaml
+++ b/internal/test/testdata/store/derived_roles/derived_roles_01.yaml
@@ -13,4 +13,4 @@ derivedRoles:
       parentRoles: ["employee"]
       condition:
         match:
-          expr: R.attr.owner == P.id
+          expr: R.attr.owner == P.id
\ No newline at end of file