From e399fe6d092bcafa0c0177ba024124bac2feaa78 Mon Sep 17 00:00:00 2001 From: "Arati R." <33031346+suntala@users.noreply.github.com> Date: Tue, 1 Oct 2024 14:03:02 +0200 Subject: [PATCH] Folders: Set folder creation permission as part of legacy create (#94040) * Add folder store to dashboard permissions * Include folder store in annotation scope resolver * Add folder store when initialising library elements * Include folder store in search v2 service initialisation * Include folder store in GetInheritedScopes * Add folder store to folder permissions provider * Include cfg, folder permissions in folder service * Move setting of folder permissions for folder service create method --- pkg/api/annotations.go | 4 +- pkg/api/annotations_test.go | 7 +- pkg/api/dashboard_test.go | 2 +- pkg/api/folder.go | 38 --------- pkg/api/folder_bench_test.go | 9 +- pkg/api/http_server.go | 3 +- .../ossaccesscontrol/dashboard.go | 4 +- .../accesscontrol/ossaccesscontrol/folder.go | 4 +- .../ossaccesscontrol/testutil/testutil.go | 83 +++++++++++++++++++ .../annotationsimpl/annotations_test.go | 6 +- pkg/services/dashboards/accesscontrol.go | 41 +++++---- pkg/services/dashboards/accesscontrol_test.go | 34 ++++---- .../database/database_folder_test.go | 4 +- .../dashboards/database/database_test.go | 10 ++- .../dashboards/service/dashboard_service.go | 4 +- pkg/services/folder/folderimpl/folder.go | 49 ++++++++++- pkg/services/folder/folderimpl/folder_test.go | 22 +++-- .../guardian/accesscontrol_guardian_test.go | 9 +- pkg/services/libraryelements/accesscontrol.go | 4 +- .../libraryelements/libraryelements.go | 4 +- .../libraryelements/libraryelements_test.go | 5 +- .../librarypanels/librarypanels_test.go | 10 ++- .../ngalert/api/api_provisioning_test.go | 4 +- .../ngalert/provisioning/alert_rules_test.go | 4 +- pkg/services/ngalert/testutil/testutil.go | 3 +- pkg/services/searchV2/auth.go | 12 +-- pkg/services/searchV2/index_test.go | 4 +- pkg/services/searchV2/service.go | 10 +-- pkg/services/searchV2/service_bench_test.go | 4 +- .../sqlstore/permissions/dashboard_test.go | 6 +- .../permissions/dashboards_bench_test.go | 3 +- 31 files changed, 269 insertions(+), 137 deletions(-) create mode 100644 pkg/services/accesscontrol/ossaccesscontrol/testutil/testutil.go diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index 5612fd4a639..df6afa33be1 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -587,7 +587,7 @@ func (hs *HTTPServer) GetAnnotationTags(c *contextmodel.ReqContext) response.Res // where is the type of annotation with id . // If annotationPermissionUpdate feature toggle is enabled, dashboard annotation scope will be resolved to the corresponding // dashboard and folder scopes (eg, "dashboards:uid:", "folders:uid:" etc). -func AnnotationTypeScopeResolver(annotationsRepo annotations.Repository, features featuremgmt.FeatureToggles, dashSvc dashboards.DashboardService, folderSvc folder.Service) (string, accesscontrol.ScopeAttributeResolver) { +func AnnotationTypeScopeResolver(annotationsRepo annotations.Repository, features featuremgmt.FeatureToggles, dashSvc dashboards.DashboardService, folderStore folder.Store) (string, accesscontrol.ScopeAttributeResolver) { prefix := accesscontrol.ScopeAnnotationsProvider.GetResourceScope("") return prefix, accesscontrol.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, initialScope string) ([]string, error) { scopeParts := strings.Split(initialScope, ":") @@ -649,7 +649,7 @@ func AnnotationTypeScopeResolver(annotationsRepo annotations.Repository, feature // Append dashboard parent scopes if dashboard is in a folder or the general scope if dashboard is not in a folder if dashboard.FolderUID != "" { scopes = append(scopes, dashboards.ScopeFoldersProvider.GetResourceScopeUID(dashboard.FolderUID)) - inheritedScopes, err := dashboards.GetInheritedScopes(ctx, orgID, dashboard.FolderUID, folderSvc) + inheritedScopes, err := dashboards.GetInheritedScopes(ctx, orgID, dashboard.FolderUID, folderStore) if err != nil { return nil, err } diff --git a/pkg/api/annotations_test.go b/pkg/api/annotations_test.go index 12eea783e5d..5fb09aa7baf 100644 --- a/pkg/api/annotations_test.go +++ b/pkg/api/annotations_test.go @@ -397,14 +397,15 @@ func TestAPI_Annotations(t *testing.T) { dashService := &dashboards.FakeDashboardService{} dashService.On("GetDashboard", mock.Anything, mock.Anything).Return(&dashboards.Dashboard{UID: dashUID, FolderUID: folderUID, FolderID: 1}, nil) folderService := &foldertest.FakeService{} + fStore := folder.NewFakeStore() folderService.ExpectedFolder = &folder.Folder{UID: folderUID, ID: 1} folderDB := &foldertest.FakeFolderStore{} folderDB.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(&folder.Folder{UID: folderUID, ID: 1}, nil) hs.DashboardService = dashService hs.folderService = folderService hs.AccessControl = acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient()) - hs.AccessControl.RegisterScopeAttributeResolver(AnnotationTypeScopeResolver(hs.annotationsRepo, hs.Features, dashService, folderService)) - hs.AccessControl.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(folderDB, dashService, folderService)) + hs.AccessControl.RegisterScopeAttributeResolver(AnnotationTypeScopeResolver(hs.annotationsRepo, hs.Features, dashService, fStore)) + hs.AccessControl.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(folderDB, dashService, fStore)) }) var body io.Reader if tt.body != "" { @@ -504,7 +505,7 @@ func TestService_AnnotationTypeScopeResolver(t *testing.T) { for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { features := featuremgmt.WithFeatures(tc.featureToggles...) - prefix, resolver := AnnotationTypeScopeResolver(fakeAnnoRepo, features, dashSvc, &foldertest.FakeService{}) + prefix, resolver := AnnotationTypeScopeResolver(fakeAnnoRepo, features, dashSvc, folder.NewFakeStore()) require.Equal(t, "annotations:id:", prefix) resolved, err := resolver.Resolve(context.Background(), 1, tc.given) diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go index 42bd4a84956..2a561916821 100644 --- a/pkg/api/dashboard_test.go +++ b/pkg/api/dashboard_test.go @@ -836,7 +836,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr db := db.InitTestDB(t) fStore := folderimpl.ProvideStore(db) folderSvc := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), - dashboardStore, folderStore, db, features, + dashboardStore, folderStore, db, features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) if dashboardService == nil { dashboardService, err = service.ProvideDashboardServiceImpl( diff --git a/pkg/api/folder.go b/pkg/api/folder.go index 5456100cd0f..c8d7949b48f 100644 --- a/pkg/api/folder.go +++ b/pkg/api/folder.go @@ -1,7 +1,6 @@ package api import ( - "context" "errors" "net/http" "strconv" @@ -12,12 +11,10 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" - "github.com/grafana/authlib/claims" "github.com/grafana/grafana/pkg/api/apierrors" "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/routing" - "github.com/grafana/grafana/pkg/apimachinery/identity" folderalpha1 "github.com/grafana/grafana/pkg/apis/folder/v0alpha1" "github.com/grafana/grafana/pkg/infra/metrics" internalfolders "github.com/grafana/grafana/pkg/registry/apis/folders" @@ -31,7 +28,6 @@ import ( "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/libraryelements/model" - "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/search" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util/errhttp" @@ -219,10 +215,6 @@ func (hs *HTTPServer) CreateFolder(c *contextmodel.ReqContext) response.Response return apierrors.ToFolderErrorResponse(err) } - if err := hs.setDefaultFolderPermissions(c.Req.Context(), cmd.OrgID, cmd.SignedInUser, folder); err != nil { - hs.log.Error("Could not set the default folder permissions", "folder", folder.Title, "user", cmd.SignedInUser, "error", err) - } - // Clear permission cache for the user who's created the folder, so that new permissions are fetched for their next call // Required for cases when caller wants to immediately interact with the newly created object hs.accesscontrolService.ClearUserPermissionCache(c.SignedInUser) @@ -236,36 +228,6 @@ func (hs *HTTPServer) CreateFolder(c *contextmodel.ReqContext) response.Response return response.JSON(http.StatusOK, folderDTO) } -func (hs *HTTPServer) setDefaultFolderPermissions(ctx context.Context, orgID int64, user identity.Requester, folder *folder.Folder) error { - if !hs.Cfg.RBAC.PermissionsOnCreation("folder") { - return nil - } - - var permissions []accesscontrol.SetResourcePermissionCommand - - if user.IsIdentityType(claims.TypeUser) { - userID, err := user.GetInternalID() - if err != nil { - return err - } - - permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ - UserID: userID, Permission: dashboardaccess.PERMISSION_ADMIN.String(), - }) - } - - isNested := folder.ParentUID != "" - if !isNested || !hs.Features.IsEnabled(ctx, featuremgmt.FlagNestedFolders) { - permissions = append(permissions, []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, - {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, - }...) - } - - _, err := hs.folderPermissionsService.SetPermissions(ctx, orgID, folder.UID, permissions...) - return err -} - // swagger:route POST /folders/{folder_uid}/move folders moveFolder // // Move folder. diff --git a/pkg/api/folder_bench_test.go b/pkg/api/folder_bench_test.go index 3d5113c715c..590a4ea0b66 100644 --- a/pkg/api/folder_bench_test.go +++ b/pkg/api/folder_bench_test.go @@ -464,14 +464,15 @@ func setupServer(b testing.TB, sc benchScenario, features featuremgmt.FeatureTog features, tracing.InitializeTracerForTest(), zanzana.NewNoopClient(), sc.db, permreg.ProvidePermissionRegistry(), ) fStore := folderimpl.ProvideStore(sc.db) - folderServiceWithFlagOn := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore, - folderStore, sc.db, features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions( - cfg, features, routing.NewRouteRegister(), sc.db, ac, license, &dashboards.FakeDashboardStore{}, folderServiceWithFlagOn, acSvc, sc.teamSvc, sc.userSvc, actionSets) + cfg, features, routing.NewRouteRegister(), sc.db, ac, license, &dashboards.FakeDashboardStore{}, fStore, acSvc, sc.teamSvc, sc.userSvc, actionSets) require.NoError(b, err) + folderServiceWithFlagOn := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore, + folderStore, sc.db, features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) + dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions( - cfg, features, routing.NewRouteRegister(), sc.db, ac, license, &dashboards.FakeDashboardStore{}, folderServiceWithFlagOn, acSvc, sc.teamSvc, sc.userSvc, actionSets) + cfg, features, routing.NewRouteRegister(), sc.db, ac, license, &dashboards.FakeDashboardStore{}, fStore, acSvc, sc.teamSvc, sc.userSvc, actionSets) require.NoError(b, err) dashboardSvc, err := dashboardservice.ProvideDashboardServiceImpl( diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go index 04fed03bcca..f9908deaadf 100644 --- a/pkg/api/http_server.go +++ b/pkg/api/http_server.go @@ -253,6 +253,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi authInfoService login.AuthInfoService, storageService store.StorageService, notificationService notifications.Service, dashboardService dashboards.DashboardService, dashboardProvisioningService dashboards.DashboardProvisioningService, folderService folder.Service, + folderStore folder.Store, dsGuardian guardian.DatasourceGuardianProvider, dashboardsnapshotsService dashboardsnapshots.Service, pluginSettings pluginSettings.Service, avatarCacheServer *avatar.AvatarCacheServer, preferenceService pref.Service, @@ -379,7 +380,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi hs.registerRoutes() // Register access control scope resolver for annotations - hs.AccessControl.RegisterScopeAttributeResolver(AnnotationTypeScopeResolver(hs.annotationsRepo, features, dashboardService, folderService)) + hs.AccessControl.RegisterScopeAttributeResolver(AnnotationTypeScopeResolver(hs.annotationsRepo, features, dashboardService, folderStore)) if err := hs.declareFixedRoles(); err != nil { return nil, err diff --git a/pkg/services/accesscontrol/ossaccesscontrol/dashboard.go b/pkg/services/accesscontrol/ossaccesscontrol/dashboard.go index 85e5d5a4960..8010ef19c27 100644 --- a/pkg/services/accesscontrol/ossaccesscontrol/dashboard.go +++ b/pkg/services/accesscontrol/ossaccesscontrol/dashboard.go @@ -93,7 +93,7 @@ func registerDashboardRoles(cfg *setting.Cfg, features featuremgmt.FeatureToggle func ProvideDashboardPermissions( cfg *setting.Cfg, features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, ac accesscontrol.AccessControl, - license licensing.Licensing, dashboardStore dashboards.Store, folderService folder.Service, service accesscontrol.Service, + license licensing.Licensing, dashboardStore dashboards.Store, folderStore folder.Store, service accesscontrol.Service, teamService team.Service, userService user.Service, actionSetService resourcepermissions.ActionSetService, ) (*DashboardPermissionsService, error) { getDashboard := func(ctx context.Context, orgID int64, resourceID string) (*dashboards.Dashboard, error) { @@ -145,7 +145,7 @@ func ProvideDashboardPermissions( } parentScope := dashboards.ScopeFoldersProvider.GetResourceScopeUID(queryResult.UID) - nestedScopes, err := dashboards.GetInheritedScopes(ctx, orgID, queryResult.UID, folderService) + nestedScopes, err := dashboards.GetInheritedScopes(ctx, orgID, queryResult.UID, folderStore) if err != nil { return nil, err } diff --git a/pkg/services/accesscontrol/ossaccesscontrol/folder.go b/pkg/services/accesscontrol/ossaccesscontrol/folder.go index 8904567d935..1af283a81c2 100644 --- a/pkg/services/accesscontrol/ossaccesscontrol/folder.go +++ b/pkg/services/accesscontrol/ossaccesscontrol/folder.go @@ -84,7 +84,7 @@ func registerFolderRoles(cfg *setting.Cfg, features featuremgmt.FeatureToggles, func ProvideFolderPermissions( cfg *setting.Cfg, features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, accesscontrol accesscontrol.AccessControl, - license licensing.Licensing, dashboardStore dashboards.Store, folderService folder.Service, service accesscontrol.Service, + license licensing.Licensing, dashboardStore dashboards.Store, folderStore folder.Store, service accesscontrol.Service, teamService team.Service, userService user.Service, actionSetService resourcepermissions.ActionSetService, ) (*FolderPermissionsService, error) { if err := registerFolderRoles(cfg, features, service); err != nil { @@ -111,7 +111,7 @@ func ProvideFolderPermissions( return nil }, InheritedScopesSolver: func(ctx context.Context, orgID int64, resourceID string) ([]string, error) { - return dashboards.GetInheritedScopes(ctx, orgID, resourceID, folderService) + return dashboards.GetInheritedScopes(ctx, orgID, resourceID, folderStore) }, Assignments: resourcepermissions.Assignments{ Users: true, diff --git a/pkg/services/accesscontrol/ossaccesscontrol/testutil/testutil.go b/pkg/services/accesscontrol/ossaccesscontrol/testutil/testutil.go new file mode 100644 index 00000000000..9dbed99aa67 --- /dev/null +++ b/pkg/services/accesscontrol/ossaccesscontrol/testutil/testutil.go @@ -0,0 +1,83 @@ +package testutil + +import ( + "github.com/grafana/grafana/pkg/api/routing" + "github.com/grafana/grafana/pkg/infra/localcache" + "github.com/grafana/grafana/pkg/infra/tracing" + "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" + acdb "github.com/grafana/grafana/pkg/services/accesscontrol/database" + "github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol" + "github.com/grafana/grafana/pkg/services/accesscontrol/permreg" + "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions" + "github.com/grafana/grafana/pkg/services/authz/zanzana" + "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/services/folder/folderimpl" + "github.com/grafana/grafana/pkg/services/licensing/licensingtest" + "github.com/grafana/grafana/pkg/services/org/orgimpl" + "github.com/grafana/grafana/pkg/services/quota/quotatest" + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/supportbundles/bundleregistry" + "github.com/grafana/grafana/pkg/services/team/teamimpl" + "github.com/grafana/grafana/pkg/services/user/userimpl" + "github.com/grafana/grafana/pkg/setting" +) + +func ProvideFolderPermissions( + features featuremgmt.FeatureToggles, + cfg *setting.Cfg, + sqlStore *sqlstore.SQLStore, +) (*ossaccesscontrol.FolderPermissionsService, error) { + actionSets := resourcepermissions.NewActionSetService(features) + acSvc := acimpl.ProvideOSSService( + cfg, acdb.ProvideService(sqlStore), actionSets, localcache.ProvideService(), + features, tracing.InitializeTracerForTest(), zanzana.NewNoopClient(), sqlStore, permreg.ProvidePermissionRegistry(), + ) + + license := licensingtest.NewFakeLicensing() + license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe() + + ac := acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient()) + + fStore := folderimpl.ProvideStore(sqlStore) + + quotaService := quotatest.New(false, nil) + orgService, err := orgimpl.ProvideService(sqlStore, cfg, quotaService) + if err != nil { + return nil, err + } + teamSvc, err := teamimpl.ProvideService(sqlStore, cfg, tracing.InitializeTracerForTest()) + if err != nil { + return nil, err + } + cache := localcache.ProvideService() + + userSvc, err := userimpl.ProvideService( + sqlStore, + orgService, + cfg, + teamSvc, + cache, + tracing.InitializeTracerForTest(), + quotaService, + bundleregistry.ProvideService(), + ) + if err != nil { + return nil, err + } + + return ossaccesscontrol.ProvideFolderPermissions( + cfg, + features, + routing.NewRouteRegister(), + sqlStore, + ac, + license, + &dashboards.FakeDashboardStore{}, + fStore, + acSvc, + teamSvc, + userSvc, + actionSets, + ) +} diff --git a/pkg/services/annotations/annotationsimpl/annotations_test.go b/pkg/services/annotations/annotationsimpl/annotations_test.go index 4263acc340c..6a1f9e56a2f 100644 --- a/pkg/services/annotations/annotationsimpl/annotations_test.go +++ b/pkg/services/annotations/annotationsimpl/annotations_test.go @@ -16,6 +16,7 @@ import ( "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" + ftestutil "github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol/testutil" "github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations/testutil" "github.com/grafana/grafana/pkg/services/authz/zanzana" @@ -227,10 +228,11 @@ func TestIntegrationAnnotationListingWithInheritedRBAC(t *testing.T) { }) ac := acimpl.ProvideAccessControl(features, zanzana.NewNoopClient()) + folderPermissions, err := ftestutil.ProvideFolderPermissions(features, cfg, sql) + require.NoError(t, err) fStore := folderimpl.ProvideStore(sql) folderSvc := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore, - folderimpl.ProvideDashboardFolderStore(sql), sql, features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) - + folderimpl.ProvideDashboardFolderStore(sql), sql, features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) cfg.AnnotationMaximumTagsLength = 60 store := NewXormStore(cfg, log.New("annotation.test"), sql, tagService) diff --git a/pkg/services/dashboards/accesscontrol.go b/pkg/services/dashboards/accesscontrol.go index c4b53df4c87..57dafdd454c 100644 --- a/pkg/services/dashboards/accesscontrol.go +++ b/pkg/services/dashboards/accesscontrol.go @@ -43,7 +43,7 @@ var ( ) // NewFolderNameScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:name:" into an uid based scope. -func NewFolderNameScopeResolver(folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { +func NewFolderNameScopeResolver(folderDB folder.FolderStore, folderStore folder.Store) (string, ac.ScopeAttributeResolver) { prefix := ScopeFoldersProvider.GetResourceScopeName("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { ctx, span := tracer.Start(ctx, "dashboards.NewFolderNameScopeResolver") @@ -63,7 +63,7 @@ func NewFolderNameScopeResolver(folderDB folder.FolderStore, folderSvc folder.Se return nil, err } - result, err := GetInheritedScopes(ctx, folder.OrgID, folder.UID, folderSvc) + result, err := GetInheritedScopes(ctx, folder.OrgID, folder.UID, folderStore) if err != nil { return nil, err } @@ -74,7 +74,7 @@ func NewFolderNameScopeResolver(folderDB folder.FolderStore, folderSvc folder.Se } // NewFolderIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:id:" into an uid based scope. -func NewFolderIDScopeResolver(folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { +func NewFolderIDScopeResolver(folderDB folder.FolderStore, folderStore folder.Store) (string, ac.ScopeAttributeResolver) { prefix := ScopeFoldersProvider.GetResourceScope("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { ctx, span := tracer.Start(ctx, "dashboards.NewFolderIDScopeResolver") @@ -98,7 +98,7 @@ func NewFolderIDScopeResolver(folderDB folder.FolderStore, folderSvc folder.Serv return nil, err } - result, err := GetInheritedScopes(ctx, folder.OrgID, folder.UID, folderSvc) + result, err := GetInheritedScopes(ctx, folder.OrgID, folder.UID, folderStore) if err != nil { return nil, err } @@ -110,7 +110,7 @@ func NewFolderIDScopeResolver(folderDB folder.FolderStore, folderSvc folder.Serv // NewFolderUIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:uid:" // into uid based scopes for folder and its parents -func NewFolderUIDScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { +func NewFolderUIDScopeResolver(folderStore folder.Store) (string, ac.ScopeAttributeResolver) { prefix := ScopeFoldersProvider.GetResourceScopeUID("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { ctx, span := tracer.Start(ctx, "dashboards.NewFolderUIDScopeResolver") @@ -125,7 +125,7 @@ func NewFolderUIDScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttrib return nil, err } - inheritedScopes, err := GetInheritedScopes(ctx, orgID, uid, folderSvc) + inheritedScopes, err := GetInheritedScopes(ctx, orgID, uid, folderStore) if err != nil { return nil, err } @@ -135,7 +135,7 @@ func NewFolderUIDScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttrib // NewDashboardIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "dashboards:id:" // into uid based scopes for both dashboard and folder -func NewDashboardIDScopeResolver(folderDB folder.FolderStore, ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { +func NewDashboardIDScopeResolver(folderDB folder.FolderStore, ds DashboardService, folderStore folder.Store) (string, ac.ScopeAttributeResolver) { prefix := ScopeDashboardsProvider.GetResourceScope("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { ctx, span := tracer.Start(ctx, "dashboards.NewDashboardIDScopeResolver") @@ -155,13 +155,13 @@ func NewDashboardIDScopeResolver(folderDB folder.FolderStore, ds DashboardServic return nil, err } - return resolveDashboardScope(ctx, folderDB, orgID, dashboard, folderSvc) + return resolveDashboardScope(ctx, folderDB, orgID, dashboard, folderStore) }) } // NewDashboardUIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "dashboards:uid:" // into uid based scopes for both dashboard and folder -func NewDashboardUIDScopeResolver(folderDB folder.FolderStore, ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { +func NewDashboardUIDScopeResolver(folderDB folder.FolderStore, ds DashboardService, folderStore folder.Store) (string, ac.ScopeAttributeResolver) { prefix := ScopeDashboardsProvider.GetResourceScopeUID("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { ctx, span := tracer.Start(ctx, "dashboards.NewDashboardUIDScopeResolver") @@ -181,11 +181,11 @@ func NewDashboardUIDScopeResolver(folderDB folder.FolderStore, ds DashboardServi return nil, err } - return resolveDashboardScope(ctx, folderDB, orgID, dashboard, folderSvc) + return resolveDashboardScope(ctx, folderDB, orgID, dashboard, folderStore) }) } -func resolveDashboardScope(ctx context.Context, folderDB folder.FolderStore, orgID int64, dashboard *Dashboard, folderSvc folder.Service) ([]string, error) { +func resolveDashboardScope(ctx context.Context, folderDB folder.FolderStore, orgID int64, dashboard *Dashboard, folderStore folder.Store) ([]string, error) { ctx, span := tracer.Start(ctx, "dashboards.resolveDashboardScope") span.End() @@ -208,7 +208,7 @@ func resolveDashboardScope(ctx context.Context, folderDB folder.FolderStore, org folderUID = folder.UID } - result, err := GetInheritedScopes(ctx, orgID, folderUID, folderSvc) + result, err := GetInheritedScopes(ctx, orgID, folderUID, folderStore) if err != nil { return nil, err } @@ -223,17 +223,24 @@ func resolveDashboardScope(ctx context.Context, folderDB folder.FolderStore, org return result, nil } -func GetInheritedScopes(ctx context.Context, orgID int64, folderUID string, folderSvc folder.Service) ([]string, error) { +func GetInheritedScopes(ctx context.Context, orgID int64, folderUID string, folderStore folder.Store) ([]string, error) { ctx, span := tracer.Start(ctx, "dashboards.GetInheritedScopes") span.End() if folderUID == ac.GeneralFolderUID { return nil, nil } - ancestors, err := folderSvc.GetParents(ctx, folder.GetParentsQuery{ - UID: folderUID, - OrgID: orgID, - }) + + var ancestors []*folder.Folder + var err error + if folderUID == folder.SharedWithMeFolderUID { + ancestors = []*folder.Folder{&folder.SharedWithMeFolder} + } else { + ancestors, err = folderStore.GetParents(ctx, folder.GetParentsQuery{ + UID: folderUID, + OrgID: orgID, + }) + } if err != nil { if errors.Is(err, folder.ErrFolderNotFound) { diff --git a/pkg/services/dashboards/accesscontrol_test.go b/pkg/services/dashboards/accesscontrol_test.go index 57e1d8e80e0..ead4055ac3f 100644 --- a/pkg/services/dashboards/accesscontrol_test.go +++ b/pkg/services/dashboards/accesscontrol_test.go @@ -18,7 +18,7 @@ import ( func TestNewFolderNameScopeResolver(t *testing.T) { t.Run("prefix should be expected", func(t *testing.T) { - prefix, _ := NewFolderNameScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + prefix, _ := NewFolderNameScopeResolver(foldertest.NewFakeFolderStore(t), folder.NewFakeStore()) require.Equal(t, "folders:name:", prefix) }) @@ -31,7 +31,7 @@ func TestNewFolderNameScopeResolver(t *testing.T) { scope := "folders:name:" + title - _, resolver := NewFolderNameScopeResolver(folderStore, foldertest.NewFakeService()) + _, resolver := NewFolderNameScopeResolver(folderStore, folder.NewFakeStore()) resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope) require.NoError(t, err) require.Len(t, resolvedScopes, 1) @@ -49,8 +49,8 @@ func TestNewFolderNameScopeResolver(t *testing.T) { scope := "folders:name:" + title - folderSvc := foldertest.NewFakeService() - folderSvc.ExpectedFolders = []*folder.Folder{ + fStore := folder.NewFakeStore() + fStore.ExpectedParentFolders = []*folder.Folder{ { UID: "parent", }, @@ -58,7 +58,7 @@ func TestNewFolderNameScopeResolver(t *testing.T) { UID: "grandparent", }, } - _, resolver := NewFolderNameScopeResolver(folderStore, folderSvc) + _, resolver := NewFolderNameScopeResolver(folderStore, fStore) resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope) require.NoError(t, err) @@ -75,20 +75,20 @@ func TestNewFolderNameScopeResolver(t *testing.T) { folderStore.AssertCalled(t, "GetFolderByTitle", mock.Anything, orgId, title, mock.Anything) }) t.Run("resolver should fail if input scope is not expected", func(t *testing.T) { - _, resolver := NewFolderNameScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + _, resolver := NewFolderNameScopeResolver(foldertest.NewFakeFolderStore(t), folder.NewFakeStore()) _, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:id:123") require.ErrorIs(t, err, ac.ErrInvalidScope) }) t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) { - _, resolver := NewFolderNameScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + _, resolver := NewFolderNameScopeResolver(foldertest.NewFakeFolderStore(t), folder.NewFakeStore()) _, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:name:") require.ErrorIs(t, err, ac.ErrInvalidScope) }) t.Run("returns 'not found' if folder does not exist", func(t *testing.T) { folderStore := foldertest.NewFakeFolderStore(t) - _, resolver := NewFolderNameScopeResolver(folderStore, foldertest.NewFakeService()) + _, resolver := NewFolderNameScopeResolver(folderStore, folder.NewFakeStore()) orgId := rand.Int63() folderStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once() @@ -103,12 +103,12 @@ func TestNewFolderNameScopeResolver(t *testing.T) { func TestNewFolderIDScopeResolver(t *testing.T) { t.Run("prefix should be expected", func(t *testing.T) { - prefix, _ := NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + prefix, _ := NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), folder.NewFakeStore()) require.Equal(t, "folders:id:", prefix) }) t.Run("resolver should fail if input scope is not expected", func(t *testing.T) { - _, resolver := NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + _, resolver := NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), folder.NewFakeStore()) _, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:uid:123") require.ErrorIs(t, err, ac.ErrInvalidScope) @@ -118,7 +118,7 @@ func TestNewFolderIDScopeResolver(t *testing.T) { var ( orgId = rand.Int63() scope = "folders:id:0" - _, resolver = NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + _, resolver = NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), folder.NewFakeStore()) ) resolved, err := resolver.Resolve(context.Background(), orgId, scope) @@ -129,7 +129,7 @@ func TestNewFolderIDScopeResolver(t *testing.T) { }) t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) { - _, resolver := NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + _, resolver := NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), folder.NewFakeStore()) _, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:id:") require.ErrorIs(t, err, ac.ErrInvalidScope) @@ -137,7 +137,7 @@ func TestNewFolderIDScopeResolver(t *testing.T) { t.Run("returns 'not found' if folder does not exist", func(t *testing.T) { folderStore := foldertest.NewFakeFolderStore(t) folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once() - _, resolver := NewFolderIDScopeResolver(folderStore, foldertest.NewFakeService()) + _, resolver := NewFolderIDScopeResolver(folderStore, folder.NewFakeStore()) orgId := rand.Int63() scope := "folders:id:10" @@ -149,12 +149,12 @@ func TestNewFolderIDScopeResolver(t *testing.T) { func TestNewDashboardIDScopeResolver(t *testing.T) { t.Run("prefix should be expected", func(t *testing.T) { - prefix, _ := NewDashboardIDScopeResolver(foldertest.NewFakeFolderStore(t), &FakeDashboardService{}, foldertest.NewFakeService()) + prefix, _ := NewDashboardIDScopeResolver(foldertest.NewFakeFolderStore(t), &FakeDashboardService{}, folder.NewFakeStore()) require.Equal(t, "dashboards:id:", prefix) }) t.Run("resolver should fail if input scope is not expected", func(t *testing.T) { - _, resolver := NewDashboardIDScopeResolver(foldertest.NewFakeFolderStore(t), &FakeDashboardService{}, foldertest.NewFakeService()) + _, resolver := NewDashboardIDScopeResolver(foldertest.NewFakeFolderStore(t), &FakeDashboardService{}, folder.NewFakeStore()) _, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:uid:123") require.ErrorIs(t, err, ac.ErrInvalidScope) }) @@ -162,12 +162,12 @@ func TestNewDashboardIDScopeResolver(t *testing.T) { func TestNewDashboardUIDScopeResolver(t *testing.T) { t.Run("prefix should be expected", func(t *testing.T) { - prefix, _ := NewDashboardUIDScopeResolver(foldertest.NewFakeFolderStore(t), &FakeDashboardService{}, foldertest.NewFakeService()) + prefix, _ := NewDashboardUIDScopeResolver(foldertest.NewFakeFolderStore(t), &FakeDashboardService{}, folder.NewFakeStore()) require.Equal(t, "dashboards:uid:", prefix) }) t.Run("resolver should fail if input scope is not expected", func(t *testing.T) { - _, resolver := NewDashboardUIDScopeResolver(foldertest.NewFakeFolderStore(t), &FakeDashboardService{}, foldertest.NewFakeService()) + _, resolver := NewDashboardUIDScopeResolver(foldertest.NewFakeFolderStore(t), &FakeDashboardService{}, folder.NewFakeStore()) _, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:id:123") require.ErrorIs(t, err, ac.ErrInvalidScope) }) diff --git a/pkg/services/dashboards/database/database_folder_test.go b/pkg/services/dashboards/database/database_folder_test.go index 177f0ba3e52..b792facc2c4 100644 --- a/pkg/services/dashboards/database/database_folder_test.go +++ b/pkg/services/dashboards/database/database_folder_test.go @@ -303,8 +303,10 @@ func TestIntegrationDashboardInheritedFolderRBAC(t *testing.T) { guardian.New = origNewGuardian }) + folderPermissions := mock.NewMockedPermissionsService() folderStore := folderimpl.ProvideStore(sqlStore) - folderSvc := folderimpl.ProvideService(folderStore, mock.New(), bus.ProvideBus(tracer), dashboardWriteStore, folderimpl.ProvideDashboardFolderStore(sqlStore), sqlStore, features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) + folderSvc := folderimpl.ProvideService(folderStore, mock.New(), bus.ProvideBus(tracer), dashboardWriteStore, folderimpl.ProvideDashboardFolderStore(sqlStore), + sqlStore, features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) parentUID := "" for i := 0; ; i++ { diff --git a/pkg/services/dashboards/database/database_test.go b/pkg/services/dashboards/database/database_test.go index 73d85983569..83259785a69 100644 --- a/pkg/services/dashboards/database/database_test.go +++ b/pkg/services/dashboards/database/database_test.go @@ -16,6 +16,8 @@ import ( "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" + "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/featuremgmt" @@ -829,10 +831,11 @@ func TestIntegrationFindDashboardsByTitle(t *testing.T) { insertTestDashboard(t, dashboardStore, "dashboard under general", orgID, 0, "", false) ac := acimpl.ProvideAccessControl(features, zanzana.NewNoopClient()) + folderPermissions := mock.NewMockedPermissionsService() folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) fStore := folderimpl.ProvideStore(sqlStore) folderServiceWithFlagOn := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore, - folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) + folderStore, sqlStore, features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) user := &user.SignedInUser{ OrgID: 1, @@ -951,8 +954,11 @@ func TestIntegrationFindDashboardsByFolder(t *testing.T) { folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) fStore := folderimpl.ProvideStore(sqlStore) + folderPermissions, err := testutil.ProvideFolderPermissions(features, cfg, sqlStore) + require.NoError(t, err) + folderServiceWithFlagOn := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore, - folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) + folderStore, sqlStore, features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) user := &user.SignedInUser{ OrgID: 1, diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index 02a1934103a..90653059b10 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -81,8 +81,8 @@ func ProvideDashboardServiceImpl( metrics: newDashboardsMetrics(r), } - ac.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(folderStore, dashSvc, folderSvc)) - ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(folderStore, dashSvc, folderSvc)) + ac.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(folderStore, dashSvc, fStore)) + ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(folderStore, dashSvc, fStore)) if err := folderSvc.RegisterService(dashSvc); err != nil { return nil, err diff --git a/pkg/services/folder/folderimpl/folder.go b/pkg/services/folder/folderimpl/folder.go index c87c7505c73..36f21e37170 100644 --- a/pkg/services/folder/folderimpl/folder.go +++ b/pkg/services/folder/folderimpl/folder.go @@ -11,6 +11,7 @@ import ( "sync" "time" + "github.com/grafana/authlib/claims" "github.com/grafana/dskit/concurrency" "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/otel/attribute" @@ -29,11 +30,13 @@ import ( "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/guardian" + "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/services/store/entity" "github.com/grafana/grafana/pkg/services/supportbundles" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) @@ -46,6 +49,8 @@ type Service struct { dashboardStore dashboards.Store dashboardFolderStore folder.FolderStore features featuremgmt.FeatureToggles + cfg *setting.Cfg + folderPermissions accesscontrol.FolderPermissionsService accessControl accesscontrol.AccessControl // bus is currently used to publish event in case of folder full path change. // For example when a folder is moved to another folder or when a folder is renamed. @@ -65,6 +70,8 @@ func ProvideService( folderStore folder.FolderStore, db db.DB, // DB for the (new) nested folder store features featuremgmt.FeatureToggles, + cfg *setting.Cfg, + folderPermissions accesscontrol.FolderPermissionsService, supportBundles supportbundles.Service, r prometheus.Registerer, tracer tracing.Tracer, @@ -75,6 +82,8 @@ func ProvideService( dashboardFolderStore: folderStore, store: store, features: features, + cfg: cfg, + folderPermissions: folderPermissions, accessControl: ac, bus: bus, db: db, @@ -86,9 +95,9 @@ func ProvideService( supportBundles.RegisterSupportItemCollector(srv.supportBundleCollector()) - ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(folderStore, srv)) - ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(folderStore, srv)) - ac.RegisterScopeAttributeResolver(dashboards.NewFolderUIDScopeResolver(srv)) + ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(folderStore, store)) + ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(folderStore, store)) + ac.RegisterScopeAttributeResolver(dashboards.NewFolderUIDScopeResolver(store)) return srv } @@ -658,9 +667,43 @@ func (s *Service) Create(ctx context.Context, cmd *folder.CreateFolderCommand) ( if nestedFolder != nil && nestedFolder.ParentUID != "" { f.ParentUID = nestedFolder.ParentUID } + if err = s.setDefaultFolderPermissions(ctx, cmd.OrgID, user, f); err != nil { + return nil, err + } + return f, nil } +func (s *Service) setDefaultFolderPermissions(ctx context.Context, orgID int64, user identity.Requester, folder *folder.Folder) error { + if !s.cfg.RBAC.PermissionsOnCreation("folder") { + return nil + } + + var permissions []accesscontrol.SetResourcePermissionCommand + + if user.IsIdentityType(claims.TypeUser) { + userID, err := user.GetInternalID() + if err != nil { + return err + } + + permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ + UserID: userID, Permission: dashboardaccess.PERMISSION_ADMIN.String(), + }) + } + + isNested := folder.ParentUID != "" + if !isNested || !s.features.IsEnabled(ctx, featuremgmt.FlagNestedFolders) { + permissions = append(permissions, []accesscontrol.SetResourcePermissionCommand{ + {BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()}, + }...) + } + + _, err := s.folderPermissions.SetPermissions(ctx, orgID, folder.UID, permissions...) + return err +} + func (s *Service) Update(ctx context.Context, cmd *folder.UpdateFolderCommand) (*folder.Folder, error) { ctx, span := s.tracer.Start(ctx, "folder.Update") defer span.End() diff --git a/pkg/services/folder/folderimpl/folder_test.go b/pkg/services/folder/folderimpl/folder_test.go index 2e5260fc594..283dcb668c1 100644 --- a/pkg/services/folder/folderimpl/folder_test.go +++ b/pkg/services/folder/folderimpl/folder_test.go @@ -62,10 +62,11 @@ func TestIntegrationProvideFolderService(t *testing.T) { } t.Run("should register scope resolvers", func(t *testing.T) { ac := acmock.New() - db, _ := db.InitTestDBWithCfg(t) + db, cfg := db.InitTestDBWithCfg(t) + folderPermissions := acmock.NewMockedPermissionsService() store := ProvideStore(db) ProvideService(store, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), nil, nil, db, - featuremgmt.WithFeatures(), supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) + featuremgmt.WithFeatures(), cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) require.Len(t, ac.Calls.RegisterAttributeScopeResolver, 3) }) @@ -97,6 +98,7 @@ func TestIntegrationFolderService(t *testing.T) { dashboardFolderStore: folderStore, store: nestedFolderStore, features: features, + cfg: cfg, bus: bus.ProvideBus(tracing.InitializeTracerForTest()), db: db, accessControl: acimpl.ProvideAccessControl(features, zanzana.NewNoopClient()), @@ -439,6 +441,7 @@ func TestIntegrationNestedFolderService(t *testing.T) { dashboardFolderStore: folderStore, store: nestedFolderStore, features: featuresFlagOn, + cfg: cfg, bus: b, db: db, accessControl: ac, @@ -494,7 +497,7 @@ func TestIntegrationNestedFolderService(t *testing.T) { alertStore, err := ngstore.ProvideDBStore(cfg, featuresFlagOn, db, serviceWithFlagOn, dashSrv, ac) require.NoError(t, err) - elementService := libraryelements.ProvideService(cfg, db, routeRegister, serviceWithFlagOn, featuresFlagOn, ac) + elementService := libraryelements.ProvideService(cfg, db, routeRegister, serviceWithFlagOn, serviceWithFlagOn.store, featuresFlagOn, ac) lps, err := librarypanels.ProvideService(cfg, db, routeRegister, elementService, serviceWithFlagOn) require.NoError(t, err) @@ -554,6 +557,7 @@ func TestIntegrationNestedFolderService(t *testing.T) { dashboardFolderStore: folderStore, store: nestedFolderStore, features: featuresFlagOff, + cfg: cfg, bus: b, db: db, registry: make(map[string]folder.RegistryService), @@ -576,7 +580,7 @@ func TestIntegrationNestedFolderService(t *testing.T) { alertStore, err := ngstore.ProvideDBStore(cfg, featuresFlagOff, db, serviceWithFlagOff, dashSrv, ac) require.NoError(t, err) - elementService := libraryelements.ProvideService(cfg, db, routeRegister, serviceWithFlagOff, featuresFlagOff, ac) + elementService := libraryelements.ProvideService(cfg, db, routeRegister, serviceWithFlagOff, serviceWithFlagOff.store, featuresFlagOff, ac) lps, err := librarypanels.ProvideService(cfg, db, routeRegister, elementService, serviceWithFlagOff) require.NoError(t, err) @@ -632,6 +636,7 @@ func TestIntegrationNestedFolderService(t *testing.T) { log: slog.New(logtest.NewTestHandler(t)).With("logger", "test-folder-service"), dashboardFolderStore: folderStore, features: featuresFlagOff, + cfg: cfg, bus: b, db: db, registry: make(map[string]folder.RegistryService), @@ -705,7 +710,7 @@ func TestIntegrationNestedFolderService(t *testing.T) { CanEditValue: true, }) - elementService := libraryelements.ProvideService(cfg, db, routeRegister, tc.service, tc.featuresFlag, ac) + elementService := libraryelements.ProvideService(cfg, db, routeRegister, tc.service, tc.service.store, tc.featuresFlag, ac) lps, err := librarypanels.ProvideService(cfg, db, routeRegister, elementService, tc.service) require.NoError(t, err) @@ -810,6 +815,7 @@ func TestNestedFolderServiceFeatureToggle(t *testing.T) { dashboardStore: &dashStore, dashboardFolderStore: dashboardFolderStore, features: featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders), + cfg: setting.NewCfg(), accessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient()), metrics: newFoldersMetrics(nil), tracer: tracing.InitializeTracerForTest(), @@ -847,6 +853,7 @@ func TestFolderServiceDualWrite(t *testing.T) { dashboardStore: dashStore, dashboardFolderStore: dashboardFolderStore, features: featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders), + cfg: cfg, accessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient()), metrics: newFoldersMetrics(nil), tracer: tracing.InitializeTracerForTest(), @@ -1479,6 +1486,7 @@ func TestIntegrationNestedFolderSharedWithMe(t *testing.T) { dashboardFolderStore: folderStore, store: nestedFolderStore, features: featuresFlagOn, + cfg: cfg, bus: b, db: db, accessControl: ac, @@ -1901,6 +1909,7 @@ func TestFolderServiceGetFolder(t *testing.T) { dashboardFolderStore: folderStore, store: nestedFolderStore, features: features, + cfg: cfg, bus: b, db: db, accessControl: ac, @@ -1983,6 +1992,7 @@ func TestFolderServiceGetFolders(t *testing.T) { dashboardFolderStore: folderStore, store: nestedFolderStore, features: featuresFlagOff, + cfg: cfg, bus: b, db: db, accessControl: ac, @@ -2070,6 +2080,7 @@ func TestGetChildrenFilterByPermission(t *testing.T) { dashboardFolderStore: folderStore, store: nestedFolderStore, features: features, + cfg: cfg, bus: b, db: db, accessControl: ac, @@ -2533,6 +2544,7 @@ func setup(t *testing.T, dashStore dashboards.Store, dashboardFolderStore folder dashboardFolderStore: dashboardFolderStore, store: nestedFolderStore, features: features, + cfg: setting.NewCfg(), accessControl: ac, db: db, metrics: newFoldersMetrics(nil), diff --git a/pkg/services/guardian/accesscontrol_guardian_test.go b/pkg/services/guardian/accesscontrol_guardian_test.go index ae6aaf279b7..ba8b19cd72f 100644 --- a/pkg/services/guardian/accesscontrol_guardian_test.go +++ b/pkg/services/guardian/accesscontrol_guardian_test.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/services/authz/zanzana" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/folder/foldertest" "github.com/grafana/grafana/pkg/services/licensing/licensingtest" "github.com/grafana/grafana/pkg/services/user" @@ -958,13 +959,13 @@ func setupAccessControlGuardianTest( fakeDashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Maybe().Return(d, nil) ac := acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient()) - folderSvc := foldertest.NewFakeService() + fStore := folder.NewFakeStore() folderStore := foldertest.NewFakeFolderStore(t) - ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(folderStore, fakeDashboardService, folderSvc)) - ac.RegisterScopeAttributeResolver(dashboards.NewFolderUIDScopeResolver(folderSvc)) - ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(folderStore, folderSvc)) + ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(folderStore, fakeDashboardService, fStore)) + ac.RegisterScopeAttributeResolver(dashboards.NewFolderUIDScopeResolver(fStore)) + ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(folderStore, fStore)) license := licensingtest.NewFakeLicensing() license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe() diff --git a/pkg/services/libraryelements/accesscontrol.go b/pkg/services/libraryelements/accesscontrol.go index 68d789cad06..9b52cdd2357 100644 --- a/pkg/services/libraryelements/accesscontrol.go +++ b/pkg/services/libraryelements/accesscontrol.go @@ -35,7 +35,7 @@ var ( // LibraryPanelUIDScopeResolver provides a ScopeAttributeResolver that is able to convert a scope prefixed with "library.panels:uid:" // into uid based scopes for a library panel and its associated folder hierarchy -func LibraryPanelUIDScopeResolver(l *LibraryElementService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { +func LibraryPanelUIDScopeResolver(l *LibraryElementService, folderStore folder.Store) (string, ac.ScopeAttributeResolver) { prefix := ScopeLibraryPanelsProvider.GetResourceScopeUID("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { if !strings.HasPrefix(scope, prefix) { @@ -60,7 +60,7 @@ func LibraryPanelUIDScopeResolver(l *LibraryElementService, folderSvc folder.Ser return nil, err } - inheritedScopes, err := dashboards.GetInheritedScopes(ctx, orgID, libElDTO.FolderUID, folderSvc) + inheritedScopes, err := dashboards.GetInheritedScopes(ctx, orgID, libElDTO.FolderUID, folderStore) if err != nil { return nil, err } diff --git a/pkg/services/libraryelements/libraryelements.go b/pkg/services/libraryelements/libraryelements.go index 02fb5f0ad73..3fbbdca72d9 100644 --- a/pkg/services/libraryelements/libraryelements.go +++ b/pkg/services/libraryelements/libraryelements.go @@ -15,7 +15,7 @@ import ( "github.com/grafana/grafana/pkg/setting" ) -func ProvideService(cfg *setting.Cfg, sqlStore db.DB, routeRegister routing.RouteRegister, folderService folder.Service, features featuremgmt.FeatureToggles, ac accesscontrol.AccessControl) *LibraryElementService { +func ProvideService(cfg *setting.Cfg, sqlStore db.DB, routeRegister routing.RouteRegister, folderService folder.Service, folderStore folder.Store, features featuremgmt.FeatureToggles, ac accesscontrol.AccessControl) *LibraryElementService { l := &LibraryElementService{ Cfg: cfg, SQLStore: sqlStore, @@ -27,7 +27,7 @@ func ProvideService(cfg *setting.Cfg, sqlStore db.DB, routeRegister routing.Rout } l.registerAPIEndpoints() - ac.RegisterScopeAttributeResolver(LibraryPanelUIDScopeResolver(l, l.folderService)) + ac.RegisterScopeAttributeResolver(LibraryPanelUIDScopeResolver(l, folderStore)) return l } diff --git a/pkg/services/libraryelements/libraryelements_test.go b/pkg/services/libraryelements/libraryelements_test.go index 36bdf451541..94e19f86380 100644 --- a/pkg/services/libraryelements/libraryelements_test.go +++ b/pkg/services/libraryelements/libraryelements_test.go @@ -324,6 +324,7 @@ func createFolder(t *testing.T, sc scenarioContext, title string) *folder.Folder features := featuremgmt.WithFeatures() cfg := setting.NewCfg() ac := actest.FakeAccessControl{ExpectedEvaluate: true} + folderPermissions := acmock.NewMockedPermissionsService() quotaService := quotatest.New(false, nil) dashboardStore, err := database.ProvideDashboardStore(sc.sqlStore, cfg, features, tagimpl.ProvideService(sc.sqlStore), quotaService) require.NoError(t, err) @@ -331,7 +332,7 @@ func createFolder(t *testing.T, sc scenarioContext, title string) *folder.Folder folderStore := folderimpl.ProvideDashboardFolderStore(sc.sqlStore) store := folderimpl.ProvideStore(sc.sqlStore) s := folderimpl.ProvideService(store, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore, folderStore, sc.sqlStore, - features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) + features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) t.Logf("Creating folder with title and UID %q", title) ctx := identity.WithRequester(context.Background(), &sc.user) folder, err := s.Create(ctx, &folder.CreateFolderCommand{ @@ -463,7 +464,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo guardian.InitAccessControlGuardian(cfg, ac, dashService) fStore := folderimpl.ProvideStore(sqlStore) folderSrv := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, - features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) + features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) service := LibraryElementService{ Cfg: cfg, features: featuremgmt.WithFeatures(), diff --git a/pkg/services/librarypanels/librarypanels_test.go b/pkg/services/librarypanels/librarypanels_test.go index 8e571be20e2..f61304f9837 100644 --- a/pkg/services/librarypanels/librarypanels_test.go +++ b/pkg/services/librarypanels/librarypanels_test.go @@ -18,6 +18,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "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/dashboards" "github.com/grafana/grafana/pkg/services/dashboards/database" dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" @@ -747,6 +748,7 @@ func createFolder(t *testing.T, sc scenarioContext, title string) *folder.Folder features := featuremgmt.WithFeatures() ac := actest.FakeAccessControl{ExpectedEvaluate: true} + folderPermissions := acmock.NewMockedPermissionsService() cfg := setting.NewCfg() quotaService := quotatest.New(false, nil) dashboardStore, err := database.ProvideDashboardStore(sc.sqlStore, cfg, features, tagimpl.ProvideService(sc.sqlStore), quotaService) @@ -754,7 +756,7 @@ func createFolder(t *testing.T, sc scenarioContext, title string) *folder.Folder folderStore := folderimpl.ProvideDashboardFolderStore(sc.sqlStore) fStore := folderimpl.ProvideStore(sc.sqlStore) s := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore, folderStore, sc.sqlStore, - features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) + features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) t.Logf("Creating folder with title and UID %q", title) ctx := identity.WithRequester(context.Background(), sc.user) @@ -838,10 +840,12 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo require.NoError(t, err) fStore := folderimpl.ProvideStore(sqlStore) + folderPermissions, err := testutil.ProvideFolderPermissions(features, cfg, sqlStore) + require.NoError(t, err) folderService := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore, folderStore, sqlStore, - features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) + features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) - elementService := libraryelements.ProvideService(cfg, sqlStore, routing.NewRouteRegister(), folderService, features, ac) + elementService := libraryelements.ProvideService(cfg, sqlStore, routing.NewRouteRegister(), folderService, fStore, features, ac) service := LibraryPanelService{ Cfg: cfg, SQLStore: sqlStore, diff --git a/pkg/services/ngalert/api/api_provisioning_test.go b/pkg/services/ngalert/api/api_provisioning_test.go index ba50444f8c8..f4e0a2e7eb5 100644 --- a/pkg/services/ngalert/api/api_provisioning_test.go +++ b/pkg/services/ngalert/api/api_provisioning_test.go @@ -27,6 +27,7 @@ import ( "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/actest" + acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards/database" @@ -1817,13 +1818,14 @@ func createTestEnv(t *testing.T, testConfig string) testEnvironment { }}, nil).Maybe() ac := &recordingAccessControlFake{} + folderPermissions := acmock.NewMockedPermissionsService() dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotatest.New(false, nil)) require.NoError(t, err) folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) fStore := folderimpl.ProvideStore(sqlStore) folderService := folderimpl.ProvideService(fStore, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore, folderStore, sqlStore, - featuremgmt.WithFeatures(), supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) + featuremgmt.WithFeatures(), cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) store := store.DBstore{ Logger: log, SQLStore: sqlStore, diff --git a/pkg/services/ngalert/provisioning/alert_rules_test.go b/pkg/services/ngalert/provisioning/alert_rules_test.go index d6d49bca373..432dc0e1b31 100644 --- a/pkg/services/ngalert/provisioning/alert_rules_test.go +++ b/pkg/services/ngalert/provisioning/alert_rules_test.go @@ -1546,11 +1546,11 @@ func TestProvisiongWithFullpath(t *testing.T) { folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) _, dashboardStore := testutil.SetupDashboardService(t, sqlStore, folderStore, cfg) ac := acmock.New() + folderPermissions := acmock.NewMockedPermissionsService() features := featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders) fStore := folderimpl.ProvideStore(sqlStore) folderService := folderimpl.ProvideService(fStore, ac, inProcBus, dashboardStore, folderStore, sqlStore, - features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) - + features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) ruleService := createAlertRuleService(t, folderService) var orgID int64 = 1 diff --git a/pkg/services/ngalert/testutil/testutil.go b/pkg/services/ngalert/testutil/testutil.go index b9885c7bd53..417680c39c2 100644 --- a/pkg/services/ngalert/testutil/testutil.go +++ b/pkg/services/ngalert/testutil/testutil.go @@ -27,9 +27,10 @@ import ( func SetupFolderService(tb testing.TB, cfg *setting.Cfg, db db.DB, dashboardStore dashboards.Store, folderStore *folderimpl.DashboardFolderStoreImpl, bus *bus.InProcBus, features featuremgmt.FeatureToggles, ac accesscontrol.AccessControl) folder.Service { tb.Helper() + folderPermissions := acmock.NewMockedPermissionsService() fStore := folderimpl.ProvideStore(db) return folderimpl.ProvideService(fStore, ac, bus, dashboardStore, folderStore, db, - features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) + features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) } func SetupDashboardService(tb testing.TB, sqlStore db.DB, fs *folderimpl.DashboardFolderStoreImpl, cfg *setting.Cfg) (*dashboardservice.DashboardServiceImpl, dashboards.Store) { diff --git a/pkg/services/searchV2/auth.go b/pkg/services/searchV2/auth.go index 5c23e6598ab..5d75fbfd24c 100644 --- a/pkg/services/searchV2/auth.go +++ b/pkg/services/searchV2/auth.go @@ -22,24 +22,24 @@ type FutureAuthService interface { var _ FutureAuthService = (*simpleAuthService)(nil) type simpleAuthService struct { - sql db.DB - ac accesscontrol.Service - folderService folder.Service - logger log.Logger + sql db.DB + ac accesscontrol.Service + folderStore folder.Store + logger log.Logger } func (a *simpleAuthService) GetDashboardReadFilter(ctx context.Context, orgID int64, user *user.SignedInUser) (ResourceFilter, error) { canReadDashboard, canReadFolder := accesscontrol.Checker(user, dashboards.ActionDashboardsRead), accesscontrol.Checker(user, dashboards.ActionFoldersRead) return func(kind entityKind, uid, parent string) bool { if kind == entityKindFolder { - scopes, err := dashboards.GetInheritedScopes(ctx, orgID, uid, a.folderService) + scopes, err := dashboards.GetInheritedScopes(ctx, orgID, uid, a.folderStore) if err != nil { a.logger.Debug("Could not retrieve inherited folder scopes:", "err", err) } scopes = append(scopes, dashboards.ScopeFoldersProvider.GetResourceScopeUID(uid)) return canReadFolder(scopes...) } else if kind == entityKindDashboard { - scopes, err := dashboards.GetInheritedScopes(ctx, orgID, parent, a.folderService) + scopes, err := dashboards.GetInheritedScopes(ctx, orgID, parent, a.folderStore) if err != nil { a.logger.Debug("Could not retrieve inherited folder scopes:", "err", err) } diff --git a/pkg/services/searchV2/index_test.go b/pkg/services/searchV2/index_test.go index e6a569fb57c..976233f7a07 100644 --- a/pkg/services/searchV2/index_test.go +++ b/pkg/services/searchV2/index_test.go @@ -18,7 +18,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol/actest" "github.com/grafana/grafana/pkg/services/dashboards/database" "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/services/folder/foldertest" + "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org/orgtest" "github.com/grafana/grafana/pkg/services/quota/quotatest" @@ -754,7 +754,7 @@ func setupIntegrationEnv(t *testing.T, folderCount, dashboardsPerFolder int, sql ExpectedOrgs: []*org.OrgDTO{{ID: 1}}, } searchService, ok := ProvideService(cfg, sqlStore, store.NewDummyEntityEventsService(), actest.FakeService{}, - tracing.InitializeTracerForTest(), features, orgSvc, nil, foldertest.NewFakeService()).(*StandardSearchService) + tracing.InitializeTracerForTest(), features, orgSvc, nil, folder.NewFakeStore()).(*StandardSearchService) require.True(t, ok) err = runSearchService(searchService) diff --git a/pkg/services/searchV2/service.go b/pkg/services/searchV2/service.go index d886ec649a0..b0fbcfe72ca 100644 --- a/pkg/services/searchV2/service.go +++ b/pkg/services/searchV2/service.go @@ -85,7 +85,7 @@ func (s *StandardSearchService) IsReady(ctx context.Context, orgId int64) IsSear func ProvideService(cfg *setting.Cfg, sql db.DB, entityEventStore store.EntityEventsService, ac accesscontrol.Service, tracer tracing.Tracer, features featuremgmt.FeatureToggles, orgService org.Service, - userService user.Service, folderService folder.Service) SearchService { + userService user.Service, folderStore folder.Store) SearchService { extender := &NoopExtender{} logger := log.New("searchV2") s := &StandardSearchService{ @@ -93,10 +93,10 @@ func ProvideService(cfg *setting.Cfg, sql db.DB, entityEventStore store.EntityEv sql: sql, ac: ac, auth: &simpleAuthService{ - sql: sql, - ac: ac, - folderService: folderService, - logger: logger, + sql: sql, + ac: ac, + folderStore: folderStore, + logger: logger, }, dashboardIndex: newSearchIndex( newSQLDashboardLoader(sql, tracer, cfg.Search), diff --git a/pkg/services/searchV2/service_bench_test.go b/pkg/services/searchV2/service_bench_test.go index 778e7bd2bf8..42a9849fd31 100644 --- a/pkg/services/searchV2/service_bench_test.go +++ b/pkg/services/searchV2/service_bench_test.go @@ -13,7 +13,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol/actest" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/services/folder/foldertest" + "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org/orgtest" "github.com/grafana/grafana/pkg/services/store" @@ -42,7 +42,7 @@ func setupBenchEnv(b *testing.B, folderCount, dashboardsPerFolder int) (*Standar ExpectedOrgs: []*org.OrgDTO{{ID: 1}}, } searchService, ok := ProvideService(cfg, sqlStore, store.NewDummyEntityEventsService(), actest.FakeService{}, - tracing.InitializeTracerForTest(), features, orgSvc, nil, foldertest.NewFakeService()).(*StandardSearchService) + tracing.InitializeTracerForTest(), features, orgSvc, nil, folder.NewFakeStore()).(*StandardSearchService) require.True(b, ok) err = runSearchService(searchService) diff --git a/pkg/services/sqlstore/permissions/dashboard_test.go b/pkg/services/sqlstore/permissions/dashboard_test.go index 57040ee9f1d..338b4fcd05a 100644 --- a/pkg/services/sqlstore/permissions/dashboard_test.go +++ b/pkg/services/sqlstore/permissions/dashboard_test.go @@ -16,6 +16,7 @@ import ( "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/actest" + "github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol/testutil" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" "github.com/grafana/grafana/pkg/services/dashboards/database" @@ -822,10 +823,11 @@ func setupNestedTest(t *testing.T, usr *user.SignedInUser, perms []accesscontrol dashStore, err := database.ProvideDashboardStore(db, cfg, features, tagimpl.ProvideService(db), quotatest.New(false, nil)) require.NoError(t, err) + folderPermissions, err := testutil.ProvideFolderPermissions(features, cfg, db) + require.NoError(t, err) fStore := folderimpl.ProvideStore(db) folderSvc := folderimpl.ProvideService(fStore, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore, - folderimpl.ProvideDashboardFolderStore(db), db, features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) - + folderimpl.ProvideDashboardFolderStore(db), db, features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) // create parent folder parent, err := folderSvc.Create(context.Background(), &folder.CreateFolderCommand{ UID: "parent", diff --git a/pkg/services/sqlstore/permissions/dashboards_bench_test.go b/pkg/services/sqlstore/permissions/dashboards_bench_test.go index 594b41dcfb2..7998e1a1adf 100644 --- a/pkg/services/sqlstore/permissions/dashboards_bench_test.go +++ b/pkg/services/sqlstore/permissions/dashboards_bench_test.go @@ -78,12 +78,13 @@ func setupBenchMark(b *testing.B, usr user.SignedInUser, features featuremgmt.Fe quotaService := quotatest.New(false, nil) + folderPermissions := mock.NewMockedPermissionsService() dashboardWriteStore, err := database.ProvideDashboardStore(store, cfg, features, tagimpl.ProvideService(store), quotaService) require.NoError(b, err) fStore := folderimpl.ProvideStore(store) folderSvc := folderimpl.ProvideService(fStore, mock.New(), bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardWriteStore, folderimpl.ProvideDashboardFolderStore(store), - store, features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) + store, features, cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest()) origNewGuardian := guardian.New guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true, CanSaveValue: true})