mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Zanzana: Search with check server side (#96268)
* pass zclient into dashboard service * Search then check implementation * Use GetNamespace() for user * remove unused orgID * simple batch check * refactor * add tests * fix batchCheckItem * client implements batch check * use batch check in search * remove unused * remove All field from response * refactor: extract checkNamespace * fix search result uniqueness * comment fix * Apply suggestions from code review Co-authored-by: Karl Persson <kalle.persson@grafana.com> * refactor * cleanup * remove unnecessary check * fix tests * fix protobuf def * Fix query page * fix type --------- Co-authored-by: Karl Persson <kalle.persson@grafana.com>
This commit is contained in:
parent
78930314c3
commit
1366197522
@ -838,14 +838,14 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
|
||||
if dashboardService == nil {
|
||||
dashboardService, err = service.ProvideDashboardServiceImpl(
|
||||
cfg, dashboardStore, folderStore, features, folderPermissions, dashboardPermissions,
|
||||
ac, folderSvc, fStore, nil,
|
||||
ac, folderSvc, fStore, nil, zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
dashboardProvisioningService, err := service.ProvideDashboardServiceImpl(
|
||||
cfg, dashboardStore, folderStore, features, folderPermissions, dashboardPermissions,
|
||||
ac, folderSvc, fStore, nil,
|
||||
ac, folderSvc, fStore, nil, zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -478,7 +478,7 @@ func setupServer(b testing.TB, sc benchScenario, features featuremgmt.FeatureTog
|
||||
dashboardSvc, err := dashboardservice.ProvideDashboardServiceImpl(
|
||||
sc.cfg, dashStore, folderStore,
|
||||
features, folderPermissions, dashboardPermissions, ac,
|
||||
folderServiceWithFlagOn, fStore, nil,
|
||||
folderServiceWithFlagOn, fStore, nil, zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(b, err)
|
||||
|
||||
|
@ -769,6 +769,242 @@ func (*WriteResponse) Descriptor() ([]byte, []int) {
|
||||
return file_extention_proto_rawDescGZIP(), []int{12}
|
||||
}
|
||||
|
||||
type BatchCheckRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Subject string `protobuf:"bytes,1,opt,name=subject,proto3" json:"subject,omitempty"`
|
||||
Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
||||
Items []*BatchCheckItem `protobuf:"bytes,3,rep,name=items,proto3" json:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (x *BatchCheckRequest) Reset() {
|
||||
*x = BatchCheckRequest{}
|
||||
mi := &file_extention_proto_msgTypes[13]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *BatchCheckRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BatchCheckRequest) ProtoMessage() {}
|
||||
|
||||
func (x *BatchCheckRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_extention_proto_msgTypes[13]
|
||||
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 BatchCheckRequest.ProtoReflect.Descriptor instead.
|
||||
func (*BatchCheckRequest) Descriptor() ([]byte, []int) {
|
||||
return file_extention_proto_rawDescGZIP(), []int{13}
|
||||
}
|
||||
|
||||
func (x *BatchCheckRequest) GetSubject() string {
|
||||
if x != nil {
|
||||
return x.Subject
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *BatchCheckRequest) GetNamespace() string {
|
||||
if x != nil {
|
||||
return x.Namespace
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *BatchCheckRequest) GetItems() []*BatchCheckItem {
|
||||
if x != nil {
|
||||
return x.Items
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type BatchCheckItem struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Verb string `protobuf:"bytes,1,opt,name=verb,proto3" json:"verb,omitempty"`
|
||||
Group string `protobuf:"bytes,2,opt,name=group,proto3" json:"group,omitempty"`
|
||||
Resource string `protobuf:"bytes,3,opt,name=resource,proto3" json:"resource,omitempty"`
|
||||
Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Subresource string `protobuf:"bytes,5,opt,name=subresource,proto3" json:"subresource,omitempty"`
|
||||
Folder string `protobuf:"bytes,6,opt,name=folder,proto3" json:"folder,omitempty"`
|
||||
}
|
||||
|
||||
func (x *BatchCheckItem) Reset() {
|
||||
*x = BatchCheckItem{}
|
||||
mi := &file_extention_proto_msgTypes[14]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *BatchCheckItem) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BatchCheckItem) ProtoMessage() {}
|
||||
|
||||
func (x *BatchCheckItem) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_extention_proto_msgTypes[14]
|
||||
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 BatchCheckItem.ProtoReflect.Descriptor instead.
|
||||
func (*BatchCheckItem) Descriptor() ([]byte, []int) {
|
||||
return file_extention_proto_rawDescGZIP(), []int{14}
|
||||
}
|
||||
|
||||
func (x *BatchCheckItem) GetVerb() string {
|
||||
if x != nil {
|
||||
return x.Verb
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *BatchCheckItem) GetGroup() string {
|
||||
if x != nil {
|
||||
return x.Group
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *BatchCheckItem) GetResource() string {
|
||||
if x != nil {
|
||||
return x.Resource
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *BatchCheckItem) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *BatchCheckItem) GetSubresource() string {
|
||||
if x != nil {
|
||||
return x.Subresource
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *BatchCheckItem) GetFolder() string {
|
||||
if x != nil {
|
||||
return x.Folder
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type BatchCheckResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Groups map[string]*BatchCheckGroupResource `protobuf:"bytes,1,rep,name=groups,proto3" json:"groups,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
}
|
||||
|
||||
func (x *BatchCheckResponse) Reset() {
|
||||
*x = BatchCheckResponse{}
|
||||
mi := &file_extention_proto_msgTypes[15]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *BatchCheckResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BatchCheckResponse) ProtoMessage() {}
|
||||
|
||||
func (x *BatchCheckResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_extention_proto_msgTypes[15]
|
||||
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 BatchCheckResponse.ProtoReflect.Descriptor instead.
|
||||
func (*BatchCheckResponse) Descriptor() ([]byte, []int) {
|
||||
return file_extention_proto_rawDescGZIP(), []int{15}
|
||||
}
|
||||
|
||||
func (x *BatchCheckResponse) GetGroups() map[string]*BatchCheckGroupResource {
|
||||
if x != nil {
|
||||
return x.Groups
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type BatchCheckGroupResource struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Items map[string]bool `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
|
||||
}
|
||||
|
||||
func (x *BatchCheckGroupResource) Reset() {
|
||||
*x = BatchCheckGroupResource{}
|
||||
mi := &file_extention_proto_msgTypes[16]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *BatchCheckGroupResource) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BatchCheckGroupResource) ProtoMessage() {}
|
||||
|
||||
func (x *BatchCheckGroupResource) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_extention_proto_msgTypes[16]
|
||||
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 BatchCheckGroupResource.ProtoReflect.Descriptor instead.
|
||||
func (*BatchCheckGroupResource) Descriptor() ([]byte, []int) {
|
||||
return file_extention_proto_rawDescGZIP(), []int{16}
|
||||
}
|
||||
|
||||
func (x *BatchCheckGroupResource) GetItems() map[string]bool {
|
||||
if x != nil {
|
||||
return x.Items
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_extention_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_extention_proto_rawDesc = []byte{
|
||||
@ -874,27 +1110,74 @@ var file_extention_proto_rawDesc = []byte{
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73,
|
||||
0x22, 0x0f, 0x0a, 0x0d, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x32, 0xfb, 0x01, 0x0a, 0x15, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x45, 0x78, 0x74, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x04, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x1f,
|
||||
0x65, 0x22, 0x85, 0x01, 0x0a, 0x11, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65,
|
||||
0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63,
|
||||
0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12,
|
||||
0x38, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22,
|
||||
0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x20, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x4c, 0x0a, 0x05, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x61, 0x75, 0x74,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x74,
|
||||
0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0xa4, 0x01, 0x0a, 0x0e, 0x42, 0x61,
|
||||
0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04,
|
||||
0x76, 0x65, 0x72, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x76, 0x65, 0x72, 0x62,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x75, 0x62, 0x72, 0x65, 0x73,
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62,
|
||||
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64,
|
||||
0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72,
|
||||
0x22, 0xc8, 0x01, 0x0a, 0x12, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70,
|
||||
0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e,
|
||||
0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74,
|
||||
0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e,
|
||||
0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x67, 0x72, 0x6f,
|
||||
0x75, 0x70, 0x73, 0x1a, 0x66, 0x0a, 0x0b, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x45, 0x6e, 0x74,
|
||||
0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x03, 0x6b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68,
|
||||
0x65, 0x63, 0x6b, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa1, 0x01, 0x0a, 0x17,
|
||||
0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52,
|
||||
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73,
|
||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65,
|
||||
0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63,
|
||||
0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05,
|
||||
0x69, 0x74, 0x65, 0x6d, 0x73, 0x1a, 0x38, 0x0a, 0x0a, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x45, 0x6e,
|
||||
0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32,
|
||||
0xd8, 0x02, 0x0a, 0x15, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x04, 0x4c, 0x69, 0x73,
|
||||
0x74, 0x12, 0x1f, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x0a, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65,
|
||||
0x63, 0x6b, 0x12, 0x25, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65,
|
||||
0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x61, 0x75, 0x74, 0x68,
|
||||
0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42,
|
||||
0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x49, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x1f, 0x2e, 0x61, 0x75, 0x74, 0x68,
|
||||
0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x52,
|
||||
0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x75, 0x74,
|
||||
0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x61,
|
||||
0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42,
|
||||
0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72,
|
||||
0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x6b,
|
||||
0x67, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x7a,
|
||||
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x05,
|
||||
0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78,
|
||||
0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e,
|
||||
0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69,
|
||||
0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61,
|
||||
0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2f, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -909,7 +1192,7 @@ func file_extention_proto_rawDescGZIP() []byte {
|
||||
return file_extention_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_extention_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
|
||||
var file_extention_proto_msgTypes = make([]protoimpl.MessageInfo, 19)
|
||||
var file_extention_proto_goTypes = []any{
|
||||
(*ListRequest)(nil), // 0: authz.extention.v1.ListRequest
|
||||
(*ListResponse)(nil), // 1: authz.extention.v1.ListResponse
|
||||
@ -924,33 +1207,45 @@ var file_extention_proto_goTypes = []any{
|
||||
(*WriteRequestDeletes)(nil), // 10: authz.extention.v1.WriteRequestDeletes
|
||||
(*WriteRequest)(nil), // 11: authz.extention.v1.WriteRequest
|
||||
(*WriteResponse)(nil), // 12: authz.extention.v1.WriteResponse
|
||||
(*timestamppb.Timestamp)(nil), // 13: google.protobuf.Timestamp
|
||||
(*structpb.Struct)(nil), // 14: google.protobuf.Struct
|
||||
(*wrapperspb.Int32Value)(nil), // 15: google.protobuf.Int32Value
|
||||
(*BatchCheckRequest)(nil), // 13: authz.extention.v1.BatchCheckRequest
|
||||
(*BatchCheckItem)(nil), // 14: authz.extention.v1.BatchCheckItem
|
||||
(*BatchCheckResponse)(nil), // 15: authz.extention.v1.BatchCheckResponse
|
||||
(*BatchCheckGroupResource)(nil), // 16: authz.extention.v1.BatchCheckGroupResource
|
||||
nil, // 17: authz.extention.v1.BatchCheckResponse.GroupsEntry
|
||||
nil, // 18: authz.extention.v1.BatchCheckGroupResource.ItemsEntry
|
||||
(*timestamppb.Timestamp)(nil), // 19: google.protobuf.Timestamp
|
||||
(*structpb.Struct)(nil), // 20: google.protobuf.Struct
|
||||
(*wrapperspb.Int32Value)(nil), // 21: google.protobuf.Int32Value
|
||||
}
|
||||
var file_extention_proto_depIdxs = []int32{
|
||||
5, // 0: authz.extention.v1.TupleKey.condition:type_name -> authz.extention.v1.RelationshipCondition
|
||||
2, // 1: authz.extention.v1.Tuple.key:type_name -> authz.extention.v1.TupleKey
|
||||
13, // 2: authz.extention.v1.Tuple.timestamp:type_name -> google.protobuf.Timestamp
|
||||
14, // 3: authz.extention.v1.RelationshipCondition.context:type_name -> google.protobuf.Struct
|
||||
19, // 2: authz.extention.v1.Tuple.timestamp:type_name -> google.protobuf.Timestamp
|
||||
20, // 3: authz.extention.v1.RelationshipCondition.context:type_name -> google.protobuf.Struct
|
||||
7, // 4: authz.extention.v1.ReadRequest.tuple_key:type_name -> authz.extention.v1.ReadRequestTupleKey
|
||||
15, // 5: authz.extention.v1.ReadRequest.page_size:type_name -> google.protobuf.Int32Value
|
||||
21, // 5: authz.extention.v1.ReadRequest.page_size:type_name -> google.protobuf.Int32Value
|
||||
3, // 6: authz.extention.v1.ReadResponse.tuples:type_name -> authz.extention.v1.Tuple
|
||||
2, // 7: authz.extention.v1.WriteRequestWrites.tuple_keys:type_name -> authz.extention.v1.TupleKey
|
||||
4, // 8: authz.extention.v1.WriteRequestDeletes.tuple_keys:type_name -> authz.extention.v1.TupleKeyWithoutCondition
|
||||
9, // 9: authz.extention.v1.WriteRequest.writes:type_name -> authz.extention.v1.WriteRequestWrites
|
||||
10, // 10: authz.extention.v1.WriteRequest.deletes:type_name -> authz.extention.v1.WriteRequestDeletes
|
||||
0, // 11: authz.extention.v1.AuthzExtentionService.List:input_type -> authz.extention.v1.ListRequest
|
||||
6, // 12: authz.extention.v1.AuthzExtentionService.Read:input_type -> authz.extention.v1.ReadRequest
|
||||
11, // 13: authz.extention.v1.AuthzExtentionService.Write:input_type -> authz.extention.v1.WriteRequest
|
||||
1, // 14: authz.extention.v1.AuthzExtentionService.List:output_type -> authz.extention.v1.ListResponse
|
||||
8, // 15: authz.extention.v1.AuthzExtentionService.Read:output_type -> authz.extention.v1.ReadResponse
|
||||
12, // 16: authz.extention.v1.AuthzExtentionService.Write:output_type -> authz.extention.v1.WriteResponse
|
||||
14, // [14:17] is the sub-list for method output_type
|
||||
11, // [11:14] is the sub-list for method input_type
|
||||
11, // [11:11] is the sub-list for extension type_name
|
||||
11, // [11:11] is the sub-list for extension extendee
|
||||
0, // [0:11] is the sub-list for field type_name
|
||||
14, // 11: authz.extention.v1.BatchCheckRequest.items:type_name -> authz.extention.v1.BatchCheckItem
|
||||
17, // 12: authz.extention.v1.BatchCheckResponse.groups:type_name -> authz.extention.v1.BatchCheckResponse.GroupsEntry
|
||||
18, // 13: authz.extention.v1.BatchCheckGroupResource.items:type_name -> authz.extention.v1.BatchCheckGroupResource.ItemsEntry
|
||||
16, // 14: authz.extention.v1.BatchCheckResponse.GroupsEntry.value:type_name -> authz.extention.v1.BatchCheckGroupResource
|
||||
0, // 15: authz.extention.v1.AuthzExtentionService.List:input_type -> authz.extention.v1.ListRequest
|
||||
13, // 16: authz.extention.v1.AuthzExtentionService.BatchCheck:input_type -> authz.extention.v1.BatchCheckRequest
|
||||
6, // 17: authz.extention.v1.AuthzExtentionService.Read:input_type -> authz.extention.v1.ReadRequest
|
||||
11, // 18: authz.extention.v1.AuthzExtentionService.Write:input_type -> authz.extention.v1.WriteRequest
|
||||
1, // 19: authz.extention.v1.AuthzExtentionService.List:output_type -> authz.extention.v1.ListResponse
|
||||
15, // 20: authz.extention.v1.AuthzExtentionService.BatchCheck:output_type -> authz.extention.v1.BatchCheckResponse
|
||||
8, // 21: authz.extention.v1.AuthzExtentionService.Read:output_type -> authz.extention.v1.ReadResponse
|
||||
12, // 22: authz.extention.v1.AuthzExtentionService.Write:output_type -> authz.extention.v1.WriteResponse
|
||||
19, // [19:23] is the sub-list for method output_type
|
||||
15, // [15:19] is the sub-list for method input_type
|
||||
15, // [15:15] is the sub-list for extension type_name
|
||||
15, // [15:15] is the sub-list for extension extendee
|
||||
0, // [0:15] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_extention_proto_init() }
|
||||
@ -964,7 +1259,7 @@ func file_extention_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_extention_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 13,
|
||||
NumMessages: 19,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
@ -10,6 +10,8 @@ import "google/protobuf/wrappers.proto";
|
||||
|
||||
service AuthzExtentionService {
|
||||
rpc List(ListRequest) returns (ListResponse);
|
||||
rpc BatchCheck(BatchCheckRequest) returns (BatchCheckResponse);
|
||||
|
||||
rpc Read(ReadRequest) returns (ReadResponse);
|
||||
rpc Write(WriteRequest) returns (WriteResponse);
|
||||
}
|
||||
@ -86,3 +88,26 @@ message WriteRequest {
|
||||
}
|
||||
|
||||
message WriteResponse {}
|
||||
|
||||
message BatchCheckRequest {
|
||||
string subject = 1;
|
||||
string namespace = 2;
|
||||
repeated BatchCheckItem items = 3;
|
||||
}
|
||||
|
||||
message BatchCheckItem {
|
||||
string verb = 1;
|
||||
string group = 2;
|
||||
string resource = 3;
|
||||
string name = 4;
|
||||
string subresource = 5;
|
||||
string folder = 6;
|
||||
}
|
||||
|
||||
message BatchCheckResponse {
|
||||
map<string, BatchCheckGroupResource> groups = 1;
|
||||
}
|
||||
|
||||
message BatchCheckGroupResource {
|
||||
map<string, bool> items = 1;
|
||||
}
|
||||
|
@ -19,9 +19,10 @@ import (
|
||||
const _ = grpc.SupportPackageIsVersion8
|
||||
|
||||
const (
|
||||
AuthzExtentionService_List_FullMethodName = "/authz.extention.v1.AuthzExtentionService/List"
|
||||
AuthzExtentionService_Read_FullMethodName = "/authz.extention.v1.AuthzExtentionService/Read"
|
||||
AuthzExtentionService_Write_FullMethodName = "/authz.extention.v1.AuthzExtentionService/Write"
|
||||
AuthzExtentionService_List_FullMethodName = "/authz.extention.v1.AuthzExtentionService/List"
|
||||
AuthzExtentionService_BatchCheck_FullMethodName = "/authz.extention.v1.AuthzExtentionService/BatchCheck"
|
||||
AuthzExtentionService_Read_FullMethodName = "/authz.extention.v1.AuthzExtentionService/Read"
|
||||
AuthzExtentionService_Write_FullMethodName = "/authz.extention.v1.AuthzExtentionService/Write"
|
||||
)
|
||||
|
||||
// AuthzExtentionServiceClient is the client API for AuthzExtentionService service.
|
||||
@ -29,6 +30,7 @@ const (
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type AuthzExtentionServiceClient interface {
|
||||
List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error)
|
||||
BatchCheck(ctx context.Context, in *BatchCheckRequest, opts ...grpc.CallOption) (*BatchCheckResponse, error)
|
||||
Read(ctx context.Context, in *ReadRequest, opts ...grpc.CallOption) (*ReadResponse, error)
|
||||
Write(ctx context.Context, in *WriteRequest, opts ...grpc.CallOption) (*WriteResponse, error)
|
||||
}
|
||||
@ -51,6 +53,16 @@ func (c *authzExtentionServiceClient) List(ctx context.Context, in *ListRequest,
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *authzExtentionServiceClient) BatchCheck(ctx context.Context, in *BatchCheckRequest, opts ...grpc.CallOption) (*BatchCheckResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(BatchCheckResponse)
|
||||
err := c.cc.Invoke(ctx, AuthzExtentionService_BatchCheck_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *authzExtentionServiceClient) Read(ctx context.Context, in *ReadRequest, opts ...grpc.CallOption) (*ReadResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ReadResponse)
|
||||
@ -76,6 +88,7 @@ func (c *authzExtentionServiceClient) Write(ctx context.Context, in *WriteReques
|
||||
// for forward compatibility
|
||||
type AuthzExtentionServiceServer interface {
|
||||
List(context.Context, *ListRequest) (*ListResponse, error)
|
||||
BatchCheck(context.Context, *BatchCheckRequest) (*BatchCheckResponse, error)
|
||||
Read(context.Context, *ReadRequest) (*ReadResponse, error)
|
||||
Write(context.Context, *WriteRequest) (*WriteResponse, error)
|
||||
}
|
||||
@ -87,6 +100,9 @@ type UnimplementedAuthzExtentionServiceServer struct {
|
||||
func (UnimplementedAuthzExtentionServiceServer) List(context.Context, *ListRequest) (*ListResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method List not implemented")
|
||||
}
|
||||
func (UnimplementedAuthzExtentionServiceServer) BatchCheck(context.Context, *BatchCheckRequest) (*BatchCheckResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method BatchCheck not implemented")
|
||||
}
|
||||
func (UnimplementedAuthzExtentionServiceServer) Read(context.Context, *ReadRequest) (*ReadResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Read not implemented")
|
||||
}
|
||||
@ -123,6 +139,24 @@ func _AuthzExtentionService_List_Handler(srv interface{}, ctx context.Context, d
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _AuthzExtentionService_BatchCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(BatchCheckRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AuthzExtentionServiceServer).BatchCheck(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: AuthzExtentionService_BatchCheck_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AuthzExtentionServiceServer).BatchCheck(ctx, req.(*BatchCheckRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _AuthzExtentionService_Read_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ReadRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@ -170,6 +204,10 @@ var AuthzExtentionService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "List",
|
||||
Handler: _AuthzExtentionService_List_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "BatchCheck",
|
||||
Handler: _AuthzExtentionService_BatchCheck_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Read",
|
||||
Handler: _AuthzExtentionService_Read_Handler,
|
||||
|
@ -16,6 +16,7 @@ type Client interface {
|
||||
List(ctx context.Context, id claims.AuthInfo, req authz.ListRequest) (*authzextv1.ListResponse, error)
|
||||
Read(ctx context.Context, req *authzextv1.ReadRequest) (*authzextv1.ReadResponse, error)
|
||||
Write(ctx context.Context, req *authzextv1.WriteRequest) error
|
||||
BatchCheck(ctx context.Context, req *authzextv1.BatchCheckRequest) (*authzextv1.BatchCheckResponse, error)
|
||||
}
|
||||
|
||||
func NewNoopClient() *client.NoopClient {
|
||||
|
@ -169,3 +169,10 @@ func (c *Client) Write(ctx context.Context, req *authzextv1.WriteRequest) error
|
||||
_, err := c.authzext.Write(ctx, req)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) BatchCheck(ctx context.Context, req *authzextv1.BatchCheckRequest) (*authzextv1.BatchCheckResponse, error) {
|
||||
ctx, span := tracer.Start(ctx, "authz.zanzana.client.Check")
|
||||
defer span.End()
|
||||
|
||||
return c.authzext.BatchCheck(ctx, req)
|
||||
}
|
||||
|
@ -36,3 +36,7 @@ func (nc NoopClient) Read(ctx context.Context, req *authzextv1.ReadRequest) (*au
|
||||
func (nc NoopClient) Write(ctx context.Context, req *authzextv1.WriteRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nc NoopClient) BatchCheck(ctx context.Context, req *authzextv1.BatchCheckRequest) (*authzextv1.BatchCheckResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
64
pkg/services/authz/zanzana/server/server_batch_check.go
Normal file
64
pkg/services/authz/zanzana/server/server_batch_check.go
Normal file
@ -0,0 +1,64 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
authzv1 "github.com/grafana/authlib/authz/proto/v1"
|
||||
|
||||
authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana/common"
|
||||
)
|
||||
|
||||
func (s *Server) BatchCheck(ctx context.Context, r *authzextv1.BatchCheckRequest) (*authzextv1.BatchCheckResponse, error) {
|
||||
ctx, span := tracer.Start(ctx, "authzServer.BatchCheck")
|
||||
defer span.End()
|
||||
|
||||
batchRes := &authzextv1.BatchCheckResponse{
|
||||
Groups: make(map[string]*authzextv1.BatchCheckGroupResource),
|
||||
}
|
||||
|
||||
subject := r.GetSubject()
|
||||
|
||||
for _, item := range r.Items {
|
||||
groupPrefix := common.FormatGroupResource(item.GetGroup(), item.GetResource())
|
||||
allowed, err := s.batchCheckItem(ctx, subject, r.Namespace, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, ok := batchRes.Groups[groupPrefix]; !ok {
|
||||
batchRes.Groups[groupPrefix] = &authzextv1.BatchCheckGroupResource{
|
||||
Items: make(map[string]bool),
|
||||
}
|
||||
}
|
||||
batchRes.Groups[groupPrefix].Items[item.GetName()] = allowed
|
||||
}
|
||||
|
||||
return batchRes, nil
|
||||
}
|
||||
|
||||
func (s *Server) batchCheckItem(ctx context.Context, subject string, namespace string, item *authzextv1.BatchCheckItem) (bool, error) {
|
||||
req := &authzv1.CheckRequest{
|
||||
Namespace: namespace,
|
||||
Subject: subject,
|
||||
Verb: item.GetVerb(),
|
||||
Group: item.GetGroup(),
|
||||
Resource: item.GetResource(),
|
||||
Name: item.GetName(),
|
||||
Folder: item.GetFolder(),
|
||||
Subresource: item.GetSubresource(),
|
||||
}
|
||||
|
||||
var res *authzv1.CheckResponse
|
||||
var err error
|
||||
if info, ok := common.GetTypeInfo(item.GetGroup(), item.GetResource()); ok {
|
||||
res, err = s.checkTyped(ctx, req, info)
|
||||
} else {
|
||||
res, err = s.checkGeneric(ctx, req)
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return res.Allowed, nil
|
||||
}
|
120
pkg/services/authz/zanzana/server/server_batch_check_test.go
Normal file
120
pkg/services/authz/zanzana/server/server_batch_check_test.go
Normal file
@ -0,0 +1,120 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
)
|
||||
|
||||
func newBatch(subject, group, resource string, items []*authzextv1.BatchCheckItem) *authzextv1.BatchCheckRequest {
|
||||
for i, item := range items {
|
||||
items[i] = &authzextv1.BatchCheckItem{
|
||||
Verb: utils.VerbGet,
|
||||
Group: group,
|
||||
Resource: resource,
|
||||
Name: item.GetName(),
|
||||
Folder: item.GetFolder(),
|
||||
}
|
||||
}
|
||||
|
||||
return &authzextv1.BatchCheckRequest{
|
||||
Namespace: "default",
|
||||
Subject: subject,
|
||||
Items: items,
|
||||
}
|
||||
}
|
||||
|
||||
func testBatchCheck(t *testing.T, server *Server) {
|
||||
t.Run("user:1 should only be able to read resource:dashboards.grafana.app/dashboards/1", func(t *testing.T) {
|
||||
groupPrefix := zanzana.FormatGroupResource(dashboardGroup, dashboardResource)
|
||||
res, err := server.BatchCheck(context.Background(), newBatch("user:1", dashboardGroup, dashboardResource, []*authzextv1.BatchCheckItem{
|
||||
{Name: "1", Folder: "1"},
|
||||
{Name: "2", Folder: "2"},
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, res.Groups[groupPrefix].Items, 2)
|
||||
|
||||
assert.True(t, res.Groups[groupPrefix].Items["1"])
|
||||
assert.False(t, res.Groups[groupPrefix].Items["2"])
|
||||
})
|
||||
|
||||
t.Run("user:2 should be able to read resource:dashboards.grafana.app/dashboards/{1,2} through namespace", func(t *testing.T) {
|
||||
groupPrefix := zanzana.FormatGroupResource(dashboardGroup, dashboardResource)
|
||||
res, err := server.BatchCheck(context.Background(), newBatch("user:2", dashboardGroup, dashboardResource, []*authzextv1.BatchCheckItem{
|
||||
{Name: "1", Folder: "1"},
|
||||
{Name: "2", Folder: "2"},
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, res.Groups[groupPrefix].Items, 2)
|
||||
})
|
||||
|
||||
t.Run("user:3 should be able to read resource:dashboards.grafana.app/dashboards/1 with set relation", func(t *testing.T) {
|
||||
groupPrefix := zanzana.FormatGroupResource(dashboardGroup, dashboardResource)
|
||||
res, err := server.BatchCheck(context.Background(), newBatch("user:3", dashboardGroup, dashboardResource, []*authzextv1.BatchCheckItem{
|
||||
{Name: "1", Folder: "1"},
|
||||
{Name: "2", Folder: "2"},
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, res.Groups[groupPrefix].Items, 2)
|
||||
|
||||
assert.True(t, res.Groups[groupPrefix].Items["1"])
|
||||
assert.False(t, res.Groups[groupPrefix].Items["2"])
|
||||
})
|
||||
|
||||
t.Run("user:4 should be able to read all dashboards.grafana.app/dashboards in folder 1 and 3", func(t *testing.T) {
|
||||
groupPrefix := zanzana.FormatGroupResource(dashboardGroup, dashboardResource)
|
||||
res, err := server.BatchCheck(context.Background(), newBatch("user:4", dashboardGroup, dashboardResource, []*authzextv1.BatchCheckItem{
|
||||
{Name: "1", Folder: "1"},
|
||||
{Name: "2", Folder: "3"},
|
||||
{Name: "3", Folder: "2"},
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, res.Groups[groupPrefix].Items, 3)
|
||||
|
||||
assert.True(t, res.Groups[groupPrefix].Items["1"])
|
||||
assert.True(t, res.Groups[groupPrefix].Items["2"])
|
||||
assert.False(t, res.Groups[groupPrefix].Items["3"])
|
||||
})
|
||||
|
||||
t.Run("user:5 should be able to read resource:dashboards.grafana.app/dashboards/1 through folder with set relation", func(t *testing.T) {
|
||||
groupPrefix := zanzana.FormatGroupResource(dashboardGroup, dashboardResource)
|
||||
res, err := server.BatchCheck(context.Background(), newBatch("user:5", dashboardGroup, dashboardResource, []*authzextv1.BatchCheckItem{
|
||||
{Name: "1", Folder: "1"},
|
||||
{Name: "2", Folder: "2"},
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, res.Groups[groupPrefix].Items, 2)
|
||||
|
||||
assert.True(t, res.Groups[groupPrefix].Items["1"])
|
||||
assert.False(t, res.Groups[groupPrefix].Items["2"])
|
||||
})
|
||||
|
||||
t.Run("user:6 should be able to read folder 1", func(t *testing.T) {
|
||||
groupPrefix := zanzana.FormatGroupResource(folderGroup, folderResource)
|
||||
res, err := server.BatchCheck(context.Background(), newBatch("user:6", folderGroup, folderResource, []*authzextv1.BatchCheckItem{
|
||||
{Name: "1"},
|
||||
{Name: "2"},
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, res.Groups[groupPrefix].Items, 2)
|
||||
|
||||
assert.True(t, res.Groups[groupPrefix].Items["1"])
|
||||
assert.False(t, res.Groups[groupPrefix].Items["2"])
|
||||
})
|
||||
|
||||
t.Run("user:7 should be able to read folder {1,2} through namespace access", func(t *testing.T) {
|
||||
groupPrefix := zanzana.FormatGroupResource(folderGroup, folderResource)
|
||||
res, err := server.BatchCheck(context.Background(), newBatch("user:7", folderGroup, folderResource, []*authzextv1.BatchCheckItem{
|
||||
{Name: "1"},
|
||||
{Name: "2"},
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, res.Groups[groupPrefix].Items, 2)
|
||||
})
|
||||
}
|
@ -20,6 +20,31 @@ func (s *Server) Check(ctx context.Context, r *authzv1.CheckRequest) (*authzv1.C
|
||||
return s.checkGeneric(ctx, r)
|
||||
}
|
||||
|
||||
// checkNamespace checks if subject has access through namespace
|
||||
func (s *Server) checkNamespace(ctx context.Context, r *authzv1.CheckRequest) (*authzv1.CheckResponse, error) {
|
||||
storeInf, err := s.getStoreInfo(ctx, r.Namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
relation := common.VerbMapping[r.GetVerb()]
|
||||
|
||||
res, err := s.openfga.Check(ctx, &openfgav1.CheckRequest{
|
||||
StoreId: storeInf.Id,
|
||||
AuthorizationModelId: storeInf.AuthorizationModelId,
|
||||
TupleKey: &openfgav1.CheckRequestTupleKey{
|
||||
User: r.GetSubject(),
|
||||
Relation: relation,
|
||||
Object: common.NewNamespaceResourceIdent(r.GetGroup(), r.GetResource()),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &authzv1.CheckResponse{Allowed: res.GetAllowed()}, nil
|
||||
}
|
||||
|
||||
func (s *Server) checkTyped(ctx context.Context, r *authzv1.CheckRequest, info common.TypeInfo) (*authzv1.CheckResponse, error) {
|
||||
storeInf, err := s.getStoreInfo(ctx, r.Namespace)
|
||||
if err != nil {
|
||||
@ -47,20 +72,12 @@ func (s *Server) checkTyped(ctx context.Context, r *authzv1.CheckRequest, info c
|
||||
}
|
||||
|
||||
// 2. check if subject has access through namespace
|
||||
res, err = s.openfga.Check(ctx, &openfgav1.CheckRequest{
|
||||
StoreId: storeInf.Id,
|
||||
AuthorizationModelId: storeInf.AuthorizationModelId,
|
||||
TupleKey: &openfgav1.CheckRequestTupleKey{
|
||||
User: r.GetSubject(),
|
||||
Relation: relation,
|
||||
Object: common.NewNamespaceResourceIdent(r.GetGroup(), r.GetResource()),
|
||||
},
|
||||
})
|
||||
nsRes, err := s.checkNamespace(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &authzv1.CheckResponse{Allowed: res.GetAllowed()}, nil
|
||||
return &authzv1.CheckResponse{Allowed: nsRes.GetAllowed()}, nil
|
||||
}
|
||||
|
||||
func (s *Server) checkGeneric(ctx context.Context, r *authzv1.CheckRequest) (*authzv1.CheckResponse, error) {
|
||||
@ -96,21 +113,12 @@ func (s *Server) checkGeneric(ctx context.Context, r *authzv1.CheckRequest) (*au
|
||||
}
|
||||
|
||||
// 2. check if subject has access through namespace
|
||||
res, err = s.openfga.Check(ctx, &openfgav1.CheckRequest{
|
||||
StoreId: storeInf.Id,
|
||||
AuthorizationModelId: storeInf.AuthorizationModelId,
|
||||
TupleKey: &openfgav1.CheckRequestTupleKey{
|
||||
User: r.GetSubject(),
|
||||
Relation: relation,
|
||||
Object: common.NewNamespaceResourceIdent(r.GetGroup(), r.GetResource()),
|
||||
},
|
||||
})
|
||||
|
||||
nsRes, err := s.checkNamespace(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if res.GetAllowed() {
|
||||
if nsRes.GetAllowed() {
|
||||
return &authzv1.CheckResponse{Allowed: true}, nil
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,10 @@ func TestIntegrationServer(t *testing.T) {
|
||||
t.Run("test list", func(t *testing.T) {
|
||||
testList(t, srv)
|
||||
})
|
||||
|
||||
t.Run("test batch check", func(t *testing.T) {
|
||||
testBatchCheck(t, srv)
|
||||
})
|
||||
}
|
||||
|
||||
func setup(t *testing.T, testDB db.DB, cfg *setting.Cfg) *Server {
|
||||
|
@ -83,6 +83,8 @@ var (
|
||||
ToOpenFGATuples = common.ToOpenFGATuples
|
||||
ToOpenFGATupleKey = common.ToOpenFGATupleKey
|
||||
ToOpenFGATupleKeyWithoutCondition = common.ToOpenFGATupleKeyWithoutCondition
|
||||
|
||||
FormatGroupResource = common.FormatGroupResource
|
||||
)
|
||||
|
||||
// NewTupleEntry constructs new openfga entry type:name[#relation].
|
||||
@ -166,6 +168,14 @@ func TranslateToCheckRequest(namespace, action, kind, folder, name string) (*aut
|
||||
return req, true
|
||||
}
|
||||
|
||||
func TranslateToGroupResource(kind string) string {
|
||||
translation, ok := resourceTranslations[kind]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return common.FormatGroupResource(translation.group, translation.resource)
|
||||
}
|
||||
|
||||
func TranslateBasicRole(name string) string {
|
||||
return basicRolesTranslations[name]
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
@ -59,6 +60,7 @@ type DashboardServiceImpl struct {
|
||||
folderPermissions accesscontrol.FolderPermissionsService
|
||||
dashboardPermissions accesscontrol.DashboardPermissionsService
|
||||
ac accesscontrol.AccessControl
|
||||
zclient zanzana.Client
|
||||
metrics *dashboardsMetrics
|
||||
}
|
||||
|
||||
@ -67,7 +69,7 @@ func ProvideDashboardServiceImpl(
|
||||
cfg *setting.Cfg, dashboardStore dashboards.Store, folderStore folder.FolderStore,
|
||||
features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService,
|
||||
dashboardPermissionsService accesscontrol.DashboardPermissionsService, ac accesscontrol.AccessControl,
|
||||
folderSvc folder.Service, fStore folder.Store, r prometheus.Registerer,
|
||||
folderSvc folder.Service, fStore folder.Store, r prometheus.Registerer, zclient zanzana.Client,
|
||||
) (*DashboardServiceImpl, error) {
|
||||
dashSvc := &DashboardServiceImpl{
|
||||
cfg: cfg,
|
||||
@ -77,6 +79,7 @@ func ProvideDashboardServiceImpl(
|
||||
folderPermissions: folderPermissionsService,
|
||||
dashboardPermissions: dashboardPermissionsService,
|
||||
ac: ac,
|
||||
zclient: zclient,
|
||||
folderStore: folderStore,
|
||||
folderService: folderSvc,
|
||||
metrics: newDashboardsMetrics(r),
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
|
||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
@ -883,6 +884,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
|
||||
foldertest.NewFakeService(),
|
||||
folder.NewFakeStore(),
|
||||
nil,
|
||||
zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
guardian.InitAccessControlGuardian(cfg, ac, dashboardService)
|
||||
@ -949,6 +951,7 @@ func callSaveWithResult(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSt
|
||||
foldertest.NewFakeService(),
|
||||
folder.NewFakeStore(),
|
||||
nil,
|
||||
zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
res, err := service.SaveDashboard(context.Background(), &dto, false)
|
||||
@ -974,6 +977,7 @@ func callSaveWithError(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSto
|
||||
foldertest.NewFakeService(),
|
||||
folder.NewFakeStore(),
|
||||
nil,
|
||||
zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
_, err = service.SaveDashboard(context.Background(), &dto, false)
|
||||
@ -1018,6 +1022,7 @@ func saveTestDashboard(t *testing.T, title string, orgID int64, folderUID string
|
||||
foldertest.NewFakeService(),
|
||||
folder.NewFakeStore(),
|
||||
nil,
|
||||
zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
res, err := service.SaveDashboard(context.Background(), &dto, false)
|
||||
@ -1069,6 +1074,7 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore db.DB) *da
|
||||
foldertest.NewFakeService(),
|
||||
folder.NewFakeStore(),
|
||||
nil,
|
||||
zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
res, err := service.SaveDashboard(context.Background(), &dto, false)
|
||||
|
@ -6,9 +6,15 @@ import (
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultQueryLimit = 1000
|
||||
)
|
||||
|
||||
type searchResult struct {
|
||||
runner string
|
||||
result []dashboards.DashboardSearchProjection
|
||||
@ -79,7 +85,113 @@ func (dr *DashboardServiceImpl) findDashboardsZanzanaCompare(ctx context.Context
|
||||
return first.result, first.err
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) findDashboardsZanzana(_ context.Context, _ dashboards.FindPersistedDashboardsQuery) ([]dashboards.DashboardSearchProjection, error) {
|
||||
// FIXME: Implement using the new schema
|
||||
return []dashboards.DashboardSearchProjection{}, nil
|
||||
func (dr *DashboardServiceImpl) findDashboardsZanzana(ctx context.Context, query dashboards.FindPersistedDashboardsQuery) ([]dashboards.DashboardSearchProjection, error) {
|
||||
return dr.findDashboardsZanzanaCheck(ctx, query)
|
||||
}
|
||||
|
||||
// findDashboardsZanzanaCheck implements "Search, then check" strategy. It first performs search query, then filters out results
|
||||
// by checking access to each item.
|
||||
func (dr *DashboardServiceImpl) findDashboardsZanzanaCheck(ctx context.Context, query dashboards.FindPersistedDashboardsQuery) ([]dashboards.DashboardSearchProjection, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.findDashboardsZanzanaCheck")
|
||||
defer span.End()
|
||||
|
||||
result := make([]dashboards.DashboardSearchProjection, 0, query.Limit)
|
||||
|
||||
query.SkipAccessControlFilter = true
|
||||
// Remember initial query limit
|
||||
limit := query.Limit
|
||||
// Set limit to default to prevent pagination issues
|
||||
query.Limit = defaultQueryLimit
|
||||
if query.Page == 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
|
||||
for len(result) < int(limit) {
|
||||
findRes, err := dr.dashboardStore.FindDashboards(ctx, &query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
remains := limit - int64(len(result))
|
||||
res, err := dr.checkDashboardsBatch(ctx, query, findRes, remains)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result = append(result, res...)
|
||||
query.Page++
|
||||
|
||||
// Stop when last page reached
|
||||
if len(findRes) < defaultQueryLimit {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) checkDashboardsBatch(ctx context.Context, query dashboards.FindPersistedDashboardsQuery, searchRes []dashboards.DashboardSearchProjection, remains int64) ([]dashboards.DashboardSearchProjection, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.checkDashboardsBatch")
|
||||
defer span.End()
|
||||
|
||||
if len(searchRes) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
batchReqItems := make([]*authzextv1.BatchCheckItem, 0, len(searchRes))
|
||||
|
||||
for _, d := range searchRes {
|
||||
// FIXME: support different access levels
|
||||
kind := zanzana.KindDashboards
|
||||
action := dashboards.ActionDashboardsRead
|
||||
if d.IsFolder {
|
||||
kind = zanzana.KindFolders
|
||||
action = dashboards.ActionFoldersRead
|
||||
}
|
||||
|
||||
checkReq, ok := zanzana.TranslateToCheckRequest("", action, kind, d.FolderUID, d.UID)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
batchReqItems = append(batchReqItems, &authzextv1.BatchCheckItem{
|
||||
Verb: checkReq.Verb,
|
||||
Group: checkReq.Group,
|
||||
Resource: checkReq.Resource,
|
||||
Name: checkReq.Name,
|
||||
Folder: checkReq.Folder,
|
||||
Subresource: checkReq.Subresource,
|
||||
})
|
||||
}
|
||||
|
||||
batchReq := authzextv1.BatchCheckRequest{
|
||||
Namespace: query.SignedInUser.GetNamespace(),
|
||||
Subject: query.SignedInUser.GetUID(),
|
||||
Items: batchReqItems,
|
||||
}
|
||||
|
||||
res, err := dr.zclient.BatchCheck(ctx, &batchReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]dashboards.DashboardSearchProjection, 0)
|
||||
for _, d := range searchRes {
|
||||
if len(result) >= int(remains) {
|
||||
break
|
||||
}
|
||||
|
||||
kind := zanzana.KindDashboards
|
||||
if d.IsFolder {
|
||||
kind = zanzana.KindFolders
|
||||
}
|
||||
groupResource := zanzana.TranslateToGroupResource(kind)
|
||||
if group, ok := res.Groups[groupResource]; ok {
|
||||
if allowed := group.Items[d.UID]; allowed {
|
||||
result = append(result, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
dashboardsnapshot "github.com/grafana/grafana/pkg/apis/dashboardsnapshot/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
dashdb "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
dashsvc "github.com/grafana/grafana/pkg/services/dashboards/service"
|
||||
@ -99,7 +100,7 @@ func TestValidateDashboardExists(t *testing.T) {
|
||||
secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(sqlStore))
|
||||
dashboardStore, err := dashdb.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotatest.New(false, nil))
|
||||
require.NoError(t, err)
|
||||
dashSvc, err := dashsvc.ProvideDashboardServiceImpl(cfg, dashboardStore, folderimpl.ProvideDashboardFolderStore(sqlStore), nil, nil, nil, acmock.New(), foldertest.NewFakeService(), folder.NewFakeStore(), nil)
|
||||
dashSvc, err := dashsvc.ProvideDashboardServiceImpl(cfg, dashboardStore, folderimpl.ProvideDashboardFolderStore(sqlStore), nil, nil, nil, acmock.New(), foldertest.NewFakeService(), folder.NewFakeStore(), nil, zanzana.NewNoopClient())
|
||||
require.NoError(t, err)
|
||||
s := ProvideService(dsStore, secretsService, dashSvc)
|
||||
ctx := context.Background()
|
||||
|
@ -490,7 +490,7 @@ func TestIntegrationNestedFolderService(t *testing.T) {
|
||||
CanEditValue: true,
|
||||
})
|
||||
|
||||
dashSrv, err := dashboardservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuresFlagOn, folderPermissions, dashboardPermissions, ac, serviceWithFlagOn, nestedFolderStore, nil)
|
||||
dashSrv, err := dashboardservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuresFlagOn, folderPermissions, dashboardPermissions, ac, serviceWithFlagOn, nestedFolderStore, nil, zanzana.NewNoopClient())
|
||||
require.NoError(t, err)
|
||||
|
||||
alertStore, err := ngstore.ProvideDBStore(cfg, featuresFlagOn, db, serviceWithFlagOn, dashSrv, ac, b)
|
||||
@ -573,7 +573,7 @@ func TestIntegrationNestedFolderService(t *testing.T) {
|
||||
})
|
||||
|
||||
dashSrv, err := dashboardservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuresFlagOff,
|
||||
folderPermissions, dashboardPermissions, ac, serviceWithFlagOff, nestedFolderStore, nil)
|
||||
folderPermissions, dashboardPermissions, ac, serviceWithFlagOff, nestedFolderStore, nil, zanzana.NewNoopClient())
|
||||
require.NoError(t, err)
|
||||
|
||||
alertStore, err := ngstore.ProvideDBStore(cfg, featuresFlagOff, db, serviceWithFlagOff, dashSrv, ac, b)
|
||||
@ -719,7 +719,7 @@ func TestIntegrationNestedFolderService(t *testing.T) {
|
||||
tc.service.dashboardStore = dashStore
|
||||
tc.service.store = nestedFolderStore
|
||||
|
||||
dashSrv, err := dashboardservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, tc.featuresFlag, folderPermissions, dashboardPermissions, ac, tc.service, tc.service.store, nil)
|
||||
dashSrv, err := dashboardservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, tc.featuresFlag, folderPermissions, dashboardPermissions, ac, tc.service, tc.service.store, nil, zanzana.NewNoopClient())
|
||||
require.NoError(t, err)
|
||||
alertStore, err := ngstore.ProvideDBStore(cfg, tc.featuresFlag, db, tc.service, dashSrv, ac, b)
|
||||
require.NoError(t, err)
|
||||
@ -1504,6 +1504,7 @@ func TestIntegrationNestedFolderSharedWithMe(t *testing.T) {
|
||||
serviceWithFlagOn,
|
||||
nestedFolderStore,
|
||||
nil,
|
||||
zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -310,6 +310,7 @@ func createDashboard(t *testing.T, sqlStore db.DB, user user.SignedInUser, dash
|
||||
foldertest.NewFakeService(),
|
||||
folder.NewFakeStore(),
|
||||
nil,
|
||||
zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
dashboard, err := service.SaveDashboard(context.Background(), dashItem, true)
|
||||
@ -396,7 +397,7 @@ func scenarioWithPanel(t *testing.T, desc string, fn func(t *testing.T, sc scena
|
||||
cfg, dashboardStore, folderStore,
|
||||
features, folderPermissions, dashboardPermissions, ac,
|
||||
foldertest.NewFakeService(), folder.NewFakeStore(),
|
||||
nil,
|
||||
nil, zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, svcErr)
|
||||
guardian.InitAccessControlGuardian(cfg, ac, dashboardService)
|
||||
@ -458,7 +459,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
||||
cfg, dashboardStore, folderStore,
|
||||
features, folderPermissions, dashboardPermissions, ac,
|
||||
foldertest.NewFakeService(), folder.NewFakeStore(),
|
||||
nil,
|
||||
nil, zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, dashSvcErr)
|
||||
guardian.InitAccessControlGuardian(cfg, ac, dashService)
|
||||
|
@ -7,6 +7,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
@ -19,6 +22,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
|
||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol/testutil"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
|
||||
@ -38,8 +42,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/user/userimpl"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tests/testsuite"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const userInDbName = "user_in_db"
|
||||
@ -734,7 +736,7 @@ func createDashboard(t *testing.T, sqlStore db.DB, user *user.SignedInUser, dash
|
||||
cfg, dashboardStore, folderStore,
|
||||
featuremgmt.WithFeatures(), acmock.NewMockedPermissionsService(), dashPermissionService, ac,
|
||||
foldertest.NewFakeService(), folder.NewFakeStore(),
|
||||
nil,
|
||||
nil, zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
dashboard, err := service.SaveDashboard(context.Background(), dashItem, true)
|
||||
@ -831,7 +833,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
||||
cfg, dashStore, folderStore,
|
||||
features, acmock.NewMockedPermissionsService(), dashPermissionService, ac,
|
||||
foldertest.NewFakeService(), folder.NewFakeStore(),
|
||||
nil,
|
||||
nil, zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
guardian.InitAccessControlGuardian(cfg, ac, dashService)
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
|
||||
@ -61,7 +62,7 @@ func SetupDashboardService(tb testing.TB, sqlStore db.DB, fs *folderimpl.Dashboa
|
||||
cfg, dashboardStore, fs,
|
||||
features, folderPermissions, dashboardPermissions, ac,
|
||||
foldertest.NewFakeService(), folder.NewFakeStore(),
|
||||
nil,
|
||||
nil, zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(tb, err)
|
||||
|
||||
|
@ -10,12 +10,13 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
@ -24,6 +25,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/annotations/annotationstest"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
dashboardStore "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/service"
|
||||
@ -324,7 +326,7 @@ func TestIntegrationUnauthenticatedUserCanGetPubdashPanelQueryData(t *testing.T)
|
||||
dashService, err := service.ProvideDashboardServiceImpl(
|
||||
cfg, dashboardStoreService, folderStore,
|
||||
featuremgmt.WithFeatures(), acmock.NewMockedPermissionsService(), dashPermissionService, ac,
|
||||
foldertest.NewFakeService(), folder.NewFakeStore(), nil,
|
||||
foldertest.NewFakeService(), folder.NewFakeStore(), nil, zanzana.NewNoopClient(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user