Folders: Allow listing folders with write permission (#83527)
* Folders: Allow listing folders with write permission * Check for subfolder access if parent does not have * Add test * GetFolders: fix ordering * Apply suggestion from code review
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -25,6 +26,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
|
||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
@@ -1798,6 +1800,247 @@ func TestFolderServiceGetFolders(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TODO replace it with an API test under /pkg/tests/api/folders
|
||||
// whenever the golang client with get updated to allow filtering child folders by permission
|
||||
func TestGetChildrenFilterByPermission(t *testing.T) {
|
||||
db := sqlstore.InitTestDB(t)
|
||||
|
||||
signedInAdminUser := user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{
|
||||
orgID: {
|
||||
dashboards.ActionFoldersCreate: {},
|
||||
dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersAll},
|
||||
dashboards.ActionFoldersRead: {dashboards.ScopeFoldersAll},
|
||||
},
|
||||
}}
|
||||
|
||||
quotaService := quotatest.New(false, nil)
|
||||
folderStore := ProvideDashboardFolderStore(db)
|
||||
|
||||
cfg := setting.NewCfg()
|
||||
|
||||
featuresFlagOff := featuremgmt.WithFeatures()
|
||||
dashStore, err := database.ProvideDashboardStore(db, db.Cfg, featuresFlagOff, tagimpl.ProvideService(db), quotaService)
|
||||
require.NoError(t, err)
|
||||
nestedFolderStore := ProvideStore(db, db.Cfg)
|
||||
|
||||
b := bus.ProvideBus(tracing.InitializeTracerForTest())
|
||||
ac := acimpl.ProvideAccessControl(cfg)
|
||||
|
||||
features := featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)
|
||||
|
||||
folderSvcOn := &Service{
|
||||
cfg: cfg,
|
||||
log: log.New("test-folder-service"),
|
||||
dashboardStore: dashStore,
|
||||
dashboardFolderStore: folderStore,
|
||||
store: nestedFolderStore,
|
||||
features: features,
|
||||
bus: b,
|
||||
db: db,
|
||||
accessControl: ac,
|
||||
registry: make(map[string]folder.RegistryService),
|
||||
metrics: newFoldersMetrics(nil),
|
||||
}
|
||||
|
||||
origGuardian := guardian.New
|
||||
fakeGuardian := &guardian.FakeDashboardGuardian{
|
||||
CanSaveValue: true,
|
||||
CanEditUIDs: []string{},
|
||||
CanViewUIDs: []string{},
|
||||
}
|
||||
guardian.MockDashboardGuardian(fakeGuardian)
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origGuardian
|
||||
})
|
||||
|
||||
viewer := user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{
|
||||
orgID: {
|
||||
dashboards.ActionFoldersRead: {},
|
||||
dashboards.ActionFoldersWrite: {},
|
||||
},
|
||||
}}
|
||||
|
||||
// no view permission
|
||||
// |_ subfolder under no view permission with view permission
|
||||
// |_ subfolder under no view permission with view permissionn and with edit permission
|
||||
// with edit permission
|
||||
// |_ subfolder under with edit permission
|
||||
// no edit permission
|
||||
// |_ subfolder under no edit permission
|
||||
// |_ subfolder under no edit permission with edit permission
|
||||
noViewPermission, err := folderSvcOn.Create(context.Background(), &folder.CreateFolderCommand{
|
||||
OrgID: orgID,
|
||||
ParentUID: "",
|
||||
Title: "no view permission",
|
||||
SignedInUser: &signedInAdminUser,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
f, err := folderSvcOn.Create(context.Background(), &folder.CreateFolderCommand{
|
||||
OrgID: orgID,
|
||||
ParentUID: noViewPermission.UID,
|
||||
Title: "subfolder under no view permission with view permission",
|
||||
SignedInUser: &signedInAdminUser,
|
||||
})
|
||||
viewer.Permissions[orgID][dashboards.ActionFoldersRead] = append(viewer.Permissions[orgID][dashboards.ActionFoldersRead], dashboards.ScopeFoldersProvider.GetResourceScopeUID(f.UID))
|
||||
fakeGuardian.CanViewUIDs = append(fakeGuardian.CanViewUIDs, f.UID)
|
||||
|
||||
require.NoError(t, err)
|
||||
f, err = folderSvcOn.Create(context.Background(), &folder.CreateFolderCommand{
|
||||
OrgID: orgID,
|
||||
ParentUID: noViewPermission.UID,
|
||||
Title: "subfolder under no view permission with view permission and with edit permission",
|
||||
SignedInUser: &signedInAdminUser,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
viewer.Permissions[orgID][dashboards.ActionFoldersRead] = append(viewer.Permissions[orgID][dashboards.ActionFoldersRead], dashboards.ScopeFoldersProvider.GetResourceScopeUID(f.UID))
|
||||
fakeGuardian.CanViewUIDs = append(fakeGuardian.CanViewUIDs, f.UID)
|
||||
viewer.Permissions[orgID][dashboards.ActionFoldersWrite] = append(viewer.Permissions[orgID][dashboards.ActionFoldersWrite], dashboards.ScopeFoldersProvider.GetResourceScopeUID(f.UID))
|
||||
fakeGuardian.CanEditUIDs = append(fakeGuardian.CanEditUIDs, f.UID)
|
||||
|
||||
withEditPermission, err := folderSvcOn.Create(context.Background(), &folder.CreateFolderCommand{
|
||||
OrgID: orgID,
|
||||
ParentUID: "",
|
||||
Title: "with edit permission",
|
||||
SignedInUser: &signedInAdminUser,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
viewer.Permissions[orgID][dashboards.ActionFoldersRead] = append(viewer.Permissions[orgID][dashboards.ActionFoldersRead], dashboards.ScopeFoldersProvider.GetResourceScopeUID(withEditPermission.UID))
|
||||
fakeGuardian.CanViewUIDs = append(fakeGuardian.CanViewUIDs, withEditPermission.UID)
|
||||
viewer.Permissions[orgID][dashboards.ActionFoldersWrite] = append(viewer.Permissions[orgID][dashboards.ActionFoldersWrite], dashboards.ScopeFoldersProvider.GetResourceScopeUID(withEditPermission.UID))
|
||||
fakeGuardian.CanEditUIDs = append(fakeGuardian.CanEditUIDs, withEditPermission.UID)
|
||||
|
||||
_, err = folderSvcOn.Create(context.Background(), &folder.CreateFolderCommand{
|
||||
OrgID: orgID,
|
||||
ParentUID: withEditPermission.UID,
|
||||
Title: "subfolder under with edit permission",
|
||||
SignedInUser: &signedInAdminUser,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
noEditPermission, err := folderSvcOn.Create(context.Background(), &folder.CreateFolderCommand{
|
||||
OrgID: orgID,
|
||||
ParentUID: "",
|
||||
Title: "no edit permission",
|
||||
SignedInUser: &signedInAdminUser,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
viewer.Permissions[orgID][dashboards.ActionFoldersRead] = append(viewer.Permissions[orgID][dashboards.ActionFoldersRead], dashboards.ScopeFoldersProvider.GetResourceScopeUID(noEditPermission.UID))
|
||||
fakeGuardian.CanViewUIDs = append(fakeGuardian.CanViewUIDs, noEditPermission.UID)
|
||||
|
||||
_, err = folderSvcOn.Create(context.Background(), &folder.CreateFolderCommand{
|
||||
OrgID: orgID,
|
||||
ParentUID: noEditPermission.UID,
|
||||
Title: "subfolder under no edit permission",
|
||||
SignedInUser: &signedInAdminUser,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
f, err = folderSvcOn.Create(context.Background(), &folder.CreateFolderCommand{
|
||||
OrgID: orgID,
|
||||
ParentUID: noEditPermission.UID,
|
||||
Title: "subfolder under no edit permission with edit permission",
|
||||
SignedInUser: &signedInAdminUser,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
viewer.Permissions[orgID][dashboards.ActionFoldersWrite] = append(viewer.Permissions[orgID][dashboards.ActionFoldersWrite], dashboards.ScopeFoldersProvider.GetResourceScopeUID(f.UID))
|
||||
fakeGuardian.CanEditUIDs = append(fakeGuardian.CanEditUIDs, f.UID)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
q folder.GetChildrenQuery
|
||||
expectedErr error
|
||||
expectedFolders []string
|
||||
}{
|
||||
{
|
||||
name: "should return root folders with view permission",
|
||||
q: folder.GetChildrenQuery{
|
||||
OrgID: orgID,
|
||||
SignedInUser: &viewer,
|
||||
},
|
||||
expectedFolders: []string{
|
||||
"Shared with me",
|
||||
"no edit permission",
|
||||
"with edit permission"},
|
||||
},
|
||||
{
|
||||
name: "should return subfolders with view permission",
|
||||
q: folder.GetChildrenQuery{
|
||||
OrgID: orgID,
|
||||
SignedInUser: &viewer,
|
||||
UID: noEditPermission.UID,
|
||||
},
|
||||
expectedFolders: []string{
|
||||
"subfolder under no edit permission",
|
||||
"subfolder under no edit permission with edit permission"},
|
||||
},
|
||||
{
|
||||
name: "should return shared with me folders with view permission",
|
||||
q: folder.GetChildrenQuery{
|
||||
OrgID: orgID,
|
||||
SignedInUser: &viewer,
|
||||
UID: folder.SharedWithMeFolderUID,
|
||||
},
|
||||
expectedFolders: []string{
|
||||
"subfolder under no view permission with view permission",
|
||||
"subfolder under no view permission with view permission and with edit permission"},
|
||||
},
|
||||
{
|
||||
name: "should return root folders with edit permission",
|
||||
q: folder.GetChildrenQuery{
|
||||
OrgID: orgID,
|
||||
SignedInUser: &viewer,
|
||||
Permission: dashboardaccess.PERMISSION_EDIT,
|
||||
},
|
||||
expectedFolders: []string{
|
||||
"Shared with me",
|
||||
"with edit permission"},
|
||||
},
|
||||
{
|
||||
name: "should fail returning subfolders with edit permission when parent folder has no edit permission",
|
||||
q: folder.GetChildrenQuery{
|
||||
OrgID: orgID,
|
||||
SignedInUser: &viewer,
|
||||
Permission: dashboardaccess.PERMISSION_EDIT,
|
||||
UID: noEditPermission.UID,
|
||||
},
|
||||
expectedErr: dashboards.ErrFolderAccessDenied,
|
||||
},
|
||||
{
|
||||
name: "should return shared with me folders with edit permission",
|
||||
q: folder.GetChildrenQuery{
|
||||
OrgID: orgID,
|
||||
SignedInUser: &viewer,
|
||||
Permission: dashboardaccess.PERMISSION_EDIT,
|
||||
UID: folder.SharedWithMeFolderUID,
|
||||
},
|
||||
expectedFolders: []string{
|
||||
"subfolder under no edit permission with edit permission",
|
||||
"subfolder under no view permission with view permission and with edit permission",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
folders, err := folderSvcOn.GetChildren(context.Background(), &tc.q)
|
||||
if tc.expectedErr != nil {
|
||||
require.Error(t, err)
|
||||
require.Equal(t, tc.expectedErr, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
actual := make([]string, 0, len(folders))
|
||||
for _, f := range folders {
|
||||
actual = append(actual, f.Title)
|
||||
}
|
||||
if cmp.Diff(tc.expectedFolders, actual) != "" {
|
||||
t.Fatalf("unexpected folders: %s", cmp.Diff(tc.expectedFolders, actual))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSupportBundle(t *testing.T) {
|
||||
f := func(uid, parent string) *folder.Folder { return &folder.Folder{UID: uid, ParentUID: parent} }
|
||||
for _, tc := range []struct {
|
||||
|
||||
Reference in New Issue
Block a user