PublicDashboards: Audit table pagination (#69823)

This commit is contained in:
Juan Cabanas
2023-06-21 10:48:09 -03:00
committed by GitHub
parent ed5a697825
commit ee73d41d24
20 changed files with 475 additions and 305 deletions
@@ -2,18 +2,24 @@ package database
import (
"context"
"fmt"
"strings"
"testing"
"time"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/dashboards"
dashboardsDB "github.com/grafana/grafana/pkg/services/dashboards/database"
"github.com/grafana/grafana/pkg/services/featuremgmt"
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
"github.com/grafana/grafana/pkg/services/publicdashboards/service"
"github.com/grafana/grafana/pkg/services/quota/quotatest"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
"github.com/stretchr/testify/assert"
@@ -34,38 +40,122 @@ func TestIntegrationListPublicDashboard(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
sqlStore, cfg := db.InitTestDBwithCfg(t, db.InitTestDBOpt{FeatureFlags: []string{featuremgmt.FlagPublicDashboards}})
quotaService := quotatest.New(false, nil)
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err)
publicdashboardStore := ProvideStore(sqlStore)
var sqlStore *sqlstore.SQLStore
var cfg *setting.Cfg
var aDash *dashboards.Dashboard
var bDash *dashboards.Dashboard
var cDash *dashboards.Dashboard
var aPublicDash *PublicDashboard
var bPublicDash *PublicDashboard
var cPublicDash *PublicDashboard
var orgId int64 = 1
bDash := insertTestDashboard(t, dashboardStore, "b", orgId, 0, true)
aDash := insertTestDashboard(t, dashboardStore, "a", orgId, 0, true)
cDash := insertTestDashboard(t, dashboardStore, "c", orgId, 0, true)
var publicdashboardStore *PublicDashboardStoreImpl
// these are in order of how they should be returned from ListPUblicDashboards
a := insertPublicDashboard(t, publicdashboardStore, aDash.UID, orgId, false, PublicShareType)
b := insertPublicDashboard(t, publicdashboardStore, bDash.UID, orgId, true, PublicShareType)
c := insertPublicDashboard(t, publicdashboardStore, cDash.UID, orgId, true, PublicShareType)
setup := func() {
sqlStore, cfg = db.InitTestDBwithCfg(t, db.InitTestDBOpt{FeatureFlags: []string{featuremgmt.FlagPublicDashboards}})
quotaService := quotatest.New(false, nil)
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err)
publicdashboardStore = ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
// this is case that can happen as of now, however, postgres and mysql sort
// null in the exact opposite fashion and there is no shared syntax to sort
// nulls in the same way in all 3 db's.
//d := insertPublicDashboard(t, publicdashboardStore, "missing", orgId, false)
bDash = insertTestDashboard(t, dashboardStore, "b", orgId, 0, false)
aDash = insertTestDashboard(t, dashboardStore, "a", orgId, 0, false)
cDash = insertTestDashboard(t, dashboardStore, "c", orgId, 0, false)
// should not be included in response
_ = insertPublicDashboard(t, publicdashboardStore, "wrongOrgId", 777, false, PublicShareType)
// these are in order of how they should be returned from ListPUblicDashboards
aPublicDash = insertPublicDashboard(t, publicdashboardStore, aDash.UID, orgId, false, PublicShareType)
bPublicDash = insertPublicDashboard(t, publicdashboardStore, bDash.UID, orgId, true, PublicShareType)
cPublicDash = insertPublicDashboard(t, publicdashboardStore, cDash.UID, orgId, true, PublicShareType)
}
resp, err := publicdashboardStore.FindAll(context.Background(), orgId)
require.NoError(t, err)
t.Run("FindAllWithPagination will return dashboard list based on orgId with pagination", func(t *testing.T) {
setup()
assert.Len(t, resp, 3)
assert.Equal(t, resp[0].Uid, a.Uid)
assert.Equal(t, resp[1].Uid, b.Uid)
assert.Equal(t, resp[2].Uid, c.Uid)
// should not be included in response
_ = insertPublicDashboard(t, publicdashboardStore, "wrongOrgId", 777, false, PublicShareType)
permissions := []accesscontrol.Permission{
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", aDash.UID)},
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", bDash.UID)},
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", cDash.UID)},
}
err := insertPermissions(sqlStore, orgId, "viewer", permissions)
require.NoError(t, err)
query := &PublicDashboardListQuery{
User: &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByAction(permissions)}},
OrgID: orgId,
Page: 1,
Limit: 50,
Offset: 0,
}
resp, err := publicdashboardStore.FindAllWithPagination(context.Background(), query)
require.NoError(t, err)
assert.Len(t, resp.PublicDashboards, 3)
assert.Equal(t, resp.PublicDashboards[0].Uid, aPublicDash.Uid)
assert.Equal(t, resp.PublicDashboards[1].Uid, bPublicDash.Uid)
assert.Equal(t, resp.PublicDashboards[2].Uid, cPublicDash.Uid)
assert.Equal(t, resp.TotalCount, int64(3))
})
t.Run("FindAllWithPagination will return dashboard list based on read permissions with pagination", func(t *testing.T) {
setup()
permissions := []accesscontrol.Permission{
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", aDash.UID)},
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", cDash.UID)},
}
err := insertPermissions(sqlStore, orgId, "viewer", permissions)
require.NoError(t, err)
query := &PublicDashboardListQuery{
User: &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByAction(permissions)}},
OrgID: orgId,
Page: 1,
Limit: 50,
Offset: 0,
}
resp, err := publicdashboardStore.FindAllWithPagination(context.Background(), query)
require.NoError(t, err)
assert.Len(t, resp.PublicDashboards, 2)
assert.Equal(t, resp.PublicDashboards[0].Uid, aPublicDash.Uid)
assert.Equal(t, resp.PublicDashboards[1].Uid, cPublicDash.Uid)
assert.Equal(t, resp.TotalCount, int64(2))
})
t.Run("FindAllWithPagination will return empty dashboard list based on read permissions with pagination", func(t *testing.T) {
setup()
permissions := []accesscontrol.Permission{
{Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:another-dashboard-uid"},
{Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:another-dashboard-2-uid"},
}
err := insertPermissions(sqlStore, orgId, "viewer", permissions)
require.NoError(t, err)
query := &PublicDashboardListQuery{
User: &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByAction(permissions)}},
OrgID: orgId,
Page: 1,
Limit: 50,
Offset: 0,
}
resp, err := publicdashboardStore.FindAllWithPagination(context.Background(), query)
require.NoError(t, err)
assert.Len(t, resp.PublicDashboards, 0)
assert.Equal(t, resp.TotalCount, int64(0))
})
}
func TestIntegrationFindDashboard(t *testing.T) {
@@ -84,7 +174,7 @@ func TestIntegrationFindDashboard(t *testing.T) {
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err)
dashboardStore = store
publicdashboardStore = ProvideStore(sqlStore)
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
}
@@ -114,7 +204,7 @@ func TestIntegrationExistsEnabledByAccessToken(t *testing.T) {
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err)
dashboardStore = store
publicdashboardStore = ProvideStore(sqlStore)
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
}
t.Run("ExistsEnabledByAccessToken will return true when at least one public dashboard has a matching access token", func(t *testing.T) {
@@ -187,7 +277,7 @@ func TestIntegrationExistsEnabledByDashboardUid(t *testing.T) {
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err)
dashboardStore = store
publicdashboardStore = ProvideStore(sqlStore)
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
}
@@ -252,7 +342,7 @@ func TestIntegrationFindByDashboardUid(t *testing.T) {
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err)
dashboardStore = store
publicdashboardStore = ProvideStore(sqlStore)
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
}
@@ -319,7 +409,7 @@ func TestIntegrationFindByAccessToken(t *testing.T) {
sqlStore, cfg = db.InitTestDBwithCfg(t)
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotatest.New(false, nil))
require.NoError(t, err)
publicdashboardStore = ProvideStore(sqlStore)
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
}
@@ -389,7 +479,7 @@ func TestIntegrationCreatePublicDashboard(t *testing.T) {
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err)
dashboardStore = store
publicdashboardStore = ProvideStore(sqlStore)
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
savedDashboard2 = insertTestDashboard(t, dashboardStore, "testDashie2", 1, 0, true)
insertPublicDashboard(t, publicdashboardStore, savedDashboard2.UID, savedDashboard2.OrgID, false, PublicShareType)
@@ -468,7 +558,7 @@ func TestIntegrationUpdatePublicDashboard(t *testing.T) {
quotaService := quotatest.New(false, nil)
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err)
publicdashboardStore = ProvideStore(sqlStore)
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
anotherSavedDashboard = insertTestDashboard(t, dashboardStore, "test another Dashie", 1, 0, true)
}
@@ -572,7 +662,7 @@ func TestIntegrationGetOrgIdByAccessToken(t *testing.T) {
quotaService := quotatest.New(false, nil)
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err)
publicdashboardStore = ProvideStore(sqlStore)
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
}
t.Run("GetOrgIdByAccessToken will OrgId when enabled", func(t *testing.T) {
@@ -644,7 +734,7 @@ func TestIntegrationDelete(t *testing.T) {
sqlStore, cfg = db.InitTestDBwithCfg(t)
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotatest.New(false, nil))
require.NoError(t, err)
publicdashboardStore = ProvideStore(sqlStore)
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
savedPublicDashboard = insertPublicDashboard(t, publicdashboardStore, savedDashboard.UID, savedDashboard.OrgID, true, PublicShareType)
}
@@ -675,7 +765,7 @@ func TestGetDashboardByFolder(t *testing.T) {
t.Run("returns nil when dashboard is not a folder", func(t *testing.T) {
sqlStore, _ := db.InitTestDBwithCfg(t)
dashboard := &dashboards.Dashboard{IsFolder: false}
store := ProvideStore(sqlStore)
store := ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
pubdashes, err := store.FindByDashboardFolder(context.Background(), dashboard)
require.NoError(t, err)
@@ -684,7 +774,7 @@ func TestGetDashboardByFolder(t *testing.T) {
t.Run("returns nil when dashboard is nil", func(t *testing.T) {
sqlStore, _ := db.InitTestDBwithCfg(t)
store := ProvideStore(sqlStore)
store := ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
pubdashes, err := store.FindByDashboardFolder(context.Background(), nil)
require.NoError(t, err)
@@ -696,7 +786,7 @@ func TestGetDashboardByFolder(t *testing.T) {
quotaService := quotatest.New(false, nil)
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err)
pubdashStore := ProvideStore(sqlStore)
pubdashStore := ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
dashboard := insertTestDashboard(t, dashboardStore, "title", 1, 1, true, PublicShareType)
pubdash := insertPublicDashboard(t, pubdashStore, dashboard.UID, dashboard.OrgID, true, PublicShareType)
dashboard2 := insertTestDashboard(t, dashboardStore, "title", 1, 2, true, PublicShareType)
@@ -729,7 +819,7 @@ func TestGetMetrics(t *testing.T) {
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err)
dashboardStore = store
publicdashboardStore = ProvideStore(sqlStore)
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, false)
savedDashboard2 = insertTestDashboard(t, dashboardStore, "testDashie2", 1, 0, false)
savedDashboard3 = insertTestDashboard(t, dashboardStore, "testDashie3", 2, 0, false)
@@ -827,3 +917,50 @@ func insertPublicDashboard(t *testing.T, publicdashboardStore *PublicDashboardSt
return pubdash
}
func insertPermissions(sqlStore *sqlstore.SQLStore, orgId int64, role string, permissions []accesscontrol.Permission) error {
return sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
newRole := &accesscontrol.Role{
OrgID: orgId,
UID: fmt.Sprintf("basic_%s", role),
Name: fmt.Sprintf("basic:%s", role),
Updated: time.Now(),
Created: time.Now(),
}
_, err := sess.Insert(newRole)
if err != nil {
return err
}
_, err = sess.Insert(accesscontrol.BuiltinRole{
OrgID: orgId,
RoleID: newRole.ID,
Role: strings.ToUpper(role[:1]) + role[1:],
Created: time.Now(),
Updated: time.Now(),
})
if err != nil {
return err
}
for i := range permissions {
permissions[i].RoleID = newRole.ID
permissions[i].Created = time.Now()
permissions[i].Updated = time.Now()
}
_, err = sess.InsertMulti(&permissions)
if err != nil {
return err
}
_, err = sess.Insert(accesscontrol.UserRole{
OrgID: orgId,
RoleID: newRole.ID,
UserID: 1,
Created: time.Now(),
})
return err
})
}