RBAC: Change annotation filter to use dashboard based annotation scopes (#78635)

change annotation filter to use dash based annotation scopes
This commit is contained in:
Ieva
2023-11-29 10:34:44 +00:00
committed by GitHub
parent ff7dd17c56
commit 791881f910
7 changed files with 130 additions and 66 deletions

View File

@@ -49,13 +49,17 @@ func (authz *AuthService) Authorize(ctx context.Context, orgID int64, user ident
if !has { if !has {
return nil, ErrReadForbidden.Errorf("user does not have permission to read annotations") return nil, ErrReadForbidden.Errorf("user does not have permission to read annotations")
} }
scopeTypes := annotationScopeTypes(scopes) scopeTypes := annotationScopeTypes(scopes)
_, canAccessOrgAnnotations := scopeTypes[annotations.Organization.String()]
_, canAccessDashAnnotations := scopeTypes[annotations.Dashboard.String()]
if authz.features.IsEnabled(ctx, featuremgmt.FlagAnnotationPermissionUpdate) {
canAccessDashAnnotations = true
}
var visibleDashboards map[string]int64 var visibleDashboards map[string]int64
var err error var err error
if _, ok := scopeTypes[annotations.Dashboard.String()]; ok { if canAccessDashAnnotations {
visibleDashboards, err = authz.userVisibleDashboards(ctx, user, orgID) visibleDashboards, err = authz.dashboardsWithVisibleAnnotations(ctx, user, orgID)
if err != nil { if err != nil {
return nil, ErrAccessControlInternal.Errorf("failed to fetch dashboards: %w", err) return nil, ErrAccessControlInternal.Errorf("failed to fetch dashboards: %w", err)
} }
@@ -63,18 +67,24 @@ func (authz *AuthService) Authorize(ctx context.Context, orgID int64, user ident
return &AccessResources{ return &AccessResources{
Dashboards: visibleDashboards, Dashboards: visibleDashboards,
ScopeTypes: scopeTypes, CanAccessDashAnnotations: canAccessDashAnnotations,
CanAccessOrgAnnotations: canAccessOrgAnnotations,
}, nil }, nil
} }
func (authz *AuthService) userVisibleDashboards(ctx context.Context, user identity.Requester, orgID int64) (map[string]int64, error) { func (authz *AuthService) dashboardsWithVisibleAnnotations(ctx context.Context, user identity.Requester, orgID int64) (map[string]int64, error) {
recursiveQueriesSupported, err := authz.db.RecursiveQueriesAreSupported() recursiveQueriesSupported, err := authz.db.RecursiveQueriesAreSupported()
if err != nil { if err != nil {
return nil, err return nil, err
} }
filterType := searchstore.TypeDashboard
if authz.features.IsEnabled(ctx, featuremgmt.FlagAnnotationPermissionUpdate) {
filterType = searchstore.TypeAnnotation
}
filters := []any{ filters := []any{
permissions.NewAccessControlDashboardPermissionFilter(user, dashboardaccess.PERMISSION_VIEW, searchstore.TypeDashboard, authz.features, recursiveQueriesSupported), permissions.NewAccessControlDashboardPermissionFilter(user, dashboardaccess.PERMISSION_VIEW, filterType, authz.features, recursiveQueriesSupported),
searchstore.OrgFilter{OrgId: orgID}, searchstore.OrgFilter{OrgId: orgID},
} }

View File

@@ -8,7 +8,6 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/annotations/testutil" "github.com/grafana/grafana/pkg/services/annotations/testutil"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
@@ -16,11 +15,6 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
var (
dashScopeType = annotations.Dashboard.String()
orgScopeType = annotations.Organization.String()
)
func TestIntegrationAuthorize(t *testing.T) { func TestIntegrationAuthorize(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Skip("skipping integration test") t.Skip("skipping integration test")
@@ -28,8 +22,6 @@ func TestIntegrationAuthorize(t *testing.T) {
sql := db.InitTestDB(t) sql := db.InitTestDB(t)
authz := NewAuthService(sql, featuremgmt.WithFeatures())
dash1 := testutil.CreateDashboard(t, sql, featuremgmt.WithFeatures(), dashboards.SaveDashboardCommand{ dash1 := testutil.CreateDashboard(t, sql, featuremgmt.WithFeatures(), dashboards.SaveDashboardCommand{
UserID: 1, UserID: 1,
OrgID: 1, OrgID: 1,
@@ -55,6 +47,7 @@ func TestIntegrationAuthorize(t *testing.T) {
type testCase struct { type testCase struct {
name string name string
permissions map[string][]string permissions map[string][]string
featureToggle string
expectedResources *AccessResources expectedResources *AccessResources
expectedErr error expectedErr error
} }
@@ -68,7 +61,45 @@ func TestIntegrationAuthorize(t *testing.T) {
}, },
expectedResources: &AccessResources{ expectedResources: &AccessResources{
Dashboards: map[string]int64{dash1.UID: dash1.ID, dash2.UID: dash2.ID}, Dashboards: map[string]int64{dash1.UID: dash1.ID, dash2.UID: dash2.ID},
ScopeTypes: map[any]struct{}{dashScopeType: {}, orgScopeType: {}}, CanAccessOrgAnnotations: true,
CanAccessDashAnnotations: true,
},
},
{
name: "should have no dashboards if missing annotation read permission on dashboards and FlagAnnotationPermissionUpdate is enabled",
permissions: map[string][]string{
accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsAll},
dashboards.ActionDashboardsRead: {dashboards.ScopeDashboardsAll},
},
featureToggle: featuremgmt.FlagAnnotationPermissionUpdate,
expectedResources: &AccessResources{
Dashboards: nil,
CanAccessOrgAnnotations: true,
CanAccessDashAnnotations: true,
},
},
{
name: "should have dashboard and organization scope and all dashboards if FlagAnnotationPermissionUpdate is enabled",
permissions: map[string][]string{
accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsTypeOrganization, dashboards.ScopeDashboardsAll},
},
featureToggle: featuremgmt.FlagAnnotationPermissionUpdate,
expectedResources: &AccessResources{
Dashboards: map[string]int64{dash1.UID: dash1.ID, dash2.UID: dash2.ID},
CanAccessOrgAnnotations: true,
CanAccessDashAnnotations: true,
},
},
{
name: "should have dashboard and organization scope and all dashboards if FlagAnnotationPermissionUpdate is enabled and folder based scope is used",
permissions: map[string][]string{
accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsTypeOrganization, dashboards.ScopeFoldersAll},
},
featureToggle: featuremgmt.FlagAnnotationPermissionUpdate,
expectedResources: &AccessResources{
Dashboards: map[string]int64{dash1.UID: dash1.ID, dash2.UID: dash2.ID},
CanAccessOrgAnnotations: true,
CanAccessDashAnnotations: true,
}, },
}, },
{ {
@@ -79,7 +110,7 @@ func TestIntegrationAuthorize(t *testing.T) {
}, },
expectedResources: &AccessResources{ expectedResources: &AccessResources{
Dashboards: nil, Dashboards: nil,
ScopeTypes: map[any]struct{}{orgScopeType: {}}, CanAccessOrgAnnotations: true,
}, },
}, },
{ {
@@ -90,7 +121,19 @@ func TestIntegrationAuthorize(t *testing.T) {
}, },
expectedResources: &AccessResources{ expectedResources: &AccessResources{
Dashboards: map[string]int64{dash1.UID: dash1.ID, dash2.UID: dash2.ID}, Dashboards: map[string]int64{dash1.UID: dash1.ID, dash2.UID: dash2.ID},
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
},
},
{
name: "should have only dashboard scope and all dashboards if FlagAnnotationPermissionUpdate is enabled",
permissions: map[string][]string{
accesscontrol.ActionAnnotationsRead: {dashboards.ScopeDashboardsAll},
},
featureToggle: featuremgmt.FlagAnnotationPermissionUpdate,
expectedResources: &AccessResources{
Dashboards: map[string]int64{dash1.UID: dash1.ID, dash2.UID: dash2.ID},
CanAccessOrgAnnotations: false,
CanAccessDashAnnotations: true,
}, },
}, },
{ {
@@ -101,7 +144,19 @@ func TestIntegrationAuthorize(t *testing.T) {
}, },
expectedResources: &AccessResources{ expectedResources: &AccessResources{
Dashboards: map[string]int64{dash1.UID: dash1.ID}, Dashboards: map[string]int64{dash1.UID: dash1.ID},
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
},
},
{
name: "should have only dashboard scope and only dashboard 1 if FlagAnnotationPermissionUpdate is enabled",
permissions: map[string][]string{
accesscontrol.ActionAnnotationsRead: {dashboards.ScopeDashboardsProvider.GetResourceScopeUID(dash1.UID)},
},
featureToggle: featuremgmt.FlagAnnotationPermissionUpdate,
expectedResources: &AccessResources{
Dashboards: map[string]int64{dash1.UID: dash1.ID},
CanAccessOrgAnnotations: false,
CanAccessDashAnnotations: true,
}, },
}, },
} }
@@ -111,6 +166,8 @@ func TestIntegrationAuthorize(t *testing.T) {
u.Permissions = map[int64]map[string][]string{1: tc.permissions} u.Permissions = map[int64]map[string][]string{1: tc.permissions}
testutil.SetupRBACPermission(t, sql, role, u) testutil.SetupRBACPermission(t, sql, role, u)
authz := NewAuthService(sql, featuremgmt.WithFeatures(tc.featureToggle))
resources, err := authz.Authorize(context.Background(), 1, u) resources, err := authz.Authorize(context.Background(), 1, u)
require.NoError(t, err) require.NoError(t, err)
@@ -118,9 +175,8 @@ func TestIntegrationAuthorize(t *testing.T) {
require.Equal(t, tc.expectedResources.Dashboards, resources.Dashboards) require.Equal(t, tc.expectedResources.Dashboards, resources.Dashboards)
} }
if tc.expectedResources.ScopeTypes != nil { require.Equal(t, tc.expectedResources.CanAccessDashAnnotations, resources.CanAccessDashAnnotations)
require.Equal(t, tc.expectedResources.ScopeTypes, resources.ScopeTypes) require.Equal(t, tc.expectedResources.CanAccessOrgAnnotations, resources.CanAccessOrgAnnotations)
}
if tc.expectedErr != nil { if tc.expectedErr != nil {
require.Equal(t, tc.expectedErr, err) require.Equal(t, tc.expectedErr, err)

View File

@@ -4,8 +4,10 @@ package accesscontrol
type AccessResources struct { type AccessResources struct {
// Dashboards is a map of dashboard UIDs to IDs // Dashboards is a map of dashboard UIDs to IDs
Dashboards map[string]int64 Dashboards map[string]int64
// ScopeTypes contains the scope types that the user has access to. At most `dashboard` and `organization` // CanAccessDashAnnotations true if the user is allowed to access some dashboard annotations
ScopeTypes map[any]struct{} CanAccessDashAnnotations bool
// CanAccessOrgAnnotations true if the user is allowed to access organization annotations
CanAccessOrgAnnotations bool
} }
type dashboardProjection struct { type dashboardProjection struct {

View File

@@ -369,11 +369,11 @@ func (r *xormRepositoryImpl) Get(ctx context.Context, query *annotations.ItemQue
func (r *xormRepositoryImpl) getAccessControlFilter(user identity.Requester, accessResources *accesscontrol.AccessResources) (string, error) { func (r *xormRepositoryImpl) getAccessControlFilter(user identity.Requester, accessResources *accesscontrol.AccessResources) (string, error) {
var filters []string var filters []string
if _, has := accessResources.ScopeTypes[annotations.Organization.String()]; has { if accessResources.CanAccessOrgAnnotations {
filters = append(filters, "a.dashboard_id = 0") filters = append(filters, "a.dashboard_id = 0")
} }
if _, has := accessResources.ScopeTypes[annotations.Dashboard.String()]; has { if accessResources.CanAccessDashAnnotations {
var dashboardIDs []int64 var dashboardIDs []int64
for _, id := range accessResources.Dashboards { for _, id := range accessResources.Dashboards {
dashboardIDs = append(dashboardIDs, id) dashboardIDs = append(dashboardIDs, id)

View File

@@ -6,11 +6,6 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/grafana/grafana/pkg/services/annotations/testutil"
"github.com/grafana/grafana/pkg/services/featuremgmt"
annotation_ac "github.com/grafana/grafana/pkg/services/annotations/accesscontrol"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -19,7 +14,10 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations"
annotation_ac "github.com/grafana/grafana/pkg/services/annotations/accesscontrol"
"github.com/grafana/grafana/pkg/services/annotations/testutil"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/tag" "github.com/grafana/grafana/pkg/services/tag"
"github.com/grafana/grafana/pkg/services/tag/tagimpl" "github.com/grafana/grafana/pkg/services/tag/tagimpl"
@@ -27,11 +25,6 @@ import (
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
var (
dashScopeType = annotations.Dashboard.String()
orgScopeType = annotations.Organization.String()
)
func TestIntegrationAnnotations(t *testing.T) { func TestIntegrationAnnotations(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Skip("skipping integration test") t.Skip("skipping integration test")
@@ -150,7 +143,7 @@ func TestIntegrationAnnotations(t *testing.T) {
Dashboards: map[string]int64{ Dashboards: map[string]int64{
dashboard.UID: dashboard.ID, dashboard.UID: dashboard.ID,
}, },
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
}) })
require.NoError(t, err) require.NoError(t, err)
@@ -190,7 +183,7 @@ func TestIntegrationAnnotations(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
query := &annotations.ItemQuery{OrgID: 100, SignedInUser: testUser} query := &annotations.ItemQuery{OrgID: 100, SignedInUser: testUser}
accRes := &annotation_ac.AccessResources{ScopeTypes: map[any]struct{}{orgScopeType: {}}} accRes := &annotation_ac.AccessResources{CanAccessOrgAnnotations: true}
inserted, err := store.Get(context.Background(), query, accRes) inserted, err := store.Get(context.Background(), query, accRes)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, inserted, count) assert.Len(t, inserted, count)
@@ -217,7 +210,7 @@ func TestIntegrationAnnotations(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
query := &annotations.ItemQuery{OrgID: 101, SignedInUser: testUser} query := &annotations.ItemQuery{OrgID: 101, SignedInUser: testUser}
accRes := &annotation_ac.AccessResources{ScopeTypes: map[any]struct{}{orgScopeType: {}}} accRes := &annotation_ac.AccessResources{CanAccessOrgAnnotations: true}
inserted, err := store.Get(context.Background(), query, accRes) inserted, err := store.Get(context.Background(), query, accRes)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, inserted, count) assert.Len(t, inserted, count)
@@ -232,7 +225,7 @@ func TestIntegrationAnnotations(t *testing.T) {
Dashboards: map[string]int64{ Dashboards: map[string]int64{
dashboard2.UID: dashboard2.ID, dashboard2.UID: dashboard2.ID,
}, },
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
}) })
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, items, 1) assert.Len(t, items, 1)
@@ -242,7 +235,7 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Should not find any when item is outside time range", func(t *testing.T) { t.Run("Should not find any when item is outside time range", func(t *testing.T) {
accRes := &annotation_ac.AccessResources{ accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1}, Dashboards: map[string]int64{"foo": 1},
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
} }
items, err := store.Get(context.Background(), &annotations.ItemQuery{ items, err := store.Get(context.Background(), &annotations.ItemQuery{
OrgID: 1, OrgID: 1,
@@ -258,7 +251,7 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Should not find one when tag filter does not match", func(t *testing.T) { t.Run("Should not find one when tag filter does not match", func(t *testing.T) {
accRes := &annotation_ac.AccessResources{ accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1}, Dashboards: map[string]int64{"foo": 1},
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
} }
items, err := store.Get(context.Background(), &annotations.ItemQuery{ items, err := store.Get(context.Background(), &annotations.ItemQuery{
OrgID: 1, OrgID: 1,
@@ -275,7 +268,7 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Should not find one when type filter does not match", func(t *testing.T) { t.Run("Should not find one when type filter does not match", func(t *testing.T) {
accRes := &annotation_ac.AccessResources{ accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1}, Dashboards: map[string]int64{"foo": 1},
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
} }
items, err := store.Get(context.Background(), &annotations.ItemQuery{ items, err := store.Get(context.Background(), &annotations.ItemQuery{
OrgID: 1, OrgID: 1,
@@ -292,7 +285,7 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Should find one when all tag filters does match", func(t *testing.T) { t.Run("Should find one when all tag filters does match", func(t *testing.T) {
accRes := &annotation_ac.AccessResources{ accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1}, Dashboards: map[string]int64{"foo": 1},
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
} }
items, err := store.Get(context.Background(), &annotations.ItemQuery{ items, err := store.Get(context.Background(), &annotations.ItemQuery{
OrgID: 1, OrgID: 1,
@@ -307,7 +300,7 @@ func TestIntegrationAnnotations(t *testing.T) {
}) })
t.Run("Should find two annotations using partial match", func(t *testing.T) { t.Run("Should find two annotations using partial match", func(t *testing.T) {
accRes := &annotation_ac.AccessResources{ScopeTypes: map[any]struct{}{orgScopeType: {}}} accRes := &annotation_ac.AccessResources{CanAccessOrgAnnotations: true}
items, err := store.Get(context.Background(), &annotations.ItemQuery{ items, err := store.Get(context.Background(), &annotations.ItemQuery{
OrgID: 1, OrgID: 1,
From: 1, From: 1,
@@ -323,7 +316,7 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Should find one when all key value tag filters does match", func(t *testing.T) { t.Run("Should find one when all key value tag filters does match", func(t *testing.T) {
accRes := &annotation_ac.AccessResources{ accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1}, Dashboards: map[string]int64{"foo": 1},
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
} }
items, err := store.Get(context.Background(), &annotations.ItemQuery{ items, err := store.Get(context.Background(), &annotations.ItemQuery{
OrgID: 1, OrgID: 1,
@@ -347,7 +340,7 @@ func TestIntegrationAnnotations(t *testing.T) {
} }
accRes := &annotation_ac.AccessResources{ accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1}, Dashboards: map[string]int64{"foo": 1},
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
} }
items, err := store.Get(context.Background(), query, accRes) items, err := store.Get(context.Background(), query, accRes)
require.NoError(t, err) require.NoError(t, err)
@@ -382,7 +375,7 @@ func TestIntegrationAnnotations(t *testing.T) {
} }
accRes := &annotation_ac.AccessResources{ accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1}, Dashboards: map[string]int64{"foo": 1},
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
} }
items, err := store.Get(context.Background(), query, accRes) items, err := store.Get(context.Background(), query, accRes)
require.NoError(t, err) require.NoError(t, err)
@@ -415,7 +408,7 @@ func TestIntegrationAnnotations(t *testing.T) {
} }
accRes := &annotation_ac.AccessResources{ accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1}, Dashboards: map[string]int64{"foo": 1},
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
} }
items, err := store.Get(context.Background(), query, accRes) items, err := store.Get(context.Background(), query, accRes)
require.NoError(t, err) require.NoError(t, err)
@@ -448,7 +441,7 @@ func TestIntegrationAnnotations(t *testing.T) {
} }
accRes := &annotation_ac.AccessResources{ accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1}, Dashboards: map[string]int64{"foo": 1},
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
} }
items, err := store.Get(context.Background(), query, accRes) items, err := store.Get(context.Background(), query, accRes)
require.NoError(t, err) require.NoError(t, err)
@@ -484,7 +477,7 @@ func TestIntegrationAnnotations(t *testing.T) {
} }
accRes := &annotation_ac.AccessResources{ accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1}, Dashboards: map[string]int64{"foo": 1},
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
} }
items, err := store.Get(context.Background(), query, accRes) items, err := store.Get(context.Background(), query, accRes)
require.NoError(t, err) require.NoError(t, err)
@@ -516,7 +509,7 @@ func TestIntegrationAnnotations(t *testing.T) {
Dashboards: map[string]int64{ Dashboards: map[string]int64{
dashboard2.UID: dashboard2.ID, dashboard2.UID: dashboard2.ID,
}, },
ScopeTypes: map[any]struct{}{dashScopeType: {}}, CanAccessDashAnnotations: true,
} }
query := &annotations.ItemQuery{ query := &annotations.ItemQuery{

View File

@@ -75,6 +75,8 @@ func NewAccessControlDashboardPermissionFilter(user identity.Requester, permissi
accesscontrol.ActionAlertingRuleCreate, accesscontrol.ActionAlertingRuleCreate,
) )
} }
} else if queryType == searchstore.TypeAnnotation {
dashboardActions = append(dashboardActions, accesscontrol.ActionAnnotationsRead)
} else { } else {
folderActions = append(folderActions, dashboards.ActionFoldersRead) folderActions = append(folderActions, dashboards.ActionFoldersRead)
dashboardActions = append(dashboardActions, dashboards.ActionDashboardsRead) dashboardActions = append(dashboardActions, dashboards.ActionDashboardsRead)

View File

@@ -13,6 +13,7 @@ const (
TypeFolder = "dash-folder" TypeFolder = "dash-folder"
TypeDashboard = "dash-db" TypeDashboard = "dash-db"
TypeAlertFolder = "dash-folder-alerting" TypeAlertFolder = "dash-folder-alerting"
TypeAnnotation = "dash-annotation"
) )
type TypeFilter struct { type TypeFilter struct {