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
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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++ {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user