Merge branch 'main' into plugin-dependency-install
This commit is contained in:
+10
-19
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
@@ -278,7 +277,7 @@ func (hs *HTTPServer) UpdateAnnotation(c *contextmodel.ReqContext) response.Resp
|
||||
}
|
||||
|
||||
if !hs.Features.IsEnabled(c.Req.Context(), featuremgmt.FlagAnnotationPermissionUpdate) {
|
||||
if canSave, err := hs.canSaveAnnotation(c, annotation); err != nil || !canSave {
|
||||
if canSave, err := hs.canSaveAnnotation(c, hs.AccessControl, annotation); err != nil || !canSave {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
}
|
||||
@@ -336,7 +335,7 @@ func (hs *HTTPServer) PatchAnnotation(c *contextmodel.ReqContext) response.Respo
|
||||
}
|
||||
|
||||
if !hs.Features.IsEnabled(c.Req.Context(), featuremgmt.FlagAnnotationPermissionUpdate) {
|
||||
if canSave, err := hs.canSaveAnnotation(c, annotation); err != nil || !canSave {
|
||||
if canSave, err := hs.canSaveAnnotation(c, hs.AccessControl, annotation); err != nil || !canSave {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
}
|
||||
@@ -502,7 +501,7 @@ func (hs *HTTPServer) DeleteAnnotationByID(c *contextmodel.ReqContext) response.
|
||||
return resp
|
||||
}
|
||||
|
||||
if canSave, err := hs.canSaveAnnotation(c, annotation); err != nil || !canSave {
|
||||
if canSave, err := hs.canSaveAnnotation(c, hs.AccessControl, annotation); err != nil || !canSave {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
}
|
||||
@@ -518,25 +517,17 @@ func (hs *HTTPServer) DeleteAnnotationByID(c *contextmodel.ReqContext) response.
|
||||
return response.Success("Annotation deleted")
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) canSaveAnnotation(c *contextmodel.ReqContext, annotation *annotations.ItemDTO) (bool, error) {
|
||||
func (hs *HTTPServer) canSaveAnnotation(c *contextmodel.ReqContext, ac accesscontrol.AccessControl, annotation *annotations.ItemDTO) (bool, error) {
|
||||
if annotation.GetType() == annotations.Dashboard {
|
||||
return canEditDashboard(c, annotation.DashboardID)
|
||||
return canEditDashboard(c, ac, annotation.DashboardID)
|
||||
} else {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
func canEditDashboard(c *contextmodel.ReqContext, dashboardID int64) (bool, error) {
|
||||
guard, err := guardian.New(c.Req.Context(), dashboardID, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if canEdit, err := guard.CanEdit(); err != nil || !canEdit {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
func canEditDashboard(c *contextmodel.ReqContext, ac accesscontrol.AccessControl, dashboardID int64) (bool, error) {
|
||||
evaluator := accesscontrol.EvalPermission(dashboards.ActionDashboardsWrite, dashboards.ScopeDashboardsProvider.GetResourceScope(strconv.FormatInt(dashboardID, 10)))
|
||||
return ac.Evaluate(c.Req.Context(), c.SignedInUser, evaluator)
|
||||
}
|
||||
|
||||
func findAnnotationByID(ctx context.Context, repo annotations.Repository, annotationID int64, user *user.SignedInUser) (*annotations.ItemDTO, response.Response) {
|
||||
@@ -680,7 +671,7 @@ func (hs *HTTPServer) canCreateAnnotation(c *contextmodel.ReqContext, dashboardI
|
||||
return canSave, err
|
||||
}
|
||||
|
||||
return canEditDashboard(c, dashboardId)
|
||||
return canEditDashboard(c, hs.AccessControl, dashboardId)
|
||||
} else { // organization annotations
|
||||
evaluator := accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsCreate, accesscontrol.ScopeAnnotationsTypeOrganization)
|
||||
return hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluator)
|
||||
@@ -708,7 +699,7 @@ func (hs *HTTPServer) canMassDeleteAnnotations(c *contextmodel.ReqContext, dashb
|
||||
return false, err
|
||||
}
|
||||
|
||||
canSave, err = canEditDashboard(c, dashboardID)
|
||||
canSave, err = canEditDashboard(c, hs.AccessControl, dashboardID)
|
||||
if err != nil || !canSave {
|
||||
return false, err
|
||||
}
|
||||
|
||||
+20
-19
@@ -19,7 +19,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/web/webtest"
|
||||
)
|
||||
@@ -110,7 +109,10 @@ func TestAPI_Annotations(t *testing.T) {
|
||||
path: "/api/annotations/2",
|
||||
method: http.MethodPut,
|
||||
expectedCode: http.StatusOK,
|
||||
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionAnnotationsWrite, Scope: accesscontrol.ScopeAnnotationsTypeDashboard}},
|
||||
permissions: []accesscontrol.Permission{
|
||||
{Action: accesscontrol.ActionAnnotationsWrite, Scope: accesscontrol.ScopeAnnotationsTypeDashboard},
|
||||
{Action: dashboards.ActionDashboardsWrite, Scope: dashboards.ScopeDashboardsAll},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should not be able to update dashboard annotation without correct permission",
|
||||
@@ -162,7 +164,10 @@ func TestAPI_Annotations(t *testing.T) {
|
||||
path: "/api/annotations/2",
|
||||
method: http.MethodPatch,
|
||||
expectedCode: http.StatusOK,
|
||||
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionAnnotationsWrite, Scope: accesscontrol.ScopeAnnotationsTypeDashboard}},
|
||||
permissions: []accesscontrol.Permission{
|
||||
{Action: accesscontrol.ActionAnnotationsWrite, Scope: accesscontrol.ScopeAnnotationsTypeDashboard},
|
||||
{Action: dashboards.ActionDashboardsWrite, Scope: dashboards.ScopeDashboardsAll},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should not be able to patch dashboard annotation without correct permission",
|
||||
@@ -215,7 +220,10 @@ func TestAPI_Annotations(t *testing.T) {
|
||||
method: http.MethodPost,
|
||||
body: "{\"dashboardId\": 2,\"text\": \"test\"}",
|
||||
expectedCode: http.StatusOK,
|
||||
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionAnnotationsCreate, Scope: accesscontrol.ScopeAnnotationsTypeDashboard}},
|
||||
permissions: []accesscontrol.Permission{
|
||||
{Action: accesscontrol.ActionAnnotationsCreate, Scope: accesscontrol.ScopeAnnotationsTypeDashboard},
|
||||
{Action: dashboards.ActionDashboardsWrite, Scope: dashboards.ScopeDashboardsAll},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should not be able to create dashboard annotation without correct permission",
|
||||
@@ -273,7 +281,10 @@ func TestAPI_Annotations(t *testing.T) {
|
||||
path: "/api/annotations/2",
|
||||
method: http.MethodDelete,
|
||||
expectedCode: http.StatusOK,
|
||||
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionAnnotationsDelete, Scope: accesscontrol.ScopeAnnotationsTypeDashboard}},
|
||||
permissions: []accesscontrol.Permission{
|
||||
{Action: accesscontrol.ActionAnnotationsDelete, Scope: accesscontrol.ScopeAnnotationsTypeDashboard},
|
||||
{Action: dashboards.ActionDashboardsWrite, Scope: dashboards.ScopeDashboardsAll},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should not be able to delete dashboard annotation without correct permission",
|
||||
@@ -341,7 +352,10 @@ func TestAPI_Annotations(t *testing.T) {
|
||||
body: "{\"dashboardId\": 2, \"panelId\": 1}",
|
||||
method: http.MethodPost,
|
||||
expectedCode: http.StatusOK,
|
||||
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionAnnotationsDelete, Scope: accesscontrol.ScopeAnnotationsTypeDashboard}},
|
||||
permissions: []accesscontrol.Permission{
|
||||
{Action: accesscontrol.ActionAnnotationsDelete, Scope: accesscontrol.ScopeAnnotationsTypeDashboard},
|
||||
{Action: dashboards.ActionDashboardsWrite, Scope: dashboards.ScopeDashboardsAll},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should not be able to mass delete dashboard annotations without correct permission",
|
||||
@@ -382,10 +396,6 @@ func TestAPI_Annotations(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
// Don't need access to dashboards if annotationPermissionUpdate is enabled
|
||||
if len(tt.featureFlags) == 0 {
|
||||
setUpRBACGuardian(t)
|
||||
}
|
||||
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = setting.NewCfg()
|
||||
repo := annotationstest.NewFakeAnnotationsRepo()
|
||||
@@ -518,12 +528,3 @@ func TestService_AnnotationTypeScopeResolver(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func setUpRBACGuardian(t *testing.T) {
|
||||
origNewGuardian := guardian.New
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanEditValue: true, CanViewValue: true})
|
||||
}
|
||||
|
||||
+15
-11
@@ -117,6 +117,7 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
r.Get("/admin/orgs/edit/:id", authorizeInOrg(ac.UseGlobalOrg, ac.OrgsAccessEvaluator), hs.Index)
|
||||
r.Get("/admin/stats", authorize(ac.EvalPermission(ac.ActionServerStatsRead)), hs.Index)
|
||||
r.Get("/admin/provisioning", reqOrgAdmin, hs.Index)
|
||||
r.Get("/admin/provisioning/*", reqOrgAdmin, hs.Index)
|
||||
|
||||
if hs.Features.IsEnabledGlobally(featuremgmt.FlagOnPremToCloudMigrations) {
|
||||
r.Get("/admin/migrate-to-cloud", authorize(cloudmigration.MigrationAssistantAccess), hs.Index)
|
||||
@@ -462,22 +463,24 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
|
||||
// Dashboard
|
||||
apiRoute.Group("/dashboards", func(dashboardRoute routing.RouteRegister) {
|
||||
dashboardRoute.Get("/uid/:uid", authorize(ac.EvalPermission(dashboards.ActionDashboardsRead)), routing.Wrap(hs.GetDashboard))
|
||||
dashUIDScope := dashboards.ScopeDashboardsProvider.GetResourceScopeUID(ac.Parameter(":uid"))
|
||||
|
||||
dashboardRoute.Get("/uid/:uid", authorize(ac.EvalPermission(dashboards.ActionDashboardsRead, dashUIDScope)), routing.Wrap(hs.GetDashboard))
|
||||
|
||||
if hs.Features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) {
|
||||
dashboardRoute.Delete("/uid/:uid", authorize(ac.EvalPermission(dashboards.ActionDashboardsDelete)), routing.Wrap(hs.SoftDeleteDashboard))
|
||||
dashboardRoute.Delete("/uid/:uid", authorize(ac.EvalPermission(dashboards.ActionDashboardsDelete, dashUIDScope)), routing.Wrap(hs.SoftDeleteDashboard))
|
||||
} else {
|
||||
dashboardRoute.Delete("/uid/:uid", authorize(ac.EvalPermission(dashboards.ActionDashboardsDelete)), routing.Wrap(hs.DeleteDashboardByUID))
|
||||
dashboardRoute.Delete("/uid/:uid", authorize(ac.EvalPermission(dashboards.ActionDashboardsDelete, dashUIDScope)), routing.Wrap(hs.DeleteDashboardByUID))
|
||||
}
|
||||
|
||||
dashboardRoute.Group("/uid/:uid", func(dashUidRoute routing.RouteRegister) {
|
||||
dashUidRoute.Get("/versions", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite)), routing.Wrap(hs.GetDashboardVersions))
|
||||
dashUidRoute.Post("/restore", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite)), routing.Wrap(hs.RestoreDashboardVersion))
|
||||
dashUidRoute.Get("/versions/:id", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite)), routing.Wrap(hs.GetDashboardVersion))
|
||||
dashUidRoute.Get("/versions", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite, dashUIDScope)), routing.Wrap(hs.GetDashboardVersions))
|
||||
dashUidRoute.Post("/restore", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite, dashUIDScope)), routing.Wrap(hs.RestoreDashboardVersion))
|
||||
dashUidRoute.Get("/versions/:id", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite, dashUIDScope)), routing.Wrap(hs.GetDashboardVersion))
|
||||
|
||||
if hs.Features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) {
|
||||
dashUidRoute.Patch("/trash", reqOrgAdmin, routing.Wrap(hs.RestoreDeletedDashboard))
|
||||
dashUidRoute.Delete("/trash", reqOrgAdmin, routing.Wrap(hs.HardDeleteDashboardByUID))
|
||||
dashUidRoute.Patch("/trash", reqOrgAdmin, authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite, dashUIDScope)), routing.Wrap(hs.RestoreDeletedDashboard))
|
||||
dashUidRoute.Delete("/trash", reqOrgAdmin, authorize(ac.EvalPermission(dashboards.ActionDashboardsDelete, dashUIDScope)), routing.Wrap(hs.HardDeleteDashboardByUID))
|
||||
}
|
||||
|
||||
dashUidRoute.Group("/permissions", func(dashboardPermissionRoute routing.RouteRegister) {
|
||||
@@ -497,9 +500,10 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
|
||||
// Deprecated: use /uid/:uid API instead.
|
||||
dashboardRoute.Group("/id/:dashboardId", func(dashIdRoute routing.RouteRegister) {
|
||||
dashIdRoute.Get("/versions", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite)), routing.Wrap(hs.GetDashboardVersions))
|
||||
dashIdRoute.Get("/versions/:id", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite)), routing.Wrap(hs.GetDashboardVersion))
|
||||
dashIdRoute.Post("/restore", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite)), routing.Wrap(hs.RestoreDashboardVersion))
|
||||
dashIDScope := dashboards.ScopeDashboardsProvider.GetResourceScope(ac.Parameter(":dashboardId"))
|
||||
dashIdRoute.Get("/versions", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite, dashIDScope)), routing.Wrap(hs.GetDashboardVersions))
|
||||
dashIdRoute.Get("/versions/:id", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite, dashIDScope)), routing.Wrap(hs.GetDashboardVersion))
|
||||
dashIdRoute.Post("/restore", authorize(ac.EvalPermission(dashboards.ActionDashboardsWrite, dashIDScope)), routing.Wrap(hs.RestoreDashboardVersion))
|
||||
|
||||
dashIdRoute.Group("/permissions", func(dashboardPermissionRoute routing.RouteRegister) {
|
||||
dashboardPermissionRoute.Get("/", authorize(ac.EvalPermission(dashboards.ActionDashboardsPermissionsRead)), routing.Wrap(hs.GetDashboardPermissionList))
|
||||
|
||||
+17
-77
@@ -27,7 +27,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboardversion/dashverimpl"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
pref "github.com/grafana/grafana/pkg/services/preference"
|
||||
publicdashboardModels "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||
@@ -141,18 +140,19 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
|
||||
dash.Data.Set("id", dash.ID)
|
||||
}
|
||||
}
|
||||
guardian, err := guardian.NewByDashboard(ctx, dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
}
|
||||
|
||||
if canView, err := guardian.CanView(); err != nil || !canView {
|
||||
return dashboardGuardianResponse(err)
|
||||
dashScope := dashboards.ScopeDashboardsProvider.GetResourceScopeUID(dash.UID)
|
||||
writeEvaluator := accesscontrol.EvalPermission(dashboards.ActionDashboardsWrite, dashScope)
|
||||
canSave, _ := hs.AccessControl.Evaluate(ctx, c.SignedInUser, writeEvaluator)
|
||||
canEdit := canSave
|
||||
//nolint:staticcheck // ViewersCanEdit is deprecated but still used for backward compatibility
|
||||
if hs.Cfg.ViewersCanEdit {
|
||||
canEdit = true
|
||||
}
|
||||
canEdit, _ := guardian.CanEdit()
|
||||
canSave, _ := guardian.CanSave()
|
||||
canAdmin, _ := guardian.CanAdmin()
|
||||
canDelete, _ := guardian.CanDelete()
|
||||
deleteEvaluator := accesscontrol.EvalPermission(dashboards.ActionDashboardsDelete, dashScope)
|
||||
canDelete, _ := hs.AccessControl.Evaluate(ctx, c.SignedInUser, deleteEvaluator)
|
||||
adminEvaluator := accesscontrol.EvalPermission(dashboards.ActionDashboardsPermissionsWrite, dashScope)
|
||||
canAdmin, _ := hs.AccessControl.Evaluate(ctx, c.SignedInUser, adminEvaluator)
|
||||
|
||||
isStarred, err := hs.isDashboardStarredByUser(c, dash.ID)
|
||||
if err != nil {
|
||||
@@ -369,15 +369,6 @@ func (hs *HTTPServer) RestoreDeletedDashboard(c *contextmodel.ReqContext) respon
|
||||
return response.Error(http.StatusNotFound, "Dashboard not found", err)
|
||||
}
|
||||
|
||||
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
}
|
||||
|
||||
if canRestore, err := guardian.CanSave(); err != nil || !canRestore {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
|
||||
err = hs.DashboardService.RestoreDashboard(c.Req.Context(), dash, c.SignedInUser, cmd.FolderUID)
|
||||
if err != nil {
|
||||
var dashboardErr dashboards.DashboardErr
|
||||
@@ -417,16 +408,7 @@ func (hs *HTTPServer) SoftDeleteDashboard(c *contextmodel.ReqContext) response.R
|
||||
return rsp
|
||||
}
|
||||
|
||||
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
}
|
||||
|
||||
if canDelete, err := guardian.CanDelete(); err != nil || !canDelete {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
|
||||
err = hs.DashboardService.SoftDeleteDashboard(c.Req.Context(), c.SignedInUser.GetOrgID(), uid)
|
||||
err := hs.DashboardService.SoftDeleteDashboard(c.Req.Context(), c.SignedInUser.GetOrgID(), uid)
|
||||
if err != nil {
|
||||
var dashboardErr dashboards.DashboardErr
|
||||
if ok := errors.As(err, &dashboardErr); ok {
|
||||
@@ -498,21 +480,12 @@ func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Respo
|
||||
}
|
||||
}
|
||||
|
||||
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
}
|
||||
|
||||
if canDelete, err := guardian.CanDelete(); err != nil || !canDelete {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
|
||||
if dash.IsFolder {
|
||||
return response.Error(http.StatusBadRequest, "Use folders endpoint for deleting folders.", nil)
|
||||
}
|
||||
|
||||
// disconnect all library elements for this dashboard
|
||||
err = hs.LibraryElementService.DisconnectElementsFromDashboard(c.Req.Context(), dash.ID)
|
||||
err := hs.LibraryElementService.DisconnectElementsFromDashboard(c.Req.Context(), dash.ID)
|
||||
if err != nil {
|
||||
hs.log.Error(
|
||||
"Failed to disconnect library elements",
|
||||
@@ -840,14 +813,6 @@ func (hs *HTTPServer) GetDashboardVersions(c *contextmodel.ReqContext) response.
|
||||
return rsp
|
||||
}
|
||||
|
||||
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
}
|
||||
if canSave, err := guardian.CanSave(); err != nil || !canSave {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
|
||||
query := dashver.ListDashboardVersionsQuery{
|
||||
OrgID: c.SignedInUser.GetOrgID(),
|
||||
DashboardID: dash.ID,
|
||||
@@ -959,15 +924,6 @@ func (hs *HTTPServer) GetDashboardVersion(c *contextmodel.ReqContext) response.R
|
||||
return rsp
|
||||
}
|
||||
|
||||
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
}
|
||||
|
||||
if canSave, err := guardian.CanSave(); err != nil || !canSave {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
|
||||
version, err := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64)
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
@@ -1027,22 +983,15 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
|
||||
if err := web.Bind(c.Req, &apiOptions); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||
}
|
||||
guardianBase, err := guardian.New(c.Req.Context(), apiOptions.Base.DashboardId, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
}
|
||||
|
||||
if canSave, err := guardianBase.CanSave(); err != nil || !canSave {
|
||||
evaluator := accesscontrol.EvalPermission(dashboards.ActionDashboardsWrite, dashboards.ScopeDashboardsProvider.GetResourceScope(strconv.FormatInt(apiOptions.Base.DashboardId, 10)))
|
||||
if canWrite, err := hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluator); err != nil || !canWrite {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
|
||||
if apiOptions.Base.DashboardId != apiOptions.New.DashboardId {
|
||||
guardianNew, err := guardian.New(c.Req.Context(), apiOptions.New.DashboardId, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
}
|
||||
|
||||
if canSave, err := guardianNew.CanSave(); err != nil || !canSave {
|
||||
evaluator = accesscontrol.EvalPermission(dashboards.ActionDashboardsWrite, dashboards.ScopeDashboardsProvider.GetResourceScope(strconv.FormatInt(apiOptions.New.DashboardId, 10)))
|
||||
if canWrite, err := hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluator); err != nil || !canWrite {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
}
|
||||
@@ -1159,15 +1108,6 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) respon
|
||||
return rsp
|
||||
}
|
||||
|
||||
guardian, err := guardian.NewByDashboard(c.Req.Context(), dash, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
}
|
||||
|
||||
if canSave, err := guardian.CanSave(); err != nil || !canSave {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
|
||||
versionQuery := dashver.GetDashboardVersionQuery{DashboardID: dashID, DashboardUID: dash.UID, Version: apiCmd.Version, OrgID: c.SignedInUser.GetOrgID()}
|
||||
version, err := hs.dashboardVersionService.Get(c.Req.Context(), &versionQuery)
|
||||
if err != nil {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
@@ -17,7 +18,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/dashboardsnapshots"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/grafana/grafana/pkg/util/errhttp"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
@@ -226,21 +226,15 @@ func (hs *HTTPServer) DeleteDashboardSnapshot(c *contextmodel.ReqContext) respon
|
||||
dashboardID := queryResult.Dashboard.Get("id").MustInt64()
|
||||
|
||||
if dashboardID != 0 {
|
||||
g, err := guardian.New(c.Req.Context(), dashboardID, c.SignedInUser.GetOrgID(), c.SignedInUser)
|
||||
if err != nil {
|
||||
if !errors.Is(err, dashboards.ErrDashboardNotFound) {
|
||||
return response.Err(err)
|
||||
}
|
||||
} else {
|
||||
canEdit, err := g.CanEdit()
|
||||
// check for permissions only if the dashboard is found
|
||||
if err != nil && !errors.Is(err, dashboards.ErrDashboardNotFound) {
|
||||
return response.Error(http.StatusInternalServerError, "Error while checking permissions for snapshot", err)
|
||||
}
|
||||
evaluator := ac.EvalPermission(dashboards.ActionDashboardsWrite, dashboards.ScopeDashboardsProvider.GetResourceScope(strconv.FormatInt(dashboardID, 10)))
|
||||
canEdit, err := hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluator)
|
||||
// check for permissions only if the dashboard is found
|
||||
if err != nil && !errors.Is(err, dashboards.ErrDashboardNotFound) {
|
||||
return response.Error(http.StatusInternalServerError, "Error while checking permissions for snapshot", err)
|
||||
}
|
||||
|
||||
if !canEdit && queryResult.UserID != c.SignedInUser.UserID && !errors.Is(err, dashboards.ErrDashboardNotFound) {
|
||||
return response.Error(http.StatusForbidden, "Access denied to this snapshot", nil)
|
||||
}
|
||||
if !canEdit && queryResult.UserID != c.SignedInUser.UserID && !errors.Is(err, dashboards.ErrDashboardNotFound) {
|
||||
return response.Error(http.StatusForbidden, "Access denied to this snapshot", nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,13 +15,12 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/db/dbtest"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/dashboardsnapshots"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -41,7 +40,7 @@ func TestHTTPServer_DeleteDashboardSnapshot(t *testing.T) {
|
||||
hs.DashboardService = svc
|
||||
|
||||
hs.AccessControl = acimpl.ProvideAccessControl(featuremgmt.WithFeatures())
|
||||
guardian.InitAccessControlGuardian(hs.Cfg, hs.AccessControl, hs.DashboardService, hs.folderService, log.NewNopLogger())
|
||||
hs.AccessControl.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(svc, nil))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -378,6 +377,7 @@ func buildHttpServer(d dashboardsnapshots.Service, snapshotEnabled bool) *HTTPSe
|
||||
Cfg: &setting.Cfg{
|
||||
SnapshotEnabled: snapshotEnabled,
|
||||
},
|
||||
AccessControl: actest.FakeAccessControl{ExpectedEvaluate: true},
|
||||
}
|
||||
return hs
|
||||
}
|
||||
|
||||
+53
-97
@@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -22,8 +23,10 @@ import (
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/db/dbtest"
|
||||
"github.com/grafana/grafana/pkg/infra/kvstore"
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/serverlock"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/infra/usagestats"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
@@ -134,7 +137,10 @@ func newTestLive(t *testing.T, store db.DB) *live.GrafanaLive {
|
||||
nil,
|
||||
&usagestats.UsageStatsMock{T: t},
|
||||
nil,
|
||||
features, acimpl.ProvideAccessControl(features), &dashboards.FakeDashboardService{}, annotationstest.NewFakeAnnotationsRepo(), nil)
|
||||
features, acimpl.ProvideAccessControl(features),
|
||||
&dashboards.FakeDashboardService{},
|
||||
annotationstest.NewFakeAnnotationsRepo(),
|
||||
nil, nil)
|
||||
require.NoError(t, err)
|
||||
return gLive
|
||||
}
|
||||
@@ -327,12 +333,16 @@ func TestHTTPServer_GetDashboardVersions_AccessControl(t *testing.T) {
|
||||
hs.AccessControl = acimpl.ProvideAccessControl(featuremgmt.WithFeatures())
|
||||
hs.starService = startest.NewStarServiceFake()
|
||||
|
||||
hs.dashboardVersionService = &dashvertest.FakeDashboardVersionService{
|
||||
ExpectedListDashboarVersions: []*dashver.DashboardVersionDTO{},
|
||||
ExpectedDashboardVersion: &dashver.DashboardVersionDTO{},
|
||||
expectedDashVersions := []*dashver.DashboardVersionDTO{
|
||||
{Data: simplejson.NewFromAny(map[string]any{"title": "Dash"})},
|
||||
{Data: simplejson.NewFromAny(map[string]any{"title": "Dash updated"})},
|
||||
}
|
||||
|
||||
guardian.InitAccessControlGuardian(hs.Cfg, hs.AccessControl, hs.DashboardService, hs.folderService, log.NewNopLogger())
|
||||
hs.dashboardVersionService = &dashvertest.FakeDashboardVersionService{
|
||||
ExpectedListDashboarVersions: []*dashver.DashboardVersionDTO{},
|
||||
ExpectedDashboardVersions: expectedDashVersions,
|
||||
ExpectedDashboardVersion: &dashver.DashboardVersionDTO{},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -344,6 +354,17 @@ func TestHTTPServer_GetDashboardVersions_AccessControl(t *testing.T) {
|
||||
return server.Send(webtest.RequestWithSignedInUser(server.NewGetRequest("/api/dashboards/uid/1/versions"), userWithPermissions(1, permissions)))
|
||||
}
|
||||
|
||||
calculateDiff := func(server *webtest.Server, permissions []accesscontrol.Permission) (*http.Response, error) {
|
||||
cmd := &dtos.CalculateDiffOptions{
|
||||
Base: dtos.CalculateDiffTarget{DashboardId: 1, Version: 1},
|
||||
New: dtos.CalculateDiffTarget{DashboardId: 1, Version: 2},
|
||||
DiffType: "json",
|
||||
}
|
||||
jsonBytes, err := json.Marshal(cmd)
|
||||
require.NoError(t, err)
|
||||
return server.SendJSON(webtest.RequestWithSignedInUser(server.NewPostRequest("/api/dashboards/calculate-diff", bytes.NewReader(jsonBytes)), userWithPermissions(1, permissions)))
|
||||
}
|
||||
|
||||
t.Run("Should not be able to list dashboard versions without correct permission", func(t *testing.T) {
|
||||
server := setup()
|
||||
|
||||
@@ -363,7 +384,6 @@ func TestHTTPServer_GetDashboardVersions_AccessControl(t *testing.T) {
|
||||
server := setup()
|
||||
|
||||
permissions := []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:1"},
|
||||
{Action: dashboards.ActionDashboardsWrite, Scope: "dashboards:uid:1"},
|
||||
}
|
||||
|
||||
@@ -378,6 +398,28 @@ func TestHTTPServer_GetDashboardVersions_AccessControl(t *testing.T) {
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
|
||||
t.Run("Should be able to diff dashboards with correct permissions", func(t *testing.T) {
|
||||
server := setup()
|
||||
|
||||
permissions := []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionDashboardsWrite, Scope: dashboards.ScopeDashboardsAll},
|
||||
}
|
||||
|
||||
res, err := calculateDiff(server, permissions)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, http.StatusOK, res.StatusCode)
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
|
||||
t.Run("Should not be able to diff dashboards without permissions", func(t *testing.T) {
|
||||
server := setup()
|
||||
|
||||
res, err := calculateDiff(server, []accesscontrol.Permission{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, http.StatusForbidden, res.StatusCode)
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
}
|
||||
|
||||
func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
@@ -527,39 +569,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
}),
|
||||
},
|
||||
}
|
||||
sqlmock := dbtest.NewFakeDB()
|
||||
cmd := dtos.CalculateDiffOptions{
|
||||
Base: dtos.CalculateDiffTarget{
|
||||
DashboardId: 1,
|
||||
Version: 1,
|
||||
},
|
||||
New: dtos.CalculateDiffTarget{
|
||||
DashboardId: 2,
|
||||
Version: 2,
|
||||
},
|
||||
DiffType: "basic",
|
||||
}
|
||||
|
||||
t.Run("when user does not have permission", func(t *testing.T) {
|
||||
role := org.RoleViewer
|
||||
postDiffScenario(t, "When calling POST on", "/api/dashboards/calculate-diff", "/api/dashboards/calculate-diff", cmd, role, func(sc *scenarioContext) {
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: false})
|
||||
|
||||
callPostDashboard(sc)
|
||||
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
|
||||
}, sqlmock, fakeDashboardVersionService)
|
||||
})
|
||||
|
||||
t.Run("when user does have permission", func(t *testing.T) {
|
||||
role := org.RoleAdmin
|
||||
postDiffScenario(t, "When calling POST on", "/api/dashboards/calculate-diff", "/api/dashboards/calculate-diff", cmd, role, func(sc *scenarioContext) {
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true})
|
||||
// This test shouldn't hit GetDashboardACLInfoList, so no setup needed
|
||||
sc.dashboardVersionService = fakeDashboardVersionService
|
||||
callPostDashboard(sc)
|
||||
assert.Equal(t, http.StatusOK, sc.resp.Code)
|
||||
}, sqlmock, fakeDashboardVersionService)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Given dashboard in folder being restored should restore to folder", func(t *testing.T) {
|
||||
@@ -588,11 +597,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
},
|
||||
}
|
||||
mockSQLStore := dbtest.NewFakeDB()
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true})
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
restoreDashboardVersionScenario(t, "When calling POST on", "/api/dashboards/id/1/restore",
|
||||
"/api/dashboards/id/:dashboardId/restore", dashboardService, fakeDashboardVersionService, cmd, func(sc *scenarioContext) {
|
||||
@@ -648,7 +652,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
qResult := &dashboards.Dashboard{ID: 1, Data: dataValue}
|
||||
dashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(qResult, nil)
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true})
|
||||
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", org.RoleEditor, func(sc *scenarioContext) {
|
||||
fakeProvisioningService := provisioning.NewProvisioningServiceMock(context.Background())
|
||||
@@ -678,7 +681,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
LibraryElementService: &libraryelementsfake.LibraryElementService{},
|
||||
dashboardProvisioningService: mockDashboardProvisioningService{},
|
||||
SQLStore: mockSQLStore,
|
||||
AccessControl: accesscontrolmock.New(),
|
||||
AccessControl: actest.FakeAccessControl{ExpectedEvaluate: true},
|
||||
DashboardService: dashboardService,
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
starService: startest.NewStarServiceFake(),
|
||||
@@ -710,7 +713,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
Data: dataValue,
|
||||
}
|
||||
dashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(qResult, nil)
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true})
|
||||
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", org.RoleEditor, func(sc *scenarioContext) {
|
||||
hs := &HTTPServer{
|
||||
@@ -718,7 +720,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
||||
LibraryPanelService: &mockLibraryPanelService{},
|
||||
LibraryElementService: &libraryelementsfake.LibraryElementService{},
|
||||
SQLStore: mockSQLStore,
|
||||
AccessControl: accesscontrolmock.New(),
|
||||
AccessControl: actest.FakeAccessControl{ExpectedEvaluate: true},
|
||||
DashboardService: dashboardService,
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
starService: startest.NewStarServiceFake(),
|
||||
@@ -753,7 +755,7 @@ func TestDashboardVersionsAPIEndpoint(t *testing.T) {
|
||||
Cfg: cfg,
|
||||
pluginStore: &pluginstore.FakePluginStore{},
|
||||
SQLStore: mockSQLStore,
|
||||
AccessControl: accesscontrolmock.New(),
|
||||
AccessControl: actest.FakeAccessControl{ExpectedEvaluate: true},
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
DashboardService: dashboardService,
|
||||
dashboardVersionService: fakeDashboardVersionService,
|
||||
@@ -765,13 +767,8 @@ func TestDashboardVersionsAPIEndpoint(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
setUp := func() {
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true})
|
||||
}
|
||||
|
||||
loggedInUserScenarioWithRole(t, "When user exists and calling GET on", "GET", "/api/dashboards/id/2/versions",
|
||||
"/api/dashboards/id/:dashboardId/versions", org.RoleEditor, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
fakeDashboardVersionService.ExpectedListDashboarVersions = []*dashver.DashboardVersionDTO{
|
||||
{
|
||||
Version: 1,
|
||||
@@ -797,7 +794,6 @@ func TestDashboardVersionsAPIEndpoint(t *testing.T) {
|
||||
|
||||
loggedInUserScenarioWithRole(t, "When user does not exist and calling GET on", "GET", "/api/dashboards/id/2/versions",
|
||||
"/api/dashboards/id/:dashboardId/versions", org.RoleEditor, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
fakeDashboardVersionService.ExpectedListDashboarVersions = []*dashver.DashboardVersionDTO{
|
||||
{
|
||||
Version: 1,
|
||||
@@ -823,7 +819,6 @@ func TestDashboardVersionsAPIEndpoint(t *testing.T) {
|
||||
|
||||
loggedInUserScenarioWithRole(t, "When failing to get user and calling GET on", "GET", "/api/dashboards/id/2/versions",
|
||||
"/api/dashboards/id/:dashboardId/versions", org.RoleEditor, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
fakeDashboardVersionService.ExpectedListDashboarVersions = []*dashver.DashboardVersionDTO{
|
||||
{
|
||||
Version: 1,
|
||||
@@ -882,6 +877,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
|
||||
cfg, dashboardStore, folderStore, features, folderPermissions,
|
||||
ac, folderSvc, fStore, nil, client.MockTestRestConfig{}, nil, quotaService, nil, nil, nil,
|
||||
dualwrite.ProvideTestService(), sort.ProvideService(),
|
||||
serverlock.ProvideService(db, tracing.InitializeTracerForTest()), kvstore.NewFakeKVStore(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
dashboardService.(dashboards.PermissionsRegistrationService).RegisterDashboardPermissions(dashboardPermissions)
|
||||
@@ -891,6 +887,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
|
||||
cfg, dashboardStore, folderStore, features, folderPermissions,
|
||||
ac, folderSvc, fStore, nil, client.MockTestRestConfig{}, nil, quotaService, nil, nil, nil,
|
||||
dualwrite.ProvideTestService(), sort.ProvideService(),
|
||||
serverlock.ProvideService(db, tracing.InitializeTracerForTest()), kvstore.NewFakeKVStore(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -978,47 +975,6 @@ func postDashboardScenario(t *testing.T, desc string, url string, routePattern s
|
||||
})
|
||||
}
|
||||
|
||||
func postDiffScenario(t *testing.T, desc string, url string, routePattern string, cmd dtos.CalculateDiffOptions,
|
||||
role org.RoleType, fn scenarioFunc, sqlmock db.DB, fakeDashboardVersionService *dashvertest.FakeDashboardVersionService,
|
||||
) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
cfg := setting.NewCfg()
|
||||
|
||||
dashSvc := dashboards.NewFakeDashboardService(t)
|
||||
hs := HTTPServer{
|
||||
Cfg: cfg,
|
||||
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
|
||||
Live: newTestLive(t, db.InitTestDB(t)),
|
||||
QuotaService: quotatest.New(false, nil),
|
||||
LibraryPanelService: &mockLibraryPanelService{},
|
||||
LibraryElementService: &libraryelementsfake.LibraryElementService{},
|
||||
SQLStore: sqlmock,
|
||||
dashboardVersionService: fakeDashboardVersionService,
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
DashboardService: dashSvc,
|
||||
tracer: tracing.InitializeTracerForTest(),
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
|
||||
c.Req.Body = mockRequestBody(cmd)
|
||||
c.Req.Header.Add("Content-Type", "application/json")
|
||||
sc.context = c
|
||||
sc.context.SignedInUser = &user.SignedInUser{
|
||||
OrgID: testOrgID,
|
||||
UserID: testUserID,
|
||||
}
|
||||
sc.context.OrgRole = role
|
||||
|
||||
return hs.CalculateDashboardDiff(c)
|
||||
})
|
||||
|
||||
sc.m.Post(routePattern, sc.defaultHandler)
|
||||
|
||||
fn(sc)
|
||||
})
|
||||
}
|
||||
|
||||
func restoreDashboardVersionScenario(t *testing.T, desc string, url string, routePattern string,
|
||||
mock *dashboards.FakeDashboardService, fakeDashboardVersionService *dashvertest.FakeDashboardVersionService,
|
||||
cmd dtos.RestoreDashboardVersionCommand, fn scenarioFunc, sqlStore db.DB,
|
||||
|
||||
@@ -154,20 +154,21 @@ type FrontendSettingsSqlConnectionLimitsDTO struct {
|
||||
}
|
||||
|
||||
type FrontendSettingsDTO struct {
|
||||
DefaultDatasource string `json:"defaultDatasource"`
|
||||
Datasources map[string]plugins.DataSourceDTO `json:"datasources"`
|
||||
MinRefreshInterval string `json:"minRefreshInterval"`
|
||||
Panels map[string]plugins.PanelDTO `json:"panels"`
|
||||
Apps map[string]*plugins.AppDTO `json:"apps"`
|
||||
AppUrl string `json:"appUrl"`
|
||||
AppSubUrl string `json:"appSubUrl"`
|
||||
AllowOrgCreate bool `json:"allowOrgCreate"`
|
||||
AuthProxyEnabled bool `json:"authProxyEnabled"`
|
||||
LdapEnabled bool `json:"ldapEnabled"`
|
||||
JwtHeaderName string `json:"jwtHeaderName"`
|
||||
JwtUrlLogin bool `json:"jwtUrlLogin"`
|
||||
LiveEnabled bool `json:"liveEnabled"`
|
||||
AutoAssignOrg bool `json:"autoAssignOrg"`
|
||||
DefaultDatasource string `json:"defaultDatasource"`
|
||||
Datasources map[string]plugins.DataSourceDTO `json:"datasources"`
|
||||
MinRefreshInterval string `json:"minRefreshInterval"`
|
||||
Panels map[string]plugins.PanelDTO `json:"panels"`
|
||||
Apps map[string]*plugins.AppDTO `json:"apps"`
|
||||
AppUrl string `json:"appUrl"`
|
||||
AppSubUrl string `json:"appSubUrl"`
|
||||
AllowOrgCreate bool `json:"allowOrgCreate"`
|
||||
AuthProxyEnabled bool `json:"authProxyEnabled"`
|
||||
LdapEnabled bool `json:"ldapEnabled"`
|
||||
JwtHeaderName string `json:"jwtHeaderName"`
|
||||
JwtUrlLogin bool `json:"jwtUrlLogin"`
|
||||
LiveEnabled bool `json:"liveEnabled"`
|
||||
LiveMessageSizeLimit int `json:"liveMessageSizeLimit"`
|
||||
AutoAssignOrg bool `json:"autoAssignOrg"`
|
||||
|
||||
VerifyEmailEnabled bool `json:"verifyEmailEnabled"`
|
||||
SigV4AuthEnabled bool `json:"sigV4AuthEnabled"`
|
||||
|
||||
@@ -18,8 +18,10 @@ import (
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/kvstore"
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/serverlock"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
||||
@@ -476,6 +478,8 @@ func setupServer(b testing.TB, sc benchScenario, features featuremgmt.FeatureTog
|
||||
sc.cfg, dashStore, folderStore,
|
||||
features, folderPermissions, ac,
|
||||
folderServiceWithFlagOn, fStore, nil, client.MockTestRestConfig{}, nil, quotaSrv, nil, nil, nil, dualwrite.ProvideTestService(), sort.ProvideService(),
|
||||
serverlock.ProvideService(sc.db, tracing.InitializeTracerForTest()),
|
||||
kvstore.NewFakeKVStore(),
|
||||
)
|
||||
require.NoError(b, err)
|
||||
|
||||
|
||||
@@ -768,3 +768,12 @@ func TestSetDefaultPermissionsWhenCreatingFolder(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func setUpRBACGuardian(t *testing.T) {
|
||||
origNewGuardian := guardian.New
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanEditValue: true, CanViewValue: true})
|
||||
}
|
||||
|
||||
@@ -194,6 +194,7 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
|
||||
JwtHeaderName: hs.Cfg.JWTAuth.HeaderName,
|
||||
JwtUrlLogin: hs.Cfg.JWTAuth.URLLogin,
|
||||
LiveEnabled: hs.Cfg.LiveMaxConnections != 0,
|
||||
LiveMessageSizeLimit: hs.Cfg.LiveMessageSizeLimit,
|
||||
AutoAssignOrg: hs.Cfg.AutoAssignOrg,
|
||||
VerifyEmailEnabled: hs.Cfg.VerifyEmailEnabled,
|
||||
SigV4AuthEnabled: hs.Cfg.SigV4AuthEnabled,
|
||||
|
||||
Reference in New Issue
Block a user