From 9e883417a37d531ed96a6dd7204080eb3c41dc96 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Thu, 7 May 2026 11:44:27 -0700 Subject: [PATCH 01/11] DSPX-3195 Add resource mapping group FQNs --- docs/grpc/index.html | 7 + .../policy/actions/actions.openapi.yaml | 4 + .../policy/attributes/attributes.openapi.yaml | 4 + docs/openapi/policy/objects.openapi.yaml | 4 + .../obligations/obligations.openapi.yaml | 4 + .../registered_resources.openapi.yaml | 4 + .../resource_mapping.openapi.yaml | 4 + .../subject_mapping.openapi.yaml | 4 + .../openapi/policy/unsafe/unsafe.openapi.yaml | 4 + otdfctl/e2e/resource-mapping-groups.bats | 22 +- protocol/go/policy/objects.pb.go | 724 +++++++++--------- service/integration/resource_mappings_test.go | 27 + .../policy/db/queries/resource_mapping.sql | 24 +- service/policy/db/resource_mapping.go | 29 +- service/policy/db/resource_mapping.sql.go | 52 +- service/policy/objects.proto | 3 + .../resourcemapping/resource_mapping.go | 129 ++-- 17 files changed, 604 insertions(+), 445 deletions(-) diff --git a/docs/grpc/index.html b/docs/grpc/index.html index 5c2c15a7d9..e332880030 100644 --- a/docs/grpc/index.html +++ b/docs/grpc/index.html @@ -3612,6 +3612,13 @@

ResourceMappingGroup

per namespace

+ + fqn + string + +

the fully qualified name of the resource mapping group

+ + metadata common.Metadata diff --git a/docs/openapi/policy/actions/actions.openapi.yaml b/docs/openapi/policy/actions/actions.openapi.yaml index 10294d2f39..4f4681fc77 100644 --- a/docs/openapi/policy/actions/actions.openapi.yaml +++ b/docs/openapi/policy/actions/actions.openapi.yaml @@ -887,6 +887,10 @@ components: description: |- the common name for the group of resource mappings, which must be unique per namespace + fqn: + type: string + title: fqn + description: the fully qualified name of the resource mapping group metadata: title: metadata description: Common metadata diff --git a/docs/openapi/policy/attributes/attributes.openapi.yaml b/docs/openapi/policy/attributes/attributes.openapi.yaml index e3db78cf37..6f32d5b4eb 100644 --- a/docs/openapi/policy/attributes/attributes.openapi.yaml +++ b/docs/openapi/policy/attributes/attributes.openapi.yaml @@ -1462,6 +1462,10 @@ components: description: |- the common name for the group of resource mappings, which must be unique per namespace + fqn: + type: string + title: fqn + description: the fully qualified name of the resource mapping group metadata: title: metadata description: Common metadata diff --git a/docs/openapi/policy/objects.openapi.yaml b/docs/openapi/policy/objects.openapi.yaml index 202bf2b533..d6e1e3806c 100644 --- a/docs/openapi/policy/objects.openapi.yaml +++ b/docs/openapi/policy/objects.openapi.yaml @@ -852,6 +852,10 @@ components: description: |- the common name for the group of resource mappings, which must be unique per namespace + fqn: + type: string + title: fqn + description: the fully qualified name of the resource mapping group metadata: title: metadata description: Common metadata diff --git a/docs/openapi/policy/obligations/obligations.openapi.yaml b/docs/openapi/policy/obligations/obligations.openapi.yaml index d2a89463e9..1780201216 100644 --- a/docs/openapi/policy/obligations/obligations.openapi.yaml +++ b/docs/openapi/policy/obligations/obligations.openapi.yaml @@ -1292,6 +1292,10 @@ components: description: |- the common name for the group of resource mappings, which must be unique per namespace + fqn: + type: string + title: fqn + description: the fully qualified name of the resource mapping group metadata: title: metadata description: Common metadata diff --git a/docs/openapi/policy/registeredresources/registered_resources.openapi.yaml b/docs/openapi/policy/registeredresources/registered_resources.openapi.yaml index 611dce1479..c6e813ea1a 100644 --- a/docs/openapi/policy/registeredresources/registered_resources.openapi.yaml +++ b/docs/openapi/policy/registeredresources/registered_resources.openapi.yaml @@ -1181,6 +1181,10 @@ components: description: |- the common name for the group of resource mappings, which must be unique per namespace + fqn: + type: string + title: fqn + description: the fully qualified name of the resource mapping group metadata: title: metadata description: Common metadata diff --git a/docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml b/docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml index bc2c45eb17..8fb2f4e53f 100644 --- a/docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml +++ b/docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml @@ -1097,6 +1097,10 @@ components: description: |- the common name for the group of resource mappings, which must be unique per namespace + fqn: + type: string + title: fqn + description: the fully qualified name of the resource mapping group metadata: title: metadata description: Common metadata diff --git a/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml b/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml index 010427f980..bf25db5752 100644 --- a/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml +++ b/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml @@ -1159,6 +1159,10 @@ components: description: |- the common name for the group of resource mappings, which must be unique per namespace + fqn: + type: string + title: fqn + description: the fully qualified name of the resource mapping group metadata: title: metadata description: Common metadata diff --git a/docs/openapi/policy/unsafe/unsafe.openapi.yaml b/docs/openapi/policy/unsafe/unsafe.openapi.yaml index 3b2ad2e3d0..17c9652a41 100644 --- a/docs/openapi/policy/unsafe/unsafe.openapi.yaml +++ b/docs/openapi/policy/unsafe/unsafe.openapi.yaml @@ -1129,6 +1129,10 @@ components: description: |- the common name for the group of resource mappings, which must be unique per namespace + fqn: + type: string + title: fqn + description: the fully qualified name of the resource mapping group metadata: title: metadata description: Common metadata diff --git a/otdfctl/e2e/resource-mapping-groups.bats b/otdfctl/e2e/resource-mapping-groups.bats index 28561ce89f..0b52c27328 100644 --- a/otdfctl/e2e/resource-mapping-groups.bats +++ b/otdfctl/e2e/resource-mapping-groups.bats @@ -7,9 +7,9 @@ setup_file() { export HOST='--host http://localhost:8080' # Create two namespaced values to be used in other tests - NS_NAME="resource-mapping-groups.io" + export NS_NAME="resource-mapping-groups.io" export NS_ID=$(./otdfctl $HOST $WITH_CREDS policy attributes namespaces create -n "$NS_NAME" --json | jq -r '.id') - NS_NAME2="resource-mapping-groups-2.io" + export NS_NAME2="resource-mapping-groups-2.io" export NS2_ID=$(./otdfctl $HOST $WITH_CREDS policy attributes namespaces create -n "$NS_NAME2" --json | jq -r '.id') ATTR_ID=$(./otdfctl $HOST $WITH_CREDS policy attributes create --namespace "$NS_ID" --name attr1 --rule ANY_OF --json | jq -r '.id') # Name is prefixed with RMG to avoid conflicts across tests when running in parallel @@ -17,6 +17,7 @@ setup_file() { # Create a resource mapping group export RMG1_NAME="rmgrp-test" + export RMG1_FQN="https://${NS_NAME}/resm/${RMG1_NAME}" export RMG1_ID=$(./otdfctl $HOST $WITH_CREDS policy resource-mapping-groups create --namespace-id "$NS_ID" --name "$RMG1_NAME" --json | jq -r '.id') # Create a couple resource mappings to val1 - comma separated @@ -42,7 +43,7 @@ teardown_file() { ./otdfctl $HOST $WITH_CREDS policy attributes namespaces unsafe delete --force --id "$NS_ID" ./otdfctl $HOST $WITH_CREDS policy attributes namespaces unsafe delete --force --id "$NS2_ID" - unset HOST WITH_CREDS RMG_VAL1_ID NS_ID NS2_ID RM1_TERMS RM1_ID RM1_OTHER_TERMS RM1_OTHER_ID RMG1_NAME RMG1_ID + unset HOST WITH_CREDS RMG_VAL1_ID NS_NAME NS_ID NS_NAME2 NS2_ID RM1_TERMS RM1_ID RM1_OTHER_TERMS RM1_OTHER_ID RMG1_NAME RMG1_FQN RMG1_ID } @test "Create resource mapping group" { @@ -52,6 +53,10 @@ teardown_file() { assert_output --partial "rmgrp1" assert_line --regexp "Namespace Id.*$NS_ID" + run_otdfctl_rmg create --namespace-id "$NS_ID" --name rmgrp1-json --json + assert_success + assert_equal "$(echo "$output" | jq -r '.fqn')" "https://${NS_NAME}/resm/rmgrp1-json" + # ns id flag must be uuid run_otdfctl_rmg create --namespace-id "something" --name testing assert_failure @@ -77,6 +82,7 @@ teardown_file() { [ $(echo $output | jq -r '.id') = "$RMG1_ID" ] [ $(echo $output | jq -r '.namespace_id') = "$NS_ID" ] [ $(echo $output | jq -r '.name') = "$RMG1_NAME" ] + [ $(echo $output | jq -r '.fqn') = "$RMG1_FQN" ] # id required run_otdfctl_rmg get @@ -104,6 +110,10 @@ teardown_file() { assert_output --partial "new-rsmg-name" refute_output --partial "$NS_ID" assert_output --partial "$NS2_ID" + + run_otdfctl_rmg update --id "$NEW_RMG_ID" --name "new-rsmg-name-json" --json + assert_success + assert_equal "$(echo "$output" | jq -r '.fqn')" "https://${NS_NAME2}/resm/new-rsmg-name-json" } @test "List resource mapping groups" { @@ -121,6 +131,7 @@ teardown_file() { found_rmg=$(echo "$output" | jq -c --arg id "$RMG1_ID" '.resource_mapping_groups as $a | ($a | map(.id) | index($id)) as $i | $a[$i]') assert_equal "$(echo "$found_rmg" | jq -r '.id')" "$RMG1_ID" assert_equal "$(echo "$found_rmg" | jq -r '.name')" "$RMG1_NAME" + assert_equal "$(echo "$found_rmg" | jq -r '.fqn')" "$RMG1_FQN" [[ "$(echo "$output" | jq -r '.pagination.total')" -ge 1 ]] assert_equal "$(echo "$output" | jq -r '.pagination.current_offset')" "null" assert_equal "$(echo "$output" | jq -r '.pagination.next_offset')" "null" @@ -133,4 +144,9 @@ teardown_file() { assert_line --regexp "Id.*$RMG1_ID" assert_line --regexp "Namespace Id.*$NS_ID" assert_line --regexp "Name.*$RMG1_NAME" + + NEW_RMG_ID=$(./otdfctl $HOST $WITH_CREDS policy resource-mapping-groups create --namespace-id "$NS_ID" --name rmgrp-delete-json --json | jq -r '.id') + run_otdfctl_rmg delete --id "$NEW_RMG_ID" --force --json + assert_success + assert_equal "$(echo "$output" | jq -r '.fqn')" "https://${NS_NAME}/resm/rmgrp-delete-json" } diff --git a/protocol/go/policy/objects.pb.go b/protocol/go/policy/objects.pb.go index cf3740f38e..6d44faec52 100644 --- a/protocol/go/policy/objects.pb.go +++ b/protocol/go/policy/objects.pb.go @@ -1647,6 +1647,8 @@ type ResourceMappingGroup struct { // the common name for the group of resource mappings, which must be unique // per namespace Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + // the fully qualified name of the resource mapping group + Fqn string `protobuf:"bytes,4,opt,name=fqn,proto3" json:"fqn,omitempty"` // Common metadata Metadata *common.Metadata `protobuf:"bytes,100,opt,name=metadata,proto3" json:"metadata,omitempty"` } @@ -1704,6 +1706,13 @@ func (x *ResourceMappingGroup) GetName() string { return "" } +func (x *ResourceMappingGroup) GetFqn() string { + if x != nil { + return x.Fqn + } + return "" +} + func (x *ResourceMappingGroup) GetMetadata() *common.Metadata { if x != nil { return x.Metadata @@ -3383,382 +3392,383 @@ var file_policy_objects_proto_rawDesc = []byte{ 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x22, 0x9b, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x6c, 0x75, 0x65, 0x22, 0xad, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x29, 0x0a, 0x0c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, - 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x22, 0xd9, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x61, - 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x71, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x66, 0x71, 0x6e, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x0f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x06, 0xba, 0x48, 0x03, - 0xc8, 0x01, 0x01, 0x52, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x05, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x32, 0x0a, 0x05, 0x67, 0x72, 0x6f, - 0x75, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, - 0x67, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x85, 0x05, - 0x0a, 0x0f, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x87, 0x03, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, - 0xf4, 0x02, 0xba, 0x48, 0xf0, 0x02, 0xba, 0x01, 0xec, 0x02, 0x0a, 0x0a, 0x75, 0x72, 0x69, 0x5f, - 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0xcf, 0x01, 0x55, 0x52, 0x49, 0x20, 0x6d, 0x75, 0x73, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x55, 0x52, 0x4c, - 0x20, 0x28, 0x65, 0x2e, 0x67, 0x2e, 0x2c, 0x20, 0x27, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, - 0x2f, 0x64, 0x65, 0x6d, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x27, 0x29, 0x20, 0x66, 0x6f, 0x6c, - 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x61, 0x6c, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x20, 0x45, 0x61, - 0x63, 0x68, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x20, 0x77, 0x69, - 0x74, 0x68, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x6e, 0x75, 0x6d, 0x65, 0x72, - 0x69, 0x63, 0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x2c, 0x20, 0x63, 0x61, - 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x68, 0x79, 0x70, 0x68, 0x65, 0x6e, - 0x73, 0x2c, 0x20, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x20, - 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, - 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x1a, 0x8b, 0x01, 0x74, 0x68, 0x69, 0x73, 0x2e, - 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3f, - 0x3a, 0x2f, 0x2f, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x5b, - 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5c, 0x5c, 0x2d, 0x5d, 0x7b, 0x30, 0x2c, - 0x36, 0x31, 0x7d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x3f, - 0x28, 0x5c, 0x5c, 0x2e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x28, - 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5c, 0x5c, 0x2d, 0x5d, 0x7b, 0x30, - 0x2c, 0x36, 0x31, 0x7d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x29, - 0x3f, 0x29, 0x2a, 0x28, 0x3a, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x29, 0x3f, 0x28, 0x2f, 0x2e, - 0x2a, 0x29, 0x3f, 0x24, 0x27, 0x29, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x30, 0x0a, 0x0a, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, - 0x65, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x33, 0x0a, - 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x2f, 0x0a, 0x08, 0x6b, 0x61, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x69, - 0x6d, 0x70, 0x6c, 0x65, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x52, 0x07, 0x6b, 0x61, 0x73, 0x4b, - 0x65, 0x79, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x61, 0x74, 0x61, 0x22, 0xd9, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x97, 0x02, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x37, 0x0a, - 0x09, 0x69, 0x73, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 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, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x69, 0x73, - 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x77, 0x61, 0x73, 0x5f, 0x6d, 0x61, - 0x70, 0x70, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, - 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x09, 0x77, 0x61, 0x73, 0x4d, 0x61, 0x70, 0x70, 0x65, - 0x64, 0x12, 0x33, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, - 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x03, 0x6b, 0x61, 0x73, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x03, 0x6b, 0x61, - 0x73, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, - 0x84, 0x01, 0x0a, 0x0c, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, - 0x12, 0x1c, 0x0a, 0x03, 0x70, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, - 0x48, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0x80, 0x40, 0x52, 0x03, 0x70, 0x65, 0x6d, 0x12, 0x1b, - 0x0a, 0x03, 0x6b, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xba, 0x48, 0x06, - 0x72, 0x04, 0x10, 0x01, 0x18, 0x20, 0x52, 0x03, 0x6b, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x03, 0x61, - 0x6c, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x41, 0x6c, - 0x67, 0x45, 0x6e, 0x75, 0x6d, 0x42, 0x0a, 0xba, 0x48, 0x07, 0x82, 0x01, 0x04, 0x10, 0x01, 0x20, - 0x00, 0x52, 0x03, 0x61, 0x6c, 0x67, 0x22, 0x3b, 0x0a, 0x0f, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x74, 0x12, 0x28, 0x0a, 0x04, 0x6b, 0x65, 0x79, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x04, 0x6b, - 0x65, 0x79, 0x73, 0x22, 0xe0, 0x03, 0x0a, 0x09, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x12, 0x84, 0x03, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x42, 0xe9, 0x02, 0xba, 0x48, 0xe5, 0x02, 0xba, 0x01, 0xe1, 0x02, 0x0a, 0x0a, 0x75, - 0x72, 0x69, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0xcf, 0x01, 0x55, 0x52, 0x49, 0x20, - 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, - 0x55, 0x52, 0x4c, 0x20, 0x28, 0x65, 0x2e, 0x67, 0x2e, 0x2c, 0x20, 0x27, 0x68, 0x74, 0x74, 0x70, - 0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x65, 0x6d, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x27, 0x29, 0x20, - 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x64, 0x64, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e, - 0x20, 0x45, 0x61, 0x63, 0x68, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x75, - 0x73, 0x74, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6e, 0x64, - 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x6e, 0x75, - 0x6d, 0x65, 0x72, 0x69, 0x63, 0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x2c, - 0x20, 0x63, 0x61, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x68, 0x79, 0x70, - 0x68, 0x65, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x6e, 0x75, 0x6d, 0x65, 0x72, - 0x69, 0x63, 0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x61, - 0x6e, 0x64, 0x20, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x1a, 0x80, 0x01, 0x74, 0x68, - 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x68, 0x74, 0x74, - 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x0f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, + 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x06, 0xba, + 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x32, 0x0a, 0x05, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x61, 0x70, 0x70, + 0x69, 0x6e, 0x67, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x22, + 0x85, 0x05, 0x0a, 0x0f, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x87, 0x03, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x42, 0xf4, 0x02, 0xba, 0x48, 0xf0, 0x02, 0xba, 0x01, 0xec, 0x02, 0x0a, 0x0a, 0x75, 0x72, + 0x69, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0xcf, 0x01, 0x55, 0x52, 0x49, 0x20, 0x6d, + 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x55, + 0x52, 0x4c, 0x20, 0x28, 0x65, 0x2e, 0x67, 0x2e, 0x2c, 0x20, 0x27, 0x68, 0x74, 0x74, 0x70, 0x73, + 0x3a, 0x2f, 0x2f, 0x64, 0x65, 0x6d, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x27, 0x29, 0x20, 0x66, + 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x20, + 0x45, 0x61, 0x63, 0x68, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, + 0x74, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x6e, 0x75, 0x6d, + 0x65, 0x72, 0x69, 0x63, 0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x2c, 0x20, + 0x63, 0x61, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x68, 0x79, 0x70, 0x68, + 0x65, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, + 0x63, 0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x1a, 0x8b, 0x01, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x68, 0x74, 0x74, 0x70, + 0x73, 0x3f, 0x3a, 0x2f, 0x2f, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5c, 0x5c, 0x2d, 0x5d, 0x7b, 0x30, 0x2c, 0x36, 0x31, 0x7d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x3f, 0x28, 0x5c, 0x5c, 0x2e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5c, 0x5c, 0x2d, 0x5d, 0x7b, 0x30, 0x2c, 0x36, 0x31, 0x7d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, - 0x5d, 0x29, 0x3f, 0x29, 0x2a, 0x28, 0x2f, 0x2e, 0x2a, 0x29, 0x3f, 0x24, 0x27, 0x29, 0x48, 0x00, - 0x52, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x63, 0x61, 0x63, 0x68, - 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x65, - 0x74, 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x42, 0x0c, 0x0a, 0x0a, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, - 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x22, 0xd0, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x37, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x09, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x6d, + 0x5d, 0x29, 0x3f, 0x29, 0x2a, 0x28, 0x3a, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x29, 0x3f, 0x28, + 0x2f, 0x2e, 0x2a, 0x29, 0x3f, 0x24, 0x27, 0x29, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x30, 0x0a, + 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, + 0x33, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x2f, 0x0a, 0x08, 0x6b, 0x61, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, + 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x52, 0x07, 0x6b, 0x61, + 0x73, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x14, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x97, 0x02, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x37, 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 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, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, + 0x69, 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x77, 0x61, 0x73, 0x5f, + 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, + 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x09, 0x77, 0x61, 0x73, 0x4d, 0x61, 0x70, + 0x70, 0x65, 0x64, 0x12, 0x33, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, + 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x2e, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x09, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x03, 0x6b, 0x61, 0x73, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, + 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x03, + 0x6b, 0x61, 0x73, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x22, 0x84, 0x01, 0x0a, 0x0c, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, + 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x03, 0x70, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x0a, 0xba, 0x48, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0x80, 0x40, 0x52, 0x03, 0x70, 0x65, 0x6d, + 0x12, 0x1b, 0x0a, 0x03, 0x6b, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xba, + 0x48, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x20, 0x52, 0x03, 0x6b, 0x69, 0x64, 0x12, 0x39, 0x0a, + 0x03, 0x61, 0x6c, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x41, 0x6c, 0x67, 0x45, 0x6e, 0x75, 0x6d, 0x42, 0x0a, 0xba, 0x48, 0x07, 0x82, 0x01, 0x04, 0x10, + 0x01, 0x20, 0x00, 0x52, 0x03, 0x61, 0x6c, 0x67, 0x22, 0x3b, 0x0a, 0x0f, 0x4b, 0x61, 0x73, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x74, 0x12, 0x28, 0x0a, 0x04, 0x6b, + 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, + 0x04, 0x6b, 0x65, 0x79, 0x73, 0x22, 0xe0, 0x03, 0x0a, 0x09, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x12, 0x84, 0x03, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0xe9, 0x02, 0xba, 0x48, 0xe5, 0x02, 0xba, 0x01, 0xe1, 0x02, 0x0a, + 0x0a, 0x75, 0x72, 0x69, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0xcf, 0x01, 0x55, 0x52, + 0x49, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x20, 0x55, 0x52, 0x4c, 0x20, 0x28, 0x65, 0x2e, 0x67, 0x2e, 0x2c, 0x20, 0x27, 0x68, 0x74, + 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x65, 0x6d, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x27, + 0x29, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x64, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x20, 0x45, 0x61, 0x63, 0x68, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, + 0x6d, 0x75, 0x73, 0x74, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65, + 0x6e, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x6c, 0x70, 0x68, 0x61, + 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, + 0x72, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x68, + 0x79, 0x70, 0x68, 0x65, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x6e, 0x75, 0x6d, + 0x65, 0x72, 0x69, 0x63, 0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x73, 0x2c, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x1a, 0x80, 0x01, + 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, + 0x39, 0x5d, 0x28, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5c, 0x5c, 0x2d, + 0x5d, 0x7b, 0x30, 0x2c, 0x36, 0x31, 0x7d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, + 0x39, 0x5d, 0x29, 0x3f, 0x28, 0x5c, 0x5c, 0x2e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, + 0x2d, 0x39, 0x5d, 0x28, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5c, 0x5c, + 0x2d, 0x5d, 0x7b, 0x30, 0x2c, 0x36, 0x31, 0x7d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, + 0x2d, 0x39, 0x5d, 0x29, 0x3f, 0x29, 0x2a, 0x28, 0x2f, 0x2e, 0x2a, 0x29, 0x3f, 0x24, 0x27, 0x29, + 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x63, 0x61, + 0x63, 0x68, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x53, 0x65, 0x74, 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x42, 0x0c, 0x0a, + 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x4a, 0x04, 0x08, 0x02, 0x10, + 0x03, 0x52, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x22, 0xd0, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x09, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x2c, 0x0a, + 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xca, 0x03, 0x0a, 0x17, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, + 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x6c, 0x0a, 0x17, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x15, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x1a, 0xb4, 0x01, 0x0a, 0x14, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x06, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x0f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x61, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3e, 0x0a, 0x16, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, + 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x08, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x4a, 0x0a, 0x0e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x38, 0x0a, 0x03, 0x70, 0x65, + 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, + 0x03, 0x70, 0x65, 0x70, 0x22, 0xd2, 0x01, 0x0a, 0x0a, 0x4f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x2f, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, + 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x2e, 0x4f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x71, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, 0x71, 0x6e, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, - 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xca, 0x03, 0x0a, 0x17, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, 0x08, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, - 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x12, 0x6c, 0x0a, 0x17, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x04, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x15, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x73, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, - 0xb4, 0x01, 0x0a, 0x14, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xe2, 0x01, 0x0a, 0x0f, 0x4f, 0x62, + 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x32, 0x0a, + 0x0a, 0x6f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4f, 0x62, 0x6c, 0x69, 0x67, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x6f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x74, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2e, 0x4f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x69, + 0x67, 0x67, 0x65, 0x72, 0x52, 0x08, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x10, + 0x0a, 0x03, 0x66, 0x71, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, 0x71, 0x6e, + 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xd8, + 0x02, 0x0a, 0x11, 0x4f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x69, + 0x67, 0x67, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x42, 0x0a, 0x10, 0x6f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x6f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x0f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x6f, 0x6c, 0x69, + 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3e, 0x0a, 0x16, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, - 0x12, 0x24, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x08, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x4a, 0x0a, 0x0e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x38, 0x0a, 0x03, 0x70, 0x65, 0x70, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x03, 0x70, - 0x65, 0x70, 0x22, 0xd2, 0x01, 0x0a, 0x0a, 0x4f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x2f, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, - 0x4f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, - 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x71, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, 0x71, 0x6e, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xe2, 0x01, 0x0a, 0x0f, 0x4f, 0x62, 0x6c, 0x69, - 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x32, 0x0a, 0x0a, 0x6f, - 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x12, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x6f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, - 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x4f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x69, 0x67, 0x67, - 0x65, 0x72, 0x52, 0x08, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x10, 0x0a, 0x03, - 0x66, 0x71, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, 0x71, 0x6e, 0x12, 0x2c, - 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xd8, 0x02, 0x0a, - 0x11, 0x4f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x69, 0x67, 0x67, - 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x12, 0x42, 0x0a, 0x10, 0x6f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x6f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, - 0x0a, 0x0f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x30, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, - 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, - 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x2f, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x09, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x61, 0x0a, 0x06, 0x4b, 0x61, 0x73, 0x4b, 0x65, - 0x79, 0x12, 0x15, 0x0a, 0x06, 0x6b, 0x61, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x6b, 0x61, 0x73, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, - 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x17, 0x0a, 0x07, 0x6b, 0x61, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x6b, 0x61, 0x73, 0x55, 0x72, 0x69, 0x22, 0x29, 0x0a, 0x0c, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12, 0x19, 0x0a, 0x03, 0x70, 0x65, - 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, - 0x52, 0x03, 0x70, 0x65, 0x6d, 0x22, 0x50, 0x0a, 0x0d, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, - 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12, 0x1e, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, - 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, - 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x72, 0x61, - 0x70, 0x70, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x22, 0xd1, 0x03, 0x0a, 0x0d, 0x41, 0x73, 0x79, 0x6d, - 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x6b, 0x65, 0x79, - 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, - 0x12, 0x36, 0x0a, 0x0d, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, - 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x52, 0x0c, 0x6b, 0x65, 0x79, 0x41, - 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x30, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x09, 0x6b, 0x65, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2a, 0x0a, 0x08, 0x6b, 0x65, - 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x07, 0x6b, - 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x3a, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, - 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x43, 0x74, 0x78, 0x52, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x43, - 0x74, 0x78, 0x12, 0x3d, 0x0a, 0x0f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, - 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x43, - 0x74, 0x78, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x43, 0x74, - 0x78, 0x12, 0x42, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x12, 0x2c, 0x0a, - 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x9e, 0x02, 0x0a, 0x0c, - 0x53, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, - 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x65, - 0x79, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x4b, 0x65, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x09, 0x6b, 0x65, 0x79, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x4b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x4d, 0x6f, 0x64, - 0x65, 0x12, 0x17, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x06, 0x6b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12, 0x42, 0x0a, 0x0f, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2c, - 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2a, 0xb3, 0x01, 0x0a, - 0x15, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x79, - 0x70, 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x28, 0x0a, 0x24, 0x41, 0x54, 0x54, 0x52, 0x49, 0x42, - 0x55, 0x54, 0x45, 0x5f, 0x52, 0x55, 0x4c, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, - 0x55, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x23, 0x0a, 0x1f, 0x41, 0x54, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x5f, 0x52, 0x55, - 0x4c, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x41, 0x4c, 0x4c, - 0x5f, 0x4f, 0x46, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x41, 0x54, 0x54, 0x52, 0x49, 0x42, 0x55, - 0x54, 0x45, 0x5f, 0x52, 0x55, 0x4c, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, 0x55, - 0x4d, 0x5f, 0x41, 0x4e, 0x59, 0x5f, 0x4f, 0x46, 0x10, 0x02, 0x12, 0x26, 0x0a, 0x22, 0x41, 0x54, - 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x5f, 0x52, 0x55, 0x4c, 0x45, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x48, 0x49, 0x45, 0x52, 0x41, 0x52, 0x43, 0x48, 0x59, - 0x10, 0x03, 0x2a, 0xca, 0x01, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x61, - 0x70, 0x70, 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x75, - 0x6d, 0x12, 0x2d, 0x0a, 0x29, 0x53, 0x55, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x4d, 0x41, 0x50, - 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x45, 0x4e, - 0x55, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x24, 0x0a, 0x20, 0x53, 0x55, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x4d, 0x41, 0x50, 0x50, - 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x45, 0x4e, 0x55, - 0x4d, 0x5f, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x28, 0x0a, 0x24, 0x53, 0x55, 0x42, 0x4a, 0x45, 0x43, - 0x54, 0x5f, 0x4d, 0x41, 0x50, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, - 0x4f, 0x52, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, 0x10, 0x02, - 0x12, 0x2d, 0x0a, 0x29, 0x53, 0x55, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x4d, 0x41, 0x50, 0x50, - 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x45, 0x4e, 0x55, - 0x4d, 0x5f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49, 0x4e, 0x53, 0x10, 0x03, 0x2a, - 0x90, 0x01, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6f, 0x6f, - 0x6c, 0x65, 0x61, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x2b, 0x0a, 0x27, - 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, - 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x23, 0x0a, 0x1f, 0x43, 0x4f, 0x4e, - 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x41, 0x4e, 0x44, 0x10, 0x01, 0x12, 0x22, - 0x0a, 0x1e, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4f, 0x4f, 0x4c, - 0x45, 0x41, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x4f, 0x52, - 0x10, 0x02, 0x2a, 0x5d, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, - 0x14, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, - 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x4f, 0x55, 0x52, 0x43, - 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x58, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, - 0x02, 0x2a, 0x88, 0x02, 0x0a, 0x13, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, - 0x65, 0x79, 0x41, 0x6c, 0x67, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x27, 0x0a, 0x23, 0x4b, 0x41, 0x53, - 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, + 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x30, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x2f, 0x0a, 0x09, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, + 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x61, 0x0a, 0x06, 0x4b, 0x61, 0x73, + 0x4b, 0x65, 0x79, 0x12, 0x15, 0x0a, 0x06, 0x6b, 0x61, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x61, 0x73, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x2e, 0x41, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x6b, 0x61, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6b, 0x61, 0x73, 0x55, 0x72, 0x69, 0x22, 0x29, 0x0a, 0x0c, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12, 0x19, 0x0a, 0x03, + 0x70, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, + 0x10, 0x01, 0x52, 0x03, 0x70, 0x65, 0x6d, 0x22, 0x50, 0x0a, 0x0d, 0x50, 0x72, 0x69, 0x76, 0x61, + 0x74, 0x65, 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12, 0x1e, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, + 0x01, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x72, 0x61, 0x70, + 0x70, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, + 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x22, 0xd1, 0x03, 0x0a, 0x0d, 0x41, 0x73, + 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x6b, + 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x65, 0x79, + 0x49, 0x64, 0x12, 0x36, 0x0a, 0x0d, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, + 0x74, 0x68, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x52, 0x0c, 0x6b, 0x65, + 0x79, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x30, 0x0a, 0x0a, 0x6b, 0x65, + 0x79, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, + 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x09, 0x6b, 0x65, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2a, 0x0a, 0x08, + 0x6b, 0x65, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, + 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x52, + 0x07, 0x6b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x3a, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x14, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x52, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x43, 0x74, 0x78, 0x12, 0x3d, 0x0a, 0x0f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, + 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, + 0x79, 0x43, 0x74, 0x78, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, + 0x43, 0x74, 0x78, 0x12, 0x42, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x67, 0x61, 0x63, + 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x12, + 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x9e, 0x02, + 0x0a, 0x0c, 0x53, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x15, + 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x6b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x09, 0x6b, 0x65, + 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x6d, + 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x4d, + 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x74, 0x78, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6b, 0x65, 0x79, 0x43, 0x74, 0x78, 0x12, 0x42, 0x0a, 0x0f, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, + 0x65, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x0e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x64, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2a, 0xb3, + 0x01, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x28, 0x0a, 0x24, 0x41, 0x54, 0x54, 0x52, + 0x49, 0x42, 0x55, 0x54, 0x45, 0x5f, 0x52, 0x55, 0x4c, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x23, 0x0a, 0x1f, 0x41, 0x54, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x5f, + 0x52, 0x55, 0x4c, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x41, + 0x4c, 0x4c, 0x5f, 0x4f, 0x46, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x41, 0x54, 0x54, 0x52, 0x49, + 0x42, 0x55, 0x54, 0x45, 0x5f, 0x52, 0x55, 0x4c, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, + 0x4e, 0x55, 0x4d, 0x5f, 0x41, 0x4e, 0x59, 0x5f, 0x4f, 0x46, 0x10, 0x02, 0x12, 0x26, 0x0a, 0x22, + 0x41, 0x54, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x5f, 0x52, 0x55, 0x4c, 0x45, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x48, 0x49, 0x45, 0x52, 0x41, 0x52, 0x43, + 0x48, 0x59, 0x10, 0x03, 0x2a, 0xca, 0x01, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x45, + 0x6e, 0x75, 0x6d, 0x12, 0x2d, 0x0a, 0x29, 0x53, 0x55, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x4d, + 0x41, 0x50, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x24, 0x0a, 0x20, 0x4b, 0x41, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, - 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x52, 0x53, - 0x41, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x4b, 0x41, 0x53, 0x5f, - 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, - 0x4e, 0x55, 0x4d, 0x5f, 0x52, 0x53, 0x41, 0x5f, 0x34, 0x30, 0x39, 0x36, 0x10, 0x02, 0x12, 0x28, - 0x0a, 0x24, 0x4b, 0x41, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, - 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x53, 0x45, 0x43, - 0x50, 0x32, 0x35, 0x36, 0x52, 0x31, 0x10, 0x05, 0x12, 0x28, 0x0a, 0x24, 0x4b, 0x41, 0x53, 0x5f, - 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, - 0x4e, 0x55, 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x53, 0x45, 0x43, 0x50, 0x33, 0x38, 0x34, 0x52, 0x31, - 0x10, 0x06, 0x12, 0x28, 0x0a, 0x24, 0x4b, 0x41, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, - 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x45, 0x43, - 0x5f, 0x53, 0x45, 0x43, 0x50, 0x35, 0x32, 0x31, 0x52, 0x31, 0x10, 0x07, 0x2a, 0x9b, 0x01, 0x0a, - 0x09, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x4c, - 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, - 0x48, 0x4d, 0x5f, 0x52, 0x53, 0x41, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x10, 0x01, 0x12, 0x16, 0x0a, - 0x12, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x52, 0x53, 0x41, 0x5f, 0x34, - 0x30, 0x39, 0x36, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, - 0x48, 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x50, 0x32, 0x35, 0x36, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, - 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x50, 0x33, 0x38, - 0x34, 0x10, 0x04, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, - 0x5f, 0x45, 0x43, 0x5f, 0x50, 0x35, 0x32, 0x31, 0x10, 0x05, 0x2a, 0x56, 0x0a, 0x09, 0x4b, 0x65, - 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x16, 0x4b, 0x45, 0x59, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x4b, 0x45, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, - 0x53, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x4b, 0x45, - 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x52, 0x4f, 0x54, 0x41, 0x54, 0x45, 0x44, - 0x10, 0x02, 0x2a, 0x94, 0x01, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, - 0x0a, 0x14, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x4b, 0x45, 0x59, 0x5f, - 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x52, 0x4f, 0x4f, 0x54, - 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x01, 0x12, 0x1e, 0x0a, 0x1a, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, - 0x44, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44, 0x45, 0x52, 0x5f, 0x52, 0x4f, 0x4f, 0x54, - 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, - 0x44, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x10, 0x03, 0x12, 0x1c, 0x0a, 0x18, 0x4b, - 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, - 0x45, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x04, 0x42, 0x82, 0x01, 0x0a, 0x0a, 0x63, 0x6f, - 0x6d, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, 0x0c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, 0x66, 0x2f, 0x70, 0x6c, 0x61, - 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x67, - 0x6f, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0xa2, 0x02, 0x03, 0x50, 0x58, 0x58, 0xaa, 0x02, - 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0xca, 0x02, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0xe2, 0x02, 0x12, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x10, 0x00, 0x12, 0x24, 0x0a, 0x20, 0x53, 0x55, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x4d, 0x41, + 0x50, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x45, + 0x4e, 0x55, 0x4d, 0x5f, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x28, 0x0a, 0x24, 0x53, 0x55, 0x42, 0x4a, + 0x45, 0x43, 0x54, 0x5f, 0x4d, 0x41, 0x50, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x52, + 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, + 0x10, 0x02, 0x12, 0x2d, 0x0a, 0x29, 0x53, 0x55, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x4d, 0x41, + 0x50, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x45, + 0x4e, 0x55, 0x4d, 0x5f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49, 0x4e, 0x53, 0x10, + 0x03, 0x2a, 0x90, 0x01, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, + 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x2b, + 0x0a, 0x27, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4f, 0x4f, 0x4c, + 0x45, 0x41, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x23, 0x0a, 0x1f, 0x43, + 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x41, 0x4e, 0x44, 0x10, 0x01, + 0x12, 0x22, 0x0a, 0x1e, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4f, + 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, + 0x4f, 0x52, 0x10, 0x02, 0x2a, 0x5d, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x18, 0x0a, 0x14, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, + 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x4f, 0x55, + 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x58, 0x54, 0x45, 0x52, 0x4e, 0x41, + 0x4c, 0x10, 0x02, 0x2a, 0x88, 0x02, 0x0a, 0x13, 0x4b, 0x61, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x41, 0x6c, 0x67, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x27, 0x0a, 0x23, 0x4b, + 0x41, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, + 0x47, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x24, 0x0a, 0x20, 0x4b, 0x41, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, + 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, + 0x52, 0x53, 0x41, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x4b, 0x41, + 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, + 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x52, 0x53, 0x41, 0x5f, 0x34, 0x30, 0x39, 0x36, 0x10, 0x02, + 0x12, 0x28, 0x0a, 0x24, 0x4b, 0x41, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, + 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x53, + 0x45, 0x43, 0x50, 0x32, 0x35, 0x36, 0x52, 0x31, 0x10, 0x05, 0x12, 0x28, 0x0a, 0x24, 0x4b, 0x41, + 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, + 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x53, 0x45, 0x43, 0x50, 0x33, 0x38, 0x34, + 0x52, 0x31, 0x10, 0x06, 0x12, 0x28, 0x0a, 0x24, 0x4b, 0x41, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, + 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x5f, + 0x45, 0x43, 0x5f, 0x53, 0x45, 0x43, 0x50, 0x35, 0x32, 0x31, 0x52, 0x31, 0x10, 0x07, 0x2a, 0x9b, + 0x01, 0x0a, 0x09, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x19, 0x0a, 0x15, + 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x4c, 0x47, 0x4f, 0x52, + 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x52, 0x53, 0x41, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x10, 0x01, 0x12, + 0x16, 0x0a, 0x12, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x52, 0x53, 0x41, + 0x5f, 0x34, 0x30, 0x39, 0x36, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x4c, 0x47, 0x4f, 0x52, + 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x50, 0x32, 0x35, 0x36, 0x10, 0x03, 0x12, 0x15, + 0x0a, 0x11, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x50, + 0x33, 0x38, 0x34, 0x10, 0x04, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, + 0x48, 0x4d, 0x5f, 0x45, 0x43, 0x5f, 0x50, 0x35, 0x32, 0x31, 0x10, 0x05, 0x2a, 0x56, 0x0a, 0x09, + 0x4b, 0x65, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x16, 0x4b, 0x45, 0x59, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x4b, 0x45, 0x59, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, + 0x4b, 0x45, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x52, 0x4f, 0x54, 0x41, 0x54, + 0x45, 0x44, 0x10, 0x02, 0x2a, 0x94, 0x01, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x4d, 0x6f, 0x64, 0x65, + 0x12, 0x18, 0x0a, 0x14, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x4b, 0x45, + 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x52, 0x4f, + 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x01, 0x12, 0x1e, 0x0a, 0x1a, 0x4b, 0x45, 0x59, 0x5f, + 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44, 0x45, 0x52, 0x5f, 0x52, 0x4f, + 0x4f, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x4b, 0x45, 0x59, 0x5f, + 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x10, 0x03, 0x12, 0x1c, 0x0a, + 0x18, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, + 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x04, 0x42, 0x82, 0x01, 0x0a, 0x0a, + 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, 0x0c, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, 0x66, 0x2f, 0x70, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0xa2, 0x02, 0x03, 0x50, 0x58, 0x58, + 0xaa, 0x02, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0xca, 0x02, 0x06, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0xe2, 0x02, 0x12, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5c, 0x47, 0x50, 0x42, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/service/integration/resource_mappings_test.go b/service/integration/resource_mappings_test.go index ff45820aad..11e028f7a9 100644 --- a/service/integration/resource_mappings_test.go +++ b/service/integration/resource_mappings_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/opentdf/platform/lib/identifier" "github.com/opentdf/platform/protocol/go/common" "github.com/opentdf/platform/protocol/go/policy" "github.com/opentdf/platform/protocol/go/policy/attributes" @@ -61,6 +62,7 @@ func (s *ResourceMappingsSuite) Test_ListResourceMappingGroups_NoPagination_Succ for _, rmGroup := range listed { if testRmGroup.ID == rmGroup.GetId() { found = true + s.Equal(s.resourceMappingGroupFqn(testRmGroup), rmGroup.GetFqn()) break } } @@ -121,6 +123,7 @@ func (s *ResourceMappingsSuite) Test_ListResourceMappingGroups_Limit_Succeeds() s.NotEmpty(rmg.GetNamespaceId()) s.NotEmpty(rmg.GetId()) s.NotEmpty(rmg.GetName()) + s.NotEmpty(rmg.GetFqn()) } } @@ -174,6 +177,7 @@ func (s *ResourceMappingsSuite) Test_ListResourceMappingGroups_WithNamespaceId_S s.Equal(scenarioDotComRmGroup.ID, list[0].GetId()) s.Equal(scenarioDotComRmGroup.NamespaceID, list[0].GetNamespaceId()) s.Equal(scenarioDotComRmGroup.Name, list[0].GetName()) + s.Equal(s.resourceMappingGroupFqn(scenarioDotComRmGroup), list[0].GetFqn()) } func (s *ResourceMappingsSuite) Test_ListResourceMappingGroups_MultipleNamespaces_Succeeds() { @@ -316,6 +320,7 @@ func (s *ResourceMappingsSuite) Test_GetResourceMappingGroup() { s.Equal(testRmGroup.ID, rmGroup.GetId()) s.Equal(testRmGroup.NamespaceID, rmGroup.GetNamespaceId()) s.Equal(testRmGroup.Name, rmGroup.GetName()) + s.Equal(s.resourceMappingGroupFqn(testRmGroup), rmGroup.GetFqn()) metadata := rmGroup.GetMetadata() createdAt := metadata.GetCreatedAt() updatedAt := metadata.GetUpdatedAt() @@ -338,6 +343,7 @@ func (s *ResourceMappingsSuite) Test_CreateResourceMappingGroup() { rmGroup, err := s.db.PolicyClient.CreateResourceMappingGroup(s.ctx, req) s.Require().NoError(err) s.NotNil(rmGroup) + s.Equal("https://example.com/resm/example.com_ns_new_group", rmGroup.GetFqn()) } func (s *ResourceMappingsSuite) Test_CreateResourceMappingGroupWithUnknownNamespaceIdFails() { @@ -407,6 +413,7 @@ func (s *ResourceMappingsSuite) Test_UpdateResourceMappingGroup() { s.Require().NoError(err) s.NotNil(updatedGroup) s.Equal(createdGroup.GetId(), updatedGroup.GetId()) + s.Equal("https://scenario.com/resm/example.com_ns_group_updated", updatedGroup.GetFqn()) gotGroup, err := s.db.PolicyClient.GetResourceMappingGroup(s.ctx, createdGroup.GetId()) s.Require().NoError(err) @@ -415,6 +422,7 @@ func (s *ResourceMappingsSuite) Test_UpdateResourceMappingGroup() { s.Equal(createdGroup.GetId(), gotGroup.GetId()) s.Equal(updateReq.GetNamespaceId(), gotGroup.GetNamespaceId()) s.Equal(updateReq.GetName(), gotGroup.GetName()) + s.Equal(updatedGroup.GetFqn(), gotGroup.GetFqn()) metadata := gotGroup.GetMetadata() createdAt := metadata.GetCreatedAt() updatedAt := metadata.GetUpdatedAt() @@ -466,6 +474,8 @@ func (s *ResourceMappingsSuite) Test_UpdateResourceMappingGroupWithNamespaceIdOn s.NotNil(gotUpdatedRmGroup) s.Equal(updateReq.GetNamespaceId(), gotUpdatedRmGroup.GetNamespaceId()) s.Equal(req.GetName(), gotUpdatedRmGroup.GetName()) + s.Equal("https://scenario.com/resm/example.com_ns_group_created_nsidonly", updatedRmGroup.GetFqn()) + s.Equal(updatedRmGroup.GetFqn(), gotUpdatedRmGroup.GetFqn()) } func (s *ResourceMappingsSuite) Test_UpdateResourceMappingGroupWithNameOnlySucceeds() { @@ -491,6 +501,8 @@ func (s *ResourceMappingsSuite) Test_UpdateResourceMappingGroupWithNameOnlySucce s.NotNil(gotUpdatedRmGroup) s.Equal(req.GetNamespaceId(), gotUpdatedRmGroup.GetNamespaceId()) s.Equal(updateReq.GetName(), gotUpdatedRmGroup.GetName()) + s.Equal("https://example.com/resm/example.com_ns_group_created_nameonly_updated", updatedRmGroup.GetFqn()) + s.Equal(updatedRmGroup.GetFqn(), gotUpdatedRmGroup.GetFqn()) } func (s *ResourceMappingsSuite) Test_DeleteResourceMappingGroup() { @@ -521,6 +533,7 @@ func (s *ResourceMappingsSuite) Test_DeleteResourceMappingGroup() { s.Require().NoError(err) s.NotNil(deletedGroup) s.Equal(createdGroup.GetId(), deletedGroup.GetId()) + s.Equal(createdGroup.GetFqn(), deletedGroup.GetFqn()) // get the mapping to verify group id is cascade set to null gotMapping, err := s.db.PolicyClient.GetResourceMapping(s.ctx, createdMapping.GetId()) @@ -1068,6 +1081,10 @@ func (s *ResourceMappingsSuite) Test_ListResourceMappings_ByGroupFqns_Succeeds() s.Equal(scenarioDotComGroup.ID, group.GetId()) s.Equal(scenarioDotComGroup.NamespaceID, group.GetNamespaceId()) s.Equal(scenarioDotComGroup.Name, group.GetName()) + s.Equal(groupFqn, group.GetFqn()) + groupByID, err := s.db.PolicyClient.GetResourceMappingGroup(s.ctx, scenarioDotComGroup.ID) + s.Require().NoError(err) + s.Equal(groupByID.GetFqn(), group.GetFqn()) groupMetadata := group.GetMetadata() createdAt := groupMetadata.GetCreatedAt() updatedAt := groupMetadata.GetUpdatedAt() @@ -1423,6 +1440,16 @@ func (s *ResourceMappingsSuite) getResourceMappingGroupFixtures() []fixtures.Fix } } +func (s *ResourceMappingsSuite) resourceMappingGroupFqn(group fixtures.FixtureDataResourceMappingGroup) string { + namespace, err := s.db.PolicyClient.GetNamespace(s.ctx, group.NamespaceID) + s.Require().NoError(err) + + return (&identifier.FullyQualifiedResourceMappingGroup{ + Namespace: namespace.GetName(), + GroupName: group.Name, + }).FQN() +} + func (s *ResourceMappingsSuite) getResourceMappingFixtures() []fixtures.FixtureDataResourceMapping { return []fixtures.FixtureDataResourceMapping{ s.f.GetResourceMappingKey("resource_mapping_to_attribute_value1"), diff --git a/service/policy/db/queries/resource_mapping.sql b/service/policy/db/queries/resource_mapping.sql index 90189910fd..ea1d75e20b 100644 --- a/service/policy/db/queries/resource_mapping.sql +++ b/service/policy/db/queries/resource_mapping.sql @@ -6,19 +6,25 @@ SELECT rmg.id, rmg.namespace_id, rmg.name, + LOWER(CONCAT('https://', ns.name, '/resm/', rmg.name)) AS fqn, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', rmg.metadata -> 'labels', 'created_at', rmg.created_at, 'updated_at', rmg.updated_at)) as metadata, COUNT(*) OVER() AS total FROM resource_mapping_groups rmg +JOIN attribute_namespaces ns ON rmg.namespace_id = ns.id WHERE (sqlc.narg('namespace_id')::uuid IS NULL OR rmg.namespace_id = sqlc.narg('namespace_id')::uuid) ORDER BY rmg.created_at DESC LIMIT @limit_ OFFSET @offset_; -- name: getResourceMappingGroup :one -SELECT id, namespace_id, name, - JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', metadata -> 'labels', 'created_at', created_at, 'updated_at', updated_at)) as metadata -FROM resource_mapping_groups -WHERE id = $1; +SELECT rmg.id, + rmg.namespace_id, + rmg.name, + LOWER(CONCAT('https://', ns.name, '/resm/', rmg.name)) AS fqn, + JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', rmg.metadata -> 'labels', 'created_at', rmg.created_at, 'updated_at', rmg.updated_at)) as metadata +FROM resource_mapping_groups rmg +JOIN attribute_namespaces ns ON rmg.namespace_id = ns.id +WHERE rmg.id = $1; -- name: createResourceMappingGroup :one INSERT INTO resource_mapping_groups (namespace_id, name, metadata) @@ -50,7 +56,11 @@ SELECT JSON_BUILD_OBJECT( 'id', rmg.id, 'name', rmg.name, - 'namespace_id', rmg.namespace_id + 'namespace_id', rmg.namespace_id, + 'fqn', CASE + WHEN rmg.id IS NULL THEN NULL + ELSE LOWER(CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)) + END ) ) AS group, COUNT(*) OVER() AS total @@ -58,8 +68,9 @@ FROM resource_mappings m LEFT JOIN attribute_values av on m.attribute_value_id = av.id LEFT JOIN attribute_fqns fqns on av.id = fqns.value_id LEFT JOIN resource_mapping_groups rmg ON m.group_id = rmg.id +LEFT JOIN attribute_namespaces rmg_ns ON rmg.namespace_id = rmg_ns.id WHERE (sqlc.narg('group_id')::uuid IS NULL OR m.group_id = sqlc.narg('group_id')::uuid) -GROUP BY av.id, m.id, fqns.fqn, rmg.id, rmg.name, rmg.namespace_id +GROUP BY av.id, m.id, fqns.fqn, rmg.id, rmg.name, rmg.namespace_id, rmg_ns.name ORDER BY m.created_at DESC LIMIT @limit_ OFFSET @offset_; @@ -73,6 +84,7 @@ WITH groups_cte AS ( 'id', g.id, 'namespace_id', g.namespace_id, 'name', g.name, + 'fqn', LOWER(CONCAT('https://', ns.name, '/resm/', g.name)), 'metadata', JSON_STRIP_NULLS(JSON_BUILD_OBJECT( 'labels', g.metadata -> 'labels', 'created_at', g.created_at, diff --git a/service/policy/db/resource_mapping.go b/service/policy/db/resource_mapping.go index 7bc238bd50..b7edac1f3c 100644 --- a/service/policy/db/resource_mapping.go +++ b/service/policy/db/resource_mapping.go @@ -46,6 +46,7 @@ func (c PolicyDBClient) ListResourceMappingGroups(ctx context.Context, r *resour Id: rmGroup.ID, NamespaceId: rmGroup.NamespaceID, Name: rmGroup.Name, + Fqn: rmGroup.Fqn, Metadata: metadata, } } @@ -82,6 +83,7 @@ func (c PolicyDBClient) GetResourceMappingGroup(ctx context.Context, id string) Id: rmGroup.ID, NamespaceId: rmGroup.NamespaceID, Name: rmGroup.Name, + Fqn: rmGroup.Fqn, Metadata: metadata, }, nil } @@ -90,7 +92,7 @@ func (c PolicyDBClient) CreateResourceMappingGroup(ctx context.Context, r *resou namespaceID := r.GetNamespaceId() name := strings.ToLower(r.GetName()) - metadataJSON, metadata, err := db.MarshalCreateMetadata(r.GetMetadata()) + metadataJSON, _, err := db.MarshalCreateMetadata(r.GetMetadata()) if err != nil { return nil, err } @@ -104,19 +106,14 @@ func (c PolicyDBClient) CreateResourceMappingGroup(ctx context.Context, r *resou return nil, db.WrapIfKnownInvalidQueryErr(err) } - return &policy.ResourceMappingGroup{ - Id: createdID, - NamespaceId: namespaceID, - Name: name, - Metadata: metadata, - }, nil + return c.GetResourceMappingGroup(ctx, createdID) } func (c PolicyDBClient) UpdateResourceMappingGroup(ctx context.Context, id string, r *resourcemapping.UpdateResourceMappingGroupRequest) (*policy.ResourceMappingGroup, error) { namespaceID := r.GetNamespaceId() name := strings.ToLower(r.GetName()) - metadataJSON, metadata, err := db.MarshalUpdateMetadata(r.GetMetadata(), r.GetMetadataUpdateBehavior(), func() (*common.Metadata, error) { + metadataJSON, _, err := db.MarshalUpdateMetadata(r.GetMetadata(), r.GetMetadataUpdateBehavior(), func() (*common.Metadata, error) { rmGroup, err := c.GetResourceMappingGroup(ctx, id) if err != nil { return nil, err @@ -140,15 +137,15 @@ func (c PolicyDBClient) UpdateResourceMappingGroup(ctx context.Context, id strin return nil, db.ErrNotFound } - return &policy.ResourceMappingGroup{ - Id: id, - NamespaceId: namespaceID, - Name: name, - Metadata: metadata, - }, nil + return c.GetResourceMappingGroup(ctx, id) } func (c PolicyDBClient) DeleteResourceMappingGroup(ctx context.Context, id string) (*policy.ResourceMappingGroup, error) { + rmGroup, err := c.GetResourceMappingGroup(ctx, id) + if err != nil { + return nil, err + } + count, err := c.queries.deleteResourceMappingGroup(ctx, id) if err != nil { return nil, db.WrapIfKnownInvalidQueryErr(err) @@ -157,9 +154,7 @@ func (c PolicyDBClient) DeleteResourceMappingGroup(ctx context.Context, id strin return nil, db.ErrNotFound } - return &policy.ResourceMappingGroup{ - Id: id, - }, nil + return rmGroup, nil } /* diff --git a/service/policy/db/resource_mapping.sql.go b/service/policy/db/resource_mapping.sql.go index ac669d51de..af4dbc0645 100644 --- a/service/policy/db/resource_mapping.sql.go +++ b/service/policy/db/resource_mapping.sql.go @@ -144,25 +144,34 @@ func (q *Queries) getResourceMapping(ctx context.Context, id string) (getResourc } const getResourceMappingGroup = `-- name: getResourceMappingGroup :one -SELECT id, namespace_id, name, - JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', metadata -> 'labels', 'created_at', created_at, 'updated_at', updated_at)) as metadata -FROM resource_mapping_groups -WHERE id = $1 +SELECT rmg.id, + rmg.namespace_id, + rmg.name, + LOWER(CONCAT('https://', ns.name, '/resm/', rmg.name)) AS fqn, + JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', rmg.metadata -> 'labels', 'created_at', rmg.created_at, 'updated_at', rmg.updated_at)) as metadata +FROM resource_mapping_groups rmg +JOIN attribute_namespaces ns ON rmg.namespace_id = ns.id +WHERE rmg.id = $1 ` type getResourceMappingGroupRow struct { ID string `json:"id"` NamespaceID string `json:"namespace_id"` Name string `json:"name"` + Fqn string `json:"fqn"` Metadata []byte `json:"metadata"` } // getResourceMappingGroup // -// SELECT id, namespace_id, name, -// JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', metadata -> 'labels', 'created_at', created_at, 'updated_at', updated_at)) as metadata -// FROM resource_mapping_groups -// WHERE id = $1 +// SELECT rmg.id, +// rmg.namespace_id, +// rmg.name, +// LOWER(CONCAT('https://', ns.name, '/resm/', rmg.name)) AS fqn, +// JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', rmg.metadata -> 'labels', 'created_at', rmg.created_at, 'updated_at', rmg.updated_at)) as metadata +// FROM resource_mapping_groups rmg +// JOIN attribute_namespaces ns ON rmg.namespace_id = ns.id +// WHERE rmg.id = $1 func (q *Queries) getResourceMappingGroup(ctx context.Context, id string) (getResourceMappingGroupRow, error) { row := q.db.QueryRow(ctx, getResourceMappingGroup, id) var i getResourceMappingGroupRow @@ -170,6 +179,7 @@ func (q *Queries) getResourceMappingGroup(ctx context.Context, id string) (getRe &i.ID, &i.NamespaceID, &i.Name, + &i.Fqn, &i.Metadata, ) return i, err @@ -180,9 +190,11 @@ const listResourceMappingGroups = `-- name: listResourceMappingGroups :many SELECT rmg.id, rmg.namespace_id, rmg.name, + LOWER(CONCAT('https://', ns.name, '/resm/', rmg.name)) AS fqn, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', rmg.metadata -> 'labels', 'created_at', rmg.created_at, 'updated_at', rmg.updated_at)) as metadata, COUNT(*) OVER() AS total FROM resource_mapping_groups rmg +JOIN attribute_namespaces ns ON rmg.namespace_id = ns.id WHERE ($1::uuid IS NULL OR rmg.namespace_id = $1::uuid) ORDER BY rmg.created_at DESC LIMIT $3 @@ -199,6 +211,7 @@ type listResourceMappingGroupsRow struct { ID string `json:"id"` NamespaceID string `json:"namespace_id"` Name string `json:"name"` + Fqn string `json:"fqn"` Metadata []byte `json:"metadata"` Total int64 `json:"total"` } @@ -210,9 +223,11 @@ type listResourceMappingGroupsRow struct { // SELECT rmg.id, // rmg.namespace_id, // rmg.name, +// LOWER(CONCAT('https://', ns.name, '/resm/', rmg.name)) AS fqn, // JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', rmg.metadata -> 'labels', 'created_at', rmg.created_at, 'updated_at', rmg.updated_at)) as metadata, // COUNT(*) OVER() AS total // FROM resource_mapping_groups rmg +// JOIN attribute_namespaces ns ON rmg.namespace_id = ns.id // WHERE ($1::uuid IS NULL OR rmg.namespace_id = $1::uuid) // ORDER BY rmg.created_at DESC // LIMIT $3 @@ -230,6 +245,7 @@ func (q *Queries) listResourceMappingGroups(ctx context.Context, arg listResourc &i.ID, &i.NamespaceID, &i.Name, + &i.Fqn, &i.Metadata, &i.Total, ); err != nil { @@ -254,7 +270,11 @@ SELECT JSON_BUILD_OBJECT( 'id', rmg.id, 'name', rmg.name, - 'namespace_id', rmg.namespace_id + 'namespace_id', rmg.namespace_id, + 'fqn', CASE + WHEN rmg.id IS NULL THEN NULL + ELSE LOWER(CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)) + END ) ) AS group, COUNT(*) OVER() AS total @@ -262,8 +282,9 @@ FROM resource_mappings m LEFT JOIN attribute_values av on m.attribute_value_id = av.id LEFT JOIN attribute_fqns fqns on av.id = fqns.value_id LEFT JOIN resource_mapping_groups rmg ON m.group_id = rmg.id +LEFT JOIN attribute_namespaces rmg_ns ON rmg.namespace_id = rmg_ns.id WHERE ($1::uuid IS NULL OR m.group_id = $1::uuid) -GROUP BY av.id, m.id, fqns.fqn, rmg.id, rmg.name, rmg.namespace_id +GROUP BY av.id, m.id, fqns.fqn, rmg.id, rmg.name, rmg.namespace_id, rmg_ns.name ORDER BY m.created_at DESC LIMIT $3 OFFSET $2 @@ -297,7 +318,11 @@ type listResourceMappingsRow struct { // JSON_BUILD_OBJECT( // 'id', rmg.id, // 'name', rmg.name, -// 'namespace_id', rmg.namespace_id +// 'namespace_id', rmg.namespace_id, +// 'fqn', CASE +// WHEN rmg.id IS NULL THEN NULL +// ELSE LOWER(CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)) +// END // ) // ) AS group, // COUNT(*) OVER() AS total @@ -305,8 +330,9 @@ type listResourceMappingsRow struct { // LEFT JOIN attribute_values av on m.attribute_value_id = av.id // LEFT JOIN attribute_fqns fqns on av.id = fqns.value_id // LEFT JOIN resource_mapping_groups rmg ON m.group_id = rmg.id +// LEFT JOIN attribute_namespaces rmg_ns ON rmg.namespace_id = rmg_ns.id // WHERE ($1::uuid IS NULL OR m.group_id = $1::uuid) -// GROUP BY av.id, m.id, fqns.fqn, rmg.id, rmg.name, rmg.namespace_id +// GROUP BY av.id, m.id, fqns.fqn, rmg.id, rmg.name, rmg.namespace_id, rmg_ns.name // ORDER BY m.created_at DESC // LIMIT $3 // OFFSET $2 @@ -345,6 +371,7 @@ WITH groups_cte AS ( 'id', g.id, 'namespace_id', g.namespace_id, 'name', g.name, + 'fqn', LOWER(CONCAT('https://', ns.name, '/resm/', g.name)), 'metadata', JSON_STRIP_NULLS(JSON_BUILD_OBJECT( 'labels', g.metadata -> 'labels', 'created_at', g.created_at, @@ -390,6 +417,7 @@ type listResourceMappingsByFullyQualifiedGroupRow struct { // 'id', g.id, // 'namespace_id', g.namespace_id, // 'name', g.name, +// 'fqn', LOWER(CONCAT('https://', ns.name, '/resm/', g.name)), // 'metadata', JSON_STRIP_NULLS(JSON_BUILD_OBJECT( // 'labels', g.metadata -> 'labels', // 'created_at', g.created_at, diff --git a/service/policy/objects.proto b/service/policy/objects.proto index f06d349b10..29ee0ea733 100644 --- a/service/policy/objects.proto +++ b/service/policy/objects.proto @@ -297,6 +297,9 @@ message ResourceMappingGroup { // per namespace string name = 3 [(buf.validate.field).required = true]; + // the fully qualified name of the resource mapping group + string fqn = 4; + // Common metadata common.Metadata metadata = 100; } diff --git a/service/policy/resourcemapping/resource_mapping.go b/service/policy/resourcemapping/resource_mapping.go index 1426dfd673..f42e866d6a 100644 --- a/service/policy/resourcemapping/resource_mapping.go +++ b/service/policy/resourcemapping/resource_mapping.go @@ -108,18 +108,26 @@ func (s ResourceMappingService) CreateResourceMappingGroup(ctx context.Context, ObjectType: audit.ObjectTypeResourceMappingGroup, } - rmGroup, err := s.dbClient.CreateResourceMappingGroup(ctx, req.Msg) + var rmGroup *policy.ResourceMappingGroup + err := s.dbClient.RunInTx(ctx, func(txClient *policydb.PolicyDBClient) error { + var err error + rmGroup, err = txClient.CreateResourceMappingGroup(ctx, req.Msg) + if err != nil { + return err + } + + auditParams.ObjectID = rmGroup.GetId() + auditParams.Original = rmGroup + s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) + + rsp.ResourceMappingGroup = rmGroup + return nil + }) if err != nil { s.logger.Audit.PolicyCRUDFailure(ctx, auditParams) return nil, db.StatusifyError(ctx, s.logger, err, db.ErrTextCreationFailed, slog.String("resourceMappingGroup", req.Msg.String())) } - auditParams.ObjectID = rmGroup.GetId() - auditParams.Original = rmGroup - s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) - - rsp.ResourceMappingGroup = rmGroup - return connect.NewResponse(rsp), nil } @@ -134,27 +142,29 @@ func (s ResourceMappingService) UpdateResourceMappingGroup(ctx context.Context, ObjectID: id, } - originalRmGroup, err := s.dbClient.GetResourceMappingGroup(ctx, id) - if err != nil { - s.logger.Audit.PolicyCRUDFailure(ctx, auditParams) - return nil, db.StatusifyError(ctx, s.logger, err, db.ErrTextGetRetrievalFailed, slog.String("id", id)) - } + err := s.dbClient.RunInTx(ctx, func(txClient *policydb.PolicyDBClient) error { + originalRmGroup, err := txClient.GetResourceMappingGroup(ctx, id) + if err != nil { + return err + } + + updatedRmGroup, err := txClient.UpdateResourceMappingGroup(ctx, id, req.Msg) + if err != nil { + return err + } - updatedRmGroup, err := s.dbClient.UpdateResourceMappingGroup(ctx, id, req.Msg) + auditParams.Original = originalRmGroup + auditParams.Updated = updatedRmGroup + s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) + + rsp.ResourceMappingGroup = updatedRmGroup + return nil + }) if err != nil { s.logger.Audit.PolicyCRUDFailure(ctx, auditParams) return nil, db.StatusifyError(ctx, s.logger, err, db.ErrTextUpdateFailed, slog.String("id", id)) } - auditParams.Original = originalRmGroup - auditParams.Updated = updatedRmGroup - - s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) - - rsp.ResourceMappingGroup = &policy.ResourceMappingGroup{ - Id: id, - } - return connect.NewResponse(rsp), nil } @@ -169,18 +179,24 @@ func (s ResourceMappingService) DeleteResourceMappingGroup(ctx context.Context, ObjectID: id, } - _, err := s.dbClient.DeleteResourceMappingGroup(ctx, id) + var deletedRmGroup *policy.ResourceMappingGroup + err := s.dbClient.RunInTx(ctx, func(txClient *policydb.PolicyDBClient) error { + var err error + deletedRmGroup, err = txClient.DeleteResourceMappingGroup(ctx, id) + if err != nil { + return err + } + + s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) + + rsp.ResourceMappingGroup = deletedRmGroup + return nil + }) if err != nil { s.logger.Audit.PolicyCRUDFailure(ctx, auditParams) return nil, db.StatusifyError(ctx, s.logger, err, db.ErrTextDeletionFailed, slog.String("id", id)) } - s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) - - rsp.ResourceMappingGroup = &policy.ResourceMappingGroup{ - Id: id, - } - return connect.NewResponse(rsp), nil } @@ -241,18 +257,26 @@ func (s ResourceMappingService) CreateResourceMapping(ctx context.Context, ObjectType: audit.ObjectTypeResourceMapping, } - rm, err := s.dbClient.CreateResourceMapping(ctx, req.Msg) + var rm *policy.ResourceMapping + err := s.dbClient.RunInTx(ctx, func(txClient *policydb.PolicyDBClient) error { + var err error + rm, err = txClient.CreateResourceMapping(ctx, req.Msg) + if err != nil { + return err + } + + auditParams.ObjectID = rm.GetId() + auditParams.Original = rm + s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) + + rsp.ResourceMapping = rm + return nil + }) if err != nil { s.logger.Audit.PolicyCRUDFailure(ctx, auditParams) return nil, db.StatusifyError(ctx, s.logger, err, db.ErrTextCreationFailed, slog.String("resourceMapping", req.Msg.String())) } - auditParams.ObjectID = rm.GetId() - auditParams.Original = rm - s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) - - rsp.ResourceMapping = rm - return connect.NewResponse(rsp), nil } @@ -269,13 +293,26 @@ func (s ResourceMappingService) UpdateResourceMapping(ctx context.Context, ObjectID: resourceMappingID, } - originalRM, err := s.dbClient.GetResourceMapping(ctx, resourceMappingID) - if err != nil { - s.logger.Audit.PolicyCRUDFailure(ctx, auditParams) - return nil, db.StatusifyError(ctx, s.logger, err, db.ErrTextListRetrievalFailed) - } + err := s.dbClient.RunInTx(ctx, func(txClient *policydb.PolicyDBClient) error { + originalRM, err := txClient.GetResourceMapping(ctx, resourceMappingID) + if err != nil { + return err + } + + updatedRM, err := txClient.UpdateResourceMapping(ctx, resourceMappingID, req.Msg) + if err != nil { + return err + } - updatedRM, err := s.dbClient.UpdateResourceMapping(ctx, resourceMappingID, req.Msg) + auditParams.Original = originalRM + auditParams.Updated = updatedRM + s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) + + rsp.ResourceMapping = &policy.ResourceMapping{ + Id: resourceMappingID, + } + return nil + }) if err != nil { s.logger.Audit.PolicyCRUDFailure(ctx, auditParams) return nil, db.StatusifyError(ctx, s.logger, err, db.ErrTextUpdateFailed, @@ -284,14 +321,6 @@ func (s ResourceMappingService) UpdateResourceMapping(ctx context.Context, ) } - auditParams.Original = originalRM - auditParams.Updated = updatedRM - s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) - - rsp.ResourceMapping = &policy.ResourceMapping{ - Id: resourceMappingID, - } - return connect.NewResponse(rsp), nil } From bff4f5ec5ecaca5a3aec8e081e65aa7724dcb4c3 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Thu, 7 May 2026 12:11:11 -0700 Subject: [PATCH 02/11] DSPX-3195 Remove redundant FQN lowercasing --- service/policy/db/queries/resource_mapping.sql | 8 ++++---- service/policy/db/resource_mapping.sql.go | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/service/policy/db/queries/resource_mapping.sql b/service/policy/db/queries/resource_mapping.sql index ea1d75e20b..abf48a90b9 100644 --- a/service/policy/db/queries/resource_mapping.sql +++ b/service/policy/db/queries/resource_mapping.sql @@ -6,7 +6,7 @@ SELECT rmg.id, rmg.namespace_id, rmg.name, - LOWER(CONCAT('https://', ns.name, '/resm/', rmg.name)) AS fqn, + CONCAT('https://', ns.name, '/resm/', rmg.name)::TEXT AS fqn, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', rmg.metadata -> 'labels', 'created_at', rmg.created_at, 'updated_at', rmg.updated_at)) as metadata, COUNT(*) OVER() AS total FROM resource_mapping_groups rmg @@ -20,7 +20,7 @@ OFFSET @offset_; SELECT rmg.id, rmg.namespace_id, rmg.name, - LOWER(CONCAT('https://', ns.name, '/resm/', rmg.name)) AS fqn, + CONCAT('https://', ns.name, '/resm/', rmg.name)::TEXT AS fqn, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', rmg.metadata -> 'labels', 'created_at', rmg.created_at, 'updated_at', rmg.updated_at)) as metadata FROM resource_mapping_groups rmg JOIN attribute_namespaces ns ON rmg.namespace_id = ns.id @@ -59,7 +59,7 @@ SELECT 'namespace_id', rmg.namespace_id, 'fqn', CASE WHEN rmg.id IS NULL THEN NULL - ELSE LOWER(CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)) + ELSE CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT END ) ) AS group, @@ -84,7 +84,7 @@ WITH groups_cte AS ( 'id', g.id, 'namespace_id', g.namespace_id, 'name', g.name, - 'fqn', LOWER(CONCAT('https://', ns.name, '/resm/', g.name)), + 'fqn', CONCAT('https://', ns.name, '/resm/', g.name)::TEXT, 'metadata', JSON_STRIP_NULLS(JSON_BUILD_OBJECT( 'labels', g.metadata -> 'labels', 'created_at', g.created_at, diff --git a/service/policy/db/resource_mapping.sql.go b/service/policy/db/resource_mapping.sql.go index af4dbc0645..6da133a789 100644 --- a/service/policy/db/resource_mapping.sql.go +++ b/service/policy/db/resource_mapping.sql.go @@ -147,7 +147,7 @@ const getResourceMappingGroup = `-- name: getResourceMappingGroup :one SELECT rmg.id, rmg.namespace_id, rmg.name, - LOWER(CONCAT('https://', ns.name, '/resm/', rmg.name)) AS fqn, + CONCAT('https://', ns.name, '/resm/', rmg.name)::TEXT AS fqn, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', rmg.metadata -> 'labels', 'created_at', rmg.created_at, 'updated_at', rmg.updated_at)) as metadata FROM resource_mapping_groups rmg JOIN attribute_namespaces ns ON rmg.namespace_id = ns.id @@ -167,7 +167,7 @@ type getResourceMappingGroupRow struct { // SELECT rmg.id, // rmg.namespace_id, // rmg.name, -// LOWER(CONCAT('https://', ns.name, '/resm/', rmg.name)) AS fqn, +// CONCAT('https://', ns.name, '/resm/', rmg.name)::TEXT AS fqn, // JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', rmg.metadata -> 'labels', 'created_at', rmg.created_at, 'updated_at', rmg.updated_at)) as metadata // FROM resource_mapping_groups rmg // JOIN attribute_namespaces ns ON rmg.namespace_id = ns.id @@ -190,7 +190,7 @@ const listResourceMappingGroups = `-- name: listResourceMappingGroups :many SELECT rmg.id, rmg.namespace_id, rmg.name, - LOWER(CONCAT('https://', ns.name, '/resm/', rmg.name)) AS fqn, + CONCAT('https://', ns.name, '/resm/', rmg.name)::TEXT AS fqn, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', rmg.metadata -> 'labels', 'created_at', rmg.created_at, 'updated_at', rmg.updated_at)) as metadata, COUNT(*) OVER() AS total FROM resource_mapping_groups rmg @@ -223,7 +223,7 @@ type listResourceMappingGroupsRow struct { // SELECT rmg.id, // rmg.namespace_id, // rmg.name, -// LOWER(CONCAT('https://', ns.name, '/resm/', rmg.name)) AS fqn, +// CONCAT('https://', ns.name, '/resm/', rmg.name)::TEXT AS fqn, // JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', rmg.metadata -> 'labels', 'created_at', rmg.created_at, 'updated_at', rmg.updated_at)) as metadata, // COUNT(*) OVER() AS total // FROM resource_mapping_groups rmg @@ -273,7 +273,7 @@ SELECT 'namespace_id', rmg.namespace_id, 'fqn', CASE WHEN rmg.id IS NULL THEN NULL - ELSE LOWER(CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)) + ELSE CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT END ) ) AS group, @@ -321,7 +321,7 @@ type listResourceMappingsRow struct { // 'namespace_id', rmg.namespace_id, // 'fqn', CASE // WHEN rmg.id IS NULL THEN NULL -// ELSE LOWER(CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)) +// ELSE CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT // END // ) // ) AS group, @@ -371,7 +371,7 @@ WITH groups_cte AS ( 'id', g.id, 'namespace_id', g.namespace_id, 'name', g.name, - 'fqn', LOWER(CONCAT('https://', ns.name, '/resm/', g.name)), + 'fqn', CONCAT('https://', ns.name, '/resm/', g.name)::TEXT, 'metadata', JSON_STRIP_NULLS(JSON_BUILD_OBJECT( 'labels', g.metadata -> 'labels', 'created_at', g.created_at, @@ -417,7 +417,7 @@ type listResourceMappingsByFullyQualifiedGroupRow struct { // 'id', g.id, // 'namespace_id', g.namespace_id, // 'name', g.name, -// 'fqn', LOWER(CONCAT('https://', ns.name, '/resm/', g.name)), +// 'fqn', CONCAT('https://', ns.name, '/resm/', g.name)::TEXT, // 'metadata', JSON_STRIP_NULLS(JSON_BUILD_OBJECT( // 'labels', g.metadata -> 'labels', // 'created_at', g.created_at, From 8df5d051b8242b2597074788558a56d32a3d92c7 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Thu, 7 May 2026 12:34:29 -0700 Subject: [PATCH 03/11] DSPX-3195 Move resource mapping success audit after commit --- .../resourcemapping/resource_mapping.go | 69 +++++++++++-------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/service/policy/resourcemapping/resource_mapping.go b/service/policy/resourcemapping/resource_mapping.go index f42e866d6a..8ed86018c6 100644 --- a/service/policy/resourcemapping/resource_mapping.go +++ b/service/policy/resourcemapping/resource_mapping.go @@ -116,11 +116,6 @@ func (s ResourceMappingService) CreateResourceMappingGroup(ctx context.Context, return err } - auditParams.ObjectID = rmGroup.GetId() - auditParams.Original = rmGroup - s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) - - rsp.ResourceMappingGroup = rmGroup return nil }) if err != nil { @@ -128,6 +123,12 @@ func (s ResourceMappingService) CreateResourceMappingGroup(ctx context.Context, return nil, db.StatusifyError(ctx, s.logger, err, db.ErrTextCreationFailed, slog.String("resourceMappingGroup", req.Msg.String())) } + auditParams.ObjectID = rmGroup.GetId() + auditParams.Original = rmGroup + s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) + + rsp.ResourceMappingGroup = rmGroup + return connect.NewResponse(rsp), nil } @@ -142,22 +143,20 @@ func (s ResourceMappingService) UpdateResourceMappingGroup(ctx context.Context, ObjectID: id, } + var originalRmGroup *policy.ResourceMappingGroup + var updatedRmGroup *policy.ResourceMappingGroup err := s.dbClient.RunInTx(ctx, func(txClient *policydb.PolicyDBClient) error { - originalRmGroup, err := txClient.GetResourceMappingGroup(ctx, id) + var err error + originalRmGroup, err = txClient.GetResourceMappingGroup(ctx, id) if err != nil { return err } - updatedRmGroup, err := txClient.UpdateResourceMappingGroup(ctx, id, req.Msg) + updatedRmGroup, err = txClient.UpdateResourceMappingGroup(ctx, id, req.Msg) if err != nil { return err } - auditParams.Original = originalRmGroup - auditParams.Updated = updatedRmGroup - s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) - - rsp.ResourceMappingGroup = updatedRmGroup return nil }) if err != nil { @@ -165,6 +164,12 @@ func (s ResourceMappingService) UpdateResourceMappingGroup(ctx context.Context, return nil, db.StatusifyError(ctx, s.logger, err, db.ErrTextUpdateFailed, slog.String("id", id)) } + auditParams.Original = originalRmGroup + auditParams.Updated = updatedRmGroup + s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) + + rsp.ResourceMappingGroup = updatedRmGroup + return connect.NewResponse(rsp), nil } @@ -187,9 +192,6 @@ func (s ResourceMappingService) DeleteResourceMappingGroup(ctx context.Context, return err } - s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) - - rsp.ResourceMappingGroup = deletedRmGroup return nil }) if err != nil { @@ -197,6 +199,10 @@ func (s ResourceMappingService) DeleteResourceMappingGroup(ctx context.Context, return nil, db.StatusifyError(ctx, s.logger, err, db.ErrTextDeletionFailed, slog.String("id", id)) } + s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) + + rsp.ResourceMappingGroup = deletedRmGroup + return connect.NewResponse(rsp), nil } @@ -265,11 +271,6 @@ func (s ResourceMappingService) CreateResourceMapping(ctx context.Context, return err } - auditParams.ObjectID = rm.GetId() - auditParams.Original = rm - s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) - - rsp.ResourceMapping = rm return nil }) if err != nil { @@ -277,6 +278,12 @@ func (s ResourceMappingService) CreateResourceMapping(ctx context.Context, return nil, db.StatusifyError(ctx, s.logger, err, db.ErrTextCreationFailed, slog.String("resourceMapping", req.Msg.String())) } + auditParams.ObjectID = rm.GetId() + auditParams.Original = rm + s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) + + rsp.ResourceMapping = rm + return connect.NewResponse(rsp), nil } @@ -293,24 +300,20 @@ func (s ResourceMappingService) UpdateResourceMapping(ctx context.Context, ObjectID: resourceMappingID, } + var originalRM *policy.ResourceMapping + var updatedRM *policy.ResourceMapping err := s.dbClient.RunInTx(ctx, func(txClient *policydb.PolicyDBClient) error { - originalRM, err := txClient.GetResourceMapping(ctx, resourceMappingID) + var err error + originalRM, err = txClient.GetResourceMapping(ctx, resourceMappingID) if err != nil { return err } - updatedRM, err := txClient.UpdateResourceMapping(ctx, resourceMappingID, req.Msg) + updatedRM, err = txClient.UpdateResourceMapping(ctx, resourceMappingID, req.Msg) if err != nil { return err } - auditParams.Original = originalRM - auditParams.Updated = updatedRM - s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) - - rsp.ResourceMapping = &policy.ResourceMapping{ - Id: resourceMappingID, - } return nil }) if err != nil { @@ -321,6 +324,14 @@ func (s ResourceMappingService) UpdateResourceMapping(ctx context.Context, ) } + auditParams.Original = originalRM + auditParams.Updated = updatedRM + s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) + + rsp.ResourceMapping = &policy.ResourceMapping{ + Id: resourceMappingID, + } + return connect.NewResponse(rsp), nil } From 92e088ab9e5959787e2e1410405ef5ffea9bb94f Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Thu, 7 May 2026 12:45:47 -0700 Subject: [PATCH 04/11] DSPX-3195 Return hydrated resource mappings --- service/integration/resource_mappings_test.go | 6 +++ .../policy/db/queries/resource_mapping.sql | 16 +++++- service/policy/db/resource_mapping.go | 50 ++++++------------- service/policy/db/resource_mapping.sql.go | 36 ++++++++++--- .../resourcemapping/resource_mapping.go | 4 +- 5 files changed, 66 insertions(+), 46 deletions(-) diff --git a/service/integration/resource_mappings_test.go b/service/integration/resource_mappings_test.go index 11e028f7a9..0336002856 100644 --- a/service/integration/resource_mappings_test.go +++ b/service/integration/resource_mappings_test.go @@ -597,6 +597,7 @@ func (s *ResourceMappingsSuite) Test_CreateResourceMappingWithGroupIdSucceeds() s.Require().NoError(err) s.NotNil(createdMapping) s.Equal(rmGroup.ID, createdMapping.GetGroup().GetId()) + s.Equal(s.resourceMappingGroupFqn(rmGroup), createdMapping.GetGroup().GetFqn()) } func (s *ResourceMappingsSuite) Test_CreateResourceMappingWithUnknownGroupIdFails() { @@ -1235,6 +1236,7 @@ func (s *ResourceMappingsSuite) Test_UpdateResourceMapping() { newLabel := "new label" rmGroup := s.getResourceMappingGroupFixtures()[0] + expectedGroupFqn := s.resourceMappingGroupFqn(rmGroup) labels := map[string]string{ "fixed": fixedLabel, @@ -1264,11 +1266,13 @@ func (s *ResourceMappingsSuite) Test_UpdateResourceMapping() { }) s.Require().NoError(err) s.NotNil(createdMapping) + s.Equal(expectedGroupFqn, createdMapping.GetGroup().GetFqn()) updateWithoutChange, err := s.db.PolicyClient.UpdateResourceMapping(s.ctx, createdMapping.GetId(), &resourcemapping.UpdateResourceMappingRequest{}) s.Require().NoError(err) s.NotNil(updateWithoutChange) s.Equal(createdMapping.GetId(), updateWithoutChange.GetId()) + s.Equal(expectedGroupFqn, updateWithoutChange.GetGroup().GetFqn()) // update the created with new metadata and terms updateWithChange, err := s.db.PolicyClient.UpdateResourceMapping(s.ctx, createdMapping.GetId(), &resourcemapping.UpdateResourceMappingRequest{ @@ -1287,6 +1291,7 @@ func (s *ResourceMappingsSuite) Test_UpdateResourceMapping() { s.Equal(updateTerms, updateWithChange.GetTerms()) s.Equal(expectedLabels, updateWithChange.GetMetadata().GetLabels()) s.Equal(createdMapping.GetGroup().GetId(), updateWithChange.GetGroup().GetId()) + s.Equal(expectedGroupFqn, updateWithChange.GetGroup().GetFqn()) // get after update to verify db reflects changes made got, err := s.db.PolicyClient.GetResourceMapping(s.ctx, createdMapping.GetId()) @@ -1303,6 +1308,7 @@ func (s *ResourceMappingsSuite) Test_UpdateResourceMapping() { s.False(updatedAt.AsTime().IsZero()) s.True(updatedAt.AsTime().After(createdAt.AsTime())) s.Equal(rmGroup.ID, got.GetGroup().GetId()) + s.Equal(expectedGroupFqn, got.GetGroup().GetFqn()) } func (s *ResourceMappingsSuite) Test_UpdateResourceMappingWithUnknownIdFails() { diff --git a/service/policy/db/queries/resource_mapping.sql b/service/policy/db/queries/resource_mapping.sql index abf48a90b9..b8605e679f 100644 --- a/service/policy/db/queries/resource_mapping.sql +++ b/service/policy/db/queries/resource_mapping.sql @@ -113,12 +113,24 @@ SELECT JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, m.terms, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, - COALESCE(m.group_id::TEXT, '')::TEXT as group_id + JSON_STRIP_NULLS( + JSON_BUILD_OBJECT( + 'id', rmg.id, + 'name', rmg.name, + 'namespace_id', rmg.namespace_id, + 'fqn', CASE + WHEN rmg.id IS NULL THEN NULL + ELSE CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT + END + ) + ) AS group FROM resource_mappings m LEFT JOIN attribute_values av on m.attribute_value_id = av.id LEFT JOIN attribute_fqns fqns on av.id = fqns.value_id +LEFT JOIN resource_mapping_groups rmg ON m.group_id = rmg.id +LEFT JOIN attribute_namespaces rmg_ns ON rmg.namespace_id = rmg_ns.id WHERE m.id = $1 -GROUP BY av.id, m.id, fqns.fqn; +GROUP BY av.id, m.id, fqns.fqn, rmg.id, rmg.name, rmg.namespace_id, rmg_ns.name; -- name: createResourceMapping :one INSERT INTO resource_mappings (attribute_value_id, terms, metadata, group_id) diff --git a/service/policy/db/resource_mapping.go b/service/policy/db/resource_mapping.go index b7edac1f3c..e7396b0faf 100644 --- a/service/policy/db/resource_mapping.go +++ b/service/policy/db/resource_mapping.go @@ -305,8 +305,9 @@ func (c PolicyDBClient) GetResourceMapping(ctx context.Context, id string) (*pol } var ( - metadata = new(common.Metadata) - attributeValue = new(policy.Value) + metadata = new(common.Metadata) + attributeValue = new(policy.Value) + resourceMappingGroup = new(policy.ResourceMappingGroup) ) if err = unmarshalMetadata(rm.Metadata, metadata); err != nil { @@ -317,15 +318,19 @@ func (c PolicyDBClient) GetResourceMapping(ctx context.Context, id string) (*pol return nil, err } + if err = unmarshalResourceMappingGroup(rm.Group, resourceMappingGroup); err != nil { + return nil, err + } + if resourceMappingGroup.GetId() == "" { + resourceMappingGroup = nil + } + policyRM := &policy.ResourceMapping{ Id: rm.ID, AttributeValue: attributeValue, Terms: rm.Terms, Metadata: metadata, - } - - if rm.GroupID != "" { - policyRM.Group = &policy.ResourceMappingGroup{Id: rm.GroupID} + Group: resourceMappingGroup, } return policyRM, nil @@ -335,7 +340,7 @@ func (c PolicyDBClient) CreateResourceMapping(ctx context.Context, r *resourcema attributeValueID := r.GetAttributeValueId() terms := r.GetTerms() groupID := r.GetGroupId() - metadataJSON, metadata, err := db.MarshalCreateMetadata(r.GetMetadata()) + metadataJSON, _, err := db.MarshalCreateMetadata(r.GetMetadata()) if err != nil { return nil, err } @@ -369,25 +374,14 @@ func (c PolicyDBClient) CreateResourceMapping(ctx context.Context, r *resourcema return nil, db.WrapIfKnownInvalidQueryErr(err) } - rm := &policy.ResourceMapping{ - Id: createdID, - AttributeValue: &policy.Value{Id: attributeValueID}, - Terms: terms, - Metadata: metadata, - } - - if groupID != "" { - rm.Group = &policy.ResourceMappingGroup{Id: groupID} - } - - return rm, nil + return c.GetResourceMapping(ctx, createdID) } func (c PolicyDBClient) UpdateResourceMapping(ctx context.Context, id string, r *resourcemapping.UpdateResourceMappingRequest) (*policy.ResourceMapping, error) { attributeValueID := r.GetAttributeValueId() terms := r.GetTerms() groupID := r.GetGroupId() - metadataJSON, metadata, err := db.MarshalUpdateMetadata(r.GetMetadata(), r.GetMetadataUpdateBehavior(), func() (*common.Metadata, error) { + metadataJSON, _, err := db.MarshalUpdateMetadata(r.GetMetadata(), r.GetMetadataUpdateBehavior(), func() (*common.Metadata, error) { rm, err := c.GetResourceMapping(ctx, id) if err != nil { return nil, db.WrapIfKnownInvalidQueryErr(err) @@ -431,21 +425,7 @@ func (c PolicyDBClient) UpdateResourceMapping(ctx context.Context, id string, r return nil, db.ErrNotFound } - rm := &policy.ResourceMapping{ - Id: id, - Terms: terms, - Metadata: metadata, - } - - if attributeValueID != "" { - rm.AttributeValue = &policy.Value{Id: attributeValueID} - } - - if groupID != "" { - rm.Group = &policy.ResourceMappingGroup{Id: groupID} - } - - return rm, nil + return c.GetResourceMapping(ctx, id) } func (c PolicyDBClient) DeleteResourceMapping(ctx context.Context, id string) (*policy.ResourceMapping, error) { diff --git a/service/policy/db/resource_mapping.sql.go b/service/policy/db/resource_mapping.sql.go index 6da133a789..31e15974dd 100644 --- a/service/policy/db/resource_mapping.sql.go +++ b/service/policy/db/resource_mapping.sql.go @@ -101,12 +101,24 @@ SELECT JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, m.terms, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, - COALESCE(m.group_id::TEXT, '')::TEXT as group_id + JSON_STRIP_NULLS( + JSON_BUILD_OBJECT( + 'id', rmg.id, + 'name', rmg.name, + 'namespace_id', rmg.namespace_id, + 'fqn', CASE + WHEN rmg.id IS NULL THEN NULL + ELSE CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT + END + ) + ) AS group FROM resource_mappings m LEFT JOIN attribute_values av on m.attribute_value_id = av.id LEFT JOIN attribute_fqns fqns on av.id = fqns.value_id +LEFT JOIN resource_mapping_groups rmg ON m.group_id = rmg.id +LEFT JOIN attribute_namespaces rmg_ns ON rmg.namespace_id = rmg_ns.id WHERE m.id = $1 -GROUP BY av.id, m.id, fqns.fqn +GROUP BY av.id, m.id, fqns.fqn, rmg.id, rmg.name, rmg.namespace_id, rmg_ns.name ` type getResourceMappingRow struct { @@ -114,7 +126,7 @@ type getResourceMappingRow struct { AttributeValue []byte `json:"attribute_value"` Terms []string `json:"terms"` Metadata []byte `json:"metadata"` - GroupID string `json:"group_id"` + Group []byte `json:"group"` } // getResourceMapping @@ -124,12 +136,24 @@ type getResourceMappingRow struct { // JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, // m.terms, // JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, -// COALESCE(m.group_id::TEXT, '')::TEXT as group_id +// JSON_STRIP_NULLS( +// JSON_BUILD_OBJECT( +// 'id', rmg.id, +// 'name', rmg.name, +// 'namespace_id', rmg.namespace_id, +// 'fqn', CASE +// WHEN rmg.id IS NULL THEN NULL +// ELSE CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT +// END +// ) +// ) AS group // FROM resource_mappings m // LEFT JOIN attribute_values av on m.attribute_value_id = av.id // LEFT JOIN attribute_fqns fqns on av.id = fqns.value_id +// LEFT JOIN resource_mapping_groups rmg ON m.group_id = rmg.id +// LEFT JOIN attribute_namespaces rmg_ns ON rmg.namespace_id = rmg_ns.id // WHERE m.id = $1 -// GROUP BY av.id, m.id, fqns.fqn +// GROUP BY av.id, m.id, fqns.fqn, rmg.id, rmg.name, rmg.namespace_id, rmg_ns.name func (q *Queries) getResourceMapping(ctx context.Context, id string) (getResourceMappingRow, error) { row := q.db.QueryRow(ctx, getResourceMapping, id) var i getResourceMappingRow @@ -138,7 +162,7 @@ func (q *Queries) getResourceMapping(ctx context.Context, id string) (getResourc &i.AttributeValue, &i.Terms, &i.Metadata, - &i.GroupID, + &i.Group, ) return i, err } diff --git a/service/policy/resourcemapping/resource_mapping.go b/service/policy/resourcemapping/resource_mapping.go index 8ed86018c6..af87df416f 100644 --- a/service/policy/resourcemapping/resource_mapping.go +++ b/service/policy/resourcemapping/resource_mapping.go @@ -328,9 +328,7 @@ func (s ResourceMappingService) UpdateResourceMapping(ctx context.Context, auditParams.Updated = updatedRM s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams) - rsp.ResourceMapping = &policy.ResourceMapping{ - Id: resourceMappingID, - } + rsp.ResourceMapping = updatedRM return connect.NewResponse(rsp), nil } From 5dcf073d8309fb671d24e6f00ba7eb4e87c0fb1f Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Thu, 7 May 2026 13:05:05 -0700 Subject: [PATCH 05/11] DSPX-3195 Return null for missing mapping groups --- .../policy/db/queries/resource_mapping.sql | 18 ++++------ service/policy/db/resource_mapping.sql.go | 36 +++++++------------ 2 files changed, 18 insertions(+), 36 deletions(-) diff --git a/service/policy/db/queries/resource_mapping.sql b/service/policy/db/queries/resource_mapping.sql index b8605e679f..a6c0b735cd 100644 --- a/service/policy/db/queries/resource_mapping.sql +++ b/service/policy/db/queries/resource_mapping.sql @@ -52,17 +52,14 @@ SELECT JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, m.terms, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, - JSON_STRIP_NULLS( + NULLIF(JSON_STRIP_NULLS( JSON_BUILD_OBJECT( 'id', rmg.id, 'name', rmg.name, 'namespace_id', rmg.namespace_id, - 'fqn', CASE - WHEN rmg.id IS NULL THEN NULL - ELSE CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT - END + 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT ) - ) AS group, + )::TEXT, '{}')::JSON AS group, COUNT(*) OVER() AS total FROM resource_mappings m LEFT JOIN attribute_values av on m.attribute_value_id = av.id @@ -113,17 +110,14 @@ SELECT JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, m.terms, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, - JSON_STRIP_NULLS( + NULLIF(JSON_STRIP_NULLS( JSON_BUILD_OBJECT( 'id', rmg.id, 'name', rmg.name, 'namespace_id', rmg.namespace_id, - 'fqn', CASE - WHEN rmg.id IS NULL THEN NULL - ELSE CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT - END + 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT ) - ) AS group + )::TEXT, '{}')::JSON AS group FROM resource_mappings m LEFT JOIN attribute_values av on m.attribute_value_id = av.id LEFT JOIN attribute_fqns fqns on av.id = fqns.value_id diff --git a/service/policy/db/resource_mapping.sql.go b/service/policy/db/resource_mapping.sql.go index 31e15974dd..d8a602329e 100644 --- a/service/policy/db/resource_mapping.sql.go +++ b/service/policy/db/resource_mapping.sql.go @@ -101,17 +101,14 @@ SELECT JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, m.terms, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, - JSON_STRIP_NULLS( + NULLIF(JSON_STRIP_NULLS( JSON_BUILD_OBJECT( 'id', rmg.id, 'name', rmg.name, 'namespace_id', rmg.namespace_id, - 'fqn', CASE - WHEN rmg.id IS NULL THEN NULL - ELSE CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT - END + 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT ) - ) AS group + )::TEXT, '{}')::JSON AS group FROM resource_mappings m LEFT JOIN attribute_values av on m.attribute_value_id = av.id LEFT JOIN attribute_fqns fqns on av.id = fqns.value_id @@ -136,17 +133,14 @@ type getResourceMappingRow struct { // JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, // m.terms, // JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, -// JSON_STRIP_NULLS( +// NULLIF(JSON_STRIP_NULLS( // JSON_BUILD_OBJECT( // 'id', rmg.id, // 'name', rmg.name, // 'namespace_id', rmg.namespace_id, -// 'fqn', CASE -// WHEN rmg.id IS NULL THEN NULL -// ELSE CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT -// END +// 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT // ) -// ) AS group +// )::TEXT, '{}')::JSON AS group // FROM resource_mappings m // LEFT JOIN attribute_values av on m.attribute_value_id = av.id // LEFT JOIN attribute_fqns fqns on av.id = fqns.value_id @@ -290,17 +284,14 @@ SELECT JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, m.terms, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, - JSON_STRIP_NULLS( + NULLIF(JSON_STRIP_NULLS( JSON_BUILD_OBJECT( 'id', rmg.id, 'name', rmg.name, 'namespace_id', rmg.namespace_id, - 'fqn', CASE - WHEN rmg.id IS NULL THEN NULL - ELSE CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT - END + 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT ) - ) AS group, + )::TEXT, '{}')::JSON AS group, COUNT(*) OVER() AS total FROM resource_mappings m LEFT JOIN attribute_values av on m.attribute_value_id = av.id @@ -338,17 +329,14 @@ type listResourceMappingsRow struct { // JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, // m.terms, // JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, -// JSON_STRIP_NULLS( +// NULLIF(JSON_STRIP_NULLS( // JSON_BUILD_OBJECT( // 'id', rmg.id, // 'name', rmg.name, // 'namespace_id', rmg.namespace_id, -// 'fqn', CASE -// WHEN rmg.id IS NULL THEN NULL -// ELSE CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT -// END +// 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT // ) -// ) AS group, +// )::TEXT, '{}')::JSON AS group, // COUNT(*) OVER() AS total // FROM resource_mappings m // LEFT JOIN attribute_values av on m.attribute_value_id = av.id From f4b96d911813b3df384cc58ce508f881fb61f54d Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Thu, 7 May 2026 13:56:57 -0700 Subject: [PATCH 06/11] DSPX-3195 Clarify resource mapping group SQL --- otdfctl/e2e/resource-mapping.bats | 8 +-- .../policy/db/queries/resource_mapping.sql | 34 +++++----- service/policy/db/resource_mapping.sql.go | 68 ++++++++++--------- 3 files changed, 58 insertions(+), 52 deletions(-) diff --git a/otdfctl/e2e/resource-mapping.bats b/otdfctl/e2e/resource-mapping.bats index 1e586c657f..c76208dd37 100755 --- a/otdfctl/e2e/resource-mapping.bats +++ b/otdfctl/e2e/resource-mapping.bats @@ -106,8 +106,8 @@ teardown_file() { # replace the terms run_otdfctl_rm update --id "$NEW_RM_ID" --terms replaced,new assert_success - refute_output --partial "test" - refute_output --partial "found" + refute_line --regexp "Terms.*test" + refute_line --regexp "Terms.*found" assert_output --partial "replaced" assert_output --partial "new" assert_output --partial "$RM_VAL2_ID" @@ -115,8 +115,8 @@ teardown_file() { # reassign the attribute value being mapped run_otdfctl_rm update --id "$NEW_RM_ID" --attribute-value-id "$RM_VAL1_ID" assert_success - refute_output --partial "test" - refute_output --partial "found" + refute_line --regexp "Terms.*test" + refute_line --regexp "Terms.*found" assert_output --partial "replaced" assert_output --partial "new" refute_output --partial "$RM_VAL2_ID" diff --git a/service/policy/db/queries/resource_mapping.sql b/service/policy/db/queries/resource_mapping.sql index a6c0b735cd..92611c909a 100644 --- a/service/policy/db/queries/resource_mapping.sql +++ b/service/policy/db/queries/resource_mapping.sql @@ -52,14 +52,15 @@ SELECT JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, m.terms, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, - NULLIF(JSON_STRIP_NULLS( - JSON_BUILD_OBJECT( - 'id', rmg.id, - 'name', rmg.name, - 'namespace_id', rmg.namespace_id, - 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT - ) - )::TEXT, '{}')::JSON AS group, + (CASE + WHEN rmg.id IS NULL THEN NULL + ELSE JSON_BUILD_OBJECT( + 'id', rmg.id, + 'name', rmg.name, + 'namespace_id', rmg.namespace_id, + 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT + ) + END)::JSON AS group, COUNT(*) OVER() AS total FROM resource_mappings m LEFT JOIN attribute_values av on m.attribute_value_id = av.id @@ -110,14 +111,15 @@ SELECT JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, m.terms, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, - NULLIF(JSON_STRIP_NULLS( - JSON_BUILD_OBJECT( - 'id', rmg.id, - 'name', rmg.name, - 'namespace_id', rmg.namespace_id, - 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT - ) - )::TEXT, '{}')::JSON AS group + (CASE + WHEN rmg.id IS NULL THEN NULL + ELSE JSON_BUILD_OBJECT( + 'id', rmg.id, + 'name', rmg.name, + 'namespace_id', rmg.namespace_id, + 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT + ) + END)::JSON AS group FROM resource_mappings m LEFT JOIN attribute_values av on m.attribute_value_id = av.id LEFT JOIN attribute_fqns fqns on av.id = fqns.value_id diff --git a/service/policy/db/resource_mapping.sql.go b/service/policy/db/resource_mapping.sql.go index d8a602329e..06313547d9 100644 --- a/service/policy/db/resource_mapping.sql.go +++ b/service/policy/db/resource_mapping.sql.go @@ -101,14 +101,15 @@ SELECT JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, m.terms, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, - NULLIF(JSON_STRIP_NULLS( - JSON_BUILD_OBJECT( - 'id', rmg.id, - 'name', rmg.name, - 'namespace_id', rmg.namespace_id, - 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT - ) - )::TEXT, '{}')::JSON AS group + (CASE + WHEN rmg.id IS NULL THEN NULL + ELSE JSON_BUILD_OBJECT( + 'id', rmg.id, + 'name', rmg.name, + 'namespace_id', rmg.namespace_id, + 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT + ) + END)::JSON AS group FROM resource_mappings m LEFT JOIN attribute_values av on m.attribute_value_id = av.id LEFT JOIN attribute_fqns fqns on av.id = fqns.value_id @@ -133,14 +134,15 @@ type getResourceMappingRow struct { // JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, // m.terms, // JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, -// NULLIF(JSON_STRIP_NULLS( -// JSON_BUILD_OBJECT( -// 'id', rmg.id, -// 'name', rmg.name, -// 'namespace_id', rmg.namespace_id, -// 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT -// ) -// )::TEXT, '{}')::JSON AS group +// (CASE +// WHEN rmg.id IS NULL THEN NULL +// ELSE JSON_BUILD_OBJECT( +// 'id', rmg.id, +// 'name', rmg.name, +// 'namespace_id', rmg.namespace_id, +// 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT +// ) +// END)::JSON AS group // FROM resource_mappings m // LEFT JOIN attribute_values av on m.attribute_value_id = av.id // LEFT JOIN attribute_fqns fqns on av.id = fqns.value_id @@ -284,14 +286,15 @@ SELECT JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, m.terms, JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, - NULLIF(JSON_STRIP_NULLS( - JSON_BUILD_OBJECT( - 'id', rmg.id, - 'name', rmg.name, - 'namespace_id', rmg.namespace_id, - 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT - ) - )::TEXT, '{}')::JSON AS group, + (CASE + WHEN rmg.id IS NULL THEN NULL + ELSE JSON_BUILD_OBJECT( + 'id', rmg.id, + 'name', rmg.name, + 'namespace_id', rmg.namespace_id, + 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT + ) + END)::JSON AS group, COUNT(*) OVER() AS total FROM resource_mappings m LEFT JOIN attribute_values av on m.attribute_value_id = av.id @@ -329,14 +332,15 @@ type listResourceMappingsRow struct { // JSON_BUILD_OBJECT('id', av.id, 'value', av.value, 'fqn', fqns.fqn) as attribute_value, // m.terms, // JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', m.metadata -> 'labels', 'created_at', m.created_at, 'updated_at', m.updated_at)) as metadata, -// NULLIF(JSON_STRIP_NULLS( -// JSON_BUILD_OBJECT( -// 'id', rmg.id, -// 'name', rmg.name, -// 'namespace_id', rmg.namespace_id, -// 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT -// ) -// )::TEXT, '{}')::JSON AS group, +// (CASE +// WHEN rmg.id IS NULL THEN NULL +// ELSE JSON_BUILD_OBJECT( +// 'id', rmg.id, +// 'name', rmg.name, +// 'namespace_id', rmg.namespace_id, +// 'fqn', CONCAT('https://', rmg_ns.name, '/resm/', rmg.name)::TEXT +// ) +// END)::JSON AS group, // COUNT(*) OVER() AS total // FROM resource_mappings m // LEFT JOIN attribute_values av on m.attribute_value_id = av.id From 96eeb5d3f27e28e80cedfb8a6105065c2ac459f7 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Thu, 7 May 2026 14:04:51 -0700 Subject: [PATCH 07/11] DSPX-3195 Use null group SQL shape in Go --- service/policy/db/resource_mapping.go | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/service/policy/db/resource_mapping.go b/service/policy/db/resource_mapping.go index e7396b0faf..beda72cd01 100644 --- a/service/policy/db/resource_mapping.go +++ b/service/policy/db/resource_mapping.go @@ -182,9 +182,8 @@ func (c PolicyDBClient) ListResourceMappings(ctx context.Context, r *resourcemap for i, rm := range list { var ( - metadata = new(common.Metadata) - attributeValue = new(policy.Value) - resourceMappingGroup = new(policy.ResourceMappingGroup) + metadata = new(common.Metadata) + attributeValue = new(policy.Value) ) if err = unmarshalMetadata(rm.Metadata, metadata); err != nil { @@ -195,11 +194,12 @@ func (c PolicyDBClient) ListResourceMappings(ctx context.Context, r *resourcemap return nil, err } - if err = unmarshalResourceMappingGroup(rm.Group, resourceMappingGroup); err != nil { - return nil, err - } - if resourceMappingGroup.GetId() == "" { - resourceMappingGroup = nil + var resourceMappingGroup *policy.ResourceMappingGroup + if rm.Group != nil { + resourceMappingGroup = new(policy.ResourceMappingGroup) + if err = unmarshalResourceMappingGroup(rm.Group, resourceMappingGroup); err != nil { + return nil, err + } } mapping := &policy.ResourceMapping{ @@ -305,9 +305,8 @@ func (c PolicyDBClient) GetResourceMapping(ctx context.Context, id string) (*pol } var ( - metadata = new(common.Metadata) - attributeValue = new(policy.Value) - resourceMappingGroup = new(policy.ResourceMappingGroup) + metadata = new(common.Metadata) + attributeValue = new(policy.Value) ) if err = unmarshalMetadata(rm.Metadata, metadata); err != nil { @@ -318,11 +317,12 @@ func (c PolicyDBClient) GetResourceMapping(ctx context.Context, id string) (*pol return nil, err } - if err = unmarshalResourceMappingGroup(rm.Group, resourceMappingGroup); err != nil { - return nil, err - } - if resourceMappingGroup.GetId() == "" { - resourceMappingGroup = nil + var resourceMappingGroup *policy.ResourceMappingGroup + if rm.Group != nil { + resourceMappingGroup = new(policy.ResourceMappingGroup) + if err = unmarshalResourceMappingGroup(rm.Group, resourceMappingGroup); err != nil { + return nil, err + } } policyRM := &policy.ResourceMapping{ From 3be7eeda62ed278eb9c7610ddd5276879d3fb4a6 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Thu, 7 May 2026 14:20:57 -0700 Subject: [PATCH 08/11] DSPX-3195 Cover listed mapping group FQNs --- service/integration/resource_mappings_test.go | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/service/integration/resource_mappings_test.go b/service/integration/resource_mappings_test.go index 0336002856..5742c49833 100644 --- a/service/integration/resource_mappings_test.go +++ b/service/integration/resource_mappings_test.go @@ -648,6 +648,14 @@ func (s *ResourceMappingsSuite) Test_ListResourceMappings_NoPagination_Succeeds( testGroups[testGroup.ID] = testGroup } + ungroupedValue := s.f.GetAttributeValueKey("example.com/attr/attr1/value/value1") + ungroupedMapping, err := s.db.PolicyClient.CreateResourceMapping(s.ctx, &resourcemapping.CreateResourceMappingRequest{ + AttributeValueId: ungroupedValue.ID, + Terms: []string{"ungrouped-list-term"}, + }) + s.Require().NoError(err) + s.Require().NotNil(ungroupedMapping) + listRsp, err := s.db.PolicyClient.ListResourceMappings(s.ctx, &resourcemapping.ListResourceMappingsRequest{}) s.Require().NoError(err) s.NotNil(listRsp) @@ -657,8 +665,15 @@ func (s *ResourceMappingsSuite) Test_ListResourceMappings_NoPagination_Succeeds( testMappingCount := len(testMappings) foundCount := 0 + foundUngroupedMapping := false for _, mapping := range list { + if mapping.GetId() == ungroupedMapping.GetId() { + foundUngroupedMapping = true + s.Nil(mapping.GetGroup()) + continue + } + testMapping, ok := testMappings[mapping.GetId()] if !ok { // only validating presence of all fixtures within the list response @@ -668,8 +683,10 @@ func (s *ResourceMappingsSuite) Test_ListResourceMappings_NoPagination_Succeeds( s.Equal(testMapping.Terms, mapping.GetTerms()) s.Equal(testMapping.GroupID, mapping.GetGroup().GetId()) - s.Equal(testGroups[mapping.GetGroup().GetId()].Name, mapping.GetGroup().GetName()) - s.Equal(testGroups[mapping.GetGroup().GetId()].NamespaceID, mapping.GetGroup().GetNamespaceId()) + testGroup := testGroups[mapping.GetGroup().GetId()] + s.Equal(testGroup.Name, mapping.GetGroup().GetName()) + s.Equal(testGroup.NamespaceID, mapping.GetGroup().GetNamespaceId()) + s.Equal(s.resourceMappingGroupFqn(testGroup), mapping.GetGroup().GetFqn()) metadata := mapping.GetMetadata() createdAt := metadata.GetCreatedAt() updatedAt := metadata.GetUpdatedAt() @@ -685,6 +702,7 @@ func (s *ResourceMappingsSuite) Test_ListResourceMappings_NoPagination_Succeeds( } s.Equal(testMappingCount, foundCount) + s.True(foundUngroupedMapping, "expected to find ungrouped mapping %s", ungroupedMapping.GetId()) } func (s *ResourceMappingsSuite) Test_ListResourceMappings_OrdersByCreatedAt_Succeeds() { From 7b8acd3237ba5551ad43bdc6cf4ca7fbca4b31cb Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Fri, 8 May 2026 07:49:22 -0700 Subject: [PATCH 09/11] update tests to prefer FQN builders --- service/integration/resource_mappings_test.go | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/service/integration/resource_mappings_test.go b/service/integration/resource_mappings_test.go index 5742c49833..022d7fa3fd 100644 --- a/service/integration/resource_mappings_test.go +++ b/service/integration/resource_mappings_test.go @@ -336,14 +336,20 @@ func (s *ResourceMappingsSuite) Test_GetResourceMappingGroupWithUnknownIdFails() } func (s *ResourceMappingsSuite) Test_CreateResourceMappingGroup() { + exampleCom := s.getExampleDotComNamespace() + groupName := "example.com_ns_new_group" req := &resourcemapping.CreateResourceMappingGroupRequest{ - NamespaceId: s.getExampleDotComNamespace().ID, - Name: "example.com_ns_new_group", + NamespaceId: exampleCom.ID, + Name: groupName, } rmGroup, err := s.db.PolicyClient.CreateResourceMappingGroup(s.ctx, req) s.Require().NoError(err) s.NotNil(rmGroup) - s.Equal("https://example.com/resm/example.com_ns_new_group", rmGroup.GetFqn()) + expectedFQN := identifier.FullyQualifiedResourceMappingGroup{ + Namespace: exampleCom.Name, + GroupName: groupName, + } + s.Equal(expectedFQN, rmGroup.GetFqn()) } func (s *ResourceMappingsSuite) Test_CreateResourceMappingGroupWithUnknownNamespaceIdFails() { @@ -401,9 +407,11 @@ func (s *ResourceMappingsSuite) Test_UpdateResourceMappingGroup() { s.Require().NoError(err) s.NotNil(createdGroup) + updateName := "example.com_ns_group_updated" + scenarioCom := s.getScenarioDotComNamespace() updateReq := &resourcemapping.UpdateResourceMappingGroupRequest{ - NamespaceId: s.getScenarioDotComNamespace().ID, - Name: "example.com_ns_group_updated", + NamespaceId: scenarioCom.ID, + Name: updateName, Metadata: &common.MetadataMutable{ Labels: updateLabels, }, @@ -413,7 +421,11 @@ func (s *ResourceMappingsSuite) Test_UpdateResourceMappingGroup() { s.Require().NoError(err) s.NotNil(updatedGroup) s.Equal(createdGroup.GetId(), updatedGroup.GetId()) - s.Equal("https://scenario.com/resm/example.com_ns_group_updated", updatedGroup.GetFqn()) + expectedFQN := (&identifier.FullyQualifiedResourceMappingGroup{ + Namespace: scenarioCom.Name, + GroupName: updateName, + }).FQN() + s.Equal(expectedFQN, updatedGroup.GetFqn()) gotGroup, err := s.db.PolicyClient.GetResourceMappingGroup(s.ctx, createdGroup.GetId()) s.Require().NoError(err) @@ -452,17 +464,19 @@ func (s *ResourceMappingsSuite) Test_UpdateResourceMappingGroupWithUnknownIdFail } func (s *ResourceMappingsSuite) Test_UpdateResourceMappingGroupWithNamespaceIdOnlySucceeds() { + groupName := "example.com_ns_group_created_nsidonly" req := &resourcemapping.CreateResourceMappingGroupRequest{ NamespaceId: s.getExampleDotComNamespace().ID, - Name: "example.com_ns_group_created_nsidonly", + Name: groupName, } rmGroup, err := s.db.PolicyClient.CreateResourceMappingGroup(s.ctx, req) s.Require().NoError(err) s.NotNil(rmGroup) + scenarioCom := s.getScenarioDotComNamespace() updateReq := &resourcemapping.UpdateResourceMappingGroupRequest{ Id: rmGroup.GetId(), - NamespaceId: s.getScenarioDotComNamespace().ID, + NamespaceId: scenarioCom.ID, } updatedRmGroup, err := s.db.PolicyClient.UpdateResourceMappingGroup(s.ctx, rmGroup.GetId(), updateReq) s.Require().NoError(err) @@ -474,22 +488,28 @@ func (s *ResourceMappingsSuite) Test_UpdateResourceMappingGroupWithNamespaceIdOn s.NotNil(gotUpdatedRmGroup) s.Equal(updateReq.GetNamespaceId(), gotUpdatedRmGroup.GetNamespaceId()) s.Equal(req.GetName(), gotUpdatedRmGroup.GetName()) - s.Equal("https://scenario.com/resm/example.com_ns_group_created_nsidonly", updatedRmGroup.GetFqn()) + expectedFQN := (&identifier.FullyQualifiedResourceMappingGroup{ + Namespace: scenarioCom.Name, + GroupName: groupName, + }).FQN() + s.Equal(expectedFQN, updatedRmGroup.GetFqn()) s.Equal(updatedRmGroup.GetFqn(), gotUpdatedRmGroup.GetFqn()) } func (s *ResourceMappingsSuite) Test_UpdateResourceMappingGroupWithNameOnlySucceeds() { + exampleCom := s.getExampleDotComNamespace() req := &resourcemapping.CreateResourceMappingGroupRequest{ - NamespaceId: s.getExampleDotComNamespace().ID, + NamespaceId: exampleCom.ID, Name: "example.com_ns_group_created_nameonly", } rmGroup, err := s.db.PolicyClient.CreateResourceMappingGroup(s.ctx, req) s.Require().NoError(err) s.NotNil(rmGroup) + updatedName := "example.com_ns_group_created_nameonly_updated" updateReq := &resourcemapping.UpdateResourceMappingGroupRequest{ Id: rmGroup.GetId(), - Name: "example.com_ns_group_created_nameonly_updated", + Name: updatedName, } updatedRmGroup, err := s.db.PolicyClient.UpdateResourceMappingGroup(s.ctx, rmGroup.GetId(), updateReq) s.Require().NoError(err) @@ -501,7 +521,11 @@ func (s *ResourceMappingsSuite) Test_UpdateResourceMappingGroupWithNameOnlySucce s.NotNil(gotUpdatedRmGroup) s.Equal(req.GetNamespaceId(), gotUpdatedRmGroup.GetNamespaceId()) s.Equal(updateReq.GetName(), gotUpdatedRmGroup.GetName()) - s.Equal("https://example.com/resm/example.com_ns_group_created_nameonly_updated", updatedRmGroup.GetFqn()) + expectedFQN := (&identifier.FullyQualifiedResourceMappingGroup{ + Namespace: exampleCom.Name, + GroupName: updatedName, + }).FQN() + s.Equal(expectedFQN, updatedRmGroup.GetFqn()) s.Equal(updatedRmGroup.GetFqn(), gotUpdatedRmGroup.GetFqn()) } From ed441eab9043da38f4d197af5fbaf8aa947d481e Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Fri, 8 May 2026 08:05:40 -0700 Subject: [PATCH 10/11] fix test --- service/integration/resource_mappings_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service/integration/resource_mappings_test.go b/service/integration/resource_mappings_test.go index 022d7fa3fd..b11c5b48b1 100644 --- a/service/integration/resource_mappings_test.go +++ b/service/integration/resource_mappings_test.go @@ -345,10 +345,10 @@ func (s *ResourceMappingsSuite) Test_CreateResourceMappingGroup() { rmGroup, err := s.db.PolicyClient.CreateResourceMappingGroup(s.ctx, req) s.Require().NoError(err) s.NotNil(rmGroup) - expectedFQN := identifier.FullyQualifiedResourceMappingGroup{ + expectedFQN := (&identifier.FullyQualifiedResourceMappingGroup{ Namespace: exampleCom.Name, GroupName: groupName, - } + }).FQN() s.Equal(expectedFQN, rmGroup.GetFqn()) } From ee671062c1f3fe52db796161cfdc9d39fab6141f Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Fri, 8 May 2026 08:25:58 -0700 Subject: [PATCH 11/11] regenerate with buf 1.68.2 --- docs/openapi/authorization/authorization.openapi.yaml | 7 ------- docs/openapi/policy/objects.openapi.yaml | 1 - .../policy/subjectmapping/subject_mapping.openapi.yaml | 1 - protocol/go/authorization/authorization.pb.go | 7 ------- protocol/go/policy/objects.pb.go | 1 - 5 files changed, 17 deletions(-) diff --git a/docs/openapi/authorization/authorization.openapi.yaml b/docs/openapi/authorization/authorization.openapi.yaml index b17083ebd1..7c5f7208e0 100644 --- a/docs/openapi/authorization/authorization.openapi.yaml +++ b/docs/openapi/authorization/authorization.openapi.yaml @@ -389,7 +389,6 @@ components: Example Request Get Decisions to answer the question - Do Bob (represented by entity chain ec1) and Alice (represented by entity chain ec2) have TRANSMIT authorization for 2 resources; resource1 (attr-set-1) defined by attributes foo:bar resource2 (attr-set-2) defined by attribute foo:bar, color:red ? - { "actions": [ { @@ -461,13 +460,11 @@ components: Example response for a Decision Request - Do Bob (represented by entity chain ec1) and Alice (represented by entity chain ec2) have TRANSMIT authorization for 2 resources; resource1 (attr-set-1) defined by attributes foo:bar resource2 (attr-set-2) defined by attribute foo:bar, color:red ? - Results: - bob has permitted authorization to transmit for a resource defined by attr-set-1 attributes and has a watermark obligation - bob has denied authorization to transmit a for a resource defined by attr-set-2 attributes - alice has permitted authorization to transmit for a resource defined by attr-set-1 attributes - alice has denied authorization to transmit a for a resource defined by attr-set-2 attributes - { "entityChainId": "ec1", "resourceAttributesId": "attr-set-1", @@ -655,9 +652,7 @@ components: additionalProperties: false description: |- Request to get entitlements for one or more entities for an optional attribute scope - Example: Get entitlements for bob and alice (both represented using an email address - { "entities": [ { @@ -688,7 +683,6 @@ components: additionalProperties: false description: |- Example Response for a request of : Get entitlements for bob and alice (both represented using an email address - { "entitlements": [ { @@ -760,7 +754,6 @@ components: Example Request Get Decisions by Token to answer the question - Do Bob and client1 (represented by token tok1) and Alice and client2 (represented by token tok2) have TRANSMIT authorization for 2 resources; resource1 (attr-set-1) defined by attributes foo:bar resource2 (attr-set-2) defined by attribute foo:bar, color:red ? - { "actions": [ { diff --git a/docs/openapi/policy/objects.openapi.yaml b/docs/openapi/policy/objects.openapi.yaml index bfde051ce7..ba1c5e3f6f 100644 --- a/docs/openapi/policy/objects.openapi.yaml +++ b/docs/openapi/policy/objects.openapi.yaml @@ -987,7 +987,6 @@ components: authoritative source such as an IDP (Identity Provider) or User Store. Examples include such ADFS/LDAP, OKTA, etc. For now, a valid property must contain both a selector expression & a resulting value. - The external_selector_value is a specifier to select a value from a flattened external representation of an Entity (such as from idP/LDAP), and the external_value is the value selected by the external_selector_value on that diff --git a/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml b/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml index e64fbc078c..bf25db5752 100644 --- a/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml +++ b/docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml @@ -1291,7 +1291,6 @@ components: authoritative source such as an IDP (Identity Provider) or User Store. Examples include such ADFS/LDAP, OKTA, etc. For now, a valid property must contain both a selector expression & a resulting value. - The external_selector_value is a specifier to select a value from a flattened external representation of an Entity (such as from idP/LDAP), and the external_value is the value selected by the external_selector_value on that diff --git a/protocol/go/authorization/authorization.pb.go b/protocol/go/authorization/authorization.pb.go index 210f7213fe..ba58718534 100644 --- a/protocol/go/authorization/authorization.pb.go +++ b/protocol/go/authorization/authorization.pb.go @@ -454,7 +454,6 @@ func (x *EntityChain) GetEntities() []*Entity { // Example Request Get Decisions to answer the question - Do Bob (represented by entity chain ec1) // and Alice (represented by entity chain ec2) have TRANSMIT authorization for // 2 resources; resource1 (attr-set-1) defined by attributes foo:bar resource2 (attr-set-2) defined by attribute foo:bar, color:red ? -// // { // "actions": [ // { @@ -561,13 +560,11 @@ func (x *DecisionRequest) GetResourceAttributes() []*ResourceAttribute { // Example response for a Decision Request - Do Bob (represented by entity chain ec1) // and Alice (represented by entity chain ec2) have TRANSMIT authorization for // 2 resources; resource1 (attr-set-1) defined by attributes foo:bar resource2 (attr-set-2) defined by attribute foo:bar, color:red ? -// // Results: // - bob has permitted authorization to transmit for a resource defined by attr-set-1 attributes and has a watermark obligation // - bob has denied authorization to transmit a for a resource defined by attr-set-2 attributes // - alice has permitted authorization to transmit for a resource defined by attr-set-1 attributes // - alice has denied authorization to transmit a for a resource defined by attr-set-2 attributes -// // { // "entityChainId": "ec1", // "resourceAttributesId": "attr-set-1", @@ -765,9 +762,7 @@ func (x *GetDecisionsResponse) GetDecisionResponses() []*DecisionResponse { } // Request to get entitlements for one or more entities for an optional attribute scope -// // Example: Get entitlements for bob and alice (both represented using an email address -// // { // "entities": [ // { @@ -964,7 +959,6 @@ func (x *ResourceAttribute) GetAttributeValueFqns() []string { } // Example Response for a request of : Get entitlements for bob and alice (both represented using an email address -// // { // "entitlements": [ // { @@ -1035,7 +1029,6 @@ func (x *GetEntitlementsResponse) GetEntitlements() []*EntityEntitlements { // Example Request Get Decisions by Token to answer the question - Do Bob and client1 (represented by token tok1) // and Alice and client2 (represented by token tok2) have TRANSMIT authorization for // 2 resources; resource1 (attr-set-1) defined by attributes foo:bar resource2 (attr-set-2) defined by attribute foo:bar, color:red ? -// // { // "actions": [ // { diff --git a/protocol/go/policy/objects.pb.go b/protocol/go/policy/objects.pb.go index 5345d9203b..78282c4edc 100644 --- a/protocol/go/policy/objects.pb.go +++ b/protocol/go/policy/objects.pb.go @@ -1575,7 +1575,6 @@ func (x *SubjectConditionSet) GetMetadata() *common.Metadata { // authoritative source such as an IDP (Identity Provider) or User Store. // Examples include such ADFS/LDAP, OKTA, etc. For now, a valid property must // contain both a selector expression & a resulting value. -// // The external_selector_value is a specifier to select a value from a flattened // external representation of an Entity (such as from idP/LDAP), and the // external_value is the value selected by the external_selector_value on that