mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Access Control: revert to using folder store from the scope resolvers (#64132)
* revert to using folder store from the resolvers * fixing tests after revert * api test fixes --------- Co-authored-by: Kristin Laemmert <mildwonkey@users.noreply.github.com>
This commit is contained in:
parent
dbb72f2c6e
commit
a52999a886
@ -47,7 +47,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
|
||||
SQLStore: mockSQLStore,
|
||||
Features: features,
|
||||
DashboardService: dashboardservice.ProvideDashboardService(
|
||||
settings, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac,
|
||||
settings, dashboardStore, foldertest.NewFakeFolderStore(t), nil, features, folderPermissions, dashboardPermissions, ac,
|
||||
folderSvc,
|
||||
),
|
||||
AccessControl: accesscontrolmock.New().WithDisabled(),
|
||||
|
@ -987,7 +987,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
|
||||
|
||||
if dashboardService == nil {
|
||||
dashboardService = service.ProvideDashboardService(
|
||||
cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions,
|
||||
cfg, dashboardStore, folderStore, nil, features, folderPermissions, dashboardPermissions,
|
||||
ac, folderSvc,
|
||||
)
|
||||
}
|
||||
@ -1000,7 +1000,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
|
||||
ProvisioningService: provisioningService,
|
||||
AccessControl: accesscontrolmock.New(),
|
||||
dashboardProvisioningService: service.ProvideDashboardService(
|
||||
cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions,
|
||||
cfg, dashboardStore, folderStore, nil, features, folderPermissions, dashboardPermissions,
|
||||
ac, folderSvc,
|
||||
),
|
||||
DashboardService: dashboardService,
|
||||
|
@ -45,7 +45,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
|
||||
folderPermissionsService: folderPermissions,
|
||||
dashboardPermissionsService: dashboardPermissions,
|
||||
DashboardService: service.ProvideDashboardService(
|
||||
settings, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac,
|
||||
settings, dashboardStore, foldertest.NewFakeFolderStore(t), nil, features, folderPermissions, dashboardPermissions, ac,
|
||||
folderService,
|
||||
),
|
||||
AccessControl: accesscontrolmock.New().WithDisabled(),
|
||||
|
@ -39,7 +39,7 @@ var (
|
||||
)
|
||||
|
||||
// NewFolderNameScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:name:" into an uid based scope.
|
||||
func NewFolderNameScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||
func NewFolderNameScopeResolver(folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||
prefix := ScopeFoldersProvider.GetResourceScopeName("")
|
||||
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
||||
if !strings.HasPrefix(scope, prefix) {
|
||||
@ -49,7 +49,7 @@ func NewFolderNameScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttri
|
||||
if len(nsName) == 0 {
|
||||
return nil, ac.ErrInvalidScope
|
||||
}
|
||||
folder, err := folderSvc.Get(ctx, &folder.GetFolderQuery{Title: &nsName})
|
||||
folder, err := folderDB.GetFolderByTitle(ctx, orgID, nsName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -65,7 +65,7 @@ func NewFolderNameScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttri
|
||||
}
|
||||
|
||||
// NewFolderIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:id:" into an uid based scope.
|
||||
func NewFolderIDScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||
func NewFolderIDScopeResolver(folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||
prefix := ScopeFoldersProvider.GetResourceScope("")
|
||||
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
||||
if !strings.HasPrefix(scope, prefix) {
|
||||
@ -81,7 +81,7 @@ func NewFolderIDScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttribu
|
||||
return []string{ScopeFoldersProvider.GetResourceScopeUID(ac.GeneralFolderUID)}, nil
|
||||
}
|
||||
|
||||
folder, err := folderSvc.Get(ctx, &folder.GetFolderQuery{OrgID: orgID, ID: &id})
|
||||
folder, err := folderDB.GetFolderByID(ctx, orgID, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -120,7 +120,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(ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||
func NewDashboardIDScopeResolver(folderDB folder.FolderStore, ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||
prefix := ScopeDashboardsProvider.GetResourceScope("")
|
||||
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
||||
if !strings.HasPrefix(scope, prefix) {
|
||||
@ -137,13 +137,13 @@ func NewDashboardIDScopeResolver(ds DashboardService, folderSvc folder.Service)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resolveDashboardScope(ctx, orgID, dashboard, folderSvc)
|
||||
return resolveDashboardScope(ctx, folderDB, orgID, dashboard, folderSvc)
|
||||
})
|
||||
}
|
||||
|
||||
// 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(ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||
func NewDashboardUIDScopeResolver(folderDB folder.FolderStore, ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||
prefix := ScopeDashboardsProvider.GetResourceScopeUID("")
|
||||
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
||||
if !strings.HasPrefix(scope, prefix) {
|
||||
@ -160,11 +160,11 @@ func NewDashboardUIDScopeResolver(ds DashboardService, folderSvc folder.Service)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resolveDashboardScope(ctx, orgID, dashboard, folderSvc)
|
||||
return resolveDashboardScope(ctx, folderDB, orgID, dashboard, folderSvc)
|
||||
})
|
||||
}
|
||||
|
||||
func resolveDashboardScope(ctx context.Context, orgID int64, dashboard *Dashboard, folderSvc folder.Service) ([]string, error) {
|
||||
func resolveDashboardScope(ctx context.Context, folderDB folder.FolderStore, orgID int64, dashboard *Dashboard, folderSvc folder.Service) ([]string, error) {
|
||||
var folderUID string
|
||||
if dashboard.FolderID < 0 {
|
||||
return []string{ScopeDashboardsProvider.GetResourceScopeUID(dashboard.UID)}, nil
|
||||
@ -173,7 +173,7 @@ func resolveDashboardScope(ctx context.Context, orgID int64, dashboard *Dashboar
|
||||
if dashboard.FolderID == 0 {
|
||||
folderUID = ac.GeneralFolderUID
|
||||
} else {
|
||||
folder, err := folderSvc.Get(ctx, &folder.GetFolderQuery{OrgID: orgID, ID: &dashboard.FolderID})
|
||||
folder, err := folderDB.GetFolderByID(ctx, orgID, dashboard.FolderID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -19,30 +19,36 @@ import (
|
||||
|
||||
func TestNewFolderNameScopeResolver(t *testing.T) {
|
||||
t.Run("prefix should be expected", func(t *testing.T) {
|
||||
prefix, _ := NewFolderNameScopeResolver(foldertest.NewFakeService())
|
||||
prefix, _ := NewFolderNameScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||
require.Equal(t, "folders:name:", prefix)
|
||||
})
|
||||
|
||||
t.Run("resolver should convert to uid scope", func(t *testing.T) {
|
||||
folderService := foldertest.NewFakeService()
|
||||
orgId := rand.Int63()
|
||||
title := "Very complex :title with: and /" + util.GenerateShortUID()
|
||||
db := &folder.Folder{Title: title, ID: rand.Int63(), UID: util.GenerateShortUID()}
|
||||
folderService.ExpectedFolder = db
|
||||
folderStore := foldertest.NewFakeFolderStore(t)
|
||||
folderStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(db, nil).Once()
|
||||
|
||||
scope := "folders:name:" + title
|
||||
|
||||
_, resolver := NewFolderNameScopeResolver(folderService)
|
||||
_, resolver := NewFolderNameScopeResolver(folderStore, foldertest.NewFakeService())
|
||||
resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, resolvedScopes, 1)
|
||||
require.Equal(t, fmt.Sprintf("folders:uid:%v", db.UID), resolvedScopes[0])
|
||||
folderStore.AssertCalled(t, "GetFolderByTitle", mock.Anything, orgId, title)
|
||||
})
|
||||
t.Run("resolver should include inherited scopes if any", func(t *testing.T) {
|
||||
orgId := rand.Int63()
|
||||
title := "Very complex :title with: and /" + util.GenerateShortUID()
|
||||
|
||||
db := &folder.Folder{Title: title, ID: rand.Int63(), UID: util.GenerateShortUID()}
|
||||
|
||||
folderStore := foldertest.NewFakeFolderStore(t)
|
||||
folderStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(db, nil).Once()
|
||||
|
||||
scope := "folders:name:" + title
|
||||
uid := util.GenerateShortUID()
|
||||
|
||||
folderSvc := foldertest.NewFakeService()
|
||||
folderSvc.ExpectedFolders = []*folder.Folder{
|
||||
@ -53,39 +59,40 @@ func TestNewFolderNameScopeResolver(t *testing.T) {
|
||||
UID: "grandparent",
|
||||
},
|
||||
}
|
||||
folderSvc.ExpectedFolder = &folder.Folder{Title: title, ID: rand.Int63(), UID: uid}
|
||||
_, resolver := NewFolderNameScopeResolver(folderSvc)
|
||||
_, resolver := NewFolderNameScopeResolver(folderStore, folderSvc)
|
||||
|
||||
resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, resolvedScopes, 3)
|
||||
|
||||
if diff := cmp.Diff([]string{
|
||||
fmt.Sprintf("folders:uid:%v", uid),
|
||||
fmt.Sprintf("folders:uid:%v", db.UID),
|
||||
"folders:uid:parent",
|
||||
"folders:uid:grandparent",
|
||||
}, resolvedScopes); diff != "" {
|
||||
t.Errorf("Result mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
|
||||
folderStore.AssertCalled(t, "GetFolderByTitle", mock.Anything, orgId, title)
|
||||
})
|
||||
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
|
||||
_, resolver := NewFolderNameScopeResolver(foldertest.NewFakeService())
|
||||
_, resolver := NewFolderNameScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||
|
||||
_, 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.NewFakeService())
|
||||
_, resolver := NewFolderNameScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||
|
||||
_, 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) {
|
||||
folderService := foldertest.NewFakeService()
|
||||
_, resolver := NewFolderNameScopeResolver(folderService)
|
||||
folderStore := foldertest.NewFakeFolderStore(t)
|
||||
_, resolver := NewFolderNameScopeResolver(folderStore, foldertest.NewFakeService())
|
||||
|
||||
orgId := rand.Int63()
|
||||
folderService.ExpectedError = ErrDashboardNotFound
|
||||
folderStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once()
|
||||
|
||||
scope := "folders:name:" + util.GenerateShortUID()
|
||||
|
||||
@ -97,26 +104,29 @@ func TestNewFolderNameScopeResolver(t *testing.T) {
|
||||
|
||||
func TestNewFolderIDScopeResolver(t *testing.T) {
|
||||
t.Run("prefix should be expected", func(t *testing.T) {
|
||||
prefix, _ := NewFolderIDScopeResolver(foldertest.NewFakeService())
|
||||
prefix, _ := NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||
require.Equal(t, "folders:id:", prefix)
|
||||
})
|
||||
|
||||
t.Run("resolver should convert to uid scope", func(t *testing.T) {
|
||||
folderSvc := foldertest.NewFakeService()
|
||||
folderStore := foldertest.NewFakeFolderStore(t)
|
||||
_, resolver := NewFolderIDScopeResolver(folderStore, foldertest.NewFakeService())
|
||||
|
||||
orgId := rand.Int63()
|
||||
uid := util.GenerateShortUID()
|
||||
db := &folder.Folder{ID: rand.Int63(), UID: uid}
|
||||
folderSvc.ExpectedFolder = db
|
||||
|
||||
_, resolver := NewFolderIDScopeResolver(folderSvc)
|
||||
folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(db, nil).Once()
|
||||
|
||||
scope := "folders:id:" + strconv.FormatInt(db.ID, 10)
|
||||
resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, resolvedScopes, 1)
|
||||
require.Equal(t, fmt.Sprintf("folders:uid:%v", db.UID), resolvedScopes[0])
|
||||
|
||||
folderStore.AssertCalled(t, "GetFolderByID", mock.Anything, orgId, db.ID)
|
||||
})
|
||||
t.Run("resolver should should include inherited scopes if any", func(t *testing.T) {
|
||||
folderStore := foldertest.NewFakeFolderStore(t)
|
||||
folderSvc := foldertest.NewFakeService()
|
||||
folderSvc.ExpectedFolders = []*folder.Folder{
|
||||
{
|
||||
@ -126,12 +136,12 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
|
||||
UID: "grandparent",
|
||||
},
|
||||
}
|
||||
_, resolver := NewFolderIDScopeResolver(folderSvc)
|
||||
_, resolver := NewFolderIDScopeResolver(folderStore, folderSvc)
|
||||
|
||||
orgId := rand.Int63()
|
||||
uid := util.GenerateShortUID()
|
||||
db := &folder.Folder{ID: rand.Int63(), UID: uid}
|
||||
folderSvc.ExpectedFolder = db
|
||||
folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(db, nil).Once()
|
||||
|
||||
scope := "folders:id:" + strconv.FormatInt(db.ID, 10)
|
||||
|
||||
@ -146,9 +156,11 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
|
||||
}, resolvedScopes); diff != "" {
|
||||
t.Errorf("Result mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
|
||||
folderStore.AssertCalled(t, "GetFolderByID", mock.Anything, orgId, db.ID)
|
||||
})
|
||||
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
|
||||
_, resolver := NewFolderIDScopeResolver(foldertest.NewFakeService())
|
||||
_, resolver := NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||
|
||||
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:uid:123")
|
||||
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
||||
@ -158,7 +170,7 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
|
||||
var (
|
||||
orgId = rand.Int63()
|
||||
scope = "folders:id:0"
|
||||
_, resolver = NewFolderIDScopeResolver(foldertest.NewFakeService())
|
||||
_, resolver = NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||
)
|
||||
|
||||
resolved, err := resolver.Resolve(context.Background(), orgId, scope)
|
||||
@ -169,18 +181,17 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) {
|
||||
_, resolver := NewFolderIDScopeResolver(foldertest.NewFakeService())
|
||||
_, resolver := NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||
|
||||
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:id:")
|
||||
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
||||
})
|
||||
t.Run("returns 'not found' if folder does not exist", func(t *testing.T) {
|
||||
svc := foldertest.NewFakeService()
|
||||
svc.ExpectedError = ErrDashboardNotFound
|
||||
_, resolver := NewFolderIDScopeResolver(svc)
|
||||
folderStore := foldertest.NewFakeFolderStore(t)
|
||||
folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once()
|
||||
_, resolver := NewFolderIDScopeResolver(folderStore, foldertest.NewFakeService())
|
||||
|
||||
orgId := rand.Int63()
|
||||
|
||||
scope := "folders:id:10"
|
||||
resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope)
|
||||
require.ErrorIs(t, err, ErrDashboardNotFound)
|
||||
@ -190,22 +201,21 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
|
||||
|
||||
func TestNewDashboardIDScopeResolver(t *testing.T) {
|
||||
t.Run("prefix should be expected", func(t *testing.T) {
|
||||
prefix, _ := NewDashboardIDScopeResolver(&FakeDashboardService{}, foldertest.NewFakeService())
|
||||
prefix, _ := NewDashboardIDScopeResolver(foldertest.NewFakeFolderStore(t), &FakeDashboardService{}, foldertest.NewFakeService())
|
||||
require.Equal(t, "dashboards:id:", prefix)
|
||||
})
|
||||
|
||||
t.Run("resolver should convert to uid dashboard and folder scope", func(t *testing.T) {
|
||||
dashSvc := NewFakeDashboardService(t)
|
||||
folderService := foldertest.NewFakeService()
|
||||
_, resolver := NewDashboardIDScopeResolver(dashSvc, folderService)
|
||||
folderStore := foldertest.NewFakeFolderStore(t)
|
||||
dashSvc := &FakeDashboardService{}
|
||||
_, resolver := NewDashboardIDScopeResolver(folderStore, dashSvc, foldertest.NewFakeService())
|
||||
|
||||
orgID := rand.Int63()
|
||||
folder := &folder.Folder{ID: 2, UID: "2"}
|
||||
dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"}
|
||||
|
||||
dashSvc.On("G")
|
||||
folderStore.On("GetFolderByID", mock.Anything, orgID, folder.ID).Return(folder, nil).Once()
|
||||
dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
|
||||
folderService.ExpectedFolder = folder
|
||||
|
||||
scope := ac.Scope("dashboards", "id", strconv.FormatInt(dashboard.ID, 10))
|
||||
resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope)
|
||||
require.NoError(t, err)
|
||||
@ -216,6 +226,7 @@ func TestNewDashboardIDScopeResolver(t *testing.T) {
|
||||
|
||||
t.Run("resolver should inlude inherited scopes if any", func(t *testing.T) {
|
||||
dashSvc := &FakeDashboardService{}
|
||||
folderStore := foldertest.NewFakeFolderStore(t)
|
||||
folderSvc := foldertest.NewFakeService()
|
||||
folderSvc.ExpectedFolders = []*folder.Folder{
|
||||
{
|
||||
@ -225,13 +236,14 @@ func TestNewDashboardIDScopeResolver(t *testing.T) {
|
||||
UID: "grandparent",
|
||||
},
|
||||
}
|
||||
_, resolver := NewDashboardIDScopeResolver(dashSvc, folderSvc)
|
||||
_, resolver := NewDashboardIDScopeResolver(folderStore, dashSvc, folderSvc)
|
||||
|
||||
orgID := rand.Int63()
|
||||
folder := &folder.Folder{ID: 2, UID: "2"}
|
||||
dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"}
|
||||
folderSvc.ExpectedFolder = folder
|
||||
|
||||
dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
|
||||
folderStore.On("GetFolderByID", mock.Anything, orgID, folder.ID).Return(folder, nil).Once()
|
||||
|
||||
scope := ac.Scope("dashboards", "id", strconv.FormatInt(dashboard.ID, 10))
|
||||
resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope)
|
||||
@ -249,14 +261,14 @@ func TestNewDashboardIDScopeResolver(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
|
||||
_, resolver := NewDashboardIDScopeResolver(&FakeDashboardService{}, foldertest.NewFakeService())
|
||||
_, resolver := NewDashboardIDScopeResolver(foldertest.NewFakeFolderStore(t), &FakeDashboardService{}, foldertest.NewFakeService())
|
||||
_, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:uid:123")
|
||||
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
||||
})
|
||||
|
||||
t.Run("resolver should convert folderID 0 to general uid scope for the folder scope", func(t *testing.T) {
|
||||
dashSvc := &FakeDashboardService{}
|
||||
_, resolver := NewDashboardIDScopeResolver(dashSvc, foldertest.NewFakeService())
|
||||
_, resolver := NewDashboardIDScopeResolver(foldertest.NewFakeFolderStore(t), dashSvc, foldertest.NewFakeService())
|
||||
|
||||
dashboard := &Dashboard{ID: 1, FolderID: 0, UID: "1"}
|
||||
dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil)
|
||||
@ -271,21 +283,21 @@ func TestNewDashboardIDScopeResolver(t *testing.T) {
|
||||
|
||||
func TestNewDashboardUIDScopeResolver(t *testing.T) {
|
||||
t.Run("prefix should be expected", func(t *testing.T) {
|
||||
prefix, _ := NewDashboardUIDScopeResolver(&FakeDashboardService{}, foldertest.NewFakeService())
|
||||
prefix, _ := NewDashboardUIDScopeResolver(foldertest.NewFakeFolderStore(t), &FakeDashboardService{}, foldertest.NewFakeService())
|
||||
require.Equal(t, "dashboards:uid:", prefix)
|
||||
})
|
||||
|
||||
t.Run("resolver should convert to uid dashboard and folder scope", func(t *testing.T) {
|
||||
service := &FakeDashboardService{}
|
||||
folderSvc := foldertest.NewFakeService()
|
||||
_, resolver := NewDashboardUIDScopeResolver(service, folderSvc)
|
||||
folderStore := foldertest.NewFakeFolderStore(t)
|
||||
dashSvc := &FakeDashboardService{}
|
||||
_, resolver := NewDashboardUIDScopeResolver(folderStore, dashSvc, foldertest.NewFakeService())
|
||||
|
||||
orgID := rand.Int63()
|
||||
folder := &folder.Folder{ID: 2, UID: "2"}
|
||||
folderSvc.ExpectedFolder = folder
|
||||
dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"}
|
||||
service.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
|
||||
|
||||
dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
|
||||
folderStore.On("GetFolderByID", mock.Anything, orgID, folder.ID).Return(folder, nil).Once()
|
||||
scope := ac.Scope("dashboards", "uid", dashboard.UID)
|
||||
resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope)
|
||||
require.NoError(t, err)
|
||||
@ -295,7 +307,7 @@ func TestNewDashboardUIDScopeResolver(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("resolver should include inherited scopes if any", func(t *testing.T) {
|
||||
svc := &FakeDashboardService{}
|
||||
folderStore := foldertest.NewFakeFolderStore(t)
|
||||
folderSvc := foldertest.NewFakeService()
|
||||
folderSvc.ExpectedFolders = []*folder.Folder{
|
||||
{
|
||||
@ -305,14 +317,14 @@ func TestNewDashboardUIDScopeResolver(t *testing.T) {
|
||||
UID: "grandparent",
|
||||
},
|
||||
}
|
||||
|
||||
_, resolver := NewDashboardUIDScopeResolver(svc, folderSvc)
|
||||
dashSvc := &FakeDashboardService{}
|
||||
_, resolver := NewDashboardUIDScopeResolver(folderStore, dashSvc, folderSvc)
|
||||
|
||||
orgID := rand.Int63()
|
||||
folder := &folder.Folder{ID: 2, UID: "2"}
|
||||
folderSvc.ExpectedFolder = folder
|
||||
dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"}
|
||||
svc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
|
||||
dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
|
||||
folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(folder, nil).Once()
|
||||
|
||||
scope := ac.Scope("dashboards", "uid", dashboard.UID)
|
||||
resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope)
|
||||
@ -330,14 +342,14 @@ func TestNewDashboardUIDScopeResolver(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
|
||||
_, resolver := NewDashboardUIDScopeResolver(&FakeDashboardService{}, foldertest.NewFakeService())
|
||||
_, resolver := NewDashboardUIDScopeResolver(foldertest.NewFakeFolderStore(t), &FakeDashboardService{}, foldertest.NewFakeService())
|
||||
_, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:id:123")
|
||||
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
||||
})
|
||||
|
||||
t.Run("resolver should convert folderID 0 to general uid scope for the folder scope", func(t *testing.T) {
|
||||
service := &FakeDashboardService{}
|
||||
_, resolver := NewDashboardUIDScopeResolver(service, foldertest.NewFakeService())
|
||||
_, resolver := NewDashboardUIDScopeResolver(foldertest.NewFakeFolderStore(t), service, foldertest.NewFakeService())
|
||||
|
||||
dashboard := &Dashboard{ID: 1, FolderID: 0, UID: "1"}
|
||||
service.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil)
|
||||
|
@ -40,6 +40,7 @@ type DashboardServiceImpl struct {
|
||||
cfg *setting.Cfg
|
||||
log log.Logger
|
||||
dashboardStore dashboards.Store
|
||||
folderStore folder.FolderStore
|
||||
folderService folder.Service
|
||||
dashAlertExtractor alerting.DashAlertExtractor
|
||||
features featuremgmt.FeatureToggles
|
||||
@ -50,7 +51,7 @@ type DashboardServiceImpl struct {
|
||||
|
||||
// This is the uber service that implements a three smaller services
|
||||
func ProvideDashboardService(
|
||||
cfg *setting.Cfg, dashboardStore dashboards.Store, dashAlertExtractor alerting.DashAlertExtractor,
|
||||
cfg *setting.Cfg, dashboardStore dashboards.Store, folderStore folder.FolderStore, dashAlertExtractor alerting.DashAlertExtractor,
|
||||
features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService,
|
||||
dashboardPermissionsService accesscontrol.DashboardPermissionsService, ac accesscontrol.AccessControl,
|
||||
folderSvc folder.Service,
|
||||
@ -64,11 +65,12 @@ func ProvideDashboardService(
|
||||
folderPermissions: folderPermissionsService,
|
||||
dashboardPermissions: dashboardPermissionsService,
|
||||
ac: ac,
|
||||
folderStore: folderStore,
|
||||
folderService: folderSvc,
|
||||
}
|
||||
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(dashSvc, folderSvc))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashSvc, folderSvc))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(folderStore, dashSvc, folderSvc))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(folderStore, dashSvc, folderSvc))
|
||||
|
||||
return dashSvc
|
||||
}
|
||||
@ -631,7 +633,7 @@ func (dr DashboardServiceImpl) CountDashboardsInFolder(ctx context.Context, quer
|
||||
return 0, err
|
||||
}
|
||||
|
||||
folder, err := dr.folderService.Get(ctx, &folder.GetFolderQuery{UID: &query.FolderUID, OrgID: u.OrgID})
|
||||
folder, err := dr.folderService.Get(ctx, &folder.GetFolderQuery{UID: &query.FolderUID, OrgID: u.OrgID, SignedInUser: u})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
@ -826,8 +827,9 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
service := ProvideDashboardService(
|
||||
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
||||
cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{},
|
||||
featuremgmt.WithFeatures(),
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
@ -886,8 +888,9 @@ func callSaveWithResult(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSt
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
service := ProvideDashboardService(
|
||||
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
||||
cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{},
|
||||
featuremgmt.WithFeatures(),
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
@ -908,8 +911,9 @@ func callSaveWithError(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSto
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
service := ProvideDashboardService(
|
||||
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
||||
cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{},
|
||||
featuremgmt.WithFeatures(),
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
@ -948,8 +952,9 @@ func saveTestDashboard(t *testing.T, title string, orgID, folderID int64, sqlSto
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
service := ProvideDashboardService(
|
||||
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
||||
cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{},
|
||||
featuremgmt.WithFeatures(),
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
@ -989,8 +994,9 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore db.DB) *da
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
service := ProvideDashboardService(
|
||||
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
||||
cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{},
|
||||
featuremgmt.WithFeatures(),
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
|
@ -62,8 +62,8 @@ func ProvideService(
|
||||
srv.DBMigration(db)
|
||||
}
|
||||
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(srv))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(srv))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(folderStore, srv))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(folderStore, srv))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderUIDScopeResolver(srv))
|
||||
return srv
|
||||
}
|
||||
|
@ -618,7 +618,7 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []acce
|
||||
|
||||
ac := accesscontrolmock.New().WithPermissions(permissions)
|
||||
// TODO replace with actual folder store implementation after resolving import cycles
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashboardSvc, foldertest.NewFakeService()))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(foldertest.NewFakeFolderStore(t), dashboardSvc, foldertest.NewFakeService()))
|
||||
license := licensingtest.NewFakeLicensing()
|
||||
license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe()
|
||||
teamSvc := teamimpl.ProvideService(store, store.Cfg)
|
||||
|
@ -294,8 +294,9 @@ func createDashboard(t *testing.T, sqlStore db.DB, user user.SignedInUser, dash
|
||||
ac := acmock.New()
|
||||
folderPermissions := acmock.NewMockedPermissionsService()
|
||||
dashboardPermissions := acmock.NewMockedPermissionsService()
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
service := dashboardservice.ProvideDashboardService(
|
||||
cfg, dashboardStore, dashAlertExtractor,
|
||||
cfg, dashboardStore, folderStore, dashAlertExtractor,
|
||||
features, folderPermissions, dashboardPermissions, ac,
|
||||
foldertest.NewFakeService(),
|
||||
)
|
||||
@ -441,7 +442,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
||||
dashboardPermissions := acmock.NewMockedPermissionsService()
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
dashboardService := dashboardservice.ProvideDashboardService(
|
||||
sqlStore.Cfg, dashboardStore, nil,
|
||||
sqlStore.Cfg, dashboardStore, folderStore, nil,
|
||||
features, folderPermissions, dashboardPermissions, ac,
|
||||
foldertest.NewFakeService(),
|
||||
)
|
||||
|
@ -706,8 +706,9 @@ func createDashboard(t *testing.T, sqlStore db.DB, user *user.SignedInUser, dash
|
||||
require.NoError(t, err)
|
||||
dashAlertService := alerting.ProvideDashAlertExtractorService(nil, nil, nil)
|
||||
ac := acmock.New()
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
service := dashboardservice.ProvideDashboardService(
|
||||
cfg, dashboardStore, dashAlertService,
|
||||
cfg, dashboardStore, folderStore, dashAlertService,
|
||||
featuremgmt.WithFeatures(), acmock.NewMockedPermissionsService(), acmock.NewMockedPermissionsService(), ac,
|
||||
foldertest.NewFakeService(),
|
||||
)
|
||||
|
@ -82,7 +82,7 @@ func SetupTestEnv(tb testing.TB, baseInterval time.Duration) (*ngalert.AlertNG,
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
|
||||
dashboardService := dashboardservice.ProvideDashboardService(
|
||||
cfg, dashboardStore, nil,
|
||||
cfg, dashboardStore, folderStore, nil,
|
||||
features, folderPermissions, dashboardPermissions, ac,
|
||||
foldertest.NewFakeService(),
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user