diff --git a/api/kessel/relations/v1beta1/check.pb.go b/api/kessel/relations/v1beta1/check.pb.go index 0c0e94fe..bcd52f3e 100644 --- a/api/kessel/relations/v1beta1/check.pb.go +++ b/api/kessel/relations/v1beta1/check.pb.go @@ -72,11 +72,61 @@ func (CheckResponse_Allowed) EnumDescriptor() ([]byte, []int) { return file_kessel_relations_v1beta1_check_proto_rawDescGZIP(), []int{1, 0} } +type CheckForUpdateResponse_Allowed int32 + +const ( + CheckForUpdateResponse_ALLOWED_UNSPECIFIED CheckForUpdateResponse_Allowed = 0 + CheckForUpdateResponse_ALLOWED_TRUE CheckForUpdateResponse_Allowed = 1 + CheckForUpdateResponse_ALLOWED_FALSE CheckForUpdateResponse_Allowed = 2 // e.g. ALLOWED_CONDITIONAL = 3; +) + +// Enum value maps for CheckForUpdateResponse_Allowed. +var ( + CheckForUpdateResponse_Allowed_name = map[int32]string{ + 0: "ALLOWED_UNSPECIFIED", + 1: "ALLOWED_TRUE", + 2: "ALLOWED_FALSE", + } + CheckForUpdateResponse_Allowed_value = map[string]int32{ + "ALLOWED_UNSPECIFIED": 0, + "ALLOWED_TRUE": 1, + "ALLOWED_FALSE": 2, + } +) + +func (x CheckForUpdateResponse_Allowed) Enum() *CheckForUpdateResponse_Allowed { + p := new(CheckForUpdateResponse_Allowed) + *p = x + return p +} + +func (x CheckForUpdateResponse_Allowed) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CheckForUpdateResponse_Allowed) Descriptor() protoreflect.EnumDescriptor { + return file_kessel_relations_v1beta1_check_proto_enumTypes[1].Descriptor() +} + +func (CheckForUpdateResponse_Allowed) Type() protoreflect.EnumType { + return &file_kessel_relations_v1beta1_check_proto_enumTypes[1] +} + +func (x CheckForUpdateResponse_Allowed) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CheckForUpdateResponse_Allowed.Descriptor instead. +func (CheckForUpdateResponse_Allowed) EnumDescriptor() ([]byte, []int) { + return file_kessel_relations_v1beta1_check_proto_rawDescGZIP(), []int{3, 0} +} + type CheckRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Resource *ObjectReference `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` Relation string `protobuf:"bytes,2,opt,name=relation,proto3" json:"relation,omitempty"` Subject *SubjectReference `protobuf:"bytes,3,opt,name=subject,proto3" json:"subject,omitempty"` + Zookie *Zookie `protobuf:"bytes,4,opt,name=zookie,proto3" json:"zookie,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -132,9 +182,17 @@ func (x *CheckRequest) GetSubject() *SubjectReference { return nil } +func (x *CheckRequest) GetZookie() *Zookie { + if x != nil { + return x.Zookie + } + return nil +} + type CheckResponse struct { state protoimpl.MessageState `protogen:"open.v1"` Allowed CheckResponse_Allowed `protobuf:"varint,1,opt,name=allowed,proto3,enum=kessel.relations.v1beta1.CheckResponse_Allowed" json:"allowed,omitempty"` + CheckedAt *Zookie `protobuf:"bytes,2,opt,name=checked_at,json=checkedAt,proto3" json:"checked_at,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -176,6 +234,125 @@ func (x *CheckResponse) GetAllowed() CheckResponse_Allowed { return CheckResponse_ALLOWED_UNSPECIFIED } +func (x *CheckResponse) GetCheckedAt() *Zookie { + if x != nil { + return x.CheckedAt + } + return nil +} + +type CheckForUpdateRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Resource *ObjectReference `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` + Relation string `protobuf:"bytes,2,opt,name=relation,proto3" json:"relation,omitempty"` + Subject *SubjectReference `protobuf:"bytes,3,opt,name=subject,proto3" json:"subject,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CheckForUpdateRequest) Reset() { + *x = CheckForUpdateRequest{} + mi := &file_kessel_relations_v1beta1_check_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CheckForUpdateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckForUpdateRequest) ProtoMessage() {} + +func (x *CheckForUpdateRequest) ProtoReflect() protoreflect.Message { + mi := &file_kessel_relations_v1beta1_check_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckForUpdateRequest.ProtoReflect.Descriptor instead. +func (*CheckForUpdateRequest) Descriptor() ([]byte, []int) { + return file_kessel_relations_v1beta1_check_proto_rawDescGZIP(), []int{2} +} + +func (x *CheckForUpdateRequest) GetResource() *ObjectReference { + if x != nil { + return x.Resource + } + return nil +} + +func (x *CheckForUpdateRequest) GetRelation() string { + if x != nil { + return x.Relation + } + return "" +} + +func (x *CheckForUpdateRequest) GetSubject() *SubjectReference { + if x != nil { + return x.Subject + } + return nil +} + +type CheckForUpdateResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Allowed CheckForUpdateResponse_Allowed `protobuf:"varint,1,opt,name=allowed,proto3,enum=kessel.relations.v1beta1.CheckForUpdateResponse_Allowed" json:"allowed,omitempty"` + CheckedAt *Zookie `protobuf:"bytes,2,opt,name=checked_at,json=checkedAt,proto3" json:"checked_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CheckForUpdateResponse) Reset() { + *x = CheckForUpdateResponse{} + mi := &file_kessel_relations_v1beta1_check_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CheckForUpdateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckForUpdateResponse) ProtoMessage() {} + +func (x *CheckForUpdateResponse) ProtoReflect() protoreflect.Message { + mi := &file_kessel_relations_v1beta1_check_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckForUpdateResponse.ProtoReflect.Descriptor instead. +func (*CheckForUpdateResponse) Descriptor() ([]byte, []int) { + return file_kessel_relations_v1beta1_check_proto_rawDescGZIP(), []int{3} +} + +func (x *CheckForUpdateResponse) GetAllowed() CheckForUpdateResponse_Allowed { + if x != nil { + return x.Allowed + } + return CheckForUpdateResponse_ALLOWED_UNSPECIFIED +} + +func (x *CheckForUpdateResponse) GetCheckedAt() *Zookie { + if x != nil { + return x.CheckedAt + } + return nil +} + var File_kessel_relations_v1beta1_check_proto protoreflect.FileDescriptor var file_kessel_relations_v1beta1_check_proto_rawDesc = string([]byte{ @@ -189,7 +366,7 @@ var file_kessel_relations_v1beta1_check_proto_rawDesc = string([]byte{ 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x62, 0x75, 0x66, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0xd0, 0x01, 0x0a, 0x0c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x74, 0x6f, 0x22, 0x8a, 0x02, 0x0a, 0x0c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4d, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, @@ -202,17 +379,54 @@ var file_kessel_relations_v1beta1_check_proto_rawDesc = string([]byte{ 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x07, 0x73, 0x75, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0xa3, 0x01, 0x0a, 0x0d, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, - 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, - 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x52, 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, - 0x65, 0x64, 0x22, 0x47, 0x0a, 0x07, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x12, 0x17, 0x0a, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x7a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, + 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x5a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x52, 0x06, 0x7a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x22, + 0xe4, 0x01, 0x0a, 0x0d, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x49, 0x0a, 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, + 0x77, 0x65, 0x64, 0x52, 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x12, 0x3f, 0x0a, 0x0a, + 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x5a, 0x6f, 0x6f, 0x6b, + 0x69, 0x65, 0x52, 0x09, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x22, 0x47, 0x0a, + 0x07, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x4c, 0x4c, 0x4f, + 0x57, 0x45, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x45, 0x44, 0x5f, 0x54, 0x52, 0x55, + 0x45, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x45, 0x44, 0x5f, 0x46, + 0x41, 0x4c, 0x53, 0x45, 0x10, 0x02, 0x22, 0xd9, 0x01, 0x0a, 0x15, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x46, 0x6f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x4d, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x06, 0xba, + 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, + 0x23, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4c, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, + 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x22, 0xf6, 0x01, 0x0a, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x46, 0x6f, 0x72, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, + 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x38, + 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x46, + 0x6f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x52, 0x07, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, + 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, + 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x5a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x52, 0x09, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, + 0x41, 0x74, 0x22, 0x47, 0x0a, 0x07, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x45, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x45, 0x44, 0x5f, 0x54, 0x52, 0x55, 0x45, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x4c, 0x4c, 0x4f, - 0x57, 0x45, 0x44, 0x5f, 0x46, 0x41, 0x4c, 0x53, 0x45, 0x10, 0x02, 0x32, 0x89, 0x01, 0x0a, 0x12, + 0x57, 0x45, 0x44, 0x5f, 0x46, 0x41, 0x4c, 0x53, 0x45, 0x10, 0x02, 0x32, 0xa3, 0x02, 0x0a, 0x12, 0x4b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x73, 0x0a, 0x05, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x26, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, @@ -221,15 +435,24 @@ var file_kessel_relations_v1beta1_check_proto_rawDesc = string([]byte{ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x72, 0x0a, 0x28, 0x6f, 0x72, 0x67, 0x2e, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2d, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, - 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2d, 0x61, 0x70, 0x69, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x31, 0x2f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x97, 0x01, 0x0a, 0x0e, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x46, 0x6f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x2f, 0x2e, 0x6b, 0x65, 0x73, + 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x46, 0x6f, 0x72, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x6b, 0x65, + 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x46, 0x6f, 0x72, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x3a, 0x01, 0x2a, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x66, 0x6f, 0x72, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x42, 0x72, 0x0a, 0x28, 0x6f, 0x72, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x50, 0x01, 0x5a, + 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x2d, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2d, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6b, 0x65, 0x73, + 0x73, 0x65, 0x6c, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( @@ -244,26 +467,38 @@ func file_kessel_relations_v1beta1_check_proto_rawDescGZIP() []byte { return file_kessel_relations_v1beta1_check_proto_rawDescData } -var file_kessel_relations_v1beta1_check_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_kessel_relations_v1beta1_check_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_kessel_relations_v1beta1_check_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_kessel_relations_v1beta1_check_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_kessel_relations_v1beta1_check_proto_goTypes = []any{ - (CheckResponse_Allowed)(0), // 0: kessel.relations.v1beta1.CheckResponse.Allowed - (*CheckRequest)(nil), // 1: kessel.relations.v1beta1.CheckRequest - (*CheckResponse)(nil), // 2: kessel.relations.v1beta1.CheckResponse - (*ObjectReference)(nil), // 3: kessel.relations.v1beta1.ObjectReference - (*SubjectReference)(nil), // 4: kessel.relations.v1beta1.SubjectReference + (CheckResponse_Allowed)(0), // 0: kessel.relations.v1beta1.CheckResponse.Allowed + (CheckForUpdateResponse_Allowed)(0), // 1: kessel.relations.v1beta1.CheckForUpdateResponse.Allowed + (*CheckRequest)(nil), // 2: kessel.relations.v1beta1.CheckRequest + (*CheckResponse)(nil), // 3: kessel.relations.v1beta1.CheckResponse + (*CheckForUpdateRequest)(nil), // 4: kessel.relations.v1beta1.CheckForUpdateRequest + (*CheckForUpdateResponse)(nil), // 5: kessel.relations.v1beta1.CheckForUpdateResponse + (*ObjectReference)(nil), // 6: kessel.relations.v1beta1.ObjectReference + (*SubjectReference)(nil), // 7: kessel.relations.v1beta1.SubjectReference + (*Zookie)(nil), // 8: kessel.relations.v1beta1.Zookie } var file_kessel_relations_v1beta1_check_proto_depIdxs = []int32{ - 3, // 0: kessel.relations.v1beta1.CheckRequest.resource:type_name -> kessel.relations.v1beta1.ObjectReference - 4, // 1: kessel.relations.v1beta1.CheckRequest.subject:type_name -> kessel.relations.v1beta1.SubjectReference - 0, // 2: kessel.relations.v1beta1.CheckResponse.allowed:type_name -> kessel.relations.v1beta1.CheckResponse.Allowed - 1, // 3: kessel.relations.v1beta1.KesselCheckService.Check:input_type -> kessel.relations.v1beta1.CheckRequest - 2, // 4: kessel.relations.v1beta1.KesselCheckService.Check:output_type -> kessel.relations.v1beta1.CheckResponse - 4, // [4:5] is the sub-list for method output_type - 3, // [3:4] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 6, // 0: kessel.relations.v1beta1.CheckRequest.resource:type_name -> kessel.relations.v1beta1.ObjectReference + 7, // 1: kessel.relations.v1beta1.CheckRequest.subject:type_name -> kessel.relations.v1beta1.SubjectReference + 8, // 2: kessel.relations.v1beta1.CheckRequest.zookie:type_name -> kessel.relations.v1beta1.Zookie + 0, // 3: kessel.relations.v1beta1.CheckResponse.allowed:type_name -> kessel.relations.v1beta1.CheckResponse.Allowed + 8, // 4: kessel.relations.v1beta1.CheckResponse.checked_at:type_name -> kessel.relations.v1beta1.Zookie + 6, // 5: kessel.relations.v1beta1.CheckForUpdateRequest.resource:type_name -> kessel.relations.v1beta1.ObjectReference + 7, // 6: kessel.relations.v1beta1.CheckForUpdateRequest.subject:type_name -> kessel.relations.v1beta1.SubjectReference + 1, // 7: kessel.relations.v1beta1.CheckForUpdateResponse.allowed:type_name -> kessel.relations.v1beta1.CheckForUpdateResponse.Allowed + 8, // 8: kessel.relations.v1beta1.CheckForUpdateResponse.checked_at:type_name -> kessel.relations.v1beta1.Zookie + 2, // 9: kessel.relations.v1beta1.KesselCheckService.Check:input_type -> kessel.relations.v1beta1.CheckRequest + 4, // 10: kessel.relations.v1beta1.KesselCheckService.CheckForUpdate:input_type -> kessel.relations.v1beta1.CheckForUpdateRequest + 3, // 11: kessel.relations.v1beta1.KesselCheckService.Check:output_type -> kessel.relations.v1beta1.CheckResponse + 5, // 12: kessel.relations.v1beta1.KesselCheckService.CheckForUpdate:output_type -> kessel.relations.v1beta1.CheckForUpdateResponse + 11, // [11:13] is the sub-list for method output_type + 9, // [9:11] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_kessel_relations_v1beta1_check_proto_init() } @@ -277,8 +512,8 @@ func file_kessel_relations_v1beta1_check_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_kessel_relations_v1beta1_check_proto_rawDesc), len(file_kessel_relations_v1beta1_check_proto_rawDesc)), - NumEnums: 1, - NumMessages: 2, + NumEnums: 2, + NumMessages: 4, NumExtensions: 0, NumServices: 1, }, diff --git a/api/kessel/relations/v1beta1/check.proto b/api/kessel/relations/v1beta1/check.proto index 721cd62b..b5caaf9b 100644 --- a/api/kessel/relations/v1beta1/check.proto +++ b/api/kessel/relations/v1beta1/check.proto @@ -20,12 +20,20 @@ service KesselCheckService { body: "*" }; }; + + rpc CheckForUpdate (CheckForUpdateRequest) returns (CheckForUpdateResponse) { + option (google.api.http) = { + post: "/v1beta1/checkforupdate" + body: "*" + }; + }; } message CheckRequest { ObjectReference resource = 1 [(buf.validate.field).required = true]; string relation = 2 [(buf.validate.field).string.min_len = 1]; SubjectReference subject = 3 [(buf.validate.field).required = true]; + Zookie zookie = 4; } message CheckResponse { @@ -36,5 +44,22 @@ message CheckResponse { // e.g. ALLOWED_CONDITIONAL = 3; } Allowed allowed = 1; + Zookie checked_at = 2; +} + +message CheckForUpdateRequest { // fully consistent + ObjectReference resource = 1 [(buf.validate.field).required = true]; + string relation = 2 [(buf.validate.field).string.min_len = 1]; + SubjectReference subject = 3 [(buf.validate.field).required = true]; } +message CheckForUpdateResponse { + enum Allowed { + ALLOWED_UNSPECIFIED = 0; + ALLOWED_TRUE = 1; + ALLOWED_FALSE = 2; + // e.g. ALLOWED_CONDITIONAL = 3; + } + Allowed allowed = 1; + Zookie checked_at = 2; +} \ No newline at end of file diff --git a/api/kessel/relations/v1beta1/check_grpc.pb.go b/api/kessel/relations/v1beta1/check_grpc.pb.go index f65ab59c..55206c60 100644 --- a/api/kessel/relations/v1beta1/check_grpc.pb.go +++ b/api/kessel/relations/v1beta1/check_grpc.pb.go @@ -19,7 +19,8 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - KesselCheckService_Check_FullMethodName = "/kessel.relations.v1beta1.KesselCheckService/Check" + KesselCheckService_Check_FullMethodName = "/kessel.relations.v1beta1.KesselCheckService/Check" + KesselCheckService_CheckForUpdate_FullMethodName = "/kessel.relations.v1beta1.KesselCheckService/CheckForUpdate" ) // KesselCheckServiceClient is the client API for KesselCheckService service. @@ -29,6 +30,7 @@ type KesselCheckServiceClient interface { // Checks for the existence of a single Relationship // (a Relation between a Resource and a Subject or Subject Set). Check(ctx context.Context, in *CheckRequest, opts ...grpc.CallOption) (*CheckResponse, error) + CheckForUpdate(ctx context.Context, in *CheckForUpdateRequest, opts ...grpc.CallOption) (*CheckForUpdateResponse, error) } type kesselCheckServiceClient struct { @@ -49,6 +51,16 @@ func (c *kesselCheckServiceClient) Check(ctx context.Context, in *CheckRequest, return out, nil } +func (c *kesselCheckServiceClient) CheckForUpdate(ctx context.Context, in *CheckForUpdateRequest, opts ...grpc.CallOption) (*CheckForUpdateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CheckForUpdateResponse) + err := c.cc.Invoke(ctx, KesselCheckService_CheckForUpdate_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // KesselCheckServiceServer is the server API for KesselCheckService service. // All implementations must embed UnimplementedKesselCheckServiceServer // for forward compatibility. @@ -56,6 +68,7 @@ type KesselCheckServiceServer interface { // Checks for the existence of a single Relationship // (a Relation between a Resource and a Subject or Subject Set). Check(context.Context, *CheckRequest) (*CheckResponse, error) + CheckForUpdate(context.Context, *CheckForUpdateRequest) (*CheckForUpdateResponse, error) mustEmbedUnimplementedKesselCheckServiceServer() } @@ -69,6 +82,9 @@ type UnimplementedKesselCheckServiceServer struct{} func (UnimplementedKesselCheckServiceServer) Check(context.Context, *CheckRequest) (*CheckResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Check not implemented") } +func (UnimplementedKesselCheckServiceServer) CheckForUpdate(context.Context, *CheckForUpdateRequest) (*CheckForUpdateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CheckForUpdate not implemented") +} func (UnimplementedKesselCheckServiceServer) mustEmbedUnimplementedKesselCheckServiceServer() {} func (UnimplementedKesselCheckServiceServer) testEmbeddedByValue() {} @@ -108,6 +124,24 @@ func _KesselCheckService_Check_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _KesselCheckService_CheckForUpdate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CheckForUpdateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KesselCheckServiceServer).CheckForUpdate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: KesselCheckService_CheckForUpdate_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KesselCheckServiceServer).CheckForUpdate(ctx, req.(*CheckForUpdateRequest)) + } + return interceptor(ctx, in, info, handler) +} + // KesselCheckService_ServiceDesc is the grpc.ServiceDesc for KesselCheckService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -119,6 +153,10 @@ var KesselCheckService_ServiceDesc = grpc.ServiceDesc{ MethodName: "Check", Handler: _KesselCheckService_Check_Handler, }, + { + MethodName: "CheckForUpdate", + Handler: _KesselCheckService_CheckForUpdate_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "kessel/relations/v1beta1/check.proto", diff --git a/api/kessel/relations/v1beta1/check_http.pb.go b/api/kessel/relations/v1beta1/check_http.pb.go index 94c81fec..63886827 100644 --- a/api/kessel/relations/v1beta1/check_http.pb.go +++ b/api/kessel/relations/v1beta1/check_http.pb.go @@ -20,16 +20,19 @@ var _ = binding.EncodeURL const _ = http.SupportPackageIsVersion1 const OperationKesselCheckServiceCheck = "/kessel.relations.v1beta1.KesselCheckService/Check" +const OperationKesselCheckServiceCheckForUpdate = "/kessel.relations.v1beta1.KesselCheckService/CheckForUpdate" type KesselCheckServiceHTTPServer interface { // Check Checks for the existence of a single Relationship // (a Relation between a Resource and a Subject or Subject Set). Check(context.Context, *CheckRequest) (*CheckResponse, error) + CheckForUpdate(context.Context, *CheckForUpdateRequest) (*CheckForUpdateResponse, error) } func RegisterKesselCheckServiceHTTPServer(s *http.Server, srv KesselCheckServiceHTTPServer) { r := s.Route("/") r.POST("/v1beta1/check", _KesselCheckService_Check0_HTTP_Handler(srv)) + r.POST("/v1beta1/checkforupdate", _KesselCheckService_CheckForUpdate0_HTTP_Handler(srv)) } func _KesselCheckService_Check0_HTTP_Handler(srv KesselCheckServiceHTTPServer) func(ctx http.Context) error { @@ -54,8 +57,31 @@ func _KesselCheckService_Check0_HTTP_Handler(srv KesselCheckServiceHTTPServer) f } } +func _KesselCheckService_CheckForUpdate0_HTTP_Handler(srv KesselCheckServiceHTTPServer) func(ctx http.Context) error { + return func(ctx http.Context) error { + var in CheckForUpdateRequest + if err := ctx.Bind(&in); err != nil { + return err + } + if err := ctx.BindQuery(&in); err != nil { + return err + } + http.SetOperation(ctx, OperationKesselCheckServiceCheckForUpdate) + h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.CheckForUpdate(ctx, req.(*CheckForUpdateRequest)) + }) + out, err := h(ctx, &in) + if err != nil { + return err + } + reply := out.(*CheckForUpdateResponse) + return ctx.Result(200, reply) + } +} + type KesselCheckServiceHTTPClient interface { Check(ctx context.Context, req *CheckRequest, opts ...http.CallOption) (rsp *CheckResponse, err error) + CheckForUpdate(ctx context.Context, req *CheckForUpdateRequest, opts ...http.CallOption) (rsp *CheckForUpdateResponse, err error) } type KesselCheckServiceHTTPClientImpl struct { @@ -78,3 +104,16 @@ func (c *KesselCheckServiceHTTPClientImpl) Check(ctx context.Context, in *CheckR } return &out, nil } + +func (c *KesselCheckServiceHTTPClientImpl) CheckForUpdate(ctx context.Context, in *CheckForUpdateRequest, opts ...http.CallOption) (*CheckForUpdateResponse, error) { + var out CheckForUpdateResponse + pattern := "/v1beta1/checkforupdate" + path := binding.EncodeURL(pattern, in, false) + opts = append(opts, http.Operation(OperationKesselCheckServiceCheckForUpdate)) + opts = append(opts, http.PathTemplate(pattern)) + err := c.cc.Invoke(ctx, "POST", path, in, &out, opts...) + if err != nil { + return nil, err + } + return &out, nil +} diff --git a/api/kessel/relations/v1beta1/common.pb.go b/api/kessel/relations/v1beta1/common.pb.go index 80a2b217..b9ccb577 100644 --- a/api/kessel/relations/v1beta1/common.pb.go +++ b/api/kessel/relations/v1beta1/common.pb.go @@ -346,6 +346,51 @@ func (x *ObjectType) GetName() string { return "" } +// The Zookie is used to provide consistency between write and read requests. +type Zookie struct { + state protoimpl.MessageState `protogen:"open.v1"` + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Zookie) Reset() { + *x = Zookie{} + mi := &file_kessel_relations_v1beta1_common_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Zookie) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Zookie) ProtoMessage() {} + +func (x *Zookie) ProtoReflect() protoreflect.Message { + mi := &file_kessel_relations_v1beta1_common_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Zookie.ProtoReflect.Descriptor instead. +func (*Zookie) Descriptor() ([]byte, []int) { + return file_kessel_relations_v1beta1_common_proto_rawDescGZIP(), []int{6} +} + +func (x *Zookie) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + var File_kessel_relations_v1beta1_common_proto protoreflect.FileDescriptor var file_kessel_relations_v1beta1_common_proto_rawDesc = string([]byte{ @@ -401,15 +446,17 @@ var file_kessel_relations_v1beta1_common_proto_rawDesc = string([]byte{ 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x72, 0x0a, 0x28, 0x6f, 0x72, 0x67, 0x2e, 0x70, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2d, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2f, 0x72, - 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2d, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x27, 0x0a, 0x06, 0x5a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x12, + 0x1d, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, + 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x72, + 0x0a, 0x28, 0x6f, 0x72, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, 0x65, + 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x2d, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2d, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, + 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( @@ -424,7 +471,7 @@ func file_kessel_relations_v1beta1_common_proto_rawDescGZIP() []byte { return file_kessel_relations_v1beta1_common_proto_rawDescData } -var file_kessel_relations_v1beta1_common_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_kessel_relations_v1beta1_common_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_kessel_relations_v1beta1_common_proto_goTypes = []any{ (*Relationship)(nil), // 0: kessel.relations.v1beta1.Relationship (*SubjectReference)(nil), // 1: kessel.relations.v1beta1.SubjectReference @@ -432,6 +479,7 @@ var file_kessel_relations_v1beta1_common_proto_goTypes = []any{ (*ResponsePagination)(nil), // 3: kessel.relations.v1beta1.ResponsePagination (*ObjectReference)(nil), // 4: kessel.relations.v1beta1.ObjectReference (*ObjectType)(nil), // 5: kessel.relations.v1beta1.ObjectType + (*Zookie)(nil), // 6: kessel.relations.v1beta1.Zookie } var file_kessel_relations_v1beta1_common_proto_depIdxs = []int32{ 4, // 0: kessel.relations.v1beta1.Relationship.resource:type_name -> kessel.relations.v1beta1.ObjectReference @@ -458,7 +506,7 @@ func file_kessel_relations_v1beta1_common_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_kessel_relations_v1beta1_common_proto_rawDesc), len(file_kessel_relations_v1beta1_common_proto_rawDesc)), NumEnums: 0, - NumMessages: 6, + NumMessages: 7, NumExtensions: 0, NumServices: 0, }, diff --git a/api/kessel/relations/v1beta1/common.proto b/api/kessel/relations/v1beta1/common.proto index 189be9fb..d06bac96 100644 --- a/api/kessel/relations/v1beta1/common.proto +++ b/api/kessel/relations/v1beta1/common.proto @@ -49,3 +49,8 @@ message ObjectType { string namespace = 1 [(buf.validate.field).string.min_len = 1]; string name = 2 [(buf.validate.field).string.min_len = 1]; } + +// The Zookie is used to provide consistency between write and read requests. +message Zookie { + string token = 1 [(buf.validate.field).string.min_len = 1]; +} diff --git a/api/kessel/relations/v1beta1/lookup.pb.go b/api/kessel/relations/v1beta1/lookup.pb.go index c3b3b508..30befcf7 100644 --- a/api/kessel/relations/v1beta1/lookup.pb.go +++ b/api/kessel/relations/v1beta1/lookup.pb.go @@ -29,6 +29,7 @@ type LookupResourcesRequest struct { Relation string `protobuf:"bytes,2,opt,name=relation,proto3" json:"relation,omitempty"` Subject *SubjectReference `protobuf:"bytes,3,opt,name=subject,proto3" json:"subject,omitempty"` Pagination *RequestPagination `protobuf:"bytes,4,opt,name=pagination,proto3,oneof" json:"pagination,omitempty"` + Zookie *Zookie `protobuf:"bytes,5,opt,name=zookie,proto3,oneof" json:"zookie,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -91,10 +92,18 @@ func (x *LookupResourcesRequest) GetPagination() *RequestPagination { return nil } +func (x *LookupResourcesRequest) GetZookie() *Zookie { + if x != nil { + return x.Zookie + } + return nil +} + type LookupResourcesResponse struct { state protoimpl.MessageState `protogen:"open.v1"` Resource *ObjectReference `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` Pagination *ResponsePagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` + LookedUpAt *Zookie `protobuf:"bytes,3,opt,name=looked_up_at,json=lookedUpAt,proto3" json:"looked_up_at,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -143,6 +152,13 @@ func (x *LookupResourcesResponse) GetPagination() *ResponsePagination { return nil } +func (x *LookupResourcesResponse) GetLookedUpAt() *Zookie { + if x != nil { + return x.LookedUpAt + } + return nil +} + type LookupSubjectsRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Resource *ObjectReference `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` @@ -150,6 +166,7 @@ type LookupSubjectsRequest struct { SubjectType *ObjectType `protobuf:"bytes,3,opt,name=subject_type,json=subjectType,proto3" json:"subject_type,omitempty"` SubjectRelation *string `protobuf:"bytes,4,opt,name=subject_relation,json=subjectRelation,proto3,oneof" json:"subject_relation,omitempty"` Pagination *RequestPagination `protobuf:"bytes,5,opt,name=pagination,proto3,oneof" json:"pagination,omitempty"` + Zookie *Zookie `protobuf:"bytes,6,opt,name=zookie,proto3,oneof" json:"zookie,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -219,10 +236,18 @@ func (x *LookupSubjectsRequest) GetPagination() *RequestPagination { return nil } +func (x *LookupSubjectsRequest) GetZookie() *Zookie { + if x != nil { + return x.Zookie + } + return nil +} + type LookupSubjectsResponse struct { state protoimpl.MessageState `protogen:"open.v1"` Subject *SubjectReference `protobuf:"bytes,1,opt,name=subject,proto3" json:"subject,omitempty"` Pagination *ResponsePagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` + LookedUpAt *Zookie `protobuf:"bytes,3,opt,name=looked_up_at,json=lookedUpAt,proto3" json:"looked_up_at,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -271,6 +296,13 @@ func (x *LookupSubjectsResponse) GetPagination() *ResponsePagination { return nil } +func (x *LookupSubjectsResponse) GetLookedUpAt() *Zookie { + if x != nil { + return x.LookedUpAt + } + return nil +} + var File_kessel_relations_v1beta1_lookup_proto protoreflect.FileDescriptor var file_kessel_relations_v1beta1_lookup_proto_rawDesc = string([]byte{ @@ -284,7 +316,7 @@ var file_kessel_relations_v1beta1_lookup_proto_rawDesc = string([]byte{ 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x62, 0x75, 0x66, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0xbf, 0x02, 0x0a, 0x16, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, + 0x6f, 0x74, 0x6f, 0x22, 0x89, 0x03, 0x0a, 0x16, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, @@ -303,82 +335,100 @@ var file_kessel_relations_v1beta1_lookup_proto_rawDesc = string([]byte{ 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x70, 0x61, 0x67, 0x69, 0x6e, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xae, 0x01, 0x0a, 0x17, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x45, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x08, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, - 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6b, - 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, - 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x82, 0x03, 0x0a, 0x15, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, - 0x70, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x4d, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x06, 0xba, - 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, - 0x23, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4f, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6b, 0x65, 0x73, - 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, - 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2e, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, - 0x00, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x50, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6b, 0x65, 0x73, 0x73, - 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, - 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x01, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x73, 0x75, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, - 0x5f, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xac, 0x01, 0x0a, 0x16, - 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, + 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x06, 0x7a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, + 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2e, 0x5a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x48, 0x01, 0x52, 0x06, 0x7a, 0x6f, 0x6f, 0x6b, + 0x69, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x7a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x22, + 0xf2, 0x01, 0x0a, 0x17, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x08, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, + 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x42, 0x0a, 0x0c, 0x6c, 0x6f, 0x6f, 0x6b, 0x65, 0x64, 0x5f, 0x75, 0x70, 0x5f, 0x61, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, + 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2e, 0x5a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x52, 0x0a, 0x6c, 0x6f, 0x6f, 0x6b, 0x65, 0x64, + 0x55, 0x70, 0x41, 0x74, 0x22, 0xcc, 0x03, 0x0a, 0x15, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4d, + 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x06, 0xba, 0x48, 0x03, + 0xc8, 0x01, 0x01, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x23, 0x0a, + 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x4f, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, + 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x42, 0x06, + 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x2e, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, + 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x88, 0x01, 0x01, 0x12, 0x50, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x4c, 0x0a, 0x0a, - 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2c, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, - 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x32, 0xbf, 0x02, 0x0a, 0x13, 0x4b, - 0x65, 0x73, 0x73, 0x65, 0x6c, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x12, 0x90, 0x01, 0x0a, 0x0e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x75, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x2f, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, + 0x61, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x01, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x06, 0x7a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, - 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, - 0x12, 0x11, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x73, 0x75, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x73, 0x30, 0x01, 0x12, 0x94, 0x01, 0x0a, 0x0f, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x30, 0x2e, 0x6b, 0x65, 0x73, 0x73, - 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x6b, 0x65, - 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x30, 0x01, 0x42, 0x72, 0x0a, 0x28, - 0x6f, 0x72, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, 0x65, 0x73, 0x73, - 0x65, 0x6c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2d, 0x6b, - 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2d, - 0x61, 0x70, 0x69, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2f, 0x72, - 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x5a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x48, 0x02, 0x52, 0x06, 0x7a, 0x6f, 0x6f, 0x6b, 0x69, + 0x65, 0x88, 0x01, 0x01, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x70, 0x61, + 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x7a, 0x6f, 0x6f, + 0x6b, 0x69, 0x65, 0x22, 0xf0, 0x01, 0x0a, 0x16, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, + 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2a, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x07, 0x73, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x12, 0x4c, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, + 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x50, 0x61, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x0c, 0x6c, 0x6f, 0x6f, 0x6b, 0x65, 0x64, 0x5f, 0x75, 0x70, 0x5f, + 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, + 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x5a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x52, 0x0a, 0x6c, 0x6f, 0x6f, 0x6b, + 0x65, 0x64, 0x55, 0x70, 0x41, 0x74, 0x32, 0xbf, 0x02, 0x0a, 0x13, 0x4b, 0x65, 0x73, 0x73, 0x65, + 0x6c, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x90, + 0x01, 0x0a, 0x0e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x12, 0x2f, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x6f, 0x6f, + 0x6b, 0x75, 0x70, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x6f, + 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x30, + 0x01, 0x12, 0x94, 0x01, 0x0a, 0x0f, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x30, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, + 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, + 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x14, 0x12, 0x12, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x30, 0x01, 0x42, 0x72, 0x0a, 0x28, 0x6f, 0x72, 0x67, 0x2e, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2d, 0x6b, 0x65, 0x73, 0x73, 0x65, + 0x6c, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2d, 0x61, 0x70, 0x69, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, }) var ( @@ -402,29 +452,34 @@ var file_kessel_relations_v1beta1_lookup_proto_goTypes = []any{ (*ObjectType)(nil), // 4: kessel.relations.v1beta1.ObjectType (*SubjectReference)(nil), // 5: kessel.relations.v1beta1.SubjectReference (*RequestPagination)(nil), // 6: kessel.relations.v1beta1.RequestPagination - (*ObjectReference)(nil), // 7: kessel.relations.v1beta1.ObjectReference - (*ResponsePagination)(nil), // 8: kessel.relations.v1beta1.ResponsePagination + (*Zookie)(nil), // 7: kessel.relations.v1beta1.Zookie + (*ObjectReference)(nil), // 8: kessel.relations.v1beta1.ObjectReference + (*ResponsePagination)(nil), // 9: kessel.relations.v1beta1.ResponsePagination } var file_kessel_relations_v1beta1_lookup_proto_depIdxs = []int32{ 4, // 0: kessel.relations.v1beta1.LookupResourcesRequest.resource_type:type_name -> kessel.relations.v1beta1.ObjectType 5, // 1: kessel.relations.v1beta1.LookupResourcesRequest.subject:type_name -> kessel.relations.v1beta1.SubjectReference 6, // 2: kessel.relations.v1beta1.LookupResourcesRequest.pagination:type_name -> kessel.relations.v1beta1.RequestPagination - 7, // 3: kessel.relations.v1beta1.LookupResourcesResponse.resource:type_name -> kessel.relations.v1beta1.ObjectReference - 8, // 4: kessel.relations.v1beta1.LookupResourcesResponse.pagination:type_name -> kessel.relations.v1beta1.ResponsePagination - 7, // 5: kessel.relations.v1beta1.LookupSubjectsRequest.resource:type_name -> kessel.relations.v1beta1.ObjectReference - 4, // 6: kessel.relations.v1beta1.LookupSubjectsRequest.subject_type:type_name -> kessel.relations.v1beta1.ObjectType - 6, // 7: kessel.relations.v1beta1.LookupSubjectsRequest.pagination:type_name -> kessel.relations.v1beta1.RequestPagination - 5, // 8: kessel.relations.v1beta1.LookupSubjectsResponse.subject:type_name -> kessel.relations.v1beta1.SubjectReference - 8, // 9: kessel.relations.v1beta1.LookupSubjectsResponse.pagination:type_name -> kessel.relations.v1beta1.ResponsePagination - 2, // 10: kessel.relations.v1beta1.KesselLookupService.LookupSubjects:input_type -> kessel.relations.v1beta1.LookupSubjectsRequest - 0, // 11: kessel.relations.v1beta1.KesselLookupService.LookupResources:input_type -> kessel.relations.v1beta1.LookupResourcesRequest - 3, // 12: kessel.relations.v1beta1.KesselLookupService.LookupSubjects:output_type -> kessel.relations.v1beta1.LookupSubjectsResponse - 1, // 13: kessel.relations.v1beta1.KesselLookupService.LookupResources:output_type -> kessel.relations.v1beta1.LookupResourcesResponse - 12, // [12:14] is the sub-list for method output_type - 10, // [10:12] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 7, // 3: kessel.relations.v1beta1.LookupResourcesRequest.zookie:type_name -> kessel.relations.v1beta1.Zookie + 8, // 4: kessel.relations.v1beta1.LookupResourcesResponse.resource:type_name -> kessel.relations.v1beta1.ObjectReference + 9, // 5: kessel.relations.v1beta1.LookupResourcesResponse.pagination:type_name -> kessel.relations.v1beta1.ResponsePagination + 7, // 6: kessel.relations.v1beta1.LookupResourcesResponse.looked_up_at:type_name -> kessel.relations.v1beta1.Zookie + 8, // 7: kessel.relations.v1beta1.LookupSubjectsRequest.resource:type_name -> kessel.relations.v1beta1.ObjectReference + 4, // 8: kessel.relations.v1beta1.LookupSubjectsRequest.subject_type:type_name -> kessel.relations.v1beta1.ObjectType + 6, // 9: kessel.relations.v1beta1.LookupSubjectsRequest.pagination:type_name -> kessel.relations.v1beta1.RequestPagination + 7, // 10: kessel.relations.v1beta1.LookupSubjectsRequest.zookie:type_name -> kessel.relations.v1beta1.Zookie + 5, // 11: kessel.relations.v1beta1.LookupSubjectsResponse.subject:type_name -> kessel.relations.v1beta1.SubjectReference + 9, // 12: kessel.relations.v1beta1.LookupSubjectsResponse.pagination:type_name -> kessel.relations.v1beta1.ResponsePagination + 7, // 13: kessel.relations.v1beta1.LookupSubjectsResponse.looked_up_at:type_name -> kessel.relations.v1beta1.Zookie + 2, // 14: kessel.relations.v1beta1.KesselLookupService.LookupSubjects:input_type -> kessel.relations.v1beta1.LookupSubjectsRequest + 0, // 15: kessel.relations.v1beta1.KesselLookupService.LookupResources:input_type -> kessel.relations.v1beta1.LookupResourcesRequest + 3, // 16: kessel.relations.v1beta1.KesselLookupService.LookupSubjects:output_type -> kessel.relations.v1beta1.LookupSubjectsResponse + 1, // 17: kessel.relations.v1beta1.KesselLookupService.LookupResources:output_type -> kessel.relations.v1beta1.LookupResourcesResponse + 16, // [16:18] is the sub-list for method output_type + 14, // [14:16] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name } func init() { file_kessel_relations_v1beta1_lookup_proto_init() } diff --git a/api/kessel/relations/v1beta1/lookup.proto b/api/kessel/relations/v1beta1/lookup.proto index e0439c4e..7c523de9 100644 --- a/api/kessel/relations/v1beta1/lookup.proto +++ b/api/kessel/relations/v1beta1/lookup.proto @@ -29,11 +29,13 @@ message LookupResourcesRequest { string relation = 2 [(buf.validate.field).string.min_len = 1]; SubjectReference subject = 3 [(buf.validate.field).required = true]; optional RequestPagination pagination = 4; + optional Zookie zookie = 5; } message LookupResourcesResponse { ObjectReference resource = 1; ResponsePagination pagination = 2; + Zookie looked_up_at = 3; } message LookupSubjectsRequest { @@ -42,9 +44,11 @@ message LookupSubjectsRequest { ObjectType subject_type = 3 [(buf.validate.field).required = true]; optional string subject_relation = 4; optional RequestPagination pagination = 5; + optional Zookie zookie = 6; } message LookupSubjectsResponse { SubjectReference subject = 1; ResponsePagination pagination = 2; + Zookie looked_up_at = 3; } \ No newline at end of file diff --git a/api/kessel/relations/v1beta1/relation_tuples.pb.go b/api/kessel/relations/v1beta1/relation_tuples.pb.go index cef5eab2..46cbf337 100644 --- a/api/kessel/relations/v1beta1/relation_tuples.pb.go +++ b/api/kessel/relations/v1beta1/relation_tuples.pb.go @@ -168,6 +168,7 @@ func (x *CreateTuplesRequest) GetTuples() []*Relationship { type CreateTuplesResponse struct { state protoimpl.MessageState `protogen:"open.v1"` + CreatedAt *Zookie `protobuf:"bytes,1,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -202,10 +203,18 @@ func (*CreateTuplesResponse) Descriptor() ([]byte, []int) { return file_kessel_relations_v1beta1_relation_tuples_proto_rawDescGZIP(), []int{3} } +func (x *CreateTuplesResponse) GetCreatedAt() *Zookie { + if x != nil { + return x.CreatedAt + } + return nil +} + type ReadTuplesRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Filter *RelationTupleFilter `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` Pagination *RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3,oneof" json:"pagination,omitempty"` + Zookie *Zookie `protobuf:"bytes,3,opt,name=zookie,proto3,oneof" json:"zookie,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -254,10 +263,18 @@ func (x *ReadTuplesRequest) GetPagination() *RequestPagination { return nil } +func (x *ReadTuplesRequest) GetZookie() *Zookie { + if x != nil { + return x.Zookie + } + return nil +} + type ReadTuplesResponse struct { state protoimpl.MessageState `protogen:"open.v1"` Tuple *Relationship `protobuf:"bytes,1,opt,name=tuple,proto3" json:"tuple,omitempty"` Pagination *ResponsePagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` + ReadAt *Zookie `protobuf:"bytes,3,opt,name=read_at,json=readAt,proto3" json:"read_at,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -306,6 +323,13 @@ func (x *ReadTuplesResponse) GetPagination() *ResponsePagination { return nil } +func (x *ReadTuplesResponse) GetReadAt() *Zookie { + if x != nil { + return x.ReadAt + } + return nil +} + type DeleteTuplesRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Filter *RelationTupleFilter `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` @@ -352,6 +376,7 @@ func (x *DeleteTuplesRequest) GetFilter() *RelationTupleFilter { type DeleteTuplesResponse struct { state protoimpl.MessageState `protogen:"open.v1"` + DeletedAt *Zookie `protobuf:"bytes,1,opt,name=deleted_at,json=deletedAt,proto3" json:"deleted_at,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -386,6 +411,13 @@ func (*DeleteTuplesResponse) Descriptor() ([]byte, []int) { return file_kessel_relations_v1beta1_relation_tuples_proto_rawDescGZIP(), []int{7} } +func (x *DeleteTuplesResponse) GetDeletedAt() *Zookie { + if x != nil { + return x.DeletedAt + } + return nil +} + // RelationTupleFilter is used to filter tuples based on their resource, relation, and subject. // All fields are optional but capabilities may vary based on the chosen store and its indexes. // At least one field must be provided. @@ -564,121 +596,138 @@ var file_kessel_relations_v1beta1_relation_tuples_proto_rawDesc = string([]byte{ 0x26, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x68, 0x69, 0x70, 0x52, 0x06, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x22, - 0x16, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xc3, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x61, 0x64, + 0x57, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6b, 0x65, + 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x5a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x52, 0x09, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x8d, 0x02, 0x0a, 0x11, 0x52, 0x65, 0x61, + 0x64, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4d, + 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, + 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x06, 0xba, + 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x50, 0x0a, + 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2b, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, + 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, + 0x3d, 0x0a, 0x06, 0x7a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x5a, 0x6f, 0x6f, 0x6b, 0x69, + 0x65, 0x48, 0x01, 0x52, 0x06, 0x7a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0d, + 0x0a, 0x0b, 0x5f, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, + 0x07, 0x5f, 0x7a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x22, 0xdb, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x61, + 0x64, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x3c, 0x0a, 0x05, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, + 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x68, 0x69, 0x70, 0x52, 0x05, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x12, 0x4c, 0x0a, + 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2c, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x07, 0x72, + 0x65, 0x61, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6b, + 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x5a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x52, 0x06, + 0x72, 0x65, 0x61, 0x64, 0x41, 0x74, 0x22, 0x64, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4d, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x06, 0xba, 0x48, - 0x03, 0xc8, 0x01, 0x01, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x50, 0x0a, 0x0a, - 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2b, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, - 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0d, - 0x0a, 0x0b, 0x5f, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa0, 0x01, - 0x0a, 0x12, 0x52, 0x65, 0x61, 0x64, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, - 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x68, 0x69, 0x70, 0x52, 0x05, 0x74, 0x75, 0x70, - 0x6c, 0x65, 0x12, 0x4c, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, - 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x64, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4d, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, - 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x75, 0x70, 0x6c, 0x65, - 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x06, 0xba, 0x48, 0x03, 0xc8, 0x01, 0x01, 0x52, 0x06, - 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x16, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe8, - 0x02, 0x0a, 0x13, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x75, 0x70, 0x6c, 0x65, - 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x48, 0x00, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x88, 0x01, 0x01, 0x12, 0x28, 0x0a, 0x0d, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x48, 0x01, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x88, 0x01, 0x01, 0x12, 0x24, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x0a, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x72, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x08, - 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x53, 0x0a, 0x0e, 0x73, - 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, - 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x48, 0x04, 0x52, 0x0d, - 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x88, 0x01, 0x01, - 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x72, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x73, 0x75, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0xf1, 0x01, 0x0a, 0x0d, 0x53, 0x75, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x11, 0x73, - 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x88, 0x01, 0x01, 0x12, 0x26, 0x0a, - 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, - 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x09, 0x73, 0x75, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x72, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x08, 0x72, - 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x73, - 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, - 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x32, 0xd3, 0x04, - 0x0a, 0x12, 0x4b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, - 0x75, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, - 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, - 0x0f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x73, - 0x12, 0x82, 0x01, 0x0a, 0x0a, 0x52, 0x65, 0x61, 0x64, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x12, - 0x2b, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x54, - 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6b, + 0x03, 0xc8, 0x01, 0x01, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x57, 0x0a, 0x14, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0a, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, + 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, + 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x5a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0xe8, 0x02, 0x0a, 0x13, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x32, 0x0a, + 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x11, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x88, 0x01, + 0x01, 0x12, 0x28, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x24, 0x0a, 0x0b, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x02, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x88, 0x01, + 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, + 0x01, 0x01, 0x12, 0x53, 0x0a, 0x0e, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6b, 0x65, 0x73, + 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x46, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x48, 0x04, 0x52, 0x0d, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x10, + 0x0a, 0x0e, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x11, 0x0a, + 0x0f, 0x5f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x22, 0xf1, 0x01, 0x0a, 0x0d, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x12, 0x30, 0x0a, 0x11, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x88, 0x01, 0x01, 0x12, 0x26, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0b, 0x73, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, + 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x02, 0x52, 0x09, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x88, 0x01, 0x01, + 0x12, 0x1f, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x03, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, + 0x01, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x73, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x73, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x72, 0x65, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x32, 0xd3, 0x04, 0x0a, 0x12, 0x4b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x54, + 0x75, 0x70, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x0c, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x54, 0x75, 0x70, 0x6c, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x74, 0x75, 0x70, - 0x6c, 0x65, 0x73, 0x30, 0x01, 0x12, 0x86, 0x01, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, + 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x6b, 0x65, + 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x70, + 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2f, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x82, 0x01, 0x0a, 0x0a, 0x52, 0x65, 0x61, 0x64, + 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x2b, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, - 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x2a, 0x0f, 0x2f, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x12, 0xa2, - 0x01, 0x0a, 0x10, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x54, 0x75, 0x70, - 0x6c, 0x65, 0x73, 0x12, 0x31, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x49, - 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, - 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x75, 0x6c, 0x6b, 0x54, 0x75, 0x70, 0x6c, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x1f, 0x3a, 0x01, 0x2a, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, - 0x74, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x62, 0x75, 0x6c, 0x6b, 0x69, 0x6d, 0x70, 0x6f, 0x72, - 0x74, 0x28, 0x01, 0x42, 0x72, 0x0a, 0x28, 0x6f, 0x72, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x5f, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x50, - 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2d, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2f, 0x72, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2d, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6b, - 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, + 0x65, 0x61, 0x64, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2f, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x30, 0x01, 0x12, 0x86, 0x01, 0x0a, + 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x2d, 0x2e, + 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, + 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x6b, + 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x75, + 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x11, 0x2a, 0x0f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x74, + 0x75, 0x70, 0x6c, 0x65, 0x73, 0x12, 0xa2, 0x01, 0x0a, 0x10, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, + 0x42, 0x75, 0x6c, 0x6b, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x31, 0x2e, 0x6b, 0x65, 0x73, + 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x75, 0x6c, 0x6b, + 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, + 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x42, + 0x75, 0x6c, 0x6b, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a, 0x01, 0x2a, 0x22, 0x1a, 0x2f, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x62, 0x75, + 0x6c, 0x6b, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x28, 0x01, 0x42, 0x72, 0x0a, 0x28, 0x6f, 0x72, + 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2d, 0x6b, 0x65, 0x73, + 0x73, 0x65, 0x6c, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2d, 0x61, 0x70, + 0x69, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6b, 0x65, 0x73, 0x73, 0x65, 0x6c, 0x2f, 0x72, 0x65, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( @@ -706,31 +755,36 @@ var file_kessel_relations_v1beta1_relation_tuples_proto_goTypes = []any{ (*RelationTupleFilter)(nil), // 8: kessel.relations.v1beta1.RelationTupleFilter (*SubjectFilter)(nil), // 9: kessel.relations.v1beta1.SubjectFilter (*Relationship)(nil), // 10: kessel.relations.v1beta1.Relationship - (*RequestPagination)(nil), // 11: kessel.relations.v1beta1.RequestPagination - (*ResponsePagination)(nil), // 12: kessel.relations.v1beta1.ResponsePagination + (*Zookie)(nil), // 11: kessel.relations.v1beta1.Zookie + (*RequestPagination)(nil), // 12: kessel.relations.v1beta1.RequestPagination + (*ResponsePagination)(nil), // 13: kessel.relations.v1beta1.ResponsePagination } var file_kessel_relations_v1beta1_relation_tuples_proto_depIdxs = []int32{ 10, // 0: kessel.relations.v1beta1.ImportBulkTuplesRequest.tuples:type_name -> kessel.relations.v1beta1.Relationship 10, // 1: kessel.relations.v1beta1.CreateTuplesRequest.tuples:type_name -> kessel.relations.v1beta1.Relationship - 8, // 2: kessel.relations.v1beta1.ReadTuplesRequest.filter:type_name -> kessel.relations.v1beta1.RelationTupleFilter - 11, // 3: kessel.relations.v1beta1.ReadTuplesRequest.pagination:type_name -> kessel.relations.v1beta1.RequestPagination - 10, // 4: kessel.relations.v1beta1.ReadTuplesResponse.tuple:type_name -> kessel.relations.v1beta1.Relationship - 12, // 5: kessel.relations.v1beta1.ReadTuplesResponse.pagination:type_name -> kessel.relations.v1beta1.ResponsePagination - 8, // 6: kessel.relations.v1beta1.DeleteTuplesRequest.filter:type_name -> kessel.relations.v1beta1.RelationTupleFilter - 9, // 7: kessel.relations.v1beta1.RelationTupleFilter.subject_filter:type_name -> kessel.relations.v1beta1.SubjectFilter - 2, // 8: kessel.relations.v1beta1.KesselTupleService.CreateTuples:input_type -> kessel.relations.v1beta1.CreateTuplesRequest - 4, // 9: kessel.relations.v1beta1.KesselTupleService.ReadTuples:input_type -> kessel.relations.v1beta1.ReadTuplesRequest - 6, // 10: kessel.relations.v1beta1.KesselTupleService.DeleteTuples:input_type -> kessel.relations.v1beta1.DeleteTuplesRequest - 0, // 11: kessel.relations.v1beta1.KesselTupleService.ImportBulkTuples:input_type -> kessel.relations.v1beta1.ImportBulkTuplesRequest - 3, // 12: kessel.relations.v1beta1.KesselTupleService.CreateTuples:output_type -> kessel.relations.v1beta1.CreateTuplesResponse - 5, // 13: kessel.relations.v1beta1.KesselTupleService.ReadTuples:output_type -> kessel.relations.v1beta1.ReadTuplesResponse - 7, // 14: kessel.relations.v1beta1.KesselTupleService.DeleteTuples:output_type -> kessel.relations.v1beta1.DeleteTuplesResponse - 1, // 15: kessel.relations.v1beta1.KesselTupleService.ImportBulkTuples:output_type -> kessel.relations.v1beta1.ImportBulkTuplesResponse - 12, // [12:16] is the sub-list for method output_type - 8, // [8:12] is the sub-list for method input_type - 8, // [8:8] is the sub-list for extension type_name - 8, // [8:8] is the sub-list for extension extendee - 0, // [0:8] is the sub-list for field type_name + 11, // 2: kessel.relations.v1beta1.CreateTuplesResponse.created_at:type_name -> kessel.relations.v1beta1.Zookie + 8, // 3: kessel.relations.v1beta1.ReadTuplesRequest.filter:type_name -> kessel.relations.v1beta1.RelationTupleFilter + 12, // 4: kessel.relations.v1beta1.ReadTuplesRequest.pagination:type_name -> kessel.relations.v1beta1.RequestPagination + 11, // 5: kessel.relations.v1beta1.ReadTuplesRequest.zookie:type_name -> kessel.relations.v1beta1.Zookie + 10, // 6: kessel.relations.v1beta1.ReadTuplesResponse.tuple:type_name -> kessel.relations.v1beta1.Relationship + 13, // 7: kessel.relations.v1beta1.ReadTuplesResponse.pagination:type_name -> kessel.relations.v1beta1.ResponsePagination + 11, // 8: kessel.relations.v1beta1.ReadTuplesResponse.read_at:type_name -> kessel.relations.v1beta1.Zookie + 8, // 9: kessel.relations.v1beta1.DeleteTuplesRequest.filter:type_name -> kessel.relations.v1beta1.RelationTupleFilter + 11, // 10: kessel.relations.v1beta1.DeleteTuplesResponse.deleted_at:type_name -> kessel.relations.v1beta1.Zookie + 9, // 11: kessel.relations.v1beta1.RelationTupleFilter.subject_filter:type_name -> kessel.relations.v1beta1.SubjectFilter + 2, // 12: kessel.relations.v1beta1.KesselTupleService.CreateTuples:input_type -> kessel.relations.v1beta1.CreateTuplesRequest + 4, // 13: kessel.relations.v1beta1.KesselTupleService.ReadTuples:input_type -> kessel.relations.v1beta1.ReadTuplesRequest + 6, // 14: kessel.relations.v1beta1.KesselTupleService.DeleteTuples:input_type -> kessel.relations.v1beta1.DeleteTuplesRequest + 0, // 15: kessel.relations.v1beta1.KesselTupleService.ImportBulkTuples:input_type -> kessel.relations.v1beta1.ImportBulkTuplesRequest + 3, // 16: kessel.relations.v1beta1.KesselTupleService.CreateTuples:output_type -> kessel.relations.v1beta1.CreateTuplesResponse + 5, // 17: kessel.relations.v1beta1.KesselTupleService.ReadTuples:output_type -> kessel.relations.v1beta1.ReadTuplesResponse + 7, // 18: kessel.relations.v1beta1.KesselTupleService.DeleteTuples:output_type -> kessel.relations.v1beta1.DeleteTuplesResponse + 1, // 19: kessel.relations.v1beta1.KesselTupleService.ImportBulkTuples:output_type -> kessel.relations.v1beta1.ImportBulkTuplesResponse + 16, // [16:20] is the sub-list for method output_type + 12, // [12:16] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name } func init() { file_kessel_relations_v1beta1_relation_tuples_proto_init() } diff --git a/api/kessel/relations/v1beta1/relation_tuples.proto b/api/kessel/relations/v1beta1/relation_tuples.proto index 1bdbffa2..e2f317d5 100644 --- a/api/kessel/relations/v1beta1/relation_tuples.proto +++ b/api/kessel/relations/v1beta1/relation_tuples.proto @@ -58,21 +58,27 @@ message CreateTuplesRequest { bool upsert = 1; repeated Relationship tuples = 2; } -message CreateTuplesResponse {} +message CreateTuplesResponse { + Zookie created_at = 1; +} message ReadTuplesRequest { RelationTupleFilter filter = 1 [(buf.validate.field).required = true]; optional RequestPagination pagination = 2; + optional Zookie zookie = 3; } message ReadTuplesResponse { Relationship tuple = 1; ResponsePagination pagination = 2; + Zookie read_at = 3; } message DeleteTuplesRequest { RelationTupleFilter filter = 1 [(buf.validate.field).required = true]; } -message DeleteTuplesResponse {} +message DeleteTuplesResponse { + Zookie deleted_at = 1; +} // RelationTupleFilter is used to filter tuples based on their resource, relation, and subject. // All fields are optional but capabilities may vary based on the chosen store and its indexes. diff --git a/cmd/kessel-relations/wire_gen.go b/cmd/kessel-relations/wire_gen.go index e8b1d6c9..536c5914 100644 --- a/cmd/kessel-relations/wire_gen.go +++ b/cmd/kessel-relations/wire_gen.go @@ -36,7 +36,8 @@ func wireApp(confServer *conf.Server, confData *conf.Data, logger log.Logger) (* isBackendAvaliableUsecase := biz.NewIsBackendAvailableUsecase(spiceDbRepository) healthService := service.NewHealthService(isBackendAvaliableUsecase) checkUsecase := biz.NewCheckUsecase(spiceDbRepository, logger) - checkService := service.NewCheckService(logger, checkUsecase) + checkForUpdateUsecase := biz.NewCheckForUpdateUsecase(spiceDbRepository, logger) + checkService := service.NewCheckService(logger, checkUsecase, checkForUpdateUsecase) getSubjectsUsecase := biz.NewGetSubjectsUseCase(spiceDbRepository) getResourcesUsecase := biz.NewGetResourcesUseCase(spiceDbRepository) lookupService := service.NewLookupService(logger, getSubjectsUsecase, getResourcesUsecase) diff --git a/configs/config.yaml b/configs/config.yaml index 0966e7cf..4f5816fe 100644 --- a/configs/config.yaml +++ b/configs/config.yaml @@ -17,4 +17,4 @@ data: token: "${PRESHARED}" # token takes precedence over tokenFile tokenFile: "${PRESHARED_FILE:.secrets/local-spicedb-secret}" schemaFile: "${SCHEMA_FILE:deploy/schema.zed}" - fullyConsistent: true + fullyConsistent: false diff --git a/internal/biz/biz.go b/internal/biz/biz.go index dc413cde..14ba9c5a 100644 --- a/internal/biz/biz.go +++ b/internal/biz/biz.go @@ -5,4 +5,4 @@ import ( ) // ProviderSet is biz providers. -var ProviderSet = wire.NewSet(NewCreateRelationshipsUsecase, NewReadRelationshipsUsecase, NewDeleteRelationshipsUsecase, NewCheckUsecase, NewGetSubjectsUseCase, NewGetResourcesUseCase, NewIsBackendAvailableUsecase, NewImportBulkTuplesUsecase) +var ProviderSet = wire.NewSet(NewCreateRelationshipsUsecase, NewReadRelationshipsUsecase, NewDeleteRelationshipsUsecase, NewCheckUsecase, NewCheckForUpdateUsecase, NewGetSubjectsUseCase, NewGetResourcesUseCase, NewIsBackendAvailableUsecase, NewImportBulkTuplesUsecase) diff --git a/internal/biz/lookup.go b/internal/biz/lookup.go index b3084da0..053971c8 100644 --- a/internal/biz/lookup.go +++ b/internal/biz/lookup.go @@ -50,7 +50,7 @@ func (s *GetSubjectsUsecase) Get(ctx context.Context, req *v1beta1.LookupSubject subs, errs, err := s.repo.LookupSubjects(ctx, req.SubjectType, subjectRelation, req.Relation, &v1beta1.ObjectReference{ Type: req.Resource.Type, Id: req.Resource.Id, - }, limit, continuation) + }, limit, continuation, req.Zookie) if err != nil { return nil, nil, err @@ -72,7 +72,7 @@ func (r *GetResourcesUsecase) Get(ctx context.Context, req *v1beta1.LookupResour continuation = ContinuationToken(*req.Pagination.ContinuationToken) } } - resources, errs, err := r.repo.LookupResources(ctx, req.ResourceType, req.Relation, req.Subject, limit, continuation) + resources, errs, err := r.repo.LookupResources(ctx, req.ResourceType, req.Relation, req.Subject, limit, continuation, req.Zookie) if err != nil { return nil, nil, err } diff --git a/internal/biz/relationships.go b/internal/biz/relationships.go index 46d63f12..59cdd030 100644 --- a/internal/biz/relationships.go +++ b/internal/biz/relationships.go @@ -2,6 +2,7 @@ package biz import ( "context" + "google.golang.org/grpc" v1beta1 "github.com/project-kessel/relations-api/api/kessel/relations/v1beta1" @@ -16,24 +17,28 @@ type ContinuationToken string type SubjectResult struct { Subject *v1beta1.SubjectReference Continuation ContinuationToken + Zookie *v1beta1.Zookie } type ResourceResult struct { Resource *v1beta1.ObjectReference Continuation ContinuationToken + Zookie *v1beta1.Zookie } type RelationshipResult struct { Relationship *v1beta1.Relationship Continuation ContinuationToken + Zookie *v1beta1.Zookie } type ZanzibarRepository interface { Check(ctx context.Context, request *v1beta1.CheckRequest) (*v1beta1.CheckResponse, error) - CreateRelationships(context.Context, []*v1beta1.Relationship, TouchSemantics) error - ReadRelationships(ctx context.Context, filter *v1beta1.RelationTupleFilter, limit uint32, continuation ContinuationToken) (chan *RelationshipResult, chan error, error) - DeleteRelationships(context.Context, *v1beta1.RelationTupleFilter) error - LookupSubjects(ctx context.Context, subjectType *v1beta1.ObjectType, subject_relation, relation string, resource *v1beta1.ObjectReference, limit uint32, continuation ContinuationToken) (chan *SubjectResult, chan error, error) - LookupResources(ctx context.Context, resouce_type *v1beta1.ObjectType, relation string, subject *v1beta1.SubjectReference, limit uint32, continuation ContinuationToken) (chan *ResourceResult, chan error, error) + CheckForUpdate(ctx context.Context, request *v1beta1.CheckForUpdateRequest) (*v1beta1.CheckForUpdateResponse, error) + CreateRelationships(context.Context, []*v1beta1.Relationship, TouchSemantics) (*v1beta1.CreateTuplesResponse, error) + ReadRelationships(ctx context.Context, filter *v1beta1.RelationTupleFilter, limit uint32, continuation ContinuationToken, zookie *v1beta1.Zookie) (chan *RelationshipResult, chan error, error) + DeleteRelationships(context.Context, *v1beta1.RelationTupleFilter) (*v1beta1.DeleteTuplesResponse, error) + LookupSubjects(ctx context.Context, subjectType *v1beta1.ObjectType, subject_relation, relation string, resource *v1beta1.ObjectReference, limit uint32, continuation ContinuationToken, zookie *v1beta1.Zookie) (chan *SubjectResult, chan error, error) + LookupResources(ctx context.Context, resouce_type *v1beta1.ObjectType, relation string, subject *v1beta1.SubjectReference, limit uint32, continuation ContinuationToken, zookie *v1beta1.Zookie) (chan *ResourceResult, chan error, error) IsBackendAvailable() error ImportBulkTuples(stream grpc.ClientStreamingServer[v1beta1.ImportBulkTuplesRequest, v1beta1.ImportBulkTuplesResponse]) error } @@ -51,6 +56,19 @@ func (rc *CheckUsecase) Check(ctx context.Context, check *v1beta1.CheckRequest) return rc.repo.Check(ctx, check) } +type CheckForUpdateUsecase struct { + repo ZanzibarRepository + log *log.Helper +} + +func NewCheckForUpdateUsecase(repo ZanzibarRepository, logger log.Logger) *CheckForUpdateUsecase { + return &CheckForUpdateUsecase{repo: repo, log: log.NewHelper(logger)} +} + +func (rc *CheckForUpdateUsecase) CheckForUpdate(ctx context.Context, check *v1beta1.CheckForUpdateRequest) (*v1beta1.CheckForUpdateResponse, error) { + return rc.repo.CheckForUpdate(ctx, check) +} + type CreateRelationshipsUsecase struct { repo ZanzibarRepository log *log.Helper @@ -60,7 +78,7 @@ func NewCreateRelationshipsUsecase(repo ZanzibarRepository, logger log.Logger) * return &CreateRelationshipsUsecase{repo: repo, log: log.NewHelper(logger)} } -func (rc *CreateRelationshipsUsecase) CreateRelationships(ctx context.Context, r []*v1beta1.Relationship, touch bool) error { +func (rc *CreateRelationshipsUsecase) CreateRelationships(ctx context.Context, r []*v1beta1.Relationship, touch bool) (*v1beta1.CreateTuplesResponse, error) { return rc.repo.CreateRelationships(ctx, r, TouchSemantics(touch)) } @@ -87,7 +105,7 @@ func (rc *ReadRelationshipsUsecase) ReadRelationships(ctx context.Context, req * } } - relationships, errs, err := rc.repo.ReadRelationships(ctx, req.Filter, limit, continuation) + relationships, errs, err := rc.repo.ReadRelationships(ctx, req.Filter, limit, continuation, req.Zookie) if err != nil { return nil, nil, err @@ -105,7 +123,7 @@ func NewDeleteRelationshipsUsecase(repo ZanzibarRepository, logger log.Logger) * return &DeleteRelationshipsUsecase{repo: repo, log: log.NewHelper(logger)} } -func (rc *DeleteRelationshipsUsecase) DeleteRelationships(ctx context.Context, r *v1beta1.RelationTupleFilter) error { +func (rc *DeleteRelationshipsUsecase) DeleteRelationships(ctx context.Context, r *v1beta1.RelationTupleFilter) (*v1beta1.DeleteTuplesResponse, error) { return rc.repo.DeleteRelationships(ctx, r) } diff --git a/internal/data/LocalSpiceDbContainer.go b/internal/data/LocalSpiceDbContainer.go index 3d3801a3..571b99c8 100644 --- a/internal/data/LocalSpiceDbContainer.go +++ b/internal/data/LocalSpiceDbContainer.go @@ -35,7 +35,7 @@ const ( SpicedbRelationsBootstrapFile = "" // FullyConsistent specifices the consistency mode used for our read API calls // may experience different results between tests and manual probing if the values differ - FullyConsistent = true // Should probably be inline with our config file. (TODO: Can we make our tests grab the same value?) + FullyConsistent = false // Should probably be inline with our config file. (TODO: Can we make our tests grab the same value?) ) // LocalSpiceDbContainer struct that holds pointers to the container, dockertest pool and exposes the port @@ -190,7 +190,7 @@ func (l *LocalSpiceDbContainer) Close() { } // CheckForRelationship returns true if the given subject has the given relationship to the given resource, otherwise false -func CheckForRelationship(client biz.ZanzibarRepository, subjectID string, subjectNamespace string, subjectType string, subjectRelationship string, relationship string, resourceNamespace string, resourceType string, resourceID string) bool { +func CheckForRelationship(client biz.ZanzibarRepository, subjectID string, subjectNamespace string, subjectType string, subjectRelationship string, relationship string, resourceNamespace string, resourceType string, resourceID string, zookie *v1beta1.Zookie) bool { ctx := context.TODO() var subjectRelationRef *string = nil //Relation is optional @@ -209,7 +209,7 @@ func CheckForRelationship(client biz.ZanzibarRepository, subjectID string, subje SubjectId: &subjectID, Relation: subjectRelationRef, }, - }, 1, biz.ContinuationToken("")) + }, 1, biz.ContinuationToken(""), zookie) if err != nil { panic(err) diff --git a/internal/data/spicedb.go b/internal/data/spicedb.go index 123f6222..030ad331 100644 --- a/internal/data/spicedb.go +++ b/internal/data/spicedb.go @@ -25,11 +25,11 @@ import ( // SpiceDbRepository . type SpiceDbRepository struct { - client *authzed.Client - healthClient grpc_health_v1.HealthClient - schemaFilePath string - isInitialized bool - consistency *v1.Consistency + client *authzed.Client + healthClient grpc_health_v1.HealthClient + schemaFilePath string + isInitialized bool + fullyConsistent bool } const ( @@ -91,15 +91,7 @@ func NewSpiceDbRepository(c *conf.Data, logger log.Logger) (*SpiceDbRepository, log.NewHelper(logger).Info("spicedb connection cleanup requested (nothing to clean up)") } - // Default consistency for read APIs is minimize_latency - // will attempt to minimize the latency of the API call by selecting data that is most likely exist in the cache. - consistency := &v1.Consistency{Requirement: &v1.Consistency_MinimizeLatency{MinimizeLatency: true}} - if c.SpiceDb.FullyConsistent { - // will ensure that all data used is fully consistent with the latest data available within the SpiceDB datastore. - consistency = &v1.Consistency{Requirement: &v1.Consistency_FullyConsistent{FullyConsistent: true}} - } - - return &SpiceDbRepository{client, healthClient, c.SpiceDb.SchemaFile, false, consistency}, cleanup, nil + return &SpiceDbRepository{client, healthClient, c.SpiceDb.SchemaFile, false, c.SpiceDb.FullyConsistent}, cleanup, nil } func (s *SpiceDbRepository) initialize() error { @@ -124,7 +116,7 @@ func (s *SpiceDbRepository) initialize() error { return nil } -func (s *SpiceDbRepository) LookupSubjects(ctx context.Context, subject_type *apiV1beta1.ObjectType, subject_relation, relation string, object *apiV1beta1.ObjectReference, limit uint32, continuation biz.ContinuationToken) (chan *biz.SubjectResult, chan error, error) { +func (s *SpiceDbRepository) LookupSubjects(ctx context.Context, subject_type *apiV1beta1.ObjectType, subject_relation, relation string, object *apiV1beta1.ObjectReference, limit uint32, continuation biz.ContinuationToken, zookie *apiV1beta1.Zookie) (chan *biz.SubjectResult, chan error, error) { if err := s.initialize(); err != nil { return nil, nil, err } @@ -137,7 +129,7 @@ func (s *SpiceDbRepository) LookupSubjects(ctx context.Context, subject_type *ap } req := &v1.LookupSubjectsRequest{ - Consistency: s.consistency, + Consistency: s.determineConsistency(zookie), Resource: &v1.ObjectReference{ ObjectType: kesselTypeToSpiceDBType(object.Type), ObjectId: object.Id, @@ -185,6 +177,7 @@ func (s *SpiceDbRepository) LookupSubjects(ctx context.Context, subject_type *ap }, }, Continuation: continuation, + Zookie: &apiV1beta1.Zookie{Token: msg.GetLookedUpAt().GetToken()}, } } }() @@ -192,7 +185,7 @@ func (s *SpiceDbRepository) LookupSubjects(ctx context.Context, subject_type *ap return subjects, errs, nil } -func (s *SpiceDbRepository) LookupResources(ctx context.Context, resouce_type *apiV1beta1.ObjectType, relation string, subject *apiV1beta1.SubjectReference, limit uint32, continuation biz.ContinuationToken) (chan *biz.ResourceResult, chan error, error) { +func (s *SpiceDbRepository) LookupResources(ctx context.Context, resouce_type *apiV1beta1.ObjectType, relation string, subject *apiV1beta1.SubjectReference, limit uint32, continuation biz.ContinuationToken, zookie *apiV1beta1.Zookie) (chan *biz.ResourceResult, chan error, error) { if err := s.initialize(); err != nil { return nil, nil, err } @@ -204,7 +197,7 @@ func (s *SpiceDbRepository) LookupResources(ctx context.Context, resouce_type *a } } client, err := s.client.LookupResources(ctx, &v1.LookupResourcesRequest{ - Consistency: s.consistency, + Consistency: s.determineConsistency(zookie), ResourceObjectType: kesselTypeToSpiceDBType(resouce_type), Permission: relation, Subject: &v1.SubjectReference{ @@ -248,6 +241,7 @@ func (s *SpiceDbRepository) LookupResources(ctx context.Context, resouce_type *a Id: resId, }, Continuation: continuation, + Zookie: &apiV1beta1.Zookie{Token: msg.GetLookedUpAt().GetToken()}, } } }() @@ -297,9 +291,9 @@ func (s *SpiceDbRepository) ImportBulkTuples(stream grpc.ClientStreamingServer[a } -func (s *SpiceDbRepository) CreateRelationships(ctx context.Context, rels []*apiV1beta1.Relationship, touch biz.TouchSemantics) error { +func (s *SpiceDbRepository) CreateRelationships(ctx context.Context, rels []*apiV1beta1.Relationship, touch biz.TouchSemantics) (*apiV1beta1.CreateTuplesResponse, error) { if err := s.initialize(); err != nil { - return err + return nil, err } var relationshipUpdates []*v1.RelationshipUpdate @@ -322,17 +316,18 @@ func (s *SpiceDbRepository) CreateRelationships(ctx context.Context, rels []*api }) } - _, err := s.client.WriteRelationships(ctx, &v1.WriteRelationshipsRequest{ + resp, err := s.client.WriteRelationships(ctx, &v1.WriteRelationshipsRequest{ Updates: relationshipUpdates, }) if err != nil { - return fmt.Errorf("error writing relationships to SpiceDB: %w", err) + return nil, fmt.Errorf("error writing relationships to SpiceDB: %w", err) } - return nil + + return &apiV1beta1.CreateTuplesResponse{CreatedAt: &apiV1beta1.Zookie{Token: resp.GetWrittenAt().GetToken()}}, nil } -func (s *SpiceDbRepository) ReadRelationships(ctx context.Context, filter *apiV1beta1.RelationTupleFilter, limit uint32, continuation biz.ContinuationToken) (chan *biz.RelationshipResult, chan error, error) { +func (s *SpiceDbRepository) ReadRelationships(ctx context.Context, filter *apiV1beta1.RelationTupleFilter, limit uint32, continuation biz.ContinuationToken, zookie *apiV1beta1.Zookie) (chan *biz.RelationshipResult, chan error, error) { if err := s.initialize(); err != nil { return nil, nil, err } @@ -358,7 +353,7 @@ func (s *SpiceDbRepository) ReadRelationships(ctx context.Context, filter *apiV1 } req := &v1.ReadRelationshipsRequest{ - Consistency: s.consistency, + Consistency: s.determineConsistency(zookie), RelationshipFilter: relationshipFilter, OptionalLimit: limit, OptionalCursor: cursor, @@ -407,6 +402,7 @@ func (s *SpiceDbRepository) ReadRelationships(ctx context.Context, filter *apiV1 }, }, Continuation: continuation, + Zookie: &apiV1beta1.Zookie{Token: msg.ReadAt.GetToken()}, } } }() @@ -414,9 +410,9 @@ func (s *SpiceDbRepository) ReadRelationships(ctx context.Context, filter *apiV1 return relationshipTuples, errs, nil } -func (s *SpiceDbRepository) DeleteRelationships(ctx context.Context, filter *apiV1beta1.RelationTupleFilter) error { +func (s *SpiceDbRepository) DeleteRelationships(ctx context.Context, filter *apiV1beta1.RelationTupleFilter) (*apiV1beta1.DeleteTuplesResponse, error) { if err := s.initialize(); err != nil { - return err + return nil, err } if filter.GetRelation() != "" { @@ -427,19 +423,19 @@ func (s *SpiceDbRepository) DeleteRelationships(ctx context.Context, filter *api relationshipFilter, err := createSpiceDbRelationshipFilter(filter) if err != nil { - return kerrors.BadRequest("SpiceDb request validation", err.Error()).WithCause(err) + return nil, kerrors.BadRequest("SpiceDb request validation", err.Error()).WithCause(err) } req := &v1.DeleteRelationshipsRequest{RelationshipFilter: relationshipFilter} - _, err = s.client.DeleteRelationships(ctx, req) + resp, err := s.client.DeleteRelationships(ctx, req) // TODO: we have not specified an option in our API to allow partial deletions, so currently it's all or nothing if err != nil { - return fmt.Errorf("error invoking DeleteRelationships in SpiceDB %w", err) + return nil, fmt.Errorf("error invoking DeleteRelationships in SpiceDB %w", err) } - return nil + return &apiV1beta1.DeleteTuplesResponse{DeletedAt: &apiV1beta1.Zookie{Token: resp.GetDeletedAt().GetToken()}}, nil } func (s *SpiceDbRepository) Check(ctx context.Context, check *apiV1beta1.CheckRequest) (*apiV1beta1.CheckResponse, error) { @@ -460,7 +456,7 @@ func (s *SpiceDbRepository) Check(ctx context.Context, check *apiV1beta1.CheckRe ObjectId: check.GetResource().GetId(), } req := &v1.CheckPermissionRequest{ - Consistency: s.consistency, + Consistency: s.determineConsistency(check.Zookie), Resource: resource, Permission: check.GetRelation(), Subject: subject, @@ -471,10 +467,57 @@ func (s *SpiceDbRepository) Check(ctx context.Context, check *apiV1beta1.CheckRe } if checkResponse.Permissionship == v1.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION { - return &apiV1beta1.CheckResponse{Allowed: apiV1beta1.CheckResponse_ALLOWED_TRUE}, nil + return &apiV1beta1.CheckResponse{ + Allowed: apiV1beta1.CheckResponse_ALLOWED_TRUE, + CheckedAt: &apiV1beta1.Zookie{Token: checkResponse.GetCheckedAt().GetToken()}, + }, nil + } + + return &apiV1beta1.CheckResponse{ + Allowed: apiV1beta1.CheckResponse_ALLOWED_FALSE, + CheckedAt: &apiV1beta1.Zookie{Token: checkResponse.GetCheckedAt().GetToken()}, + }, nil +} + +func (s *SpiceDbRepository) CheckForUpdate(ctx context.Context, check *apiV1beta1.CheckForUpdateRequest) (*apiV1beta1.CheckForUpdateResponse, error) { + if err := s.initialize(); err != nil { + return nil, err + } + + subject := &v1.SubjectReference{ + Object: &v1.ObjectReference{ + ObjectType: kesselTypeToSpiceDBType(check.GetSubject().GetSubject().Type), + ObjectId: check.GetSubject().GetSubject().GetId(), + }, + OptionalRelation: check.GetSubject().GetRelation(), + } + + resource := &v1.ObjectReference{ + ObjectType: kesselTypeToSpiceDBType(check.GetResource().GetType()), + ObjectId: check.GetResource().GetId(), + } + req := &v1.CheckPermissionRequest{ + Consistency: &v1.Consistency{Requirement: &v1.Consistency_FullyConsistent{FullyConsistent: true}}, + Resource: resource, + Permission: check.GetRelation(), + Subject: subject, + } + checkResponse, err := s.client.CheckPermission(ctx, req) + if err != nil { + return &apiV1beta1.CheckForUpdateResponse{Allowed: apiV1beta1.CheckForUpdateResponse_ALLOWED_UNSPECIFIED}, fmt.Errorf("error invoking CheckPermission in SpiceDB: %w", err) + } + + if checkResponse.Permissionship == v1.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION { + return &apiV1beta1.CheckForUpdateResponse{ + Allowed: apiV1beta1.CheckForUpdateResponse_ALLOWED_TRUE, + CheckedAt: &apiV1beta1.Zookie{Token: checkResponse.GetCheckedAt().GetToken()}, + }, nil } - return &apiV1beta1.CheckResponse{Allowed: apiV1beta1.CheckResponse_ALLOWED_FALSE}, nil + return &apiV1beta1.CheckForUpdateResponse{ + Allowed: apiV1beta1.CheckForUpdateResponse_ALLOWED_FALSE, + CheckedAt: &apiV1beta1.Zookie{Token: checkResponse.GetCheckedAt().GetToken()}, + }, nil } func (s *SpiceDbRepository) IsBackendAvailable() error { @@ -621,3 +664,24 @@ func readFile(file string) (string, error) { return string(bytes), nil } + +func (s *SpiceDbRepository) determineConsistency(zookie *apiV1beta1.Zookie) *v1.Consistency { + if s.fullyConsistent { + // will ensure that all data used is fully consistent with the latest data available within the SpiceDB datastore. + return &v1.Consistency{Requirement: &v1.Consistency_FullyConsistent{FullyConsistent: true}} + } + + if zookie != nil { + return &v1.Consistency{ + Requirement: &v1.Consistency_AtLeastAsFresh{ + AtLeastAsFresh: &v1.ZedToken{Token: zookie.GetToken()}, + }, + } + } + // Default consistency for read APIs is minimize_latency + return &v1.Consistency{ + Requirement: &v1.Consistency_MinimizeLatency{ + MinimizeLatency: true, + }, + } +} diff --git a/internal/data/spicedb_test.go b/internal/data/spicedb_test.go index dd051dc7..57766c31 100644 --- a/internal/data/spicedb_test.go +++ b/internal/data/spicedb_test.go @@ -52,7 +52,7 @@ func TestCreateRelationship(t *testing.T) { spiceDbRepo, err := container.CreateSpiceDbRepository() assert.NoError(t, err) - preExisting := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club") + preExisting := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club", nil) assert.False(t, preExisting) rels := []*apiV1beta1.Relationship{ @@ -61,12 +61,35 @@ func TestCreateRelationship(t *testing.T) { touch := biz.TouchSemantics(false) - err = spiceDbRepo.CreateRelationships(ctx, rels, touch) + _, err = spiceDbRepo.CreateRelationships(ctx, rels, touch) assert.NoError(t, err) container.WaitForQuantizationInterval() - exists := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club") + exists := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club", nil) + assert.True(t, exists) +} + +func TestCreateRelationshipWithZookie(t *testing.T) { + t.Parallel() + + ctx := context.Background() + spiceDbRepo, err := container.CreateSpiceDbRepository() + assert.NoError(t, err) + + preExisting := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club", nil) + assert.False(t, preExisting) + + rels := []*apiV1beta1.Relationship{ + createRelationship("rbac", "group", "bob_club", "member", "rbac", "principal", "bob", ""), + } + + touch := biz.TouchSemantics(false) + + resp, err := spiceDbRepo.CreateRelationships(ctx, rels, touch) + assert.NoError(t, err) + + exists := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club", resp.GetCreatedAt()) assert.True(t, exists) } @@ -77,7 +100,7 @@ func TestCreateRelationshipWithSubjectRelation(t *testing.T) { spiceDbRepo, err := container.CreateSpiceDbRepository() assert.NoError(t, err) - preExisting := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club") + preExisting := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club", nil) assert.False(t, preExisting) rels := []*apiV1beta1.Relationship{ @@ -89,15 +112,15 @@ func TestCreateRelationshipWithSubjectRelation(t *testing.T) { touch := biz.TouchSemantics(false) - err = spiceDbRepo.CreateRelationships(ctx, rels, touch) + _, err = spiceDbRepo.CreateRelationships(ctx, rels, touch) assert.NoError(t, err) container.WaitForQuantizationInterval() - exists := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club") + exists := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club", nil) assert.True(t, exists) - exists = CheckForRelationship(spiceDbRepo, "bob_club", "rbac", "group", "member", "subject", "rbac", "role_binding", "fan_binding") + exists = CheckForRelationship(spiceDbRepo, "bob_club", "rbac", "group", "member", "subject", "rbac", "role_binding", "fan_binding", nil) assert.True(t, exists) // zed permission check rbac/role_binding:fan_binding subject rbac/principal:bob @@ -132,7 +155,7 @@ func TestSecondCreateRelationshipFailsWithTouchFalse(t *testing.T) { spiceDbRepo, err := container.CreateSpiceDbRepository() assert.NoError(t, err) - preExisting := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club") + preExisting := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club", nil) assert.False(t, preExisting) rels := []*apiV1beta1.Relationship{ @@ -141,16 +164,16 @@ func TestSecondCreateRelationshipFailsWithTouchFalse(t *testing.T) { touch := biz.TouchSemantics(false) - err = spiceDbRepo.CreateRelationships(ctx, rels, touch) + _, err = spiceDbRepo.CreateRelationships(ctx, rels, touch) assert.NoError(t, err) - err = spiceDbRepo.CreateRelationships(ctx, rels, touch) + _, err = spiceDbRepo.CreateRelationships(ctx, rels, touch) assert.Error(t, err) assert.Equal(t, codes.AlreadyExists, status.Convert(err).Code()) container.WaitForQuantizationInterval() - exists := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club") + exists := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club", nil) assert.True(t, exists) } @@ -161,7 +184,7 @@ func TestSecondCreateRelationshipSucceedsWithTouchTrue(t *testing.T) { spiceDbRepo, err := container.CreateSpiceDbRepository() assert.NoError(t, err) - preExisting := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club") + preExisting := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club", nil) assert.False(t, preExisting) rels := []*apiV1beta1.Relationship{ @@ -170,17 +193,17 @@ func TestSecondCreateRelationshipSucceedsWithTouchTrue(t *testing.T) { touch := biz.TouchSemantics(false) - err = spiceDbRepo.CreateRelationships(ctx, rels, touch) + _, err = spiceDbRepo.CreateRelationships(ctx, rels, touch) assert.NoError(t, err) touch = true - err = spiceDbRepo.CreateRelationships(ctx, rels, touch) + _, err = spiceDbRepo.CreateRelationships(ctx, rels, touch) assert.NoError(t, err) container.WaitForQuantizationInterval() - exists := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club") + exists := CheckForRelationship(spiceDbRepo, "bob", "rbac", "principal", "", "member", "rbac", "group", "bob_club", nil) assert.True(t, exists) } @@ -254,7 +277,7 @@ func TestImportBulkTuples(t *testing.T) { assert.NoError(t, err) container.WaitForQuantizationInterval() - exists := CheckForRelationship(spiceDbRepo, "bob5", "rbac", "principal", "", "member", "rbac", "group", "bob_club") + exists := CheckForRelationship(spiceDbRepo, "bob5", "rbac", "principal", "", "member", "rbac", "group", "bob_club", nil) assert.True(t, exists) } @@ -298,7 +321,7 @@ func TestDoesNotCreateRelationshipWithSlashInSubjectType(t *testing.T) { touch := biz.TouchSemantics(false) - err = spiceDbRepo.CreateRelationships(ctx, rels, touch) + _, err = spiceDbRepo.CreateRelationships(ctx, rels, touch) assert.Error(t, err) } @@ -317,7 +340,7 @@ func TestDoesNotCreateRelationshipWithSlashInObjectType(t *testing.T) { touch := biz.TouchSemantics(false) - err = spiceDbRepo.CreateRelationships(ctx, rels, touch) + _, err = spiceDbRepo.CreateRelationships(ctx, rels, touch) assert.Error(t, err) } @@ -336,7 +359,7 @@ func TestCreateRelationshipFailsWithBadSubjectType(t *testing.T) { touch := biz.TouchSemantics(false) - err = spiceDbRepo.CreateRelationships(ctx, rels, touch) + _, err = spiceDbRepo.CreateRelationships(ctx, rels, touch) assert.Error(t, err) assert.Equal(t, codes.FailedPrecondition, status.Convert(err).Code()) assert.Contains(t, err.Error(), @@ -358,7 +381,7 @@ func TestCreateRelationshipFailsWithBadObjectType(t *testing.T) { touch := biz.TouchSemantics(false) - err = spiceDbRepo.CreateRelationships(ctx, rels, touch) + _, err = spiceDbRepo.CreateRelationships(ctx, rels, touch) assert.Error(t, err) assert.Equal(t, codes.FailedPrecondition, status.Convert(err).Code()) assert.Contains(t, err.Error(), @@ -386,7 +409,7 @@ func TestSupportedNsTypeTupleFilterCombinationsInReadRelationships(t *testing.T) SubjectNamespace: pointerize("rbac"), SubjectType: pointerize("principal"), }, - }, 0, "") + }, 0, "", nil) assert.Error(t, err) @@ -399,7 +422,7 @@ func TestSupportedNsTypeTupleFilterCombinationsInReadRelationships(t *testing.T) SubjectNamespace: pointerize("rbac"), SubjectType: pointerize("principal"), }, - }, 0, "") + }, 0, "", nil) assert.Error(t, err) @@ -412,7 +435,7 @@ func TestSupportedNsTypeTupleFilterCombinationsInReadRelationships(t *testing.T) SubjectId: pointerize("bob"), SubjectType: pointerize("principal"), }, - }, 0, "") + }, 0, "", nil) assert.Error(t, err) @@ -425,7 +448,7 @@ func TestSupportedNsTypeTupleFilterCombinationsInReadRelationships(t *testing.T) SubjectId: pointerize("bob"), SubjectNamespace: pointerize("rbac"), }, - }, 0, "") + }, 0, "", nil) assert.Error(t, err) @@ -439,7 +462,7 @@ func TestSupportedNsTypeTupleFilterCombinationsInReadRelationships(t *testing.T) SubjectNamespace: pointerize("rbac"), SubjectType: pointerize("principal"), }, - }, 0, "") + }, 0, "", nil) assert.NoError(t, err) @@ -451,7 +474,7 @@ func TestSupportedNsTypeTupleFilterCombinationsInReadRelationships(t *testing.T) SubjectNamespace: pointerize("rbac"), SubjectType: pointerize("principal"), }, - }, 0, "") + }, 0, "", nil) assert.NoError(t, err) @@ -463,7 +486,7 @@ func TestSupportedNsTypeTupleFilterCombinationsInReadRelationships(t *testing.T) SubjectFilter: &apiV1beta1.SubjectFilter{ SubjectId: pointerize("bob"), }, - }, 0, "") + }, 0, "", nil) assert.NoError(t, err) @@ -473,7 +496,7 @@ func TestSupportedNsTypeTupleFilterCombinationsInReadRelationships(t *testing.T) SubjectFilter: &apiV1beta1.SubjectFilter{ SubjectId: pointerize("bob"), }, - }, 0, "") + }, 0, "", nil) assert.NoError(t, err) @@ -484,7 +507,7 @@ func TestSupportedNsTypeTupleFilterCombinationsInReadRelationships(t *testing.T) SubjectFilter: &apiV1beta1.SubjectFilter{ SubjectId: pointerize("bob"), }, - }, 0, "") + }, 0, "", nil) assert.NoError(t, err) } @@ -503,7 +526,7 @@ func TestWriteAndReadBackRelationships(t *testing.T) { createRelationship("rbac", "group", "bob_club", "member", "rbac", "principal", "bob", ""), } - err = spiceDbRepo.CreateRelationships(ctx, rels, biz.TouchSemantics(true)) + _, err = spiceDbRepo.CreateRelationships(ctx, rels, biz.TouchSemantics(true)) if !assert.NoError(t, err) { return } @@ -520,7 +543,7 @@ func TestWriteAndReadBackRelationships(t *testing.T) { SubjectNamespace: pointerize("rbac"), SubjectType: pointerize("principal"), }, - }, 0, "") + }, 0, "", nil) if !assert.NoError(t, err) { return @@ -544,7 +567,7 @@ func TestWriteReadBackDeleteAndReadBackRelationships(t *testing.T) { createRelationship("rbac", "group", "bob_club", "member", "rbac", "principal", "bob", ""), } - err = spiceDbRepo.CreateRelationships(ctx, rels, biz.TouchSemantics(true)) + _, err = spiceDbRepo.CreateRelationships(ctx, rels, biz.TouchSemantics(true)) if !assert.NoError(t, err) { return } @@ -561,7 +584,7 @@ func TestWriteReadBackDeleteAndReadBackRelationships(t *testing.T) { SubjectNamespace: pointerize("rbac"), SubjectType: pointerize("principal"), }, - }, 0, "") + }, 0, "", nil) if !assert.NoError(t, err) { return @@ -570,7 +593,7 @@ func TestWriteReadBackDeleteAndReadBackRelationships(t *testing.T) { readrels := spiceRelChanToSlice(readRelChan) assert.Equal(t, 1, len(readrels)) - err = spiceDbRepo.DeleteRelationships(ctx, &apiV1beta1.RelationTupleFilter{ + _, err = spiceDbRepo.DeleteRelationships(ctx, &apiV1beta1.RelationTupleFilter{ ResourceId: pointerize("bob_club"), ResourceNamespace: pointerize("rbac"), ResourceType: pointerize("group"), @@ -598,7 +621,82 @@ func TestWriteReadBackDeleteAndReadBackRelationships(t *testing.T) { SubjectNamespace: pointerize("rbac"), SubjectType: pointerize("principal"), }, - }, 0, "") + }, 0, "", nil) + + if !assert.NoError(t, err) { + return + } + + readrels = spiceRelChanToSlice(readRelChan) + assert.Equal(t, 0, len(readrels)) + +} + +func TestWriteReadBackDeleteAndReadBackRelationships_WithZookie(t *testing.T) { + t.Parallel() + + ctx := context.Background() + spiceDbRepo, err := container.CreateSpiceDbRepository() + if !assert.NoError(t, err) { + return + } + + assert.NoError(t, err) + rels := []*apiV1beta1.Relationship{ + createRelationship("rbac", "group", "bob_club", "member", "rbac", "principal", "bob", ""), + } + + respCreate, err := spiceDbRepo.CreateRelationships(ctx, rels, biz.TouchSemantics(true)) + if !assert.NoError(t, err) { + return + } + + readRelChan, _, err := spiceDbRepo.ReadRelationships(ctx, &apiV1beta1.RelationTupleFilter{ + ResourceId: pointerize("bob_club"), + ResourceNamespace: pointerize("rbac"), + ResourceType: pointerize("group"), + Relation: pointerize("member"), + SubjectFilter: &apiV1beta1.SubjectFilter{ + SubjectId: pointerize("bob"), + SubjectNamespace: pointerize("rbac"), + SubjectType: pointerize("principal"), + }, + }, 0, "", respCreate.GetCreatedAt()) + + if !assert.NoError(t, err) { + return + } + + readrels := spiceRelChanToSlice(readRelChan) + assert.Equal(t, 1, len(readrels)) + + respDelete, err := spiceDbRepo.DeleteRelationships(ctx, &apiV1beta1.RelationTupleFilter{ + ResourceId: pointerize("bob_club"), + ResourceNamespace: pointerize("rbac"), + ResourceType: pointerize("group"), + Relation: pointerize("member"), + SubjectFilter: &apiV1beta1.SubjectFilter{ + SubjectId: pointerize("bob"), + SubjectNamespace: pointerize("rbac"), + SubjectType: pointerize("principal"), + }, + }) + + if !assert.NoError(t, err) { + return + } + + readRelChan, _, err = spiceDbRepo.ReadRelationships(ctx, &apiV1beta1.RelationTupleFilter{ + ResourceId: pointerize("bob_club"), + ResourceNamespace: pointerize("rbac"), + ResourceType: pointerize("group"), + Relation: pointerize("member"), + SubjectFilter: &apiV1beta1.SubjectFilter{ + SubjectId: pointerize("bob"), + SubjectNamespace: pointerize("rbac"), + SubjectType: pointerize("principal"), + }, + }, 0, "", respDelete.GetDeletedAt()) if !assert.NoError(t, err) { return @@ -609,6 +707,121 @@ func TestWriteReadBackDeleteAndReadBackRelationships(t *testing.T) { } +func TestSpiceDbRepository_CheckPermission_WithZookie(t *testing.T) { + t.Parallel() + + ctx := context.Background() + spiceDbRepo, err := container.CreateSpiceDbRepository() + if !assert.NoError(t, err) { + return + } + + rels := []*apiV1beta1.Relationship{ + createRelationship("rbac", "group", "bob_club", "member", "rbac", "principal", "bob", ""), + createRelationship("rbac", "workspace", "test", "user_grant", "rbac", "role_binding", "rb_test", ""), + createRelationship("rbac", "role_binding", "rb_test", "granted", "rbac", "role", "rl1", ""), + createRelationship("rbac", "role_binding", "rb_test", "subject", "rbac", "principal", "bob", ""), + createRelationship("rbac", "role", "rl1", "view_widget", "rbac", "principal", "*", ""), + } + + relationshipResp, err := spiceDbRepo.CreateRelationships(ctx, rels, biz.TouchSemantics(true)) + if !assert.NoError(t, err) { + return + } + + subject := &apiV1beta1.SubjectReference{ + Subject: &apiV1beta1.ObjectReference{ + Type: &apiV1beta1.ObjectType{ + Name: "principal", Namespace: "rbac", + }, + Id: "bob", + }, + } + + resource := &apiV1beta1.ObjectReference{ + Type: &apiV1beta1.ObjectType{ + Name: "workspace", Namespace: "rbac", + }, + Id: "test", + } + // no wait, immediately read after write. + // zed permission check rbac/workspace:test view_widget rbac/principal:bob --explain + check := apiV1beta1.CheckRequest{ + Subject: subject, + Relation: "view_widget", + Resource: resource, + Zookie: relationshipResp.GetCreatedAt(), // pass createdAt zookie + } + resp, err := spiceDbRepo.Check(ctx, &check) + if !assert.NoError(t, err) { + return + } + //apiV1.CheckResponse_ALLOWED_TRUE + checkResponse := apiV1beta1.CheckResponse{ + Allowed: apiV1beta1.CheckResponse_ALLOWED_TRUE, + CheckedAt: resp.GetCheckedAt(), // returned zookie may not be same as created zookie. + } + assert.Equal(t, &checkResponse, resp) + +} + +func TestSpiceDbRepository_CheckForUpdatePermission(t *testing.T) { + t.Parallel() + + ctx := context.Background() + spiceDbRepo, err := container.CreateSpiceDbRepository() + if !assert.NoError(t, err) { + return + } + + rels := []*apiV1beta1.Relationship{ + createRelationship("rbac", "group", "bob_club", "member", "rbac", "principal", "bob", ""), + createRelationship("rbac", "workspace", "test", "user_grant", "rbac", "role_binding", "rb_test", ""), + createRelationship("rbac", "role_binding", "rb_test", "granted", "rbac", "role", "rl1", ""), + createRelationship("rbac", "role_binding", "rb_test", "subject", "rbac", "principal", "bob", ""), + createRelationship("rbac", "role", "rl1", "view_widget", "rbac", "principal", "*", ""), + } + + _, err = spiceDbRepo.CreateRelationships(ctx, rels, biz.TouchSemantics(true)) + if !assert.NoError(t, err) { + return + } + + subject := &apiV1beta1.SubjectReference{ + Subject: &apiV1beta1.ObjectReference{ + Type: &apiV1beta1.ObjectType{ + Name: "principal", Namespace: "rbac", + }, + Id: "bob", + }, + } + + resource := &apiV1beta1.ObjectReference{ + Type: &apiV1beta1.ObjectType{ + Name: "workspace", Namespace: "rbac", + }, + Id: "test", + } + // no wait, immediately read after write. + // zed permission check rbac/workspace:test view_widget rbac/principal:bob --explain + check := apiV1beta1.CheckForUpdateRequest{ + Subject: subject, + Relation: "view_widget", + Resource: resource, + } + resp, err := spiceDbRepo.CheckForUpdate(ctx, &check) + if !assert.NoError(t, err) { + return + } + //apiV1.CheckForUpdateResponse_ALLOWED_TRUE + checkResponse := apiV1beta1.CheckForUpdateResponse{ + Allowed: apiV1beta1.CheckForUpdateResponse_ALLOWED_TRUE, + CheckedAt: resp.GetCheckedAt(), // returned zookie may not be same as created zookie. + } + assert.Equal(t, &checkResponse, resp) + +} + func TestSpiceDbRepository_CheckPermission(t *testing.T) { t.Parallel() @@ -626,7 +839,7 @@ func TestSpiceDbRepository_CheckPermission(t *testing.T) { createRelationship("rbac", "role", "rl1", "view_widget", "rbac", "principal", "*", ""), } - err = spiceDbRepo.CreateRelationships(ctx, rels, biz.TouchSemantics(true)) + _, err = spiceDbRepo.CreateRelationships(ctx, rels, biz.TouchSemantics(true)) if !assert.NoError(t, err) { return } @@ -659,13 +872,16 @@ func TestSpiceDbRepository_CheckPermission(t *testing.T) { return } //apiV1.CheckResponse_ALLOWED_TRUE + dummyZookie := "AAAAAAAAHHHHH" checkResponse := apiV1beta1.CheckResponse{ - Allowed: apiV1beta1.CheckResponse_ALLOWED_TRUE, + Allowed: apiV1beta1.CheckResponse_ALLOWED_TRUE, + CheckedAt: &apiV1beta1.Zookie{Token: dummyZookie}, } + resp.CheckedAt = &apiV1beta1.Zookie{Token: dummyZookie} assert.Equal(t, &checkResponse, resp) //Remove // rbac/role_binding:rb_test#t_subject@rbac/principal:bob - err = spiceDbRepo.DeleteRelationships(ctx, &apiV1beta1.RelationTupleFilter{ + _, err = spiceDbRepo.DeleteRelationships(ctx, &apiV1beta1.RelationTupleFilter{ ResourceId: pointerize("rb_test"), ResourceNamespace: pointerize("rbac"), ResourceType: pointerize("role_binding"), @@ -691,12 +907,260 @@ func TestSpiceDbRepository_CheckPermission(t *testing.T) { if !assert.NoError(t, err) { return } + dummyZookie = "AAAAAAAAHHHHH" checkResponsev2 := apiV1beta1.CheckResponse{ - Allowed: apiV1beta1.CheckResponse_ALLOWED_FALSE, + Allowed: apiV1beta1.CheckResponse_ALLOWED_FALSE, + CheckedAt: &apiV1beta1.Zookie{Token: dummyZookie}, } + resp2.CheckedAt = &apiV1beta1.Zookie{Token: dummyZookie} assert.Equal(t, &checkResponsev2, resp2) } +func TestSpiceDbRepository_NewEnemyProblem_Success(t *testing.T) { + t.Parallel() + + ctx := context.Background() + spiceDbRepo, err := container.CreateSpiceDbRepository() + if !assert.NoError(t, err) { + return + } + + rels := []*apiV1beta1.Relationship{ + createRelationship("rbac", "group", "bob_club", "member", "rbac", "principal", "bob", ""), + createRelationship("rbac", "workspace", "test", "user_grant", "rbac", "role_binding", "rb_test", ""), + createRelationship("rbac", "role_binding", "rb_test", "granted", "rbac", "role", "rl1", ""), + createRelationship("rbac", "role_binding", "rb_test", "subject", "rbac", "principal", "u1", ""), + createRelationship("rbac", "role_binding", "rb_test", "subject", "rbac", "principal", "u2", ""), + createRelationship("rbac", "role", "rl1", "view_widget", "rbac", "principal", "*", ""), + } + + relationshipResp, err := spiceDbRepo.CreateRelationships(ctx, rels, biz.TouchSemantics(true)) + if !assert.NoError(t, err) { + return + } + + // u1 + u1Check := apiV1beta1.CheckRequest{ + Subject: &apiV1beta1.SubjectReference{ + Subject: &apiV1beta1.ObjectReference{ + Type: &apiV1beta1.ObjectType{ + Name: "principal", Namespace: "rbac", + }, + Id: "u1", + }, + }, + Relation: "view_widget", + Resource: &apiV1beta1.ObjectReference{ + Type: &apiV1beta1.ObjectType{ + Name: "workspace", Namespace: "rbac", + }, + Id: "test", + }, + Zookie: relationshipResp.GetCreatedAt(), // pass createdAt zookie + } + + // no wait, immediately read after write. + // zed permission check rbac/workspace:test user_grant rbac/principal:u1 --explain + resp, err := spiceDbRepo.Check(ctx, &u1Check) + if !assert.NoError(t, err) { + return + } + //apiV1.CheckResponse_ALLOWED_TRUE + checkResponse := apiV1beta1.CheckResponse{ + Allowed: apiV1beta1.CheckResponse_ALLOWED_TRUE, + CheckedAt: resp.GetCheckedAt(), // returned zookie may not be same as created zookie. + } + assert.Equal(t, &checkResponse, resp) + + // u2 + u2Check := apiV1beta1.CheckRequest{ + Subject: &apiV1beta1.SubjectReference{ + Subject: &apiV1beta1.ObjectReference{ + Type: &apiV1beta1.ObjectType{ + Name: "principal", Namespace: "rbac", + }, + Id: "u2", + }, + }, + Relation: "view_widget", + Resource: &apiV1beta1.ObjectReference{ + Type: &apiV1beta1.ObjectType{ + Name: "workspace", Namespace: "rbac", + }, + Id: "test", + }, + Zookie: relationshipResp.GetCreatedAt(), // pass createdAt zookie + } + + // zed permission check rbac/workspace:test user_grant rbac/principal:u2 --explain + resp, err = spiceDbRepo.Check(ctx, &u2Check) + if !assert.NoError(t, err) { + return + } + //apiV1.CheckResponse_ALLOWED_TRUE + checkResponse = apiV1beta1.CheckResponse{ + Allowed: apiV1beta1.CheckResponse_ALLOWED_TRUE, + CheckedAt: resp.GetCheckedAt(), // returned zookie may not be same as created zookie. + } + assert.Equal(t, &checkResponse, resp) + + // remove access from u1, keep access for u2. + respDelete, err := spiceDbRepo.DeleteRelationships(ctx, &apiV1beta1.RelationTupleFilter{ + ResourceId: pointerize("rb_test"), + ResourceNamespace: pointerize("rbac"), + ResourceType: pointerize("role_binding"), + Relation: pointerize("subject"), + SubjectFilter: &apiV1beta1.SubjectFilter{ + SubjectId: pointerize("u1"), + SubjectNamespace: pointerize("rbac"), + SubjectType: pointerize("principal"), + }, + }) + if !assert.NoError(t, err) { + return + } + + // ensure u1 no longer has access, while u2 still does. + + // zed permission check rbac/workspace:test user_grant rbac/principal:u1 --explain + u1Check.Zookie = respDelete.GetDeletedAt() + resp, err = spiceDbRepo.Check(ctx, &u1Check) + if !assert.NoError(t, err) { + return + } + //apiV1.CheckResponse_ALLOWED_FALSE + checkResponse = apiV1beta1.CheckResponse{ + Allowed: apiV1beta1.CheckResponse_ALLOWED_FALSE, + CheckedAt: resp.GetCheckedAt(), // returned zookie may not be same as created zookie. + } + assert.Equal(t, &checkResponse, resp) + + // zed permission check rbac/workspace:test user_grant rbac/principal:u2 --explain + u2Check.Zookie = respDelete.GetDeletedAt() + resp, err = spiceDbRepo.Check(ctx, &u2Check) + if !assert.NoError(t, err) { + return + } + //apiV1.CheckResponse_ALLOWED_TRUE + checkResponse = apiV1beta1.CheckResponse{ + Allowed: apiV1beta1.CheckResponse_ALLOWED_TRUE, + CheckedAt: resp.GetCheckedAt(), // returned zookie may not be same as created zookie. + } + assert.Equal(t, &checkResponse, resp) +} + +func TestSpiceDbRepository_NewEnemyProblem_Failure(t *testing.T) { + t.Parallel() + + ctx := context.Background() + spiceDbRepo, err := container.CreateSpiceDbRepository() + if !assert.NoError(t, err) { + return + } + + rels := []*apiV1beta1.Relationship{ + createRelationship("rbac", "group", "bob_club", "member", "rbac", "principal", "bob", ""), + createRelationship("rbac", "workspace", "test", "user_grant", "rbac", "role_binding", "rb_test", ""), + createRelationship("rbac", "role_binding", "rb_test", "granted", "rbac", "role", "rl1", ""), + createRelationship("rbac", "role_binding", "rb_test", "subject", "rbac", "principal", "u1", ""), + createRelationship("rbac", "role_binding", "rb_test", "subject", "rbac", "principal", "u2", ""), + createRelationship("rbac", "role", "rl1", "view_widget", "rbac", "principal", "*", ""), + } + + relationshipResp, err := spiceDbRepo.CreateRelationships(ctx, rels, biz.TouchSemantics(true)) + if !assert.NoError(t, err) { + return + } + + // u1 + u1Check := apiV1beta1.CheckRequest{ + Subject: &apiV1beta1.SubjectReference{ + Subject: &apiV1beta1.ObjectReference{ + Type: &apiV1beta1.ObjectType{ + Name: "principal", Namespace: "rbac", + }, + Id: "u1", + }, + }, + Relation: "view_widget", + Resource: &apiV1beta1.ObjectReference{ + Type: &apiV1beta1.ObjectType{ + Name: "workspace", Namespace: "rbac", + }, + Id: "test", + }, + Zookie: relationshipResp.GetCreatedAt(), // pass createdAt zookie + } + + // u2 + u2Check := apiV1beta1.CheckRequest{ + Subject: &apiV1beta1.SubjectReference{ + Subject: &apiV1beta1.ObjectReference{ + Type: &apiV1beta1.ObjectType{ + Name: "principal", Namespace: "rbac", + }, + Id: "u2", + }, + }, + Relation: "view_widget", + Resource: &apiV1beta1.ObjectReference{ + Type: &apiV1beta1.ObjectType{ + Name: "workspace", Namespace: "rbac", + }, + Id: "test", + }, + Zookie: relationshipResp.GetCreatedAt(), // pass createdAt zookie + } + + // remove access from u1, keep access for u2. + _, err = spiceDbRepo.DeleteRelationships(ctx, &apiV1beta1.RelationTupleFilter{ + ResourceId: pointerize("rb_test"), + ResourceNamespace: pointerize("rbac"), + ResourceType: pointerize("role_binding"), + Relation: pointerize("subject"), + SubjectFilter: &apiV1beta1.SubjectFilter{ + SubjectId: pointerize("u1"), + SubjectNamespace: pointerize("rbac"), + SubjectType: pointerize("principal"), + }, + }) + if !assert.NoError(t, err) { + return + } + + // u1 has access even though we removed access. u2 still has access. + + // zed permission check rbac/workspace:test user_grant rbac/principal:u1 --explain + resp, err := spiceDbRepo.Check(ctx, &u1Check) // we're passing a zookie revision before deletion occurred. + if !assert.NoError(t, err) { + return + } + //apiV1.CheckResponse_ALLOWED_TRUE + checkResponse := apiV1beta1.CheckResponse{ + Allowed: apiV1beta1.CheckResponse_ALLOWED_TRUE, + CheckedAt: resp.GetCheckedAt(), // returned zookie may not be same as created zookie. + } + + if spiceDbRepo.fullyConsistent { // new enemy problem doesn't apply if we're fully consistent. + checkResponse.Allowed = apiV1beta1.CheckResponse_ALLOWED_FALSE + assert.Equal(t, &checkResponse, resp) + } else { // we technically dont have access, but according to zookie revision we do! + assert.Equal(t, &checkResponse, resp) // we expect true even with removed access. + } + + // zed permission check rbac/workspace:test user_grant rbac/principal:u2 --explain + resp, err = spiceDbRepo.Check(ctx, &u2Check) + if !assert.NoError(t, err) { + return + } + //apiV1.CheckResponse_ALLOWED_TRUE + checkResponse = apiV1beta1.CheckResponse{ + Allowed: apiV1beta1.CheckResponse_ALLOWED_TRUE, + CheckedAt: resp.GetCheckedAt(), // returned zookie may not be same as created zookie. + } + assert.Equal(t, &checkResponse, resp) +} + func pointerize(value string) *string { //Used to turn string literals into pointers return &value } @@ -727,9 +1191,12 @@ func runSpiceDBCheck(t *testing.T, ctx context.Context, spiceDbRepo *SpiceDbRepo resp, err := spiceDbRepo.Check(ctx, &check) assert.NoError(t, err) + dummyZookie := "AAAAAAAAHHHHH" expectedResponse := apiV1beta1.CheckResponse{ - Allowed: expectedAllowed, + Allowed: expectedAllowed, + CheckedAt: &apiV1beta1.Zookie{Token: dummyZookie}, } + resp.CheckedAt = &apiV1beta1.Zookie{Token: dummyZookie} assert.Equal(t, &expectedResponse, resp) } diff --git a/internal/service/check.go b/internal/service/check.go index 361530e9..a41bde18 100644 --- a/internal/service/check.go +++ b/internal/service/check.go @@ -13,14 +13,16 @@ import ( type CheckService struct { pb.UnimplementedKesselCheckServiceServer - check *biz.CheckUsecase - log *log.Helper + check *biz.CheckUsecase + checkForUpdate *biz.CheckForUpdateUsecase + log *log.Helper } -func NewCheckService(logger log.Logger, checkUseCase *biz.CheckUsecase) *CheckService { +func NewCheckService(logger log.Logger, checkUseCase *biz.CheckUsecase, checkForUpdateUseCase *biz.CheckForUpdateUsecase) *CheckService { return &CheckService{ - check: checkUseCase, - log: log.NewHelper(logger), + check: checkUseCase, + checkForUpdate: checkForUpdateUseCase, + log: log.NewHelper(logger), } } @@ -31,3 +33,11 @@ func (s *CheckService) Check(ctx context.Context, req *pb.CheckRequest) (*pb.Che } return resp, nil } + +func (s *CheckService) CheckForUpdate(ctx context.Context, req *pb.CheckForUpdateRequest) (*pb.CheckForUpdateResponse, error) { + resp, err := s.checkForUpdate.CheckForUpdate(ctx, req) + if err != nil { + return resp, fmt.Errorf("failed to perform checkForUpdate: %w", err) + } + return resp, nil +} diff --git a/internal/service/lookup.go b/internal/service/lookup.go index ced3089d..6562d57b 100644 --- a/internal/service/lookup.go +++ b/internal/service/lookup.go @@ -37,6 +37,7 @@ func (s *LookupService) LookupSubjects(req *pb.LookupSubjectsRequest, conn pb.Ke err = conn.Send(&pb.LookupSubjectsResponse{ Subject: sub.Subject, Pagination: &pb.ResponsePagination{ContinuationToken: string(sub.Continuation)}, + LookedUpAt: sub.Zookie, }) if err != nil { return fmt.Errorf("error sending retrieved subject to the client: %w", err) @@ -63,6 +64,7 @@ func (s *LookupService) LookupResources(req *pb.LookupResourcesRequest, conn pb. err = conn.Send(&pb.LookupResourcesResponse{ Resource: re.Resource, Pagination: &pb.ResponsePagination{ContinuationToken: string(re.Continuation)}, + LookedUpAt: re.Zookie, }) if err != nil { return fmt.Errorf("error sending retrieved resource to the client: %w", err) diff --git a/internal/service/lookup_test.go b/internal/service/lookup_test.go index 5fcf1ec1..5a7ed09f 100644 --- a/internal/service/lookup_test.go +++ b/internal/service/lookup_test.go @@ -21,7 +21,7 @@ func TestLookupService_LookupSubjects_NoResults(t *testing.T) { spicedb, err := container.CreateSpiceDbRepository() assert.NoError(t, err) - err = seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") + _, err = seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") assert.NoError(t, err) container.WaitForQuantizationInterval() @@ -39,13 +39,37 @@ func TestLookupService_LookupSubjects_NoResults(t *testing.T) { assert.Empty(t, results) } +func TestLookupService_LookupSubjects_NoResults_WithZookie(t *testing.T) { + t.Parallel() + ctx := context.TODO() + spicedb, err := container.CreateSpiceDbRepository() + assert.NoError(t, err) + + resp, err := seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") + assert.NoError(t, err) + + service := createLookupService(spicedb) + + responseCollector := NewLookup_SubjectsServerStub(ctx) + err = service.LookupSubjects(&v1beta1.LookupSubjectsRequest{ + SubjectType: rbac_ns_type("principal"), + Relation: "view", + Resource: &v1beta1.ObjectReference{Type: rbac_ns_type("widget"), Id: "thing1"}, + Zookie: resp.GetCreatedAt(), + }, responseCollector) + assert.NoError(t, err) + results := responseCollector.GetResponses() + + assert.Empty(t, results) +} + func TestLookupService_LookupResources_NoResults(t *testing.T) { t.Parallel() ctx := context.TODO() spicedb, err := container.CreateSpiceDbRepository() assert.NoError(t, err) - err = seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") + _, err = seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") assert.NoError(t, err) container.WaitForQuantizationInterval() @@ -66,15 +90,42 @@ func TestLookupService_LookupResources_NoResults(t *testing.T) { assert.Empty(t, results) } +func TestLookupService_LookupResources_NoResults_WithZookie(t *testing.T) { + t.Parallel() + ctx := context.TODO() + spicedb, err := container.CreateSpiceDbRepository() + assert.NoError(t, err) + + resp, err := seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") + assert.NoError(t, err) + + service := createLookupService(spicedb) + + responseCollector := NewLookup_ResourcesServerStub(ctx) + err = service.LookupResources(&v1beta1.LookupResourcesRequest{ + Subject: &v1beta1.SubjectReference{Subject: &v1beta1.ObjectReference{Type: rbac_ns_type("workspace"), Id: "default"}}, + Relation: "view_widget", + ResourceType: &v1beta1.ObjectType{ + Name: "workspace", + Namespace: "rbac", + }, + Zookie: resp.GetCreatedAt(), + }, responseCollector) + assert.NoError(t, err) + results := responseCollector.GetResponses() + + assert.Empty(t, results) +} + func TestLookupService_LookupSubjects_OneResult(t *testing.T) { t.Parallel() ctx := context.TODO() spicedb, err := container.CreateSpiceDbRepository() assert.NoError(t, err) - err = seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") + _, err = seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") assert.NoError(t, err) - err = seedUserWithViewThingInDefaultWorkspace(ctx, spicedb, "u1") + _, err = seedUserWithViewThingInDefaultWorkspace(ctx, spicedb, "u1") assert.NoError(t, err) container.WaitForQuantizationInterval() @@ -92,13 +143,39 @@ func TestLookupService_LookupSubjects_OneResult(t *testing.T) { assert.ElementsMatch(t, []string{"u1"}, ids) } +func TestLookupService_LookupSubjects_OneResult_WithZookie(t *testing.T) { + t.Parallel() + ctx := context.TODO() + spicedb, err := container.CreateSpiceDbRepository() + assert.NoError(t, err) + + _, err = seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") + assert.NoError(t, err) + resp, err := seedUserWithViewThingInDefaultWorkspace(ctx, spicedb, "u1") + assert.NoError(t, err) + + service := createLookupService(spicedb) + + responseCollector := NewLookup_SubjectsServerStub(ctx) + err = service.LookupSubjects(&v1beta1.LookupSubjectsRequest{ + SubjectType: rbac_ns_type("principal"), + Relation: "view", + Resource: &v1beta1.ObjectReference{Type: rbac_ns_type("widget"), Id: "thing1"}, + Zookie: resp.GetCreatedAt(), + }, responseCollector) + assert.NoError(t, err) + ids := responseCollector.GetIDs() + + assert.ElementsMatch(t, []string{"u1"}, ids) +} + func TestLookupService_LookupResources_OneResult(t *testing.T) { t.Parallel() ctx := context.TODO() spicedb, err := container.CreateSpiceDbRepository() assert.NoError(t, err) - err = seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") + _, err = seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") assert.NoError(t, err) container.WaitForQuantizationInterval() @@ -118,6 +195,32 @@ func TestLookupService_LookupResources_OneResult(t *testing.T) { assert.ElementsMatch(t, []string{"thing1"}, ids) } +func TestLookupService_LookupResources_OneResult_WithZookie(t *testing.T) { + t.Parallel() + ctx := context.TODO() + spicedb, err := container.CreateSpiceDbRepository() + assert.NoError(t, err) + + resp, err := seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") + assert.NoError(t, err) + + service := createLookupService(spicedb) + + responseCollector := NewLookup_ResourcesServerStub(ctx) + err = service.LookupResources(&v1beta1.LookupResourcesRequest{ + Subject: &v1beta1.SubjectReference{Subject: &v1beta1.ObjectReference{Type: rbac_ns_type("workspace"), Id: "default"}}, + Relation: "workspace", + ResourceType: &v1beta1.ObjectType{ + Name: "widget", + Namespace: "rbac", + }, + Zookie: resp.GetCreatedAt(), + }, responseCollector) + assert.NoError(t, err) + ids := responseCollector.GetIDs() + + assert.ElementsMatch(t, []string{"thing1"}, ids) +} func TestLookupService_LookupResources_TwoResults(t *testing.T) { t.Parallel() @@ -125,9 +228,9 @@ func TestLookupService_LookupResources_TwoResults(t *testing.T) { spicedb, err := container.CreateSpiceDbRepository() assert.NoError(t, err) - err = seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") + _, err = seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") assert.NoError(t, err) - err = seedUserWithViewThingInDefaultWorkspace(ctx, spicedb, "u1") + _, err = seedUserWithViewThingInDefaultWorkspace(ctx, spicedb, "u1") assert.NoError(t, err) container.WaitForQuantizationInterval() @@ -155,11 +258,11 @@ func TestLookupService_LookupSubjects_TwoResults(t *testing.T) { spicedb, err := container.CreateSpiceDbRepository() assert.NoError(t, err) - err = seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") + _, err = seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") assert.NoError(t, err) - err = seedUserWithViewThingInDefaultWorkspace(ctx, spicedb, "u1") + _, err = seedUserWithViewThingInDefaultWorkspace(ctx, spicedb, "u1") assert.NoError(t, err) - err = seedUserWithViewThingInDefaultWorkspace(ctx, spicedb, "u2") + _, err = seedUserWithViewThingInDefaultWorkspace(ctx, spicedb, "u2") assert.NoError(t, err) container.WaitForQuantizationInterval() @@ -177,6 +280,46 @@ func TestLookupService_LookupSubjects_TwoResults(t *testing.T) { assert.ElementsMatch(t, []string{"u1", "u2"}, ids) } +func TestLookupService_LookupSubjectsMissingItems_WithWrongZookie(t *testing.T) { + t.Parallel() + ctx := context.TODO() + spicedb, err := container.CreateSpiceDbRepository() + assert.NoError(t, err) + + resp1, err := seedWidgetInDefaultWorkspace(ctx, spicedb, "thing1") + assert.NoError(t, err) + resp2, err := seedUserWithViewThingInDefaultWorkspace(ctx, spicedb, "u1") + assert.NoError(t, err) + + service := createLookupService(spicedb) + + // using first zookie resp1 we expect missing ids + responseCollector := NewLookup_SubjectsServerStub(ctx) + err = service.LookupSubjects(&v1beta1.LookupSubjectsRequest{ + SubjectType: rbac_ns_type("principal"), + Relation: "view", + Resource: &v1beta1.ObjectReference{Type: rbac_ns_type("widget"), Id: "thing1"}, + Zookie: resp1.GetCreatedAt(), + }, responseCollector) + assert.NoError(t, err) + ids := responseCollector.GetIDs() + + assert.ElementsMatch(t, []string{}, ids) + + // using latest zookie resp2 we expect all ids! + responseCollector = NewLookup_SubjectsServerStub(ctx) + err = service.LookupSubjects(&v1beta1.LookupSubjectsRequest{ + SubjectType: rbac_ns_type("principal"), + Relation: "view", + Resource: &v1beta1.ObjectReference{Type: rbac_ns_type("widget"), Id: "thing1"}, + Zookie: resp2.GetCreatedAt(), + }, responseCollector) + assert.NoError(t, err) + ids = responseCollector.GetIDs() + + assert.ElementsMatch(t, []string{"u1"}, ids) +} + func TestLookupService_LookupResources_IgnoresSubjectRelation(t *testing.T) { t.Parallel() ctx := context.TODO() @@ -184,7 +327,7 @@ func TestLookupService_LookupResources_IgnoresSubjectRelation(t *testing.T) { assert.NoError(t, err) memberRelation := "member" - err = spicedb.CreateRelationships(ctx, []*v1beta1.Relationship{ + _, err = spicedb.CreateRelationships(ctx, []*v1beta1.Relationship{ { Resource: &v1beta1.ObjectReference{Type: rbac_ns_type("role_binding"), Id: "rb1"}, Relation: "subject", @@ -193,7 +336,7 @@ func TestLookupService_LookupResources_IgnoresSubjectRelation(t *testing.T) { }, biz.TouchSemantics(true)) assert.NoError(t, err) - err = spicedb.CreateRelationships(ctx, []*v1beta1.Relationship{ + _, err = spicedb.CreateRelationships(ctx, []*v1beta1.Relationship{ { Resource: &v1beta1.ObjectReference{Type: rbac_ns_type("group"), Id: "g1"}, Relation: "member", @@ -244,7 +387,7 @@ func createLookupService(spicedb *data.SpiceDbRepository) *LookupService { ) return NewLookupService(logger, biz.NewGetSubjectsUseCase(spicedb), biz.NewGetResourcesUseCase(spicedb)) } -func seedWidgetInDefaultWorkspace(ctx context.Context, spicedb *data.SpiceDbRepository, thing string) error { +func seedWidgetInDefaultWorkspace(ctx context.Context, spicedb *data.SpiceDbRepository, thing string) (*v1beta1.CreateTuplesResponse, error) { return spicedb.CreateRelationships(ctx, []*v1beta1.Relationship{ { Resource: &v1beta1.ObjectReference{Type: rbac_ns_type("widget"), Id: thing}, @@ -254,7 +397,7 @@ func seedWidgetInDefaultWorkspace(ctx context.Context, spicedb *data.SpiceDbRepo }, biz.TouchSemantics(true)) } -func seedUserWithViewThingInDefaultWorkspace(ctx context.Context, spicedb *data.SpiceDbRepository, user string) error { +func seedUserWithViewThingInDefaultWorkspace(ctx context.Context, spicedb *data.SpiceDbRepository, user string) (*v1beta1.CreateTuplesResponse, error) { return spicedb.CreateRelationships(ctx, []*v1beta1.Relationship{ { Resource: &v1beta1.ObjectReference{Type: rbac_ns_type("role"), Id: "viewers"}, diff --git a/internal/service/relationships.go b/internal/service/relationships.go index 1a736d25..33983a65 100644 --- a/internal/service/relationships.go +++ b/internal/service/relationships.go @@ -3,6 +3,7 @@ package service import ( "context" "fmt" + "google.golang.org/grpc" "github.com/project-kessel/relations-api/internal/biz" @@ -32,12 +33,12 @@ func NewRelationshipsService(logger log.Logger, createUseCase *biz.CreateRelatio } func (s *RelationshipsService) CreateTuples(ctx context.Context, req *pb.CreateTuplesRequest) (*pb.CreateTuplesResponse, error) { - err := s.createUsecase.CreateRelationships(ctx, req.Tuples, req.GetUpsert()) //The generated .GetUpsert() defaults to false + resp, err := s.createUsecase.CreateRelationships(ctx, req.Tuples, req.GetUpsert()) //The generated .GetUpsert() defaults to false if err != nil { return nil, fmt.Errorf("error creating tuples: %w", err) } - return &pb.CreateTuplesResponse{}, nil + return &pb.CreateTuplesResponse{CreatedAt: resp.GetCreatedAt()}, nil } func (s *RelationshipsService) ReadTuples(req *pb.ReadTuplesRequest, conn pb.KesselTupleService_ReadTuplesServer) error { @@ -53,6 +54,7 @@ func (s *RelationshipsService) ReadTuples(req *pb.ReadTuplesRequest, conn pb.Kes err = conn.Send(&pb.ReadTuplesResponse{ Tuple: rel.Relationship, Pagination: &pb.ResponsePagination{ContinuationToken: string(rel.Continuation)}, + ReadAt: rel.Zookie, }) if err != nil { return fmt.Errorf("error sending retrieved tuple to the client: %w", err) @@ -68,12 +70,12 @@ func (s *RelationshipsService) ReadTuples(req *pb.ReadTuplesRequest, conn pb.Kes } func (s *RelationshipsService) DeleteTuples(ctx context.Context, req *pb.DeleteTuplesRequest) (*pb.DeleteTuplesResponse, error) { - err := s.deleteUsecase.DeleteRelationships(ctx, req.Filter) + resp, err := s.deleteUsecase.DeleteRelationships(ctx, req.Filter) if err != nil { return nil, fmt.Errorf("error deleting tuples: %w", err) } - return &pb.DeleteTuplesResponse{}, nil + return &pb.DeleteTuplesResponse{DeletedAt: resp.GetDeletedAt()}, nil } func (s *RelationshipsService) ImportBulkTuples(stream grpc.ClientStreamingServer[pb.ImportBulkTuplesRequest, pb.ImportBulkTuplesResponse]) error { diff --git a/internal/service/relationships_test.go b/internal/service/relationships_test.go index 3a096aca..a392e55d 100644 --- a/internal/service/relationships_test.go +++ b/internal/service/relationships_test.go @@ -92,6 +92,53 @@ func TestRelationshipsService_CreateRelationships(t *testing.T) { } +func TestRelationshipsService_CreateRelationships_WithZookie(t *testing.T) { + t.Parallel() + err, relationshipsService := setup(t) + assert.NoError(t, err) + ctx := context.Background() + expected := createRelationship(rbac_ns_type("group"), "bob_club", "member", rbac_ns_type("principal"), "bob", "") + + req := &v1beta1.CreateTuplesRequest{ + Tuples: []*v1beta1.Relationship{ + expected, + }, + } + reqCopy := proto.Clone(req) + resp, err := relationshipsService.CreateTuples(ctx, reqCopy.(*v1beta1.CreateTuplesRequest)) + assert.NoError(t, err) + + readReq := &v1beta1.ReadTuplesRequest{Filter: &v1beta1.RelationTupleFilter{ + ResourceId: pointerize("bob_club"), + ResourceNamespace: pointerize("rbac"), + ResourceType: pointerize("group"), + Relation: pointerize("member"), + SubjectFilter: &v1beta1.SubjectFilter{ + SubjectId: pointerize("bob"), + SubjectNamespace: pointerize("rbac"), + SubjectType: pointerize("principal"), + }, + }, + Zookie: resp.GetCreatedAt(), + } + collectingServer := NewRelationships_ReadRelationshipsServerStub(ctx) + err = relationshipsService.ReadTuples(readReq, collectingServer) + if err != nil { + t.FailNow() + } + responseRelationships := collectingServer.responses + + for _, resp := range responseRelationships { + assert.Equal(t, expected.Resource.Id, resp.Tuple.Resource.Id) + assert.Equal(t, expected.Resource.Type.Namespace, resp.Tuple.Resource.Type.Namespace) + assert.Equal(t, expected.Resource.Type.Name, resp.Tuple.Resource.Type.Name) + assert.Equal(t, expected.Subject.Subject.Id, resp.Tuple.Subject.Subject.Id) + assert.Equal(t, expected.Subject.Subject.Type.Namespace, resp.Tuple.Subject.Subject.Type.Namespace) + assert.Equal(t, expected.Subject.Subject.Type.Name, resp.Tuple.Subject.Subject.Type.Name) + assert.Equal(t, expected.Relation, resp.Tuple.Relation) + } +} + func TestRelationshipsService_CreateRelationshipsWithTouchFalse(t *testing.T) { t.Parallel() err, relationshipsService := setup(t) @@ -254,6 +301,61 @@ func TestRelationshipsService_DeleteRelationships(t *testing.T) { assert.NoError(t, err) } +func TestRelationshipsService_DeleteRelationships_WithZookie(t *testing.T) { + t.Parallel() + err, relationshipsService := setup(t) + assert.NoError(t, err) + + expected := createRelationship(rbac_ns_type("group"), "bob_club", "member", rbac_ns_type("principal"), "bob", "") + + ctx := context.Background() + req := &v1beta1.CreateTuplesRequest{ + Tuples: []*v1beta1.Relationship{ + expected, + }, + } + _, err = relationshipsService.CreateTuples(ctx, req) + assert.NoError(t, err) + + delreq := &v1beta1.DeleteTuplesRequest{Filter: &v1beta1.RelationTupleFilter{ + ResourceId: pointerize("bob_club"), + ResourceNamespace: pointerize("rbac"), + ResourceType: pointerize("group"), + Relation: pointerize("member"), + SubjectFilter: &v1beta1.SubjectFilter{ + SubjectId: pointerize("bob"), + SubjectNamespace: pointerize("rbac"), + SubjectType: pointerize("principal"), + }, + }} + resp, err := relationshipsService.DeleteTuples(ctx, delreq) + assert.NoError(t, err) + + readReq := &v1beta1.ReadTuplesRequest{Filter: &v1beta1.RelationTupleFilter{ + ResourceId: pointerize("bob_club"), + ResourceNamespace: pointerize("rbac"), + ResourceType: pointerize("group"), + Relation: pointerize("member"), + SubjectFilter: &v1beta1.SubjectFilter{ + SubjectId: pointerize("bob"), + SubjectNamespace: pointerize("rbac"), + SubjectType: pointerize("principal"), + }, + }, + Zookie: resp.GetDeletedAt(), + } + + collectingServer := NewRelationships_ReadRelationshipsServerStub(ctx) + err = relationshipsService.ReadTuples(readReq, collectingServer) + if err != nil { + t.FailNow() + } + responses := collectingServer.responses + + assert.Equal(t, 0, len(responses)) + assert.NoError(t, err) +} + func setup(t *testing.T) (error, *RelationshipsService) { logger := log.With(log.NewStdLogger(os.Stdout), "ts", log.DefaultTimestamp, diff --git a/openapi.yaml b/openapi.yaml index ac9c016e..8cf57d08 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -49,6 +49,24 @@ paths: application/json: schema: $ref: '#/components/schemas/kessel.relations.v1beta1.CheckResponse' + /v1beta1/checkforupdate: + post: + tags: + - KesselCheckService + operationId: KesselCheckService_CheckForUpdate + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/kessel.relations.v1beta1.CheckForUpdateRequest' + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/kessel.relations.v1beta1.CheckForUpdateResponse' /v1beta1/resources: get: tags: @@ -95,6 +113,10 @@ paths: in: query schema: type: string + - name: zookie.token + in: query + schema: + type: string responses: "200": description: OK @@ -145,6 +167,10 @@ paths: in: query schema: type: string + - name: zookie.token + in: query + schema: + type: string responses: "200": description: OK @@ -199,6 +225,10 @@ paths: in: query schema: type: string + - name: zookie.token + in: query + schema: + type: string responses: "200": description: OK @@ -303,6 +333,23 @@ components: code: type: integer format: uint32 + kessel.relations.v1beta1.CheckForUpdateRequest: + type: object + properties: + resource: + $ref: '#/components/schemas/kessel.relations.v1beta1.ObjectReference' + relation: + type: string + subject: + $ref: '#/components/schemas/kessel.relations.v1beta1.SubjectReference' + kessel.relations.v1beta1.CheckForUpdateResponse: + type: object + properties: + allowed: + type: integer + format: enum + checkedAt: + $ref: '#/components/schemas/kessel.relations.v1beta1.Zookie' kessel.relations.v1beta1.CheckRequest: type: object properties: @@ -312,12 +359,16 @@ components: type: string subject: $ref: '#/components/schemas/kessel.relations.v1beta1.SubjectReference' + zookie: + $ref: '#/components/schemas/kessel.relations.v1beta1.Zookie' kessel.relations.v1beta1.CheckResponse: type: object properties: allowed: type: integer format: enum + checkedAt: + $ref: '#/components/schemas/kessel.relations.v1beta1.Zookie' kessel.relations.v1beta1.CreateTuplesRequest: type: object properties: @@ -333,10 +384,14 @@ components: $ref: '#/components/schemas/kessel.relations.v1beta1.Relationship' kessel.relations.v1beta1.CreateTuplesResponse: type: object - properties: {} + properties: + createdAt: + $ref: '#/components/schemas/kessel.relations.v1beta1.Zookie' kessel.relations.v1beta1.DeleteTuplesResponse: type: object - properties: {} + properties: + deletedAt: + $ref: '#/components/schemas/kessel.relations.v1beta1.Zookie' kessel.relations.v1beta1.ImportBulkTuplesRequest: type: object properties: @@ -356,6 +411,8 @@ components: $ref: '#/components/schemas/kessel.relations.v1beta1.ObjectReference' pagination: $ref: '#/components/schemas/kessel.relations.v1beta1.ResponsePagination' + lookedUpAt: + $ref: '#/components/schemas/kessel.relations.v1beta1.Zookie' kessel.relations.v1beta1.LookupSubjectsResponse: type: object properties: @@ -363,6 +420,8 @@ components: $ref: '#/components/schemas/kessel.relations.v1beta1.SubjectReference' pagination: $ref: '#/components/schemas/kessel.relations.v1beta1.ResponsePagination' + lookedUpAt: + $ref: '#/components/schemas/kessel.relations.v1beta1.Zookie' kessel.relations.v1beta1.ObjectReference: type: object properties: @@ -384,6 +443,8 @@ components: $ref: '#/components/schemas/kessel.relations.v1beta1.Relationship' pagination: $ref: '#/components/schemas/kessel.relations.v1beta1.ResponsePagination' + readAt: + $ref: '#/components/schemas/kessel.relations.v1beta1.Zookie' kessel.relations.v1beta1.Relationship: type: object properties: @@ -410,6 +471,12 @@ components: subject: $ref: '#/components/schemas/kessel.relations.v1beta1.ObjectReference' description: A reference to a Subject or, if a `relation` is provided, a Subject Set. + kessel.relations.v1beta1.Zookie: + type: object + properties: + token: + type: string + description: The Zookie is used to provide consistency between write and read requests. tags: - name: KesselCheckService - name: KesselLookupService