FeatureToggles: Add context and and an explicit global check (#78081)

This commit is contained in:
Ryan McKinley
2023-11-14 12:50:27 -08:00
committed by GitHub
parent c887ef2c9a
commit f69fd3726b
94 changed files with 228 additions and 208 deletions
+9 -9
View File
@@ -108,13 +108,13 @@ 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/authentication/ldap", authorize(ac.EvalPermission(ac.ActionLDAPStatusRead)), hs.Index)
if hs.Features.IsEnabled(featuremgmt.FlagStorage) {
if hs.Features.IsEnabledGlobally(featuremgmt.FlagStorage) {
r.Get("/admin/storage", reqSignedIn, hs.Index)
r.Get("/admin/storage/*", reqSignedIn, hs.Index)
}
// feature toggle admin page
if hs.Features.IsEnabled(featuremgmt.FlagFeatureToggleAdminPage) {
if hs.Features.IsEnabledGlobally(featuremgmt.FlagFeatureToggleAdminPage) {
r.Get("/admin/featuretoggles", authorize(ac.EvalPermission(ac.ActionFeatureManagementRead)), hs.Index)
}
@@ -156,11 +156,11 @@ func (hs *HTTPServer) registerRoutes() {
r.Get("/dashboards/*", reqSignedIn, hs.Index)
r.Get("/goto/:uid", reqSignedIn, hs.redirectFromShortURL, hs.Index)
if hs.Features.IsEnabled(featuremgmt.FlagDashboardEmbed) {
if hs.Features.IsEnabledGlobally(featuremgmt.FlagDashboardEmbed) {
r.Get("/d-embed", reqSignedIn, middleware.AddAllowEmbeddingHeader(), hs.Index)
}
if hs.Features.IsEnabled(featuremgmt.FlagPublicDashboards) {
if hs.Features.IsEnabledGlobally(featuremgmt.FlagPublicDashboards) {
// list public dashboards
r.Get("/public-dashboards/list", reqSignedIn, hs.Index)
@@ -216,7 +216,7 @@ func (hs *HTTPServer) registerRoutes() {
r.Get("/swagger-ui", swaggerUI)
r.Get("/openapi3", openapi3)
if hs.Features.IsEnabled(featuremgmt.FlagClientTokenRotation) {
if hs.Features.IsEnabledGlobally(featuremgmt.FlagClientTokenRotation) {
r.Post("/api/user/auth-tokens/rotate", routing.Wrap(hs.RotateUserAuthToken))
r.Get("/user/auth-tokens/rotate", routing.Wrap(hs.RotateUserAuthTokenRedirect))
}
@@ -277,12 +277,12 @@ func (hs *HTTPServer) registerRoutes() {
orgRoute.Get("/quotas", authorize(ac.EvalPermission(ac.ActionOrgsQuotasRead)), routing.Wrap(hs.GetCurrentOrgQuotas))
})
if hs.Features.IsEnabled(featuremgmt.FlagStorage) {
if hs.Features.IsEnabledGlobally(featuremgmt.FlagStorage) {
// Will eventually be replaced with the 'object' route
apiRoute.Group("/storage", hs.StorageService.RegisterHTTPRoutes)
}
if hs.Features.IsEnabled(featuremgmt.FlagPanelTitleSearch) {
if hs.Features.IsEnabledGlobally(featuremgmt.FlagPanelTitleSearch) {
apiRoute.Group("/search-v2", hs.SearchV2HTTPService.RegisterHTTPRoutes)
}
@@ -392,7 +392,7 @@ func (hs *HTTPServer) registerRoutes() {
apiRoute.Any("/plugin-proxy/:pluginId/*", requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow), authorize(ac.EvalPermission(pluginaccesscontrol.ActionAppAccess, pluginIDScope)), hs.ProxyPluginRequest)
apiRoute.Any("/plugin-proxy/:pluginId", requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow), authorize(ac.EvalPermission(pluginaccesscontrol.ActionAppAccess, pluginIDScope)), hs.ProxyPluginRequest)
if hs.Cfg.PluginAdminEnabled && (hs.Features.IsEnabled(featuremgmt.FlagManagedPluginsInstall) || !hs.Cfg.PluginAdminExternalManageEnabled) {
if hs.Cfg.PluginAdminEnabled && (hs.Features.IsEnabledGlobally(featuremgmt.FlagManagedPluginsInstall) || !hs.Cfg.PluginAdminExternalManageEnabled) {
apiRoute.Group("/plugins", func(pluginRoute routing.RouteRegister) {
pluginRoute.Post("/:pluginId/install", authorize(ac.EvalPermission(pluginaccesscontrol.ActionInstall)), routing.Wrap(hs.InstallPlugin))
pluginRoute.Post("/:pluginId/uninstall", authorize(ac.EvalPermission(pluginaccesscontrol.ActionInstall)), routing.Wrap(hs.UninstallPlugin))
@@ -405,7 +405,7 @@ func (hs *HTTPServer) registerRoutes() {
pluginRoute.Get("/:pluginId/metrics", reqOrgAdmin, routing.Wrap(hs.CollectPluginMetrics))
})
if hs.Features.IsEnabled(featuremgmt.FlagFeatureToggleAdminPage) {
if hs.Features.IsEnabledGlobally(featuremgmt.FlagFeatureToggleAdminPage) {
apiRoute.Group("/featuremgmt", func(featuremgmtRoute routing.RouteRegister) {
featuremgmtRoute.Get("/state", authorize(ac.EvalPermission(ac.ActionFeatureManagementRead)), hs.GetFeatureMgmtState)
featuremgmtRoute.Get("/", authorize(ac.EvalPermission(ac.ActionFeatureManagementRead)), hs.GetFeatureToggles)
+1 -1
View File
@@ -228,7 +228,7 @@ func setupSimpleHTTPServer(features *featuremgmt.FeatureManager) *HTTPServer {
features = featuremgmt.WithFeatures()
}
// nolint:staticcheck
cfg := setting.NewCfgWithFeatures(features.IsEnabled)
cfg := setting.NewCfgWithFeatures(features.IsEnabledGlobally)
return &HTTPServer{
Cfg: cfg,
+1 -1
View File
@@ -94,7 +94,7 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
// If public dashboards is enabled and we have a public dashboard, update meta
// values
if hs.Features.IsEnabled(featuremgmt.FlagPublicDashboards) {
if hs.Features.IsEnabledGlobally(featuremgmt.FlagPublicDashboards) {
publicDashboard, err := hs.PublicDashboardsApi.PublicDashboardService.FindByDashboardUid(c.Req.Context(), c.SignedInUser.GetOrgID(), dash.UID)
if err != nil && !errors.Is(err, publicdashboardModels.ErrPublicDashboardNotFound) {
return response.Error(http.StatusInternalServerError, "Error while retrieving public dashboards", err)
+2 -1
View File
@@ -15,6 +15,7 @@ import (
"golang.org/x/exp/slices"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/api/datasource"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
@@ -356,7 +357,7 @@ func validateJSONData(ctx context.Context, jsonData *simplejson.Json, cfg *setti
}
// Prevent adding a data source team header with a name that matches the auth proxy header name
if features.IsEnabled(featuremgmt.FlagTeamHttpHeaders) {
if features.IsEnabled(ctx, featuremgmt.FlagTeamHttpHeaders) {
err := validateTeamHTTPHeaderJSON(jsonData)
if err != nil {
return err
+4 -4
View File
@@ -43,7 +43,7 @@ const REDACTED = "redacted"
func (hs *HTTPServer) GetFolders(c *contextmodel.ReqContext) response.Response {
var folders []*folder.Folder
var err error
if hs.Features.IsEnabled(featuremgmt.FlagNestedFolders) {
if hs.Features.IsEnabled(c.Req.Context(), featuremgmt.FlagNestedFolders) {
folders, err = hs.folderService.GetChildren(c.Req.Context(), &folder.GetChildrenQuery{
OrgID: c.SignedInUser.GetOrgID(),
Limit: c.QueryInt64("limit"),
@@ -190,7 +190,7 @@ func (hs *HTTPServer) setDefaultFolderPermissions(ctx context.Context, orgID int
}
isNested := folder.ParentUID != ""
if !isNested || !hs.Features.IsEnabled(featuremgmt.FlagNestedFolders) {
if !isNested || !hs.Features.IsEnabled(ctx, featuremgmt.FlagNestedFolders) {
permissions = append(permissions, []accesscontrol.SetResourcePermissionCommand{
{BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()},
{BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()},
@@ -212,7 +212,7 @@ func (hs *HTTPServer) setDefaultFolderPermissions(ctx context.Context, orgID int
// 404: notFoundError
// 500: internalServerError
func (hs *HTTPServer) MoveFolder(c *contextmodel.ReqContext) response.Response {
if hs.Features.IsEnabled(featuremgmt.FlagNestedFolders) {
if hs.Features.IsEnabled(c.Req.Context(), featuremgmt.FlagNestedFolders) {
cmd := folder.MoveFolderCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
@@ -390,7 +390,7 @@ func (hs *HTTPServer) newToFolderDto(c *contextmodel.ReqContext, f *folder.Folde
return dtos.Folder{}, err
}
if !hs.Features.IsEnabled(featuremgmt.FlagNestedFolders) {
if !hs.Features.IsEnabled(c.Req.Context(), featuremgmt.FlagNestedFolders) {
return folderDTO, nil
}
+1 -1
View File
@@ -66,7 +66,7 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
continue
}
if panel.ID == "datagrid" && !hs.Features.IsEnabled(featuremgmt.FlagEnableDatagridEditing) {
if panel.ID == "datagrid" && !hs.Features.IsEnabled(c.Req.Context(), featuremgmt.FlagEnableDatagridEditing) {
continue
}
+1 -1
View File
@@ -35,7 +35,7 @@ func setupTestEnvironment(t *testing.T, cfg *setting.Cfg, features *featuremgmt.
t.Helper()
db.InitTestDB(t)
// nolint:staticcheck
cfg.IsFeatureToggleEnabled = features.IsEnabled
cfg.IsFeatureToggleEnabled = features.IsEnabledGlobally
{
oldVersion := setting.BuildVersion
+3 -3
View File
@@ -38,7 +38,7 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV
return nil, err
}
if hs.Features.IsEnabled(featuremgmt.FlagIndividualCookiePreferences) {
if hs.Features.IsEnabled(c.Req.Context(), featuremgmt.FlagIndividualCookiePreferences) {
if !prefs.Cookies("analytics") {
settings.GoogleAnalytics4Id = ""
settings.GoogleAnalyticsId = ""
@@ -166,7 +166,7 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV
hs.HooksService.RunIndexDataHooks(&data, c)
data.NavTree.ApplyAdminIA(hs.Features.IsEnabled(featuremgmt.FlagNavAdminSubsections))
data.NavTree.ApplyAdminIA(hs.Features.IsEnabled(c.Req.Context(), featuremgmt.FlagNavAdminSubsections))
data.NavTree.Sort()
return &data, nil
@@ -244,7 +244,7 @@ func (hs *HTTPServer) getThemeForIndexData(themePrefId string, themeURLParam str
if pref.IsValidThemeID(themePrefId) {
theme := pref.GetThemeByID(themePrefId)
if !theme.IsExtra || hs.Features.IsEnabled(featuremgmt.FlagExtraThemes) {
if !theme.IsExtra || hs.Features.IsEnabledGlobally(featuremgmt.FlagExtraThemes) {
return theme
}
}
+2 -2
View File
@@ -91,7 +91,7 @@ func (hs *HTTPServer) CookieOptionsFromCfg() cookies.CookieOptions {
}
func (hs *HTTPServer) LoginView(c *contextmodel.ReqContext) {
if hs.Features.IsEnabled(featuremgmt.FlagClientTokenRotation) {
if hs.Features.IsEnabled(c.Req.Context(), featuremgmt.FlagClientTokenRotation) {
if errors.Is(c.LookupTokenErr, authn.ErrTokenNeedsRotation) {
c.Redirect(hs.Cfg.AppSubURL + "/")
return
@@ -334,7 +334,7 @@ func (hs *HTTPServer) RedirectResponseWithError(c *contextmodel.ReqContext, err
func (hs *HTTPServer) redirectURLWithErrorCookie(c *contextmodel.ReqContext, err error) string {
setCookie := true
if hs.Features.IsEnabled(featuremgmt.FlagIndividualCookiePreferences) {
if hs.Features.IsEnabled(c.Req.Context(), featuremgmt.FlagIndividualCookiePreferences) {
var userID int64
if c.SignedInUser != nil && !c.SignedInUser.IsNil() {
var errID error
+1 -1
View File
@@ -63,7 +63,7 @@ func (hs *HTTPServer) QueryMetricsV2(c *contextmodel.ReqContext) response.Respon
func (hs *HTTPServer) toJsonStreamingResponse(ctx context.Context, qdr *backend.QueryDataResponse) response.Response {
statusWhenError := http.StatusBadRequest
if hs.Features.IsEnabled(featuremgmt.FlagDatasourceQueryMultiStatus) {
if hs.Features.IsEnabled(ctx, featuremgmt.FlagDatasourceQueryMultiStatus) {
statusWhenError = http.StatusMultiStatus
}
+1 -1
View File
@@ -26,7 +26,7 @@ import (
func (hs *HTTPServer) registerPlaylistAPI(apiRoute routing.RouteRegister) {
// Register the actual handlers
apiRoute.Group("/playlists", func(playlistRoute routing.RouteRegister) {
if hs.Features.IsEnabled(featuremgmt.FlagKubernetesPlaylists) {
if hs.Features.IsEnabledGlobally(featuremgmt.FlagKubernetesPlaylists) {
// Use k8s client to implement legacy API
handler := newPlaylistK8sHandler(hs)
playlistRoute.Get("/", handler.searchPlaylists)
+1 -1
View File
@@ -270,7 +270,7 @@ func (proxy *DataSourceProxy) director(req *http.Request) {
}
}
if proxy.features.IsEnabled(featuremgmt.FlagIdForwarding) && auth.IsIDForwardingEnabledForDataSource(proxy.ds) {
if proxy.features.IsEnabled(req.Context(), featuremgmt.FlagIdForwarding) && auth.IsIDForwardingEnabledForDataSource(proxy.ds) {
proxyutil.ApplyForwardIDHeader(req, proxy.ctx.SignedInUser)
}
}
+3 -2
View File
@@ -7,6 +7,8 @@ import (
"net/http"
"net/url"
"go.opentelemetry.io/otel/attribute"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/plugins"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
@@ -17,7 +19,6 @@ import (
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/util/proxyutil"
"github.com/grafana/grafana/pkg/web"
"go.opentelemetry.io/otel/attribute"
)
type PluginProxy struct {
@@ -161,7 +162,7 @@ func (proxy PluginProxy) director(req *http.Request) {
proxyutil.ApplyUserHeader(proxy.cfg.SendUserHeader, req, proxy.ctx.SignedInUser)
if proxy.features.IsEnabled(featuremgmt.FlagIdForwarding) {
if proxy.features.IsEnabled(req.Context(), featuremgmt.FlagIdForwarding) {
proxyutil.ApplyForwardIDHeader(req, proxy.ctx.SignedInUser)
}