diff --git a/cmd/migrate.go b/cmd/migrate.go index 45dd4dfce6..7e3e087191 100644 --- a/cmd/migrate.go +++ b/cmd/migrate.go @@ -31,7 +31,6 @@ var ( fmt.Print("migration down applied successfully") }, } - migrateUpCmd = &cobra.Command{ Use: "up", Short: "Run database migrations up to the latest version", diff --git a/docs/grpc/index.html b/docs/grpc/index.html index e50e45f427..5c3348d365 100644 --- a/docs/grpc/index.html +++ b/docs/grpc/index.html @@ -2068,7 +2068,7 @@

Value

members - string + Value repeated

list of attribute values that this value is related to (attribute group)

diff --git a/docs/openapi/policy/attributes/attributes.swagger.json b/docs/openapi/policy/attributes/attributes.swagger.json index 126cf1361f..858fb377ba 100644 --- a/docs/openapi/policy/attributes/attributes.swagger.json +++ b/docs/openapi/policy/attributes/attributes.swagger.json @@ -1050,7 +1050,8 @@ "members": { "type": "array", "items": { - "type": "string" + "type": "object", + "$ref": "#/definitions/policyValue" }, "title": "list of attribute values that this value is related to (attribute group)" }, diff --git a/docs/openapi/policy/resourcemapping/resource_mapping.swagger.json b/docs/openapi/policy/resourcemapping/resource_mapping.swagger.json index 4fd9884ba5..834f3138b1 100644 --- a/docs/openapi/policy/resourcemapping/resource_mapping.swagger.json +++ b/docs/openapi/policy/resourcemapping/resource_mapping.swagger.json @@ -532,7 +532,8 @@ "members": { "type": "array", "items": { - "type": "string" + "type": "object", + "$ref": "#/definitions/policyValue" }, "title": "list of attribute values that this value is related to (attribute group)" }, diff --git a/docs/openapi/policy/subjectmapping/subject_mapping.swagger.json b/docs/openapi/policy/subjectmapping/subject_mapping.swagger.json index 81b8061e32..80ffb3faec 100644 --- a/docs/openapi/policy/subjectmapping/subject_mapping.swagger.json +++ b/docs/openapi/policy/subjectmapping/subject_mapping.swagger.json @@ -715,7 +715,8 @@ "members": { "type": "array", "items": { - "type": "string" + "type": "object", + "$ref": "#/definitions/policyValue" }, "title": "list of attribute values that this value is related to (attribute group)" }, diff --git a/integration/attribute_values_test.go b/integration/attribute_values_test.go index c64019d0fc..8e6c66fa5e 100644 --- a/integration/attribute_values_test.go +++ b/integration/attribute_values_test.go @@ -3,6 +3,7 @@ package integration import ( "context" "log/slog" + "sort" "testing" "github.com/opentdf/platform/internal/db" @@ -138,7 +139,24 @@ func (s *AttributeValuesSuite) Test_CreateAttributeValue_NoMembers_Succeeds() { assert.Equal(s.T(), len(createdValue.Members), len(got.Members)) assert.EqualValues(s.T(), createdValue.Metadata.Labels, got.Metadata.Labels) } - +func equalMembers(t *testing.T, v1 *policy.Value, v2 *policy.Value, withFqn bool) { + m1 := v1.Members + m2 := v2.Members + sort.Slice(m1, func(x, y int) bool { + return m1[x].Id < m1[y].Id + }) + sort.Slice(m2, func(x, y int) bool { + return m2[x].Id < m2[y].Id + }) + for idx := range m1 { + assert.Equal(t, m1[idx].Id, m2[idx].Id) + assert.Equal(t, m1[idx].Value, m2[idx].Value) + if withFqn { + assert.Equal(t, m1[idx].Fqn, m2[idx].Fqn) + } + assert.Equal(t, m1[idx].Active.Value, m2[idx].Active.Value) + } +} func (s *AttributeValuesSuite) Test_CreateAttributeValue_WithMembers_Succeeds() { attrDef := s.f.GetAttributeKey("example.net/attr/attr1") metadata := &common.MetadataMutable{ @@ -165,7 +183,16 @@ func (s *AttributeValuesSuite) Test_CreateAttributeValue_WithMembers_Succeeds() assert.Equal(s.T(), createdValue.Id, got.Id) assert.Equal(s.T(), createdValue.Value, got.Value) assert.EqualValues(s.T(), createdValue.Metadata.Labels, got.Metadata.Labels) - assert.EqualValues(s.T(), createdValue.Members, got.Members) + assert.Equal(s.T(), len(createdValue.Members), len(got.Members)) + + assert.True(s.T(), len(got.Members) > 0) + equalMembers(s.T(), createdValue, got, true) + + // test uniqueness + createdValue, err = s.db.PolicyClient.CreateAttributeValue(s.ctx, attrDef.Id, value) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), createdValue) + assert.ErrorIs(s.T(), err, db.ErrUniqueConstraintViolation) } func (s *AttributeValuesSuite) Test_CreateAttributeValue_WithInvalidAttributeId_Fails() { @@ -178,6 +205,34 @@ func (s *AttributeValuesSuite) Test_CreateAttributeValue_WithInvalidAttributeId_ assert.ErrorIs(s.T(), err, db.ErrForeignKeyViolation) } +func (s *AttributeValuesSuite) Test_CreateAttributeValue_WithInvalidMember_Fails() { + attrDef := s.f.GetAttributeKey("example.net/attr/attr2") + metadata := &common.MetadataMutable{ + Labels: map[string]string{ + "name": "testing create with members", + }, + } + + value := &attributes.CreateAttributeValueRequest{ + Value: "value3", + Members: []string{ + nonExistentAttributeValueUuid, + }, + Metadata: metadata, + } + createdValue, err := s.db.PolicyClient.CreateAttributeValue(s.ctx, attrDef.Id, value) + assert.Nil(s.T(), createdValue) + assert.NotNil(s.T(), err) + assert.ErrorIs(s.T(), err, db.ErrForeignKeyViolation) + + attrDef = s.f.GetAttributeKey("example.net/attr/attr3") + value.Members[0] = "not a uuid" + createdValue, err = s.db.PolicyClient.CreateAttributeValue(s.ctx, attrDef.Id, value) + assert.Nil(s.T(), createdValue) + assert.NotNil(s.T(), err) + assert.ErrorIs(s.T(), err, db.ErrUuidInvalid) +} + func (s *AttributeValuesSuite) Test_UpdateAttributeValue() { fixedLabel := "fixed label" updateLabel := "update label" diff --git a/integration/resource_mappings_test.go b/integration/resource_mappings_test.go index bf7eb11507..267d230879 100644 --- a/integration/resource_mappings_test.go +++ b/integration/resource_mappings_test.go @@ -43,6 +43,7 @@ func (s *ResourceMappingsSuite) getResourceMappingFixtures() []fixtures.FixtureD s.f.GetResourceMappingKey("resource_mapping_to_attribute_value1"), s.f.GetResourceMappingKey("resource_mapping_to_attribute_value2"), s.f.GetResourceMappingKey("resource_mapping_to_attribute_value3"), + s.f.GetResourceMappingKey("resource_mapping_to_attribute_value4"), } } @@ -115,13 +116,23 @@ func (s *ResourceMappingsSuite) Test_ListResourceMappings() { func (s *ResourceMappingsSuite) Test_GetResourceMapping() { // make sure we can get all fixtures testData := s.getResourceMappingFixtures() - for _, testMapping := range testData { + testedMembers := false + for idx, testMapping := range testData { mapping, err := s.db.PolicyClient.GetResourceMapping(s.ctx, testMapping.Id) assert.Nil(s.T(), err) assert.NotNil(s.T(), mapping) assert.Equal(s.T(), testMapping.Id, mapping.Id) assert.Equal(s.T(), testMapping.AttributeValueId, mapping.AttributeValue.Id) assert.Equal(s.T(), testMapping.Terms, mapping.Terms) + av, err := s.db.PolicyClient.GetAttributeValue(s.ctx, testMapping.AttributeValueId) + assert.Nil(s.T(), err) + if len(av.Members) > 0 { + testedMembers = true + } + if idx == len(testData)-1 { + assert.True(s.T(), testedMembers, "expected to test at least one attribute value member") + } + equalMembers(s.T(), av, mapping.AttributeValue, false) } } diff --git a/integration/subject_mappings_test.go b/integration/subject_mappings_test.go index f9d0433106..4bc538a446 100644 --- a/integration/subject_mappings_test.go +++ b/integration/subject_mappings_test.go @@ -346,7 +346,7 @@ func (s *SubjectMappingsSuite) TestUpdateSubjectMapping_NonExistentSubjectCondit } func (s *SubjectMappingsSuite) TestGetSubjectMapping() { - fixture := s.f.GetSubjectMappingKey("subject_mapping_subject_attribute3") + fixture := s.f.GetSubjectMappingKey("subject_mapping_subject_attribute2") sm, err := s.db.PolicyClient.GetSubjectMapping(s.ctx, fixture.Id) assert.Nil(s.T(), err) @@ -367,6 +367,12 @@ func (s *SubjectMappingsSuite) TestGetSubjectMapping() { assert.Equal(s.T(), "custom:\""+fixture.Actions[i].Custom+"\"", a.String()) } } + got, err := s.db.PolicyClient.GetAttributeValue(s.ctx, fixture.AttributeValueId) + assert.Nil(s.T(), err) + assert.NotNil(s.T(), got) + assert.Equal(s.T(), fixture.AttributeValueId, got.Id) + assert.True(s.T(), len(got.Members) > 0) + equalMembers(s.T(), got, sm.AttributeValue, false) } func (s *SubjectMappingsSuite) TestGetSubjectMapping_NonExistentId_Fails() { diff --git a/internal/db/db.go b/internal/db/db.go index 5187ea5841..d4dae863d7 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -7,7 +7,6 @@ import ( "net" sq "github.com/Masterminds/squirrel" - "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" "github.com/jackc/pgx/v5/pgxpool" diff --git a/internal/fixtures/fixtures.go b/internal/fixtures/fixtures.go index d2d1f13a97..cc72a6c007 100644 --- a/internal/fixtures/fixtures.go +++ b/internal/fixtures/fixtures.go @@ -46,6 +46,12 @@ type FixtureDataAttributeValue struct { Active bool `yaml:"active"` } +type FixtureDataValueMember struct { + Id string `yaml:"id"` + ValueID string `yaml:"value_id"` + MemberID string `yaml:"member_id"` +} + type FixtureDataAttributeValueKeyAccessServer struct { ValueID string `yaml:"value_id"` KeyAccessServerID string `yaml:"key_access_server_id"` @@ -123,6 +129,10 @@ type FixtureData struct { Metadata FixtureMetadata `yaml:"metadata"` Data map[string]FixtureDataKasRegistry `yaml:"data"` } `yaml:"kas_registry"` + ValueMembers struct { + Metadata FixtureMetadata `yaml:"metadata"` + Data map[string]FixtureDataValueMember `yaml:"data"` + } `yaml:"attribute_value_members"` } func LoadFixtureData(file string) { @@ -176,6 +186,14 @@ func (f *Fixtures) GetAttributeValueKey(key string) FixtureDataAttributeValue { return av } +func (f *Fixtures) GetValueMemberKey(key string) FixtureDataValueMember { + if fixtureData.ValueMembers.Data[key].Id == "" { + slog.Error("could not find value-members", slog.String("id", key)) + panic("could not find value-members") + } + return fixtureData.ValueMembers.Data[key] +} + func (f *Fixtures) GetSubjectMappingKey(key string) FixtureDataSubjectMapping { sm, ok := fixtureData.SubjectMappings.Data[key] if !ok || sm.Id == "" { @@ -225,6 +243,8 @@ func (f *Fixtures) Provision() { a := f.provisionAttribute() slog.Info("📦 provisioning attribute value data") aV := f.provisionAttributeValues() + slog.Info("📦 provisioning value member data") + vM := f.provisionValueMembers() slog.Info("📦 provisioning subject condition set data") sc := f.provisionSubjectConditionSet() slog.Info("📦 provisioning subject mapping data") @@ -242,6 +262,7 @@ func (f *Fixtures) Provision() { slog.Int64("namespaces", n), slog.Int64("attributes", a), slog.Int64("attribute_values", aV), + slog.Int64("attribute_value_members", vM), slog.Int64("subject_mappings", sM), slog.Int64("subject_condition_set", sc), slog.Int64("resource_mappings", rM), @@ -304,6 +325,18 @@ func (f *Fixtures) provisionAttributeValues() int64 { return f.provision(fixtureData.AttributeValues.Metadata.TableName, fixtureData.AttributeValues.Metadata.Columns, values) } +func (f *Fixtures) provisionValueMembers() int64 { + values := make([][]string, 0, len(fixtureData.ValueMembers.Data)) + for _, d := range fixtureData.ValueMembers.Data { + values = append(values, []string{ + f.db.StringWrap(d.Id), + f.db.StringWrap(d.ValueID), + f.db.StringWrap(d.MemberID), + }) + } + return f.provision(fixtureData.ValueMembers.Metadata.TableName, fixtureData.ValueMembers.Metadata.Columns, values) +} + func (f *Fixtures) provisionSubjectConditionSet() int64 { values := make([][]string, 0, len(fixtureData.SubjectConditionSet.Data)) for _, d := range fixtureData.SubjectConditionSet.Data { diff --git a/internal/fixtures/policy_fixtures.yaml b/internal/fixtures/policy_fixtures.yaml index b28ae0cef3..b2deeb7302 100644 --- a/internal/fixtures/policy_fixtures.yaml +++ b/internal/fixtures/policy_fixtures.yaml @@ -140,10 +140,10 @@ attribute_values: attribute_definition_id: 6a261d68-0899-4e17-bb2f-124abba7c09c value: value2 members: - # example.com/attr/attr2/value/value1 - - 0fd363db-27b1-4210-b77b-8c82fe044d41 - # example.net/attr/attr1/value/value1 - - 532e5957-28f7-466d-91e2-493e9431cd83 + # pivots value: example.com/attr/attr2/value/value1 + - bf461e97-a918-4aa5-83ad-9bb768a58d12 + # pivots value: example.net/attr/attr1/value/value1 + - ddd9c539-2a2b-47ba-aad3-95b54dd022ef active: true example.com/attr/attr2/value/value1: @@ -187,6 +187,22 @@ attribute_value_key_access_servers: - value_id: 74babca6-016f-4f3e-a99b-4e46ea8d0fd8 key_access_server_id: e36640a6-61c5-4d4c-a45b-0e0a26d1c45f +attribute_value_members: + metadata: + table_name: attribute_value_members + columns: + - id + - value_id + - member_id + data: + member1: + id: bf461e97-a918-4aa5-83ad-9bb768a58d12 + value_id: 2fe8dea1-3555-498c-afe9-99724f35f3d3 + member_id: 0fd363db-27b1-4210-b77b-8c82fe044d41 + member2: + id: ddd9c539-2a2b-47ba-aad3-95b54dd022ef + value_id: 2fe8dea1-3555-498c-afe9-99724f35f3d3 + member_id: 532e5957-28f7-466d-91e2-493e9431cd83 ## # Subject Mappings -> 1 Group of Subject Condition Sets ## @@ -386,6 +402,11 @@ resource_mappings: attribute_value_id: 04bd2657-de10-46bc-a88f-5d687de4816b terms: - helloworld + resource_mapping_to_attribute_value4: + id: f99d1c97-ad8a-40c8-8148-6539764e2743 + attribute_value_id: 2fe8dea1-3555-498c-afe9-99724f35f3d3 + terms: + - with_members ## # KAS Registry (key access server registry) diff --git a/migrations/20240313000000_create_val_members.md b/migrations/20240313000000_create_val_members.md new file mode 100644 index 0000000000..592914c41a --- /dev/null +++ b/migrations/20240313000000_create_val_members.md @@ -0,0 +1,29 @@ +# Diagram for 20240223000000_create_val_members.sql + +```mermaid +--- +title: Attribute Value Mermaid Diagram +nodes: | +--- + +erDiagram + AttributeValue ||--o{ ValueMember: "has group members" + + AttributeValue { + uuid id PK + uuid namespace_id FK + uuid attribute_definition_id FK + varchar value + jsonb metadata + compIdx comp_key UK "ns_id + ad_id + value" + bool active + } + + ValueMember { + uuid id PK + uuid value_id FK + uuid member_id FK + compIdx comp_key UK "value_id + member_id" + } + +``` diff --git a/migrations/20240313000000_create_val_members.sql b/migrations/20240313000000_create_val_members.sql new file mode 100644 index 0000000000..0e88e7615f --- /dev/null +++ b/migrations/20240313000000_create_val_members.sql @@ -0,0 +1,18 @@ +-- +goose Up +-- +goose StatementBegin + +CREATE TABLE IF NOT EXISTS attribute_value_members +( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + value_id UUID NOT NULL REFERENCES attribute_values(id), + member_id UUID NOT NULL REFERENCES attribute_values(id), + UNIQUE (value_id, member_id) +); + +-- +goose StatementEnd + +-- +goose Down + +-- +goose StatementBegin +DROP TABLE IF EXISTS attribute_value_members; +-- +goose StatementEnd diff --git a/protocol/go/policy/objects.pb.go b/protocol/go/policy/objects.pb.go index 9330caea3f..7dccb24e78 100644 --- a/protocol/go/policy/objects.pb.go +++ b/protocol/go/policy/objects.pb.go @@ -435,7 +435,7 @@ type Value struct { Attribute *Attribute `protobuf:"bytes,2,opt,name=attribute,proto3" json:"attribute,omitempty"` Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` // list of attribute values that this value is related to (attribute group) - Members []string `protobuf:"bytes,4,rep,name=members,proto3" json:"members,omitempty"` + Members []*Value `protobuf:"bytes,4,rep,name=members,proto3" json:"members,omitempty"` // list of key access servers Grants []*kasregistry.KeyAccessServer `protobuf:"bytes,5,rep,name=grants,proto3" json:"grants,omitempty"` Fqn string `protobuf:"bytes,6,opt,name=fqn,proto3" json:"fqn,omitempty"` @@ -500,7 +500,7 @@ func (x *Value) GetValue() string { return "" } -func (x *Value) GetMembers() []string { +func (x *Value) GetMembers() []*Value { if x != nil { return x.Members } @@ -1146,155 +1146,156 @@ var file_policy_objects_proto_rawDesc = []byte{ 0x75, 0x65, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 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, 0xe5, 0x02, 0x0a, 0x05, 0x56, 0x61, 0x6c, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xf4, 0x02, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2f, 0x0a, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x12, 0x34, 0x0a, 0x06, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x52, 0x06, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x71, 0x6e, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, 0x71, 0x6e, 0x12, 0x32, 0x0a, 0x06, 0x61, - 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x07, 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, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, - 0x41, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, - 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x2e, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, - 0x67, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, - 0x67, 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, 0xd6, 0x01, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x08, 0x73, - 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74, - 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x08, - 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x06, 0x63, 0x75, 0x73, 0x74, - 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x63, 0x75, 0x73, 0x74, - 0x6f, 0x6d, 0x22, 0x6c, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x1b, 0x53, 0x54, 0x41, 0x4e, 0x44, 0x41, 0x52, 0x44, - 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x54, 0x41, 0x4e, 0x44, 0x41, 0x52, - 0x44, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50, 0x54, - 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x54, 0x41, 0x4e, 0x44, 0x41, 0x52, 0x44, 0x5f, 0x41, - 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x4d, 0x49, 0x54, 0x10, 0x02, - 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x81, 0x02, 0x0a, 0x0e, 0x53, 0x75, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x0f, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 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, 0x4f, 0x0a, 0x15, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x75, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, - 0x52, 0x13, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x12, 0x28, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0xc6, 0x01, - 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x16, 0x73, - 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, - 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x73, 0x75, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x65, 0x6c, - 0x64, 0x12, 0x4b, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 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, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, - 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x36, - 0x0a, 0x17, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x15, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x64, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x3b, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, - 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x42, 0x08, 0xba, 0x48, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x58, 0x0a, 0x10, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, - 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x20, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x45, 0x6e, - 0x75, 0x6d, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, - 0x0f, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, - 0x22, 0x59, 0x0a, 0x0a, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x74, 0x12, 0x4b, - 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x42, 0x08, 0xba, 0x48, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x64, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0x94, 0x01, 0x0a, 0x13, - 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x53, 0x65, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x3f, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, - 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x2e, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x74, 0x42, 0x08, 0xba, - 0x48, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x53, 0x65, 0x74, 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, 0x6f, 0x0a, 0x0f, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x50, 0x72, 0x6f, - 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, 0x2d, 0x0a, 0x0e, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xba, - 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x12, 0x2d, 0x0a, 0x0e, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xba, 0x48, - 0x03, 0xc8, 0x01, 0x01, 0x52, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x22, 0xa5, 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, 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, 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, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x27, 0x0a, 0x07, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x12, 0x34, 0x0a, 0x06, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, + 0x2e, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x52, 0x06, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x71, 0x6e, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, 0x71, 0x6e, 0x12, 0x32, 0x0a, 0x06, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x18, 0x07, 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, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x41, + 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, + 0x67, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x2e, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, + 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, + 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, + 0xd6, 0x01, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x08, 0x73, 0x74, + 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, + 0x6e, 0x64, 0x61, 0x72, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x08, 0x73, + 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x06, 0x63, 0x75, 0x73, 0x74, 0x6f, + 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x63, 0x75, 0x73, 0x74, 0x6f, + 0x6d, 0x22, 0x6c, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x1b, 0x53, 0x54, 0x41, 0x4e, 0x44, 0x41, 0x52, 0x44, 0x5f, + 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x54, 0x41, 0x4e, 0x44, 0x41, 0x52, 0x44, + 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50, 0x54, 0x10, + 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x54, 0x41, 0x4e, 0x44, 0x41, 0x52, 0x44, 0x5f, 0x41, 0x43, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x4d, 0x49, 0x54, 0x10, 0x02, 0x42, + 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x81, 0x02, 0x0a, 0x0e, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x0f, 0x61, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 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, 0x4f, 0x0a, 0x15, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x63, + 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x52, + 0x13, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x65, 0x74, 0x12, 0x28, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0xc6, 0x01, 0x0a, + 0x09, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x73, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x65, 0x6c, 0x64, + 0x12, 0x4b, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 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, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, 0x01, + 0x02, 0x10, 0x01, 0x52, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x36, 0x0a, + 0x17, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x15, + 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x3b, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, + 0x08, 0xba, 0x48, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x58, 0x0a, 0x10, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, + 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x20, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x45, 0x6e, 0x75, + 0x6d, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, + 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, + 0x59, 0x0a, 0x0a, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x74, 0x12, 0x4b, 0x0a, + 0x10, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x42, + 0x08, 0xba, 0x48, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0x94, 0x01, 0x0a, 0x13, 0x53, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x65, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x3f, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, + 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x2e, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x74, 0x42, 0x08, 0xba, 0x48, + 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, + 0x65, 0x74, 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, 0x6f, 0x0a, 0x0f, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x50, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x74, 0x79, 0x12, 0x2d, 0x0a, 0x0e, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xba, 0x48, + 0x03, 0xc8, 0x01, 0x01, 0x52, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x46, 0x69, + 0x65, 0x6c, 0x64, 0x12, 0x2d, 0x0a, 0x0e, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xba, 0x48, 0x03, + 0xc8, 0x01, 0x01, 0x52, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x22, 0xa5, 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, 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, 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, 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, 0x9b, 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, + 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, 0x9b, 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, 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, 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, 0x42, 0x92, 0x01, 0x0a, 0x1a, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, - 0x66, 0x2e, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 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, + 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, 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, 0x42, 0x92, 0x01, 0x0a, 0x1a, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, 0x66, + 0x2e, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 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 ( @@ -1341,28 +1342,29 @@ var file_policy_objects_proto_depIdxs = []int32{ 15, // 6: policy.Attribute.active:type_name -> google.protobuf.BoolValue 16, // 7: policy.Attribute.metadata:type_name -> common.Metadata 5, // 8: policy.Value.attribute:type_name -> policy.Attribute - 17, // 9: policy.Value.grants:type_name -> kasregistry.KeyAccessServer - 15, // 10: policy.Value.active:type_name -> google.protobuf.BoolValue - 8, // 11: policy.Value.subject_mappings:type_name -> policy.SubjectMapping - 16, // 12: policy.Value.metadata:type_name -> common.Metadata - 3, // 13: policy.Action.standard:type_name -> policy.Action.StandardAction - 6, // 14: policy.SubjectMapping.attribute_value:type_name -> policy.Value - 12, // 15: policy.SubjectMapping.subject_condition_set:type_name -> policy.SubjectConditionSet - 7, // 16: policy.SubjectMapping.actions:type_name -> policy.Action - 16, // 17: policy.SubjectMapping.metadata:type_name -> common.Metadata - 1, // 18: policy.Condition.operator:type_name -> policy.SubjectMappingOperatorEnum - 9, // 19: policy.ConditionGroup.conditions:type_name -> policy.Condition - 2, // 20: policy.ConditionGroup.boolean_operator:type_name -> policy.ConditionBooleanTypeEnum - 10, // 21: policy.SubjectSet.condition_groups:type_name -> policy.ConditionGroup - 11, // 22: policy.SubjectConditionSet.subject_sets:type_name -> policy.SubjectSet - 16, // 23: policy.SubjectConditionSet.metadata:type_name -> common.Metadata - 16, // 24: policy.ResourceMapping.metadata:type_name -> common.Metadata - 6, // 25: policy.ResourceMapping.attribute_value:type_name -> policy.Value - 26, // [26:26] is the sub-list for method output_type - 26, // [26:26] is the sub-list for method input_type - 26, // [26:26] is the sub-list for extension type_name - 26, // [26:26] is the sub-list for extension extendee - 0, // [0:26] is the sub-list for field type_name + 6, // 9: policy.Value.members:type_name -> policy.Value + 17, // 10: policy.Value.grants:type_name -> kasregistry.KeyAccessServer + 15, // 11: policy.Value.active:type_name -> google.protobuf.BoolValue + 8, // 12: policy.Value.subject_mappings:type_name -> policy.SubjectMapping + 16, // 13: policy.Value.metadata:type_name -> common.Metadata + 3, // 14: policy.Action.standard:type_name -> policy.Action.StandardAction + 6, // 15: policy.SubjectMapping.attribute_value:type_name -> policy.Value + 12, // 16: policy.SubjectMapping.subject_condition_set:type_name -> policy.SubjectConditionSet + 7, // 17: policy.SubjectMapping.actions:type_name -> policy.Action + 16, // 18: policy.SubjectMapping.metadata:type_name -> common.Metadata + 1, // 19: policy.Condition.operator:type_name -> policy.SubjectMappingOperatorEnum + 9, // 20: policy.ConditionGroup.conditions:type_name -> policy.Condition + 2, // 21: policy.ConditionGroup.boolean_operator:type_name -> policy.ConditionBooleanTypeEnum + 10, // 22: policy.SubjectSet.condition_groups:type_name -> policy.ConditionGroup + 11, // 23: policy.SubjectConditionSet.subject_sets:type_name -> policy.SubjectSet + 16, // 24: policy.SubjectConditionSet.metadata:type_name -> common.Metadata + 16, // 25: policy.ResourceMapping.metadata:type_name -> common.Metadata + 6, // 26: policy.ResourceMapping.attribute_value:type_name -> policy.Value + 27, // [27:27] is the sub-list for method output_type + 27, // [27:27] is the sub-list for method input_type + 27, // [27:27] is the sub-list for extension type_name + 27, // [27:27] is the sub-list for extension extendee + 0, // [0:27] is the sub-list for field type_name } func init() { file_policy_objects_proto_init() } diff --git a/sdkjava/src/main/java/io/opentdf/platform/policy/ObjectsProto.java b/sdkjava/src/main/java/io/opentdf/platform/policy/ObjectsProto.java index b685634683..e89e8e91c2 100644 --- a/sdkjava/src/main/java/io/opentdf/platform/policy/ObjectsProto.java +++ b/sdkjava/src/main/java/io/opentdf/platform/policy/ObjectsProto.java @@ -96,66 +96,67 @@ public static void registerAllExtensions( "AccessServerR\006grants\022\020\n\003fqn\030\007 \001(\tR\003fqn\0222" + "\n\006active\030\010 \001(\0132\032.google.protobuf.BoolVal" + "ueR\006active\022,\n\010metadata\030d \001(\0132\020.common.Me" + - "tadataR\010metadata\"\345\002\n\005Value\022\016\n\002id\030\001 \001(\tR\002" + + "tadataR\010metadata\"\364\002\n\005Value\022\016\n\002id\030\001 \001(\tR\002" + "id\022/\n\tattribute\030\002 \001(\0132\021.policy.Attribute" + - "R\tattribute\022\024\n\005value\030\003 \001(\tR\005value\022\030\n\007mem" + - "bers\030\004 \003(\tR\007members\0224\n\006grants\030\005 \003(\0132\034.ka" + - "sregistry.KeyAccessServerR\006grants\022\020\n\003fqn" + - "\030\006 \001(\tR\003fqn\0222\n\006active\030\007 \001(\0132\032.google.pro" + - "tobuf.BoolValueR\006active\022A\n\020subject_mappi" + - "ngs\030\010 \003(\0132\026.policy.SubjectMappingR\017subje" + - "ctMappings\022,\n\010metadata\030d \001(\0132\020.common.Me" + - "tadataR\010metadata\"\326\001\n\006Action\022;\n\010standard\030" + - "\001 \001(\0162\035.policy.Action.StandardActionH\000R\010" + - "standard\022\030\n\006custom\030\002 \001(\tH\000R\006custom\"l\n\016St" + - "andardAction\022\037\n\033STANDARD_ACTION_UNSPECIF" + - "IED\020\000\022\033\n\027STANDARD_ACTION_DECRYPT\020\001\022\034\n\030ST" + - "ANDARD_ACTION_TRANSMIT\020\002B\007\n\005value\"\201\002\n\016Su" + - "bjectMapping\022\016\n\002id\030\001 \001(\tR\002id\0226\n\017attribut" + - "e_value\030\002 \001(\0132\r.policy.ValueR\016attributeV" + - "alue\022O\n\025subject_condition_set\030\003 \001(\0132\033.po" + - "licy.SubjectConditionSetR\023subjectConditi" + - "onSet\022(\n\007actions\030\004 \003(\0132\016.policy.ActionR\007" + - "actions\022,\n\010metadata\030d \001(\0132\020.common.Metad" + - "ataR\010metadata\"\306\001\n\tCondition\0224\n\026subject_e" + - "xternal_field\030\001 \001(\tR\024subjectExternalFiel" + - "d\022K\n\010operator\030\002 \001(\0162\".policy.SubjectMapp" + - "ingOperatorEnumB\013\272H\010\202\001\002\020\001\310\001\001R\010operator\0226" + - "\n\027subject_external_values\030\003 \003(\tR\025subject" + - "ExternalValues\"\247\001\n\016ConditionGroup\022;\n\ncon" + - "ditions\030\001 \003(\0132\021.policy.ConditionB\010\272H\005\222\001\002" + - "\010\001R\nconditions\022X\n\020boolean_operator\030\002 \001(\016" + - "2 .policy.ConditionBooleanTypeEnumB\013\272H\010\202" + - "\001\002\020\001\310\001\001R\017booleanOperator\"Y\n\nSubjectSet\022K" + - "\n\020condition_groups\030\001 \003(\0132\026.policy.Condit" + - "ionGroupB\010\272H\005\222\001\002\010\001R\017conditionGroups\"\224\001\n\023" + - "SubjectConditionSet\022\016\n\002id\030\001 \001(\tR\002id\022?\n\014s" + - "ubject_sets\030\003 \003(\0132\022.policy.SubjectSetB\010\272" + - "H\005\222\001\002\010\001R\013subjectSets\022,\n\010metadata\030d \001(\0132\020" + - ".common.MetadataR\010metadata\"o\n\017SubjectPro" + - "perty\022-\n\016external_field\030\001 \001(\tB\006\272H\003\310\001\001R\re" + - "xternalField\022-\n\016external_value\030\002 \001(\tB\006\272H" + - "\003\310\001\001R\rexternalValue\"\245\001\n\017ResourceMapping\022" + - "\016\n\002id\030\001 \001(\tR\002id\022,\n\010metadata\030\002 \001(\0132\020.comm" + - "on.MetadataR\010metadata\022>\n\017attribute_value" + - "\030\003 \001(\0132\r.policy.ValueB\006\272H\003\310\001\001R\016attribute" + - "Value\022\024\n\005terms\030\004 \003(\tR\005terms*\263\001\n\025Attribut" + - "eRuleTypeEnum\022(\n$ATTRIBUTE_RULE_TYPE_ENU" + - "M_UNSPECIFIED\020\000\022#\n\037ATTRIBUTE_RULE_TYPE_E" + - "NUM_ALL_OF\020\001\022#\n\037ATTRIBUTE_RULE_TYPE_ENUM" + - "_ANY_OF\020\002\022&\n\"ATTRIBUTE_RULE_TYPE_ENUM_HI" + - "ERARCHY\020\003*\233\001\n\032SubjectMappingOperatorEnum" + - "\022-\n)SUBJECT_MAPPING_OPERATOR_ENUM_UNSPEC" + - "IFIED\020\000\022$\n SUBJECT_MAPPING_OPERATOR_ENUM" + - "_IN\020\001\022(\n$SUBJECT_MAPPING_OPERATOR_ENUM_N" + - "OT_IN\020\002*\220\001\n\030ConditionBooleanTypeEnum\022+\n\'" + - "CONDITION_BOOLEAN_TYPE_ENUM_UNSPECIFIED\020" + - "\000\022#\n\037CONDITION_BOOLEAN_TYPE_ENUM_AND\020\001\022\"" + - "\n\036CONDITION_BOOLEAN_TYPE_ENUM_OR\020\002B\222\001\n\032i" + - "o.opentdf.platform.policyB\014ObjectsProtoP" + - "\001Z.github.com/opentdf/platform/protocol/" + - "go/policy\242\002\003PXX\252\002\006Policy\312\002\006Policy\342\002\022Poli" + - "cy\\GPBMetadata\352\002\006Policyb\006proto3" + "R\tattribute\022\024\n\005value\030\003 \001(\tR\005value\022\'\n\007mem" + + "bers\030\004 \003(\0132\r.policy.ValueR\007members\0224\n\006gr" + + "ants\030\005 \003(\0132\034.kasregistry.KeyAccessServer" + + "R\006grants\022\020\n\003fqn\030\006 \001(\tR\003fqn\0222\n\006active\030\007 \001" + + "(\0132\032.google.protobuf.BoolValueR\006active\022A" + + "\n\020subject_mappings\030\010 \003(\0132\026.policy.Subjec" + + "tMappingR\017subjectMappings\022,\n\010metadata\030d " + + "\001(\0132\020.common.MetadataR\010metadata\"\326\001\n\006Acti" + + "on\022;\n\010standard\030\001 \001(\0162\035.policy.Action.Sta" + + "ndardActionH\000R\010standard\022\030\n\006custom\030\002 \001(\tH" + + "\000R\006custom\"l\n\016StandardAction\022\037\n\033STANDARD_" + + "ACTION_UNSPECIFIED\020\000\022\033\n\027STANDARD_ACTION_" + + "DECRYPT\020\001\022\034\n\030STANDARD_ACTION_TRANSMIT\020\002B" + + "\007\n\005value\"\201\002\n\016SubjectMapping\022\016\n\002id\030\001 \001(\tR" + + "\002id\0226\n\017attribute_value\030\002 \001(\0132\r.policy.Va" + + "lueR\016attributeValue\022O\n\025subject_condition" + + "_set\030\003 \001(\0132\033.policy.SubjectConditionSetR" + + "\023subjectConditionSet\022(\n\007actions\030\004 \003(\0132\016." + + "policy.ActionR\007actions\022,\n\010metadata\030d \001(\013" + + "2\020.common.MetadataR\010metadata\"\306\001\n\tConditi" + + "on\0224\n\026subject_external_field\030\001 \001(\tR\024subj" + + "ectExternalField\022K\n\010operator\030\002 \001(\0162\".pol" + + "icy.SubjectMappingOperatorEnumB\013\272H\010\202\001\002\020\001" + + "\310\001\001R\010operator\0226\n\027subject_external_values" + + "\030\003 \003(\tR\025subjectExternalValues\"\247\001\n\016Condit" + + "ionGroup\022;\n\nconditions\030\001 \003(\0132\021.policy.Co" + + "nditionB\010\272H\005\222\001\002\010\001R\nconditions\022X\n\020boolean" + + "_operator\030\002 \001(\0162 .policy.ConditionBoolea" + + "nTypeEnumB\013\272H\010\202\001\002\020\001\310\001\001R\017booleanOperator\"" + + "Y\n\nSubjectSet\022K\n\020condition_groups\030\001 \003(\0132" + + "\026.policy.ConditionGroupB\010\272H\005\222\001\002\010\001R\017condi" + + "tionGroups\"\224\001\n\023SubjectConditionSet\022\016\n\002id" + + "\030\001 \001(\tR\002id\022?\n\014subject_sets\030\003 \003(\0132\022.polic" + + "y.SubjectSetB\010\272H\005\222\001\002\010\001R\013subjectSets\022,\n\010m" + + "etadata\030d \001(\0132\020.common.MetadataR\010metadat" + + "a\"o\n\017SubjectProperty\022-\n\016external_field\030\001" + + " \001(\tB\006\272H\003\310\001\001R\rexternalField\022-\n\016external_" + + "value\030\002 \001(\tB\006\272H\003\310\001\001R\rexternalValue\"\245\001\n\017R" + + "esourceMapping\022\016\n\002id\030\001 \001(\tR\002id\022,\n\010metada" + + "ta\030\002 \001(\0132\020.common.MetadataR\010metadata\022>\n\017" + + "attribute_value\030\003 \001(\0132\r.policy.ValueB\006\272H" + + "\003\310\001\001R\016attributeValue\022\024\n\005terms\030\004 \003(\tR\005ter" + + "ms*\263\001\n\025AttributeRuleTypeEnum\022(\n$ATTRIBUT" + + "E_RULE_TYPE_ENUM_UNSPECIFIED\020\000\022#\n\037ATTRIB" + + "UTE_RULE_TYPE_ENUM_ALL_OF\020\001\022#\n\037ATTRIBUTE" + + "_RULE_TYPE_ENUM_ANY_OF\020\002\022&\n\"ATTRIBUTE_RU" + + "LE_TYPE_ENUM_HIERARCHY\020\003*\233\001\n\032SubjectMapp" + + "ingOperatorEnum\022-\n)SUBJECT_MAPPING_OPERA" + + "TOR_ENUM_UNSPECIFIED\020\000\022$\n SUBJECT_MAPPIN" + + "G_OPERATOR_ENUM_IN\020\001\022(\n$SUBJECT_MAPPING_" + + "OPERATOR_ENUM_NOT_IN\020\002*\220\001\n\030ConditionBool" + + "eanTypeEnum\022+\n\'CONDITION_BOOLEAN_TYPE_EN" + + "UM_UNSPECIFIED\020\000\022#\n\037CONDITION_BOOLEAN_TY" + + "PE_ENUM_AND\020\001\022\"\n\036CONDITION_BOOLEAN_TYPE_" + + "ENUM_OR\020\002B\222\001\n\032io.opentdf.platform.policy" + + "B\014ObjectsProtoP\001Z.github.com/opentdf/pla" + + "tform/protocol/go/policy\242\002\003PXX\252\002\006Policy\312" + + "\002\006Policy\342\002\022Policy\\GPBMetadata\352\002\006Policyb\006" + + "proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom(descriptorData, diff --git a/sdkjava/src/main/java/io/opentdf/platform/policy/Value.java b/sdkjava/src/main/java/io/opentdf/platform/policy/Value.java index edf1ed26fd..752bb06495 100644 --- a/sdkjava/src/main/java/io/opentdf/platform/policy/Value.java +++ b/sdkjava/src/main/java/io/opentdf/platform/policy/Value.java @@ -19,8 +19,7 @@ private Value(com.google.protobuf.GeneratedMessageV3.Builder builder) { private Value() { id_ = ""; value_ = ""; - members_ = - com.google.protobuf.LazyStringArrayList.emptyList(); + members_ = java.util.Collections.emptyList(); grants_ = java.util.Collections.emptyList(); fqn_ = ""; subjectMappings_ = java.util.Collections.emptyList(); @@ -161,18 +160,28 @@ public java.lang.String getValue() { public static final int MEMBERS_FIELD_NUMBER = 4; @SuppressWarnings("serial") - private com.google.protobuf.LazyStringArrayList members_ = - com.google.protobuf.LazyStringArrayList.emptyList(); + private java.util.List members_; /** *
    * list of attribute values that this value is related to (attribute group)
    * 
* - * repeated string members = 4 [json_name = "members"]; - * @return A list containing the members. + * repeated .policy.Value members = 4 [json_name = "members"]; */ - public com.google.protobuf.ProtocolStringList - getMembersList() { + @java.lang.Override + public java.util.List getMembersList() { + return members_; + } + /** + *
+   * list of attribute values that this value is related to (attribute group)
+   * 
+ * + * repeated .policy.Value members = 4 [json_name = "members"]; + */ + @java.lang.Override + public java.util.List + getMembersOrBuilderList() { return members_; } /** @@ -180,9 +189,9 @@ public java.lang.String getValue() { * list of attribute values that this value is related to (attribute group) * * - * repeated string members = 4 [json_name = "members"]; - * @return The count of members. + * repeated .policy.Value members = 4 [json_name = "members"]; */ + @java.lang.Override public int getMembersCount() { return members_.size(); } @@ -191,11 +200,10 @@ public int getMembersCount() { * list of attribute values that this value is related to (attribute group) * * - * repeated string members = 4 [json_name = "members"]; - * @param index The index of the element to return. - * @return The members at the given index. + * repeated .policy.Value members = 4 [json_name = "members"]; */ - public java.lang.String getMembers(int index) { + @java.lang.Override + public io.opentdf.platform.policy.Value getMembers(int index) { return members_.get(index); } /** @@ -203,13 +211,12 @@ public java.lang.String getMembers(int index) { * list of attribute values that this value is related to (attribute group) * * - * repeated string members = 4 [json_name = "members"]; - * @param index The index of the value to return. - * @return The bytes of the members at the given index. + * repeated .policy.Value members = 4 [json_name = "members"]; */ - public com.google.protobuf.ByteString - getMembersBytes(int index) { - return members_.getByteString(index); + @java.lang.Override + public io.opentdf.platform.policy.ValueOrBuilder getMembersOrBuilder( + int index) { + return members_.get(index); } public static final int GRANTS_FIELD_NUMBER = 5; @@ -473,7 +480,7 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) com.google.protobuf.GeneratedMessageV3.writeString(output, 3, value_); } for (int i = 0; i < members_.size(); i++) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 4, members_.getRaw(i)); + output.writeMessage(4, members_.get(i)); } for (int i = 0; i < grants_.size(); i++) { output.writeMessage(5, grants_.get(i)); @@ -509,13 +516,9 @@ public int getSerializedSize() { if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(value_)) { size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, value_); } - { - int dataSize = 0; - for (int i = 0; i < members_.size(); i++) { - dataSize += computeStringSizeNoTag(members_.getRaw(i)); - } - size += dataSize; - size += 1 * getMembersList().size(); + for (int i = 0; i < members_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, members_.get(i)); } for (int i = 0; i < grants_.size(); i++) { size += com.google.protobuf.CodedOutputStream @@ -750,6 +753,7 @@ private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessageV3 .alwaysUseFieldBuilders) { getAttributeFieldBuilder(); + getMembersFieldBuilder(); getGrantsFieldBuilder(); getActiveFieldBuilder(); getSubjectMappingsFieldBuilder(); @@ -767,8 +771,13 @@ public Builder clear() { attributeBuilder_ = null; } value_ = ""; - members_ = - com.google.protobuf.LazyStringArrayList.emptyList(); + if (membersBuilder_ == null) { + members_ = java.util.Collections.emptyList(); + } else { + members_ = null; + membersBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000008); if (grantsBuilder_ == null) { grants_ = java.util.Collections.emptyList(); } else { @@ -827,6 +836,15 @@ public io.opentdf.platform.policy.Value buildPartial() { } private void buildPartialRepeatedFields(io.opentdf.platform.policy.Value result) { + if (membersBuilder_ == null) { + if (((bitField0_ & 0x00000008) != 0)) { + members_ = java.util.Collections.unmodifiableList(members_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.members_ = members_; + } else { + result.members_ = membersBuilder_.build(); + } if (grantsBuilder_ == null) { if (((bitField0_ & 0x00000010) != 0)) { grants_ = java.util.Collections.unmodifiableList(grants_); @@ -862,10 +880,6 @@ private void buildPartial0(io.opentdf.platform.policy.Value result) { if (((from_bitField0_ & 0x00000004) != 0)) { result.value_ = value_; } - if (((from_bitField0_ & 0x00000008) != 0)) { - members_.makeImmutable(); - result.members_ = members_; - } if (((from_bitField0_ & 0x00000020) != 0)) { result.fqn_ = fqn_; } @@ -941,15 +955,31 @@ public Builder mergeFrom(io.opentdf.platform.policy.Value other) { bitField0_ |= 0x00000004; onChanged(); } - if (!other.members_.isEmpty()) { - if (members_.isEmpty()) { - members_ = other.members_; - bitField0_ |= 0x00000008; - } else { - ensureMembersIsMutable(); - members_.addAll(other.members_); + if (membersBuilder_ == null) { + if (!other.members_.isEmpty()) { + if (members_.isEmpty()) { + members_ = other.members_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensureMembersIsMutable(); + members_.addAll(other.members_); + } + onChanged(); + } + } else { + if (!other.members_.isEmpty()) { + if (membersBuilder_.isEmpty()) { + membersBuilder_.dispose(); + membersBuilder_ = null; + members_ = other.members_; + bitField0_ = (bitField0_ & ~0x00000008); + membersBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getMembersFieldBuilder() : null; + } else { + membersBuilder_.addAllMessages(other.members_); + } } - onChanged(); } if (grantsBuilder_ == null) { if (!other.grants_.isEmpty()) { @@ -1058,9 +1088,16 @@ public Builder mergeFrom( break; } // case 26 case 34: { - java.lang.String s = input.readStringRequireUtf8(); - ensureMembersIsMutable(); - members_.add(s); + io.opentdf.platform.policy.Value m = + input.readMessage( + io.opentdf.platform.policy.Value.parser(), + extensionRegistry); + if (membersBuilder_ == null) { + ensureMembersIsMutable(); + members_.add(m); + } else { + membersBuilder_.addMessage(m); + } break; } // case 34 case 42: { @@ -1410,80 +1447,97 @@ public Builder setValueBytes( return this; } - private com.google.protobuf.LazyStringArrayList members_ = - com.google.protobuf.LazyStringArrayList.emptyList(); + private java.util.List members_ = + java.util.Collections.emptyList(); private void ensureMembersIsMutable() { - if (!members_.isModifiable()) { - members_ = new com.google.protobuf.LazyStringArrayList(members_); - } - bitField0_ |= 0x00000008; + if (!((bitField0_ & 0x00000008) != 0)) { + members_ = new java.util.ArrayList(members_); + bitField0_ |= 0x00000008; + } } + + private com.google.protobuf.RepeatedFieldBuilderV3< + io.opentdf.platform.policy.Value, io.opentdf.platform.policy.Value.Builder, io.opentdf.platform.policy.ValueOrBuilder> membersBuilder_; + /** *
      * list of attribute values that this value is related to (attribute group)
      * 
* - * repeated string members = 4 [json_name = "members"]; - * @return A list containing the members. + * repeated .policy.Value members = 4 [json_name = "members"]; */ - public com.google.protobuf.ProtocolStringList - getMembersList() { - members_.makeImmutable(); - return members_; + public java.util.List getMembersList() { + if (membersBuilder_ == null) { + return java.util.Collections.unmodifiableList(members_); + } else { + return membersBuilder_.getMessageList(); + } } /** *
      * list of attribute values that this value is related to (attribute group)
      * 
* - * repeated string members = 4 [json_name = "members"]; - * @return The count of members. + * repeated .policy.Value members = 4 [json_name = "members"]; */ public int getMembersCount() { - return members_.size(); + if (membersBuilder_ == null) { + return members_.size(); + } else { + return membersBuilder_.getCount(); + } } /** *
      * list of attribute values that this value is related to (attribute group)
      * 
* - * repeated string members = 4 [json_name = "members"]; - * @param index The index of the element to return. - * @return The members at the given index. + * repeated .policy.Value members = 4 [json_name = "members"]; */ - public java.lang.String getMembers(int index) { - return members_.get(index); + public io.opentdf.platform.policy.Value getMembers(int index) { + if (membersBuilder_ == null) { + return members_.get(index); + } else { + return membersBuilder_.getMessage(index); + } } /** *
      * list of attribute values that this value is related to (attribute group)
      * 
* - * repeated string members = 4 [json_name = "members"]; - * @param index The index of the value to return. - * @return The bytes of the members at the given index. + * repeated .policy.Value members = 4 [json_name = "members"]; */ - public com.google.protobuf.ByteString - getMembersBytes(int index) { - return members_.getByteString(index); + public Builder setMembers( + int index, io.opentdf.platform.policy.Value value) { + if (membersBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureMembersIsMutable(); + members_.set(index, value); + onChanged(); + } else { + membersBuilder_.setMessage(index, value); + } + return this; } /** *
      * list of attribute values that this value is related to (attribute group)
      * 
* - * repeated string members = 4 [json_name = "members"]; - * @param index The index to set the value at. - * @param value The members to set. - * @return This builder for chaining. + * repeated .policy.Value members = 4 [json_name = "members"]; */ public Builder setMembers( - int index, java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureMembersIsMutable(); - members_.set(index, value); - bitField0_ |= 0x00000008; - onChanged(); + int index, io.opentdf.platform.policy.Value.Builder builderForValue) { + if (membersBuilder_ == null) { + ensureMembersIsMutable(); + members_.set(index, builderForValue.build()); + onChanged(); + } else { + membersBuilder_.setMessage(index, builderForValue.build()); + } return this; } /** @@ -1491,17 +1545,40 @@ public Builder setMembers( * list of attribute values that this value is related to (attribute group) * * - * repeated string members = 4 [json_name = "members"]; - * @param value The members to add. - * @return This builder for chaining. + * repeated .policy.Value members = 4 [json_name = "members"]; + */ + public Builder addMembers(io.opentdf.platform.policy.Value value) { + if (membersBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureMembersIsMutable(); + members_.add(value); + onChanged(); + } else { + membersBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * list of attribute values that this value is related to (attribute group)
+     * 
+ * + * repeated .policy.Value members = 4 [json_name = "members"]; */ public Builder addMembers( - java.lang.String value) { - if (value == null) { throw new NullPointerException(); } - ensureMembersIsMutable(); - members_.add(value); - bitField0_ |= 0x00000008; - onChanged(); + int index, io.opentdf.platform.policy.Value value) { + if (membersBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureMembersIsMutable(); + members_.add(index, value); + onChanged(); + } else { + membersBuilder_.addMessage(index, value); + } return this; } /** @@ -1509,17 +1586,54 @@ public Builder addMembers( * list of attribute values that this value is related to (attribute group) * * - * repeated string members = 4 [json_name = "members"]; - * @param values The members to add. - * @return This builder for chaining. + * repeated .policy.Value members = 4 [json_name = "members"]; + */ + public Builder addMembers( + io.opentdf.platform.policy.Value.Builder builderForValue) { + if (membersBuilder_ == null) { + ensureMembersIsMutable(); + members_.add(builderForValue.build()); + onChanged(); + } else { + membersBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * list of attribute values that this value is related to (attribute group)
+     * 
+ * + * repeated .policy.Value members = 4 [json_name = "members"]; + */ + public Builder addMembers( + int index, io.opentdf.platform.policy.Value.Builder builderForValue) { + if (membersBuilder_ == null) { + ensureMembersIsMutable(); + members_.add(index, builderForValue.build()); + onChanged(); + } else { + membersBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * list of attribute values that this value is related to (attribute group)
+     * 
+ * + * repeated .policy.Value members = 4 [json_name = "members"]; */ public Builder addAllMembers( - java.lang.Iterable values) { - ensureMembersIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, members_); - bitField0_ |= 0x00000008; - onChanged(); + java.lang.Iterable values) { + if (membersBuilder_ == null) { + ensureMembersIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, members_); + onChanged(); + } else { + membersBuilder_.addAllMessages(values); + } return this; } /** @@ -1527,14 +1641,16 @@ public Builder addAllMembers( * list of attribute values that this value is related to (attribute group) * * - * repeated string members = 4 [json_name = "members"]; - * @return This builder for chaining. + * repeated .policy.Value members = 4 [json_name = "members"]; */ public Builder clearMembers() { - members_ = - com.google.protobuf.LazyStringArrayList.emptyList(); - bitField0_ = (bitField0_ & ~0x00000008);; - onChanged(); + if (membersBuilder_ == null) { + members_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + } else { + membersBuilder_.clear(); + } return this; } /** @@ -1542,20 +1658,106 @@ public Builder clearMembers() { * list of attribute values that this value is related to (attribute group) * * - * repeated string members = 4 [json_name = "members"]; - * @param value The bytes of the members to add. - * @return This builder for chaining. + * repeated .policy.Value members = 4 [json_name = "members"]; */ - public Builder addMembersBytes( - com.google.protobuf.ByteString value) { - if (value == null) { throw new NullPointerException(); } - checkByteStringIsUtf8(value); - ensureMembersIsMutable(); - members_.add(value); - bitField0_ |= 0x00000008; - onChanged(); + public Builder removeMembers(int index) { + if (membersBuilder_ == null) { + ensureMembersIsMutable(); + members_.remove(index); + onChanged(); + } else { + membersBuilder_.remove(index); + } return this; } + /** + *
+     * list of attribute values that this value is related to (attribute group)
+     * 
+ * + * repeated .policy.Value members = 4 [json_name = "members"]; + */ + public io.opentdf.platform.policy.Value.Builder getMembersBuilder( + int index) { + return getMembersFieldBuilder().getBuilder(index); + } + /** + *
+     * list of attribute values that this value is related to (attribute group)
+     * 
+ * + * repeated .policy.Value members = 4 [json_name = "members"]; + */ + public io.opentdf.platform.policy.ValueOrBuilder getMembersOrBuilder( + int index) { + if (membersBuilder_ == null) { + return members_.get(index); } else { + return membersBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * list of attribute values that this value is related to (attribute group)
+     * 
+ * + * repeated .policy.Value members = 4 [json_name = "members"]; + */ + public java.util.List + getMembersOrBuilderList() { + if (membersBuilder_ != null) { + return membersBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(members_); + } + } + /** + *
+     * list of attribute values that this value is related to (attribute group)
+     * 
+ * + * repeated .policy.Value members = 4 [json_name = "members"]; + */ + public io.opentdf.platform.policy.Value.Builder addMembersBuilder() { + return getMembersFieldBuilder().addBuilder( + io.opentdf.platform.policy.Value.getDefaultInstance()); + } + /** + *
+     * list of attribute values that this value is related to (attribute group)
+     * 
+ * + * repeated .policy.Value members = 4 [json_name = "members"]; + */ + public io.opentdf.platform.policy.Value.Builder addMembersBuilder( + int index) { + return getMembersFieldBuilder().addBuilder( + index, io.opentdf.platform.policy.Value.getDefaultInstance()); + } + /** + *
+     * list of attribute values that this value is related to (attribute group)
+     * 
+ * + * repeated .policy.Value members = 4 [json_name = "members"]; + */ + public java.util.List + getMembersBuilderList() { + return getMembersFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilderV3< + io.opentdf.platform.policy.Value, io.opentdf.platform.policy.Value.Builder, io.opentdf.platform.policy.ValueOrBuilder> + getMembersFieldBuilder() { + if (membersBuilder_ == null) { + membersBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + io.opentdf.platform.policy.Value, io.opentdf.platform.policy.Value.Builder, io.opentdf.platform.policy.ValueOrBuilder>( + members_, + ((bitField0_ & 0x00000008) != 0), + getParentForChildren(), + isClean()); + members_ = null; + } + return membersBuilder_; + } private java.util.List grants_ = java.util.Collections.emptyList(); diff --git a/sdkjava/src/main/java/io/opentdf/platform/policy/ValueOrBuilder.java b/sdkjava/src/main/java/io/opentdf/platform/policy/ValueOrBuilder.java index b2983a0069..9f79c4e909 100644 --- a/sdkjava/src/main/java/io/opentdf/platform/policy/ValueOrBuilder.java +++ b/sdkjava/src/main/java/io/opentdf/platform/policy/ValueOrBuilder.java @@ -60,18 +60,24 @@ public interface ValueOrBuilder extends * list of attribute values that this value is related to (attribute group) * * - * repeated string members = 4 [json_name = "members"]; - * @return A list containing the members. + * repeated .policy.Value members = 4 [json_name = "members"]; */ - java.util.List + java.util.List getMembersList(); /** *
    * list of attribute values that this value is related to (attribute group)
    * 
* - * repeated string members = 4 [json_name = "members"]; - * @return The count of members. + * repeated .policy.Value members = 4 [json_name = "members"]; + */ + io.opentdf.platform.policy.Value getMembers(int index); + /** + *
+   * list of attribute values that this value is related to (attribute group)
+   * 
+ * + * repeated .policy.Value members = 4 [json_name = "members"]; */ int getMembersCount(); /** @@ -79,22 +85,19 @@ public interface ValueOrBuilder extends * list of attribute values that this value is related to (attribute group) * * - * repeated string members = 4 [json_name = "members"]; - * @param index The index of the element to return. - * @return The members at the given index. + * repeated .policy.Value members = 4 [json_name = "members"]; */ - java.lang.String getMembers(int index); + java.util.List + getMembersOrBuilderList(); /** *
    * list of attribute values that this value is related to (attribute group)
    * 
* - * repeated string members = 4 [json_name = "members"]; - * @param index The index of the value to return. - * @return The bytes of the members at the given index. + * repeated .policy.Value members = 4 [json_name = "members"]; */ - com.google.protobuf.ByteString - getMembersBytes(int index); + io.opentdf.platform.policy.ValueOrBuilder getMembersOrBuilder( + int index); /** *
diff --git a/services/policy/db/attribute_values.go b/services/policy/db/attribute_values.go
index 843cf24a14..267e848b67 100644
--- a/services/policy/db/attribute_values.go
+++ b/services/policy/db/attribute_values.go
@@ -3,6 +3,7 @@ package db
 import (
 	"context"
 	"database/sql"
+	"fmt"
 	"log/slog"
 
 	sq "github.com/Masterminds/squirrel"
@@ -32,26 +33,33 @@ func attributeValueHydrateItem(row pgx.Row, opts attributeValueSelectOptions) (*
 		id           string
 		value        string
 		active       bool
-		members      []string
+		membersJson  []byte
 		metadataJson []byte
 		attributeId  string
 		fqn          sql.NullString
+		members      []*policy.Value
 	)
-
 	fields := []interface{}{
 		&id,
 		&value,
 		&active,
-		&members,
+		&membersJson,
 		&metadataJson,
 		&attributeId,
 	}
+
 	if opts.withFqn {
 		fields = append(fields, &fqn)
 	}
-
 	if err := row.Scan(fields...); err != nil {
 		return nil, db.WrapIfKnownInvalidQueryErr(err)
+	} else {
+		if membersJson != nil {
+			members, err = attributesValuesProtojson(membersJson)
+			if err != nil {
+				return nil, err
+			}
+		}
 	}
 
 	m := &common.Metadata{}
@@ -67,7 +75,9 @@ func attributeValueHydrateItem(row pgx.Row, opts attributeValueSelectOptions) (*
 		Active:   &wrapperspb.BoolValue{Value: active},
 		Members:  members,
 		Metadata: m,
-		// TODO: get & hydrate full attribute
+		Attribute: &policy.Attribute{
+			Id: attributeId,
+		},
 		Fqn: fqn.String,
 	}
 	return v, nil
@@ -89,10 +99,37 @@ func attributeValueHydrateItems(rows pgx.Rows, opts attributeValueSelectOptions)
 /// CRUD
 ///
 
+func addMemberSql(value_id string, member_id string) (string, []interface{}, error) {
+	t := Tables.ValueMembers
+	return db.NewStatementBuilder().
+		Insert(t.Name()).
+		Columns(
+			"value_id",
+			"member_id",
+		).
+		Values(
+			value_id,
+			member_id,
+		).
+		Suffix("RETURNING id").
+		ToSql()
+}
+
+func removeMemberSql(value_id string, member_id string) (string, []interface{}, error) {
+	t := Tables.ValueMembers
+	return db.NewStatementBuilder().
+		Delete(t.Name()).
+		Where(sq.Eq{
+			t.Field("value_id"):  value_id,
+			t.Field("member_id"): member_id,
+		}).
+		Suffix("RETURNING id").
+		ToSql()
+}
+
 func createAttributeValueSql(
 	attribute_id string,
 	value string,
-	members []string,
 	metadata []byte,
 ) (string, []interface{}, error) {
 	t := Tables.AttributeValues
@@ -101,13 +138,11 @@ func createAttributeValueSql(
 		Columns(
 			"attribute_definition_id",
 			"value",
-			"members",
 			"metadata",
 		).
 		Values(
 			attribute_id,
 			value,
-			members,
 			metadata,
 		).
 		Suffix("RETURNING id").
@@ -123,7 +158,6 @@ func (c PolicyDbClient) CreateAttributeValue(ctx context.Context, attributeId st
 	sql, args, err := createAttributeValueSql(
 		attributeId,
 		v.Value,
-		v.Members,
 		metadataJson,
 	)
 	if err != nil {
@@ -137,6 +171,27 @@ func (c PolicyDbClient) CreateAttributeValue(ctx context.Context, attributeId st
 		return nil, db.WrapIfKnownInvalidQueryErr(err)
 	}
 
+	var members []*policy.Value
+
+	// Add members
+	for _, member := range v.Members {
+		var vm_id string
+		sql, args, err := addMemberSql(id, member)
+		if err != nil {
+			return nil, err
+		}
+		if r, err := c.QueryRow(ctx, sql, args, err); err != nil {
+			return nil, err
+		} else if err := r.Scan(&vm_id); err != nil {
+			return nil, db.WrapIfKnownInvalidQueryErr(err)
+		}
+		attr, err := c.GetAttributeValue(ctx, member)
+		if err != nil {
+			return nil, err
+		}
+		members = append(members, attr)
+	}
+
 	// Update FQN
 	c.upsertAttrFqn(ctx, attrFqnUpsertOptions{valueId: id})
 
@@ -144,7 +199,7 @@ func (c PolicyDbClient) CreateAttributeValue(ctx context.Context, attributeId st
 		Id:        id,
 		Attribute: &policy.Attribute{Id: attributeId},
 		Value:     v.Value,
-		Members:   v.Members,
+		Members:   members,
 		Metadata:  metadata,
 		Active:    &wrapperspb.BoolValue{Value: true},
 	}
@@ -153,34 +208,60 @@ func (c PolicyDbClient) CreateAttributeValue(ctx context.Context, attributeId st
 
 func getAttributeValueSql(id string, opts attributeValueSelectOptions) (string, []interface{}, error) {
 	t := Tables.AttributeValues
+	fqnT := Tables.AttrFqn
+	members := "COALESCE(JSON_AGG(JSON_BUILD_OBJECT(" +
+		"'id', vmv.id, " +
+		"'value', vmv.value, " +
+		"'active', vmv.active, " +
+		"'members', vmv.members || ARRAY[]::UUID[], " +
+		"'metadata', vmv.metadata, " +
+		"'attribute', JSON_BUILD_OBJECT(" +
+		"'id', vmv.attribute_definition_id )" // TODO: get the rest of the attribute here from the JOIN?
+	if opts.withFqn {
+		members += ", 'fqn', " + "fqn1.fqn"
+	}
+	members += ")) FILTER (WHERE vmv.id IS NOT NULL ), '[]') AS members"
 	fields := []string{
-		t.Field("id"),
-		t.Field("value"),
-		t.Field("active"),
-		t.Field("members"),
-		t.Field("metadata"),
-		t.Field("attribute_definition_id"),
+		"av.id",
+		"av.value",
+		"av.active",
+		members,
+		"av.metadata",
+		"av.attribute_definition_id",
 	}
 	if opts.withFqn {
-		fields = append(fields, Tables.AttrFqn.Field("fqn"))
+		fields = append(fields, "MAX(fqn2.fqn) AS fqn")
 	}
 
 	sb := db.NewStatementBuilder().
 		Select(fields...).
-		From(t.Name())
+		From(t.Name() + " av")
+
+	// join members
+	sb = sb.LeftJoin(Tables.ValueMembers.Name() + " vm ON av.id = vm.value_id")
+
+	// join attribute values
+	sb = sb.LeftJoin(t.Name() + " vmv ON vm.member_id = vmv.id")
 
 	if opts.withFqn {
-		fqnT := Tables.AttrFqn
-		sb = sb.LeftJoin(fqnT.Name() + " ON " + fqnT.Field("value_id") + " = " + t.Field("id"))
+		sb = sb.LeftJoin(fqnT.Name() + " AS fqn1 ON " + "fqn1.value_id" + " = " + "vmv.id")
+		sb = sb.LeftJoin(fqnT.Name() + " AS fqn2 ON " + "fqn2.value_id" + " = " + "av.id")
 	}
 
-	return sb.Where(sq.Eq{t.Field("id"): id}).
+	return sb.Where(sq.Eq{
+		"av.id": id,
+	}).
+		GroupBy(
+			"av.id",
+			// fqnT.Field("fqn"),
+		).
 		ToSql()
 }
 
 func (c PolicyDbClient) GetAttributeValue(ctx context.Context, id string) (*policy.Value, error) {
 	opts := attributeValueSelectOptions{withFqn: true}
 	sql, args, err := getAttributeValueSql(id, opts)
+	fmt.Println("\nsql: ", sql)
 	row, err := c.QueryRow(ctx, sql, args, err)
 	if err != nil {
 		slog.Error("error getting attribute value", slog.String("id", id), slog.String("sql", sql), slog.String("error", err.Error()))
@@ -197,34 +278,55 @@ func (c PolicyDbClient) GetAttributeValue(ctx context.Context, id string) (*poli
 
 func listAttributeValuesSql(attribute_id string, opts attributeValueSelectOptions) (string, []interface{}, error) {
 	t := Tables.AttributeValues
+	members := "COALESCE(JSON_AGG(JSON_BUILD_OBJECT(" +
+		"'id', vmv.id, " +
+		"'value', vmv.value, " +
+		"'active', vmv.active, " +
+		"'members', vmv.members || ARRAY[]::UUID[], " +
+		"'metadata', vmv.metadata, " +
+		"'attribute', JSON_BUILD_OBJECT(" +
+		"'id', vmv.attribute_definition_id )"
+	if opts.withFqn {
+		members += ", 'fqn', " + "fqn1.fqn"
+	}
+	members += ")) FILTER (WHERE vmv.id IS NOT NULL ), '[]') AS members"
 	fields := []string{
-		t.Field("id"),
-		t.Field("value"),
-		t.Field("active"),
-		t.Field("members"),
-		t.Field("metadata"),
-		t.Field("attribute_definition_id"),
+		"av.id",
+		"av.value",
+		"av.active",
+		members,
+		"av.metadata",
+		"av.attribute_definition_id",
 	}
 	if opts.withFqn {
-		fields = append(fields, "fqn")
+		fields = append(fields, "MAX(fqn2.fqn) AS fqn")
 	}
 
 	sb := db.NewStatementBuilder().
 		Select(fields...)
 
+	// join members
+	sb = sb.LeftJoin(Tables.ValueMembers.Name() + " vm ON av.id = vm.value_id")
+
+	// join attribute values
+	sb = sb.LeftJoin(t.Name() + " vmv ON vm.member_id = vmv.id")
+
 	if opts.withFqn {
 		fqnT := Tables.AttrFqn
-		sb = sb.LeftJoin(fqnT.Name() + " ON " + fqnT.Field("value_id") + " = " + t.Field("id"))
+		sb = sb.LeftJoin(fqnT.Name() + " AS fqn1 ON " + "fqn1.value_id" + " = " + "vmv.id")
+		sb = sb.LeftJoin(fqnT.Name() + " AS fqn2 ON " + "fqn2.value_id" + " = " + "av.id")
 	}
 
+	sb = sb.GroupBy("av.id")
+
 	where := sq.Eq{}
 	if opts.state != "" && opts.state != StateAny {
-		where[t.Field("active")] = opts.state == StateActive
+		where["av.active"] = opts.state == StateActive
 	}
-	where[t.Field("attribute_definition_id")] = attribute_id
+	where["av.attribute_definition_id"] = attribute_id
 
 	return sb.
-		From(t.Name()).
+		From(t.Name() + " av").
 		Where(where).
 		ToSql()
 }
@@ -243,27 +345,48 @@ func (c PolicyDbClient) ListAttributeValues(ctx context.Context, attribute_id st
 
 func listAllAttributeValuesSql(opts attributeValueSelectOptions) (string, []interface{}, error) {
 	t := Tables.AttributeValues
+	members := "COALESCE(JSON_AGG(JSON_BUILD_OBJECT(" +
+		"'id', vmv.id, " +
+		"'value', vmv.value, " +
+		"'active', vmv.active, " +
+		"'members', vmv.members || ARRAY[]::UUID[], " +
+		"'metadata', vmv.metadata, " +
+		"'attribute', JSON_BUILD_OBJECT(" +
+		"'id', vmv.attribute_definition_id )"
+	if opts.withFqn {
+		members += ", 'fqn', " + "fqn1.fqn"
+	}
+	members += ")) FILTER (WHERE vmv.id IS NOT NULL ), '[]') AS members"
 	fields := []string{
-		t.Field("id"),
-		t.Field("value"),
-		t.Field("active"),
-		t.Field("members"),
-		t.Field("metadata"),
-		t.Field("attribute_definition_id"),
+		"av.id",
+		"av.value",
+		"av.active",
+		members,
+		"av.metadata",
+		"av.attribute_definition_id",
 	}
 	if opts.withFqn {
-		fields = append(fields, "fqn")
+		fields = append(fields, "MAX(fqn2.fqn) AS fqn")
 	}
 	sb := db.NewStatementBuilder().
 		Select(fields...)
 
+	// join members
+	sb = sb.LeftJoin(Tables.ValueMembers.Name() + " vm ON av.id = vm.value_id")
+
+	// join attribute values
+	sb = sb.LeftJoin(t.Name() + " vmv ON vm.member_id = vmv.id")
+
 	if opts.withFqn {
 		fqnT := Tables.AttrFqn
-		sb = sb.LeftJoin(fqnT.Name() + " ON " + fqnT.Field("value_id") + " = " + t.Field("id"))
+		sb = sb.LeftJoin(fqnT.Name() + " AS fqn1 ON " + "fqn1.value_id" + " = " + "vmv.id")
+		sb = sb.LeftJoin(fqnT.Name() + " AS fqn2 ON " + "fqn2.value_id" + " = " + "av.id")
 	}
 
+	sb = sb.GroupBy("av.id")
+
 	return sb.
-		From(t.Name()).
+		From(t.Name() + " av").
 		ToSql()
 }
 
@@ -280,7 +403,6 @@ func (c PolicyDbClient) ListAllAttributeValues(ctx context.Context, state string
 
 func updateAttributeValueSql(
 	id string,
-	members []string,
 	metadata []byte,
 ) (string, []interface{}, error) {
 	t := Tables.AttributeValues
@@ -290,10 +412,6 @@ func updateAttributeValueSql(
 		sb = sb.Set("metadata", metadata)
 	}
 
-	if members != nil {
-		sb = sb.Set("members", members)
-	}
-
 	return sb.Where(sq.Eq{t.Field("id"): id}).ToSql()
 }
 
@@ -311,7 +429,6 @@ func (c PolicyDbClient) UpdateAttributeValue(ctx context.Context, r *attributes.
 
 	sql, args, err := updateAttributeValueSql(
 		r.Id,
-		r.Members,
 		metadataJson,
 	)
 	if db.IsQueryBuilderSetClauseError(err) {
@@ -323,9 +440,60 @@ func (c PolicyDbClient) UpdateAttributeValue(ctx context.Context, r *attributes.
 		return nil, err
 	}
 
+	prev, err := c.GetAttributeValue(ctx, r.Id)
+	if err != nil {
+		return nil, err
+	}
+
 	if err := c.Exec(ctx, sql, args); err != nil {
 		return nil, err
 	}
+	prevMembersSet := map[string]bool{}
+
+	for _, member := range prev.Members {
+		prevMembersSet[member.Id] = true
+	}
+
+	membersSet := map[string]bool{}
+	for _, member := range r.Members {
+		membersSet[member] = true
+	}
+
+	toRemove := map[string]bool{}
+	toAdd := map[string]bool{}
+
+	for member := range prevMembersSet {
+		if _, ok := membersSet[member]; !ok {
+			toRemove[member] = true
+		}
+	}
+
+	for member := range membersSet {
+		if _, ok := prevMembersSet[member]; !ok {
+			toAdd[member] = true
+		}
+	}
+
+	// Remove members
+	for member := range toRemove {
+		sql, args, err := removeMemberSql(r.Id, member)
+		if err != nil {
+			return nil, err
+		}
+		if err := c.Exec(ctx, sql, args); err != nil {
+			return nil, err
+		}
+	}
+
+	for member := range toAdd {
+		sql, args, err := addMemberSql(r.Id, member)
+		if err != nil {
+			return nil, err
+		}
+		if err := c.Exec(ctx, sql, args); err != nil {
+			return nil, err
+		}
+	}
 
 	// Update FQN
 	c.upsertAttrFqn(ctx, attrFqnUpsertOptions{valueId: r.Id})
diff --git a/services/policy/db/attributes.go b/services/policy/db/attributes.go
index 9e744b5750..620b81da16 100644
--- a/services/policy/db/attributes.go
+++ b/services/policy/db/attributes.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"database/sql"
 	"encoding/json"
+	"fmt"
 	"log/slog"
 	"strings"
 
@@ -34,16 +35,19 @@ func attributesValuesProtojson(valuesJson []byte) ([]*policy.Value, error) {
 		raw    []json.RawMessage
 		values []*policy.Value
 	)
+
 	if err := json.Unmarshal(valuesJson, &raw); err != nil {
 		return nil, err
 	}
 
 	for _, r := range raw {
-		value := policy.Value{}
-		if err := protojson.Unmarshal(r, &value); err != nil {
+		value := &policy.Value{}
+		err := protojson.Unmarshal(r, value)
+		if err != nil {
+			fmt.Println("error unmarshaling a value: ", err, string(r))
 			return nil, err
 		}
-		values = append(values, &value)
+		values = append(values, value)
 	}
 	return values, nil
 }
@@ -82,10 +86,10 @@ func attributesSelect(opts attributesSelectOptions) sq.SelectBuilder {
 	if opts.withAttributeValues || opts.withOneValueByFqn != "" {
 		valueSelect := "JSON_AGG(" +
 			"JSON_BUILD_OBJECT(" +
-			"'id', " + avt.Field("id") + ", " +
-			"'value', " + avt.Field("value") + "," +
-			"'members', " + avt.Field("members") + "," +
-			"'active', " + avt.Field("active")
+			"'id', avt.id," +
+			"'value', avt.value," +
+			"'members', avt.members," +
+			"'active', avt.active"
 
 		// include the subject mapping / subject condition set for each value
 		if opts.withOneValueByFqn != "" {
@@ -123,7 +127,13 @@ func attributesSelect(opts attributesSelectOptions) sq.SelectBuilder {
 		LeftJoin(nt.Name() + " ON " + nt.Field("id") + " = " + t.Field("namespace_id"))
 
 	if opts.withAttributeValues {
-		sb = sb.LeftJoin(avt.Name() + " ON " + avt.Field("attribute_definition_id") + " = " + t.Field("id"))
+		sb = sb.LeftJoin("(SELECT av.id, av.value, av.active, COALESCE(JSON_AGG(JSON_BUILD_OBJECT(" +
+			"'id', vmv.id, " +
+			"'value', vmv.value, " +
+			"'active', vmv.active, " +
+			"'members', vmv.members || ARRAY[]::UUID[], " +
+			"'attribute', JSON_BUILD_OBJECT(" +
+			"'id', vmv.attribute_definition_id ))) FILTER (WHERE vmv.id IS NOT NULL ), '[]') AS members, av.attribute_definition_id FROM " + avt.Name() + " av LEFT JOIN " + Tables.ValueMembers.Name() + " vm ON av.id = vm.value_id LEFT JOIN " + avt.Name() + " vmv ON vm.member_id = vmv.id GROUP BY av.id) avt ON avt.attribute_definition_id = " + t.Field("id"))
 	}
 	if opts.withKeyAccessGrants {
 		sb = sb.LeftJoin(Tables.AttributeKeyAccessGrants.Name() + " ON " + Tables.AttributeKeyAccessGrants.WithoutSchema().Name() + ".attribute_definition_id = " + t.Field("id")).
@@ -154,11 +164,10 @@ func attributesSelect(opts attributesSelectOptions) sq.SelectBuilder {
 				"INNER JOIN " + fqnt.Name() + " AS inner_fqns ON " + avt.Field("id") + " = inner_fqns.value_id " +
 				"WHERE inner_fqns.fqn = '" + opts.withOneValueByFqn + "' " +
 				"GROUP BY " + avt.Field("id") + ", inner_fqns.fqn " +
-				") AS val_sm_fqn_join ON " + avt.Field("id") + " = val_sm_fqn_join.av_id " +
-				"AND " + avt.Field("id") + " = " + fqnt.Field("value_id"),
+				") AS val_sm_fqn_join ON " + "avt.id" + " = val_sm_fqn_join.av_id " +
+				"AND " + "avt.id" + " = " + fqnt.Field("value_id"),
 			)
 	}
-
 	g := []string{t.Field("id"), nt.Field("name")}
 
 	if opts.withFqn {
@@ -209,7 +218,6 @@ func attributesHydrateItem(row pgx.Row, opts attributesSelectOptions) (*policy.A
 			return nil, err
 		}
 	}
-
 	var v []*policy.Value
 	if valuesJson != nil {
 		v, err = attributesValuesProtojson(valuesJson)
@@ -328,7 +336,8 @@ func getAttributeSql(id string, opts attributesSelectOptions) (string, []interfa
 
 func (c PolicyDbClient) GetAttribute(ctx context.Context, id string) (*policy.Attribute, error) {
 	opts := attributesSelectOptions{
-		withFqn: true,
+		withFqn:             true,
+		withAttributeValues: true,
 	}
 	sql, args, err := getAttributeSql(id, opts)
 	row, err := c.QueryRow(ctx, sql, args, err)
diff --git a/services/policy/db/policy.go b/services/policy/db/policy.go
index 9c22c2353d..b56440b8ae 100644
--- a/services/policy/db/policy.go
+++ b/services/policy/db/policy.go
@@ -18,6 +18,7 @@ type PolicyDbClient struct {
 var (
 	TableAttributes                    = "attribute_definitions"
 	TableAttributeValues               = "attribute_values"
+	TableValueMembers                  = "attribute_value_members"
 	TableNamespaces                    = "attribute_namespaces"
 	TableAttrFqn                       = "attribute_fqns"
 	TableAttributeKeyAccessGrants      = "attribute_definition_key_access_grants"
@@ -30,6 +31,7 @@ var (
 var Tables struct {
 	Attributes                    db.Table
 	AttributeValues               db.Table
+	ValueMembers                  db.Table
 	Namespaces                    db.Table
 	AttrFqn                       db.Table
 	AttributeKeyAccessGrants      db.Table
@@ -42,6 +44,7 @@ var Tables struct {
 func NewClient(c db.Client) *PolicyDbClient {
 	Tables.Attributes = db.NewTable(TableAttributes)
 	Tables.AttributeValues = db.NewTable(TableAttributeValues)
+	Tables.ValueMembers = db.NewTable(TableValueMembers)
 	Tables.Namespaces = db.NewTable(TableNamespaces)
 	Tables.AttrFqn = db.NewTable(TableAttrFqn)
 	Tables.AttributeKeyAccessGrants = db.NewTable(TableAttributeKeyAccessGrants)
diff --git a/services/policy/db/resource_mapping.go b/services/policy/db/resource_mapping.go
index 3f3bff4e62..2bfe853e9d 100644
--- a/services/policy/db/resource_mapping.go
+++ b/services/policy/db/resource_mapping.go
@@ -54,9 +54,11 @@ func resourceMappingHydrateItem(row pgx.Row) (*policy.ResourceMapping, error) {
 		}
 	}
 
-	err = protojson.Unmarshal(attributeValueJSON, attributeValue)
-	if err != nil {
-		return nil, err
+	if attributeValueJSON != nil {
+		if err := protojson.Unmarshal(attributeValueJSON, attributeValue); err != nil {
+			slog.Error("failed to unmarshal attribute value", slog.String("error", err.Error()), slog.String("attribute value JSON", string(attributeValueJSON)))
+			return nil, err
+		}
 	}
 
 	return &policy.ResourceMapping{
@@ -70,19 +72,27 @@ func resourceMappingHydrateItem(row pgx.Row) (*policy.ResourceMapping, error) {
 func resourceMappingSelect() sq.SelectBuilder {
 	t := Tables.ResourceMappings
 	at := Tables.AttributeValues
+	members := "COALESCE(JSON_AGG(JSON_BUILD_OBJECT(" +
+		"'id', vmv.id, " +
+		"'value', vmv.value, " +
+		"'active', vmv.active, " +
+		"'members', vmv.members || ARRAY[]::UUID[] " +
+		")) FILTER (WHERE vmv.id IS NOT NULL ), '[]')"
 	return db.NewStatementBuilder().Select(
 		t.Field("id"),
 		t.Field("metadata"),
 		t.Field("terms"),
 		"JSON_BUILD_OBJECT("+
-			"'id', "+at.Field("id")+", "+
-			"'value', "+at.Field("value")+","+
-			"'members', "+at.Field("members")+
-			")"+
-			" AS attribute_value",
+			"'id', av.id,"+
+			"'value', av.value,"+
+			"'members', "+members+
+			") AS attribute_value",
 	).
-		LeftJoin(at.Name()+" ON "+at.Field("id")+" = "+t.Field("attribute_value_id")).
-		GroupBy(t.Field("id"), at.Field("id"))
+		LeftJoin(at.Name() + " av ON " + t.Field("attribute_value_id") + " = " + "av.id").
+		LeftJoin(Tables.ValueMembers.Name() + " vm ON av.id = vm.value_id").
+		LeftJoin(at.Name() + " vmv ON vm.member_id = vmv.id").
+		GroupBy("av.id").
+		GroupBy(t.Field("id"))
 }
 
 /*
diff --git a/services/policy/db/subject_mappings.go b/services/policy/db/subject_mappings.go
index d8054956fa..3270df4724 100644
--- a/services/policy/db/subject_mappings.go
+++ b/services/policy/db/subject_mappings.go
@@ -146,7 +146,12 @@ func subjectMappingSelect() sq.SelectBuilder {
 	t := Tables.SubjectMappings
 	avT := Tables.AttributeValues
 	scsT := Tables.SubjectConditionSet
-
+	members := "COALESCE(JSON_AGG(JSON_BUILD_OBJECT(" +
+		"'id', vmv.id, " +
+		"'value', vmv.value, " +
+		"'active', vmv.active, " +
+		"'members', vmv.members || ARRAY[]::UUID[] " +
+		")) FILTER (WHERE vmv.id IS NOT NULL ), '[]')"
 	return db.NewStatementBuilder().Select(
 		t.Field("id"),
 		t.Field("actions"),
@@ -157,15 +162,17 @@ func subjectMappingSelect() sq.SelectBuilder {
 			"'subject_sets', "+scsT.Field("condition")+
 			") AS subject_condition_set",
 		"JSON_BUILD_OBJECT("+
-			"'id', "+avT.Field("id")+", "+
-			"'value', "+avT.Field("value")+", "+
-			"'members', "+avT.Field("members")+", "+
-			"'active'", avT.Field("active")+
+			"'id', av.id,"+
+			"'value', av.value,"+
+			"'members', "+members+","+
+			"'active', av.active"+
 			") AS attribute_value",
 	).
-		LeftJoin(avT.Name() + " ON " + t.Field("attribute_value_id") + " = " + avT.Field("id")).
+		LeftJoin(avT.Name() + " av ON " + t.Field("attribute_value_id") + " = " + "av.id").
+		LeftJoin(Tables.ValueMembers.Name() + " vm ON av.id = vm.value_id").
+		LeftJoin(avT.Name() + " vmv ON vm.member_id = vmv.id").
+		GroupBy("av.id").
 		GroupBy(t.Field("id")).
-		GroupBy(avT.Field("id")).
 		LeftJoin(scsT.Name() + " ON " + scsT.Field("id") + " = " + t.Field("subject_condition_set_id")).
 		GroupBy(scsT.Field("id"))
 }
diff --git a/services/policy/objects.proto b/services/policy/objects.proto
index f21393bd67..33bd99c628 100644
--- a/services/policy/objects.proto
+++ b/services/policy/objects.proto
@@ -67,7 +67,7 @@ message Value {
   string value = 3;
 
   // list of attribute values that this value is related to (attribute group)
-  repeated string members = 4;
+  repeated Value members = 4;
 
   // list of key access servers
   repeated kasregistry.KeyAccessServer grants = 5;