Compare commits

...

2 Commits

Author SHA1 Message Date
grafana-delivery-bot[bot] 84df4b68cd Release: Bump version to 11.1.3 (#91893)
* bump version 11.1.3

* Lint

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Andreas Christou <andreas.christou@grafana.com>
2024-08-15 11:59:58 +01:00
Kevin Minehart 9cdba084a9 RBAC: Allow plugins to use scoped actions (#90945)
Co-authored-by: gamab <gabriel.mabille@grafana.com>
2024-07-26 08:33:56 -05:00
60 changed files with 431 additions and 271 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"npmClient": "yarn",
"version": "11.1.1"
"version": "11.1.3"
}
+1 -1
View File
@@ -3,7 +3,7 @@
"license": "AGPL-3.0-only",
"private": true,
"name": "grafana",
"version": "11.1.1",
"version": "11.1.3",
"repository": "github:grafana/grafana",
"scripts": {
"build": "NODE_ENV=production nx exec --verbose -- webpack --config scripts/webpack/webpack.prod.js",
+2 -2
View File
@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/data",
"version": "11.1.1",
"version": "11.1.3",
"description": "Grafana Data Library",
"keywords": [
"typescript"
@@ -36,7 +36,7 @@
},
"dependencies": {
"@braintree/sanitize-url": "7.0.1",
"@grafana/schema": "11.1.1",
"@grafana/schema": "11.1.3",
"@types/d3-interpolate": "^3.0.0",
"@types/string-hash": "1.1.3",
"d3-interpolate": "3.0.1",
+1 -1
View File
@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/e2e-selectors",
"version": "11.1.1",
"version": "11.1.3",
"description": "Grafana End-to-End Test Selectors Library",
"keywords": [
"cli",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@grafana/eslint-plugin",
"description": "ESLint rules for use within the Grafana repo. Not suitable (or supported) for external use.",
"version": "11.1.1",
"version": "11.1.3",
"main": "./index.cjs",
"author": "Grafana Labs",
"license": "Apache-2.0",
+3 -3
View File
@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/flamegraph",
"version": "11.1.1",
"version": "11.1.3",
"description": "Grafana flamegraph visualization component",
"keywords": [
"grafana",
@@ -44,8 +44,8 @@
],
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.1.1",
"@grafana/ui": "11.1.1",
"@grafana/data": "11.1.3",
"@grafana/ui": "11.1.3",
"@leeoniya/ufuzzy": "1.0.14",
"d3": "^7.8.5",
"lodash": "4.17.21",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@grafana/saga-icons",
"version": "11.1.1",
"version": "11.1.3",
"private": true,
"description": "Icons for Grafana",
"author": "Grafana Labs",
@@ -3,7 +3,7 @@
"license": "AGPL-3.0-only",
"name": "@grafana/o11y-ds-frontend",
"private": true,
"version": "11.1.1",
"version": "11.1.3",
"description": "Library to manage traces in Grafana.",
"sideEffects": false,
"repository": {
@@ -18,12 +18,12 @@
},
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.1.1",
"@grafana/e2e-selectors": "11.1.1",
"@grafana/data": "11.1.3",
"@grafana/e2e-selectors": "11.1.3",
"@grafana/experimental": "1.7.11",
"@grafana/runtime": "11.1.1",
"@grafana/schema": "11.1.1",
"@grafana/ui": "11.1.1",
"@grafana/runtime": "11.1.3",
"@grafana/schema": "11.1.3",
"@grafana/ui": "11.1.3",
"react-select": "5.8.0",
"react-use": "17.5.0",
"rxjs": "7.8.1",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "@grafana/plugin-configs",
"description": "Shared dependencies and files for core plugins",
"private": true,
"version": "11.1.1",
"version": "11.1.3",
"dependencies": {
"tslib": "2.6.3"
},
+6 -6
View File
@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "AGPL-3.0-only",
"name": "@grafana/prometheus",
"version": "11.1.1",
"version": "11.1.3",
"description": "Grafana Prometheus Library",
"keywords": [
"typescript"
@@ -38,12 +38,12 @@
"dependencies": {
"@emotion/css": "11.11.2",
"@floating-ui/react": "0.26.16",
"@grafana/data": "11.1.1",
"@grafana/data": "11.1.3",
"@grafana/experimental": "1.7.11",
"@grafana/faro-web-sdk": "1.7.3",
"@grafana/runtime": "11.1.1",
"@grafana/schema": "11.1.1",
"@grafana/ui": "11.1.1",
"@grafana/runtime": "11.1.3",
"@grafana/schema": "11.1.3",
"@grafana/ui": "11.1.3",
"@leeoniya/ufuzzy": "1.0.14",
"@lezer/common": "1.2.1",
"@lezer/highlight": "1.2.0",
@@ -76,7 +76,7 @@
},
"devDependencies": {
"@emotion/eslint-plugin": "11.11.0",
"@grafana/e2e-selectors": "11.1.1",
"@grafana/e2e-selectors": "11.1.3",
"@grafana/tsconfig": "^1.3.0-rc1",
"@rollup/plugin-image": "3.0.3",
"@rollup/plugin-node-resolve": "15.2.3",
+5 -5
View File
@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/runtime",
"version": "11.1.1",
"version": "11.1.3",
"description": "Grafana Runtime Library",
"keywords": [
"grafana",
@@ -37,11 +37,11 @@
"postpack": "mv package.json.bak package.json"
},
"dependencies": {
"@grafana/data": "11.1.1",
"@grafana/e2e-selectors": "11.1.1",
"@grafana/data": "11.1.3",
"@grafana/e2e-selectors": "11.1.3",
"@grafana/faro-web-sdk": "^1.3.6",
"@grafana/schema": "11.1.1",
"@grafana/ui": "11.1.1",
"@grafana/schema": "11.1.3",
"@grafana/ui": "11.1.3",
"history": "4.10.1",
"lodash": "4.17.21",
"rxjs": "7.8.1",
+1 -1
View File
@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/schema",
"version": "11.1.1",
"version": "11.1.3",
"description": "Grafana Schema Library",
"keywords": [
"typescript"
@@ -8,7 +8,7 @@
//
// Run 'make gen-cue' from repository root to regenerate.
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options {
limit: number;
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options extends common.OptionsWithLegend, common.OptionsWithTooltip, common.OptionsWithTextFormatting {
/**
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options extends common.SingleStatBaseOptions {
displayMode: common.BarGaugeDisplayMode;
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export enum VizDisplayMode {
Candles = 'candles',
@@ -10,7 +10,7 @@
import * as ui from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export enum HorizontalConstraint {
Center = 'center',
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface MetricStat {
/**
@@ -8,7 +8,7 @@
//
// Run 'make gen-cue' from repository root to regenerate.
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options {
/**
@@ -8,7 +8,7 @@
//
// Run 'make gen-cue' from repository root to regenerate.
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options {
selectedSeries: number;
@@ -8,7 +8,7 @@
//
// Run 'make gen-cue' from repository root to regenerate.
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export type UpdateConfig = {
render: boolean,
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export type BucketAggregation = (DateHistogram | Histogram | Terms | Filters | GeoHashGrid | Nested);
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options extends common.SingleStatBaseOptions {
minVizHeight: number;
@@ -10,7 +10,7 @@
import * as ui from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options {
basemap: ui.MapLayerOptions;
@@ -10,7 +10,7 @@
import * as ui from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
/**
* Controls the color mode of the heatmap
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options extends common.OptionsWithLegend, common.OptionsWithTooltip {
/**
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options {
dedupStrategy: common.LogsDedupStrategy;
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export enum QueryEditorMode {
Builder = 'builder',
@@ -8,7 +8,7 @@
//
// Run 'make gen-cue' from repository root to regenerate.
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options {
/**
@@ -8,7 +8,7 @@
//
// Run 'make gen-cue' from repository root to regenerate.
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface ArcOption {
/**
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
/**
* Select the pie chart display style.
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options extends common.SingleStatBaseOptions {
colorMode: common.BigValueColorMode;
@@ -10,7 +10,7 @@
import * as ui from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options extends ui.OptionsWithLegend, ui.OptionsWithTooltip, ui.OptionsWithTimezones {
/**
@@ -10,7 +10,7 @@
import * as ui from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options extends ui.OptionsWithLegend, ui.OptionsWithTooltip, ui.OptionsWithTimezones {
/**
@@ -10,7 +10,7 @@
import * as ui from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options {
/**
@@ -8,7 +8,7 @@
//
// Run 'make gen-cue' from repository root to regenerate.
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export enum TextMode {
Code = 'code',
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
export interface Options extends common.OptionsWithTimezones {
legend: common.VizLegendOptions;
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
/**
* Identical to timeseries... except it does not have timezone settings
@@ -10,7 +10,7 @@
import * as common from '@grafana/schema';
export const pluginVersion = "11.1.1";
export const pluginVersion = "11.1.3";
/**
* Auto is "table" in the UI
+5 -5
View File
@@ -3,7 +3,7 @@
"license": "AGPL-3.0-only",
"private": true,
"name": "@grafana/sql",
"version": "11.1.1",
"version": "11.1.3",
"repository": {
"type": "git",
"url": "http://github.com/grafana/grafana.git",
@@ -15,11 +15,11 @@
},
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.1.1",
"@grafana/e2e-selectors": "11.1.1",
"@grafana/data": "11.1.3",
"@grafana/e2e-selectors": "11.1.3",
"@grafana/experimental": "1.7.11",
"@grafana/runtime": "11.1.1",
"@grafana/ui": "11.1.1",
"@grafana/runtime": "11.1.3",
"@grafana/ui": "11.1.3",
"@react-awesome-query-builder/ui": "6.5.2",
"immutable": "4.3.6",
"lodash": "4.17.21",
+4 -4
View File
@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/ui",
"version": "11.1.1",
"version": "11.1.3",
"description": "Grafana Components Library",
"keywords": [
"grafana",
@@ -50,10 +50,10 @@
"@emotion/css": "11.11.2",
"@emotion/react": "11.11.4",
"@floating-ui/react": "0.26.16",
"@grafana/data": "11.1.1",
"@grafana/e2e-selectors": "11.1.1",
"@grafana/data": "11.1.3",
"@grafana/e2e-selectors": "11.1.3",
"@grafana/faro-web-sdk": "^1.3.6",
"@grafana/schema": "11.1.1",
"@grafana/schema": "11.1.3",
"@leeoniya/ufuzzy": "1.0.14",
"@monaco-editor/react": "4.6.0",
"@popperjs/core": "2.11.8",
+5 -5
View File
@@ -19,11 +19,11 @@ import (
glog "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/accesscontrol"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/oauthtoken"
pluginac "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/util/proxyutil"
@@ -341,12 +341,12 @@ func (proxy *DataSourceProxy) hasAccessToRoute(route *plugins.Route) bool {
ctxLogger := logger.FromContext(proxy.ctx.Req.Context())
useRBAC := proxy.features.IsEnabled(proxy.ctx.Req.Context(), featuremgmt.FlagAccessControlOnCall) && route.ReqAction != ""
if useRBAC {
routeEval := accesscontrol.EvalPermission(route.ReqAction)
ok := routeEval.Evaluate(proxy.ctx.GetPermissions())
if !ok {
routeEval := pluginac.GetDataSourceRouteEvaluator(proxy.ds.UID, route.ReqAction)
hasAccess := routeEval.Evaluate(proxy.ctx.GetPermissions())
if !hasAccess {
ctxLogger.Debug("plugin route is covered by RBAC, user doesn't have access", "route", proxy.ctx.Req.URL.Path, "action", route.ReqAction, "path", route.Path, "method", route.Method)
}
return ok
return hasAccess
}
if route.ReqRole.IsValid() {
if hasUserRole := proxy.ctx.HasUserRole(route.ReqRole); !hasUserRole {
+55 -1
View File
@@ -108,9 +108,18 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
Path: "mypath",
URL: "https://example.com/api/v1/",
},
{
Path: "api/rbac-home",
ReqAction: "datasources:read",
},
{
Path: "api/rbac-restricted",
ReqAction: "test-app.settings:read",
},
}
ds := &datasources.DataSource{
UID: "dsUID",
JsonData: simplejson.NewFromAny(map[string]any{
"clientId": "asd",
"dynamicUrl": "https://dynamic.grafana.com",
@@ -249,6 +258,51 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
require.NoError(t, err)
})
})
t.Run("plugin route with RBAC protection user is allowed", func(t *testing.T) {
ctx, _ := setUp()
ctx.SignedInUser.OrgID = int64(1)
ctx.SignedInUser.OrgRole = org.RoleNone
ctx.SignedInUser.Permissions = map[int64]map[string][]string{1: {"test-app.settings:read": nil}}
proxy, err := setupDSProxyTest(t, ctx, ds, routes, "api/rbac-restricted")
require.NoError(t, err)
err = proxy.validateRequest()
require.NoError(t, err)
})
t.Run("plugin route with RBAC protection user is not allowed", func(t *testing.T) {
ctx, _ := setUp()
ctx.SignedInUser.OrgID = int64(1)
ctx.SignedInUser.OrgRole = org.RoleNone
ctx.SignedInUser.Permissions = map[int64]map[string][]string{1: {"test-app:read": nil}}
proxy, err := setupDSProxyTest(t, ctx, ds, routes, "api/rbac-restricted")
require.NoError(t, err)
err = proxy.validateRequest()
require.Error(t, err)
})
t.Run("plugin route with dynamic RBAC protection user is allowed", func(t *testing.T) {
ctx, _ := setUp()
ctx.SignedInUser.OrgID = int64(1)
ctx.SignedInUser.OrgRole = org.RoleNone
ctx.SignedInUser.Permissions = map[int64]map[string][]string{1: {"datasources:read": {"datasources:uid:dsUID"}}}
proxy, err := setupDSProxyTest(t, ctx, ds, routes, "api/rbac-home")
require.NoError(t, err)
err = proxy.validateRequest()
require.NoError(t, err)
})
t.Run("plugin route with dynamic RBAC protection user is not allowed", func(t *testing.T) {
ctx, _ := setUp()
ctx.SignedInUser.OrgID = int64(1)
ctx.SignedInUser.OrgRole = org.RoleNone
// Has access but to another app
ctx.SignedInUser.Permissions = map[int64]map[string][]string{1: {"datasources:read": {"datasources:uid:notTheDsUID"}}}
proxy, err := setupDSProxyTest(t, ctx, ds, routes, "api/rbac-home")
require.NoError(t, err)
err = proxy.validateRequest()
require.Error(t, err)
})
})
t.Run("Plugin with multiple routes for token auth", func(t *testing.T) {
@@ -1021,7 +1075,7 @@ func setupDSProxyTest(t *testing.T, ctx *contextmodel.ReqContext, ds *datasource
cfg := setting.NewCfg()
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
secretsStore := secretskvs.NewSQLSecretsKVStore(dbtest.NewFakeDB(), secretsService, log.NewNopLogger())
features := featuremgmt.WithFeatures()
features := featuremgmt.WithFeatures(featuremgmt.FlagAccessControlOnCall)
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, features, acimpl.ProvideAccessControl(features),
&actest.FakePermissionsService{}, quotatest.New(false, nil), &pluginstore.FakePluginStore{}, &pluginfakes.FakePluginClient{},
plugincontext.ProvideBaseService(cfg, pluginconfig.NewFakePluginRequestConfigProvider()))
+3 -1
View File
@@ -15,6 +15,7 @@ import (
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/featuremgmt"
pluginac "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
"github.com/grafana/grafana/pkg/services/secrets"
"github.com/grafana/grafana/pkg/setting"
@@ -130,7 +131,8 @@ func (proxy *PluginProxy) HandleRequest() {
func (proxy *PluginProxy) hasAccessToRoute(route *plugins.Route) bool {
useRBAC := proxy.features.IsEnabled(proxy.ctx.Req.Context(), featuremgmt.FlagAccessControlOnCall) && route.ReqAction != ""
if useRBAC {
hasAccess := ac.HasAccess(proxy.accessControl, proxy.ctx)(ac.EvalPermission(route.ReqAction))
routeEval := pluginac.GetPluginRouteEvaluator(proxy.ps.PluginID, route.ReqAction)
hasAccess := ac.HasAccess(proxy.accessControl, proxy.ctx)(routeEval)
if !hasAccess {
proxy.ctx.Logger.Debug("plugin route is covered by RBAC, user doesn't have access", "route", proxy.ctx.Req.URL.Path)
}
+21 -2
View File
@@ -454,7 +454,13 @@ func TestPluginProxyRoutesAccessControl(t *testing.T) {
Path: "projects",
Method: "GET",
URL: "http://localhost/api/projects",
ReqAction: "plugin-id.projects:read", // Protected by RBAC action
ReqAction: "test-app.projects:read", // Protected by RBAC action
},
{
Path: "home",
Method: "GET",
URL: "http://localhost/api/home",
ReqAction: "plugins.app:access", // Protected by RBAC action with plugin scope
},
}
@@ -479,7 +485,7 @@ func TestPluginProxyRoutesAccessControl(t *testing.T) {
},
{
proxyPath: "/projects",
usrPerms: map[string][]string{"plugin-id.projects:read": {}},
usrPerms: map[string][]string{"test-app.projects:read": {}},
expectedURLPath: "/api/projects",
expectedStatus: http.StatusOK,
},
@@ -489,6 +495,18 @@ func TestPluginProxyRoutesAccessControl(t *testing.T) {
expectedURLPath: "/api/projects",
expectedStatus: http.StatusForbidden,
},
{
proxyPath: "/home",
usrPerms: map[string][]string{"plugins.app:access": {"plugins:id:not-the-test-app"}},
expectedURLPath: "/api/home",
expectedStatus: http.StatusForbidden,
},
{
proxyPath: "/home",
usrPerms: map[string][]string{"plugins.app:access": {"plugins:id:test-app"}},
expectedURLPath: "/api/home",
expectedStatus: http.StatusOK,
},
}
for _, tc := range tcs {
@@ -533,6 +551,7 @@ func TestPluginProxyRoutesAccessControl(t *testing.T) {
},
}
ps := &pluginsettings.DTO{
PluginID: "test-app",
SecureJSONData: map[string][]byte{},
}
cfg := &setting.Cfg{}
+1 -1
View File
@@ -127,7 +127,7 @@ func RoleAppPluginAuth(accessControl ac.AccessControl, ps pluginstore.Store, fea
if normalizeIncludePath(u.Path) == path {
useRBAC := features.IsEnabledGlobally(featuremgmt.FlagAccessControlOnCall) && i.RequiresRBACAction()
if useRBAC && !hasAccess(ac.EvalPermission(i.Action)) {
if useRBAC && !hasAccess(pluginaccesscontrol.GetPluginRouteEvaluator(pluginID, i.Action)) {
logger.Debug("Plugin include is covered by RBAC, user doesn't have access", "plugin", pluginID, "include", i.Name)
permitted = false
break
+1 -1
View File
@@ -269,7 +269,7 @@ func (s *ServiceImpl) hasAccessToInclude(c *contextmodel.ReqContext, pluginID st
hasAccess := ac.HasAccess(s.accessControl, c)
return func(include *plugins.Includes) bool {
useRBAC := s.features.IsEnabledGlobally(featuremgmt.FlagAccessControlOnCall) && include.RequiresRBACAction()
if useRBAC && !hasAccess(ac.EvalPermission(include.Action)) {
if useRBAC && !hasAccess(pluginaccesscontrol.GetPluginRouteEvaluator(pluginID, include.Action)) {
s.log.Debug("plugin include is covered by RBAC, user doesn't have access",
"plugin", pluginID,
"include", include.Name)
+117 -72
View File
@@ -406,20 +406,28 @@ func TestAddAppLinksAccessControl(t *testing.T) {
ID: "test-app1", Name: "Test app1 name", Type: plugins.TypeApp,
Includes: []*plugins.Includes{
{
Name: "Catalog",
Path: "/a/test-app1/catalog",
Name: "Home",
Path: "/a/test-app1/home",
Type: "page",
AddToNav: true,
DefaultNav: true,
Role: roletype.RoleEditor,
Action: catalogReadAction,
Role: roletype.RoleViewer,
},
{
Name: "Page2",
Path: "/a/test-app1/page2",
Name: "Catalog",
Path: "/a/test-app1/catalog",
Type: "page",
AddToNav: true,
Role: roletype.RoleEditor,
Action: catalogReadAction,
},
{
Name: "Announcements",
Path: "/a/test-app1/announcements",
Type: "page",
AddToNav: true,
Role: roletype.RoleViewer,
Action: pluginaccesscontrol.ActionAppAccess,
},
},
},
@@ -442,77 +450,114 @@ func TestAddAppLinksAccessControl(t *testing.T) {
},
}
t.Run("Should not add app links when the user cannot access app plugins", func(t *testing.T) {
treeRoot := navtree.NavTreeRoot{}
user.Permissions = map[int64]map[string][]string{}
user.OrgRole = roletype.RoleAdmin
t.Run("Without plugin RBAC - Enforce role", func(t *testing.T) {
t.Run("Should not add app links when the user cannot access app plugins", func(t *testing.T) {
treeRoot := navtree.NavTreeRoot{}
user.Permissions = map[int64]map[string][]string{}
user.OrgRole = roletype.RoleAdmin
err := service.addAppLinks(&treeRoot, reqCtx)
require.NoError(t, err)
require.Len(t, treeRoot.Children, 0)
err := service.addAppLinks(&treeRoot, reqCtx)
require.NoError(t, err)
require.Len(t, treeRoot.Children, 0)
})
t.Run(" Should add all includes when the user is an editor", func(t *testing.T) {
treeRoot := navtree.NavTreeRoot{}
user.Permissions = map[int64]map[string][]string{
1: {pluginaccesscontrol.ActionAppAccess: []string{"*"}},
}
user.OrgRole = roletype.RoleEditor
err := service.addAppLinks(&treeRoot, reqCtx)
require.NoError(t, err)
appsNode := treeRoot.FindById(navtree.NavIDApps)
require.Len(t, appsNode.Children, 1)
require.Equal(t, "Test app1 name", appsNode.Children[0].Text)
require.Equal(t, "/a/test-app1/home", appsNode.Children[0].Url)
require.Len(t, appsNode.Children[0].Children, 2)
require.Equal(t, "/a/test-app1/catalog", appsNode.Children[0].Children[0].Url)
require.Equal(t, "/a/test-app1/announcements", appsNode.Children[0].Children[1].Url)
})
t.Run("Should add two includes when the user is a viewer", func(t *testing.T) {
treeRoot := navtree.NavTreeRoot{}
user.Permissions = map[int64]map[string][]string{
1: {pluginaccesscontrol.ActionAppAccess: []string{"*"}},
}
user.OrgRole = roletype.RoleViewer
err := service.addAppLinks(&treeRoot, reqCtx)
require.NoError(t, err)
appsNode := treeRoot.FindById(navtree.NavIDApps)
require.Len(t, appsNode.Children, 1)
require.Equal(t, "Test app1 name", appsNode.Children[0].Text)
require.Equal(t, "/a/test-app1/home", appsNode.Children[0].Url)
require.Len(t, appsNode.Children[0].Children, 1)
require.Equal(t, "/a/test-app1/announcements", appsNode.Children[0].Children[0].Url)
})
})
t.Run("Should add both includes when the user is an editor", func(t *testing.T) {
treeRoot := navtree.NavTreeRoot{}
user.Permissions = map[int64]map[string][]string{
1: {pluginaccesscontrol.ActionAppAccess: []string{"*"}},
}
user.OrgRole = roletype.RoleEditor
err := service.addAppLinks(&treeRoot, reqCtx)
require.NoError(t, err)
appsNode := treeRoot.FindById(navtree.NavIDApps)
require.Len(t, appsNode.Children, 1)
require.Equal(t, "Test app1 name", appsNode.Children[0].Text)
require.Equal(t, "/a/test-app1/catalog", appsNode.Children[0].Url)
require.Len(t, appsNode.Children[0].Children, 1)
require.Equal(t, "/a/test-app1/page2", appsNode.Children[0].Children[0].Url)
})
t.Run("Should add one include when the user is a viewer", func(t *testing.T) {
treeRoot := navtree.NavTreeRoot{}
user.Permissions = map[int64]map[string][]string{
1: {pluginaccesscontrol.ActionAppAccess: []string{"*"}},
}
user.OrgRole = roletype.RoleViewer
t.Run("With plugin RBAC - Enforce action first", func(t *testing.T) {
t.Run("Should not see any includes with no app access", func(t *testing.T) {
treeRoot := navtree.NavTreeRoot{}
user.Permissions = map[int64]map[string][]string{
1: {pluginaccesscontrol.ActionAppAccess: []string{"plugins:id:not-the-test-app1"}},
}
user.OrgRole = roletype.RoleNone
service.features = featuremgmt.WithFeatures(featuremgmt.FlagAccessControlOnCall)
err := service.addAppLinks(&treeRoot, reqCtx)
require.NoError(t, err)
appsNode := treeRoot.FindById(navtree.NavIDApps)
require.Len(t, appsNode.Children, 1)
require.Equal(t, "Test app1 name", appsNode.Children[0].Text)
require.Len(t, appsNode.Children[0].Children, 1)
require.Equal(t, "/a/test-app1/page2", appsNode.Children[0].Children[0].Url)
})
t.Run("Should add both includes when the user is a viewer with catalog read", func(t *testing.T) {
treeRoot := navtree.NavTreeRoot{}
user.Permissions = map[int64]map[string][]string{
1: {pluginaccesscontrol.ActionAppAccess: []string{"*"}, catalogReadAction: []string{}},
}
user.OrgRole = roletype.RoleViewer
service.features = featuremgmt.WithFeatures(featuremgmt.FlagAccessControlOnCall)
err := service.addAppLinks(&treeRoot, reqCtx)
require.NoError(t, err)
require.Len(t, treeRoot.Children, 0)
})
t.Run("Should only see the announcements as a none role user with app access", func(t *testing.T) {
treeRoot := navtree.NavTreeRoot{}
user.Permissions = map[int64]map[string][]string{
1: {pluginaccesscontrol.ActionAppAccess: []string{"plugins:id:test-app1"}},
}
user.OrgRole = roletype.RoleNone
service.features = featuremgmt.WithFeatures(featuremgmt.FlagAccessControlOnCall)
err := service.addAppLinks(&treeRoot, reqCtx)
require.NoError(t, err)
appsNode := treeRoot.FindById(navtree.NavIDApps)
require.Len(t, appsNode.Children, 1)
require.Equal(t, "Test app1 name", appsNode.Children[0].Text)
require.Equal(t, "/a/test-app1/catalog", appsNode.Children[0].Url)
require.Len(t, appsNode.Children[0].Children, 1)
require.Equal(t, "/a/test-app1/page2", appsNode.Children[0].Children[0].Url)
})
t.Run("Should add one include when the user is an editor without catalog read", func(t *testing.T) {
treeRoot := navtree.NavTreeRoot{}
user.Permissions = map[int64]map[string][]string{
1: {pluginaccesscontrol.ActionAppAccess: []string{"*"}},
}
user.OrgRole = roletype.RoleEditor
service.features = featuremgmt.WithFeatures(featuremgmt.FlagAccessControlOnCall)
err := service.addAppLinks(&treeRoot, reqCtx)
require.NoError(t, err)
appsNode := treeRoot.FindById(navtree.NavIDApps)
require.Len(t, appsNode.Children, 1)
require.Equal(t, "Test app1 name", appsNode.Children[0].Text)
require.Len(t, appsNode.Children[0].Children, 1)
require.Equal(t, "/a/test-app1/announcements", appsNode.Children[0].Children[0].Url)
})
t.Run("Should now see the catalog as a viewer with catalog read", func(t *testing.T) {
treeRoot := navtree.NavTreeRoot{}
user.Permissions = map[int64]map[string][]string{
1: {pluginaccesscontrol.ActionAppAccess: []string{"plugins:id:test-app1"}, catalogReadAction: []string{}},
}
user.OrgRole = roletype.RoleViewer
service.features = featuremgmt.WithFeatures(featuremgmt.FlagAccessControlOnCall)
err := service.addAppLinks(&treeRoot, reqCtx)
require.NoError(t, err)
appsNode := treeRoot.FindById(navtree.NavIDApps)
require.Len(t, appsNode.Children, 1)
require.Equal(t, "Test app1 name", appsNode.Children[0].Text)
require.Len(t, appsNode.Children[0].Children, 1)
require.Equal(t, "/a/test-app1/page2", appsNode.Children[0].Children[0].Url)
err := service.addAppLinks(&treeRoot, reqCtx)
require.NoError(t, err)
appsNode := treeRoot.FindById(navtree.NavIDApps)
require.Len(t, appsNode.Children, 1)
require.Equal(t, "Test app1 name", appsNode.Children[0].Text)
require.Equal(t, "/a/test-app1/home", appsNode.Children[0].Url)
require.Len(t, appsNode.Children[0].Children, 2)
require.Equal(t, "/a/test-app1/catalog", appsNode.Children[0].Children[0].Url)
require.Equal(t, "/a/test-app1/announcements", appsNode.Children[0].Children[1].Url)
})
t.Run("Should not see the catalog include as an editor without catalog read", func(t *testing.T) {
treeRoot := navtree.NavTreeRoot{}
user.Permissions = map[int64]map[string][]string{
1: {pluginaccesscontrol.ActionAppAccess: []string{"*"}},
}
user.OrgRole = roletype.RoleEditor
service.features = featuremgmt.WithFeatures(featuremgmt.FlagAccessControlOnCall)
err := service.addAppLinks(&treeRoot, reqCtx)
require.NoError(t, err)
appsNode := treeRoot.FindById(navtree.NavIDApps)
require.Len(t, appsNode.Children, 1)
require.Equal(t, "Test app1 name", appsNode.Children[0].Text)
require.Equal(t, "/a/test-app1/home", appsNode.Children[0].Url)
require.Len(t, appsNode.Children[0].Children, 1)
require.Equal(t, "/a/test-app1/announcements", appsNode.Children[0].Children[0].Url)
})
})
}
@@ -3,6 +3,7 @@ package pluginaccesscontrol
import (
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/setting"
@@ -75,3 +76,42 @@ func DeclareRBACRoles(service ac.Service, cfg *setting.Cfg, features featuremgmt
return service.DeclareFixedRoles(AppPluginsReader, PluginsWriter, PluginsMaintainer)
}
var datasourcesActions = map[string]bool{
datasources.ActionIDRead: true,
datasources.ActionQuery: true,
datasources.ActionRead: true,
datasources.ActionWrite: true,
datasources.ActionDelete: true,
datasources.ActionPermissionsRead: true,
datasources.ActionPermissionsWrite: true,
"datasources.caching:read": true,
"datasources.caching:write": true,
ac.ActionAlertingRuleExternalRead: true,
ac.ActionAlertingRuleExternalWrite: true,
ac.ActionAlertingInstancesExternalRead: true,
ac.ActionAlertingInstancesExternalWrite: true,
ac.ActionAlertingNotificationsExternalRead: true,
ac.ActionAlertingNotificationsExternalWrite: true,
}
// GetDataSourceRouteEvaluator returns an evaluator for the given data source UID and action.
func GetDataSourceRouteEvaluator(dsUID, action string) ac.Evaluator {
if datasourcesActions[action] {
return ac.EvalPermission(action, "datasources:uid:"+dsUID)
}
return ac.EvalPermission(action)
}
var pluginsActions = map[string]bool{
ActionWrite: true,
ActionAppAccess: true,
}
// GetPluginRouteEvaluator returns an evaluator for the given plugin ID and action.
func GetPluginRouteEvaluator(pluginID, action string) ac.Evaluator {
if pluginsActions[action] {
return ac.EvalPermission(action, "plugins:id:"+pluginID)
}
return ac.EvalPermission(action)
}
@@ -2,14 +2,14 @@
"name": "@grafana-plugins/grafana-azure-monitor-datasource",
"description": "Grafana data source for Azure Monitor",
"private": true,
"version": "11.1.1",
"version": "11.1.3",
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.1.1",
"@grafana/data": "11.1.3",
"@grafana/experimental": "1.7.11",
"@grafana/runtime": "11.1.1",
"@grafana/schema": "11.1.1",
"@grafana/ui": "11.1.1",
"@grafana/runtime": "11.1.3",
"@grafana/schema": "11.1.3",
"@grafana/ui": "11.1.3",
"@kusto/monaco-kusto": "^10.0.0",
"fast-deep-equal": "^3.1.3",
"i18next": "^23.0.0",
@@ -25,8 +25,8 @@
"tslib": "2.6.3"
},
"devDependencies": {
"@grafana/e2e-selectors": "11.1.1",
"@grafana/plugin-configs": "11.1.1",
"@grafana/e2e-selectors": "11.1.3",
"@grafana/plugin-configs": "11.1.3",
"@testing-library/dom": "10.0.0",
"@testing-library/react": "15.0.2",
"@testing-library/user-event": "14.5.2",
@@ -2,15 +2,15 @@
"name": "@grafana-plugins/stackdriver",
"description": "Grafana data source for Google Cloud Monitoring",
"private": true,
"version": "11.1.1",
"version": "11.1.3",
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.1.1",
"@grafana/data": "11.1.3",
"@grafana/experimental": "1.7.11",
"@grafana/google-sdk": "0.1.2",
"@grafana/runtime": "11.1.1",
"@grafana/schema": "11.1.1",
"@grafana/ui": "11.1.1",
"@grafana/runtime": "11.1.3",
"@grafana/schema": "11.1.3",
"@grafana/ui": "11.1.3",
"debounce-promise": "3.1.2",
"fast-deep-equal": "^3.1.3",
"i18next": "^23.0.0",
@@ -26,8 +26,8 @@
"tslib": "2.6.3"
},
"devDependencies": {
"@grafana/e2e-selectors": "11.1.1",
"@grafana/plugin-configs": "11.1.1",
"@grafana/e2e-selectors": "11.1.3",
"@grafana/plugin-configs": "11.1.3",
"@testing-library/dom": "10.0.0",
"@testing-library/react": "15.0.2",
"@testing-library/user-event": "14.5.2",
@@ -2,22 +2,22 @@
"name": "@grafana-plugins/grafana-postgresql-datasource",
"description": "PostgreSQL data source plugin",
"private": true,
"version": "11.1.1",
"version": "11.1.3",
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.1.1",
"@grafana/data": "11.1.3",
"@grafana/experimental": "1.7.11",
"@grafana/runtime": "11.1.1",
"@grafana/sql": "11.1.1",
"@grafana/ui": "11.1.1",
"@grafana/runtime": "11.1.3",
"@grafana/sql": "11.1.3",
"@grafana/ui": "11.1.3",
"lodash": "4.17.21",
"react": "18.2.0",
"rxjs": "7.8.1",
"tslib": "2.6.3"
},
"devDependencies": {
"@grafana/e2e-selectors": "11.1.1",
"@grafana/plugin-configs": "11.1.1",
"@grafana/e2e-selectors": "11.1.3",
"@grafana/plugin-configs": "11.1.3",
"@testing-library/react": "15.0.2",
"@testing-library/user-event": "14.5.2",
"@types/jest": "29.5.12",
@@ -2,13 +2,13 @@
"name": "@grafana-plugins/grafana-pyroscope-datasource",
"description": "Continuous profiling for analysis of CPU and memory usage, down to the line number and throughout time. Saving infrastructure cost, improving performance, and increasing reliability.",
"private": true,
"version": "11.1.1",
"version": "11.1.3",
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.1.1",
"@grafana/runtime": "11.1.1",
"@grafana/schema": "11.1.1",
"@grafana/ui": "11.1.1",
"@grafana/data": "11.1.3",
"@grafana/runtime": "11.1.3",
"@grafana/schema": "11.1.3",
"@grafana/ui": "11.1.3",
"fast-deep-equal": "^3.1.3",
"lodash": "4.17.21",
"monaco-editor": "0.34.1",
@@ -20,7 +20,7 @@
"tslib": "2.6.3"
},
"devDependencies": {
"@grafana/plugin-configs": "11.1.1",
"@grafana/plugin-configs": "11.1.3",
"@testing-library/dom": "10.0.0",
"@testing-library/jest-dom": "6.4.2",
"@testing-library/react": "15.0.2",
@@ -2,14 +2,14 @@
"name": "@grafana-plugins/grafana-testdata-datasource",
"description": "Generates test data in different forms",
"private": true,
"version": "11.1.1",
"version": "11.1.3",
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.1.1",
"@grafana/data": "11.1.3",
"@grafana/experimental": "1.7.11",
"@grafana/runtime": "11.1.1",
"@grafana/schema": "11.1.1",
"@grafana/ui": "11.1.1",
"@grafana/runtime": "11.1.3",
"@grafana/schema": "11.1.3",
"@grafana/ui": "11.1.3",
"d3-random": "^3.0.1",
"lodash": "4.17.21",
"micro-memoize": "^4.1.2",
@@ -22,8 +22,8 @@
"uuid": "9.0.1"
},
"devDependencies": {
"@grafana/e2e-selectors": "11.1.1",
"@grafana/plugin-configs": "11.1.1",
"@grafana/e2e-selectors": "11.1.3",
"@grafana/plugin-configs": "11.1.3",
"@testing-library/dom": "10.0.0",
"@testing-library/react": "15.0.2",
"@testing-library/user-event": "14.5.2",
@@ -2,7 +2,7 @@
"name": "@grafana-plugins/jaeger",
"description": "Jaeger plugin for Grafana",
"private": true,
"version": "11.1.1",
"version": "11.1.3",
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "workspace:*",
@@ -2,22 +2,22 @@
"name": "@grafana-plugins/mysql",
"description": "MySQL data source plugin",
"private": true,
"version": "11.1.1",
"version": "11.1.3",
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.1.1",
"@grafana/data": "11.1.3",
"@grafana/experimental": "1.7.11",
"@grafana/runtime": "11.1.1",
"@grafana/sql": "11.1.1",
"@grafana/ui": "11.1.1",
"@grafana/runtime": "11.1.3",
"@grafana/sql": "11.1.3",
"@grafana/ui": "11.1.3",
"lodash": "4.17.21",
"react": "18.2.0",
"rxjs": "7.8.1",
"tslib": "2.6.3"
},
"devDependencies": {
"@grafana/e2e-selectors": "11.1.1",
"@grafana/plugin-configs": "11.1.1",
"@grafana/e2e-selectors": "11.1.3",
"@grafana/plugin-configs": "11.1.3",
"@testing-library/react": "15.0.2",
"@testing-library/user-event": "14.5.2",
"@types/jest": "29.5.12",
@@ -2,13 +2,13 @@
"name": "@grafana-plugins/parca",
"description": "Continuous profiling for analysis of CPU and memory usage, down to the line number and throughout time. Saving infrastructure cost, improving performance, and increasing reliability.",
"private": true,
"version": "11.1.1",
"version": "11.1.3",
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.1.1",
"@grafana/runtime": "11.1.1",
"@grafana/schema": "11.1.1",
"@grafana/ui": "11.1.1",
"@grafana/data": "11.1.3",
"@grafana/runtime": "11.1.3",
"@grafana/schema": "11.1.3",
"@grafana/ui": "11.1.3",
"lodash": "4.17.21",
"monaco-editor": "0.34.1",
"react": "18.2.0",
@@ -18,7 +18,7 @@
"tslib": "2.6.3"
},
"devDependencies": {
"@grafana/plugin-configs": "11.1.1",
"@grafana/plugin-configs": "11.1.3",
"@testing-library/dom": "10.0.0",
"@testing-library/react": "15.0.2",
"@testing-library/user-event": "14.5.2",
@@ -2,7 +2,7 @@
"name": "@grafana-plugins/tempo",
"description": "Grafana plugin for the Tempo data source.",
"private": true,
"version": "11.1.1",
"version": "11.1.3",
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "workspace:*",
@@ -39,7 +39,7 @@
"uuid": "9.0.1"
},
"devDependencies": {
"@grafana/plugin-configs": "11.1.1",
"@grafana/plugin-configs": "11.1.3",
"@testing-library/dom": "10.0.0",
"@testing-library/jest-dom": "6.4.2",
"@testing-library/react": "15.0.2",
@@ -2,7 +2,7 @@
"name": "@grafana-plugins/zipkin",
"description": "Zipkin plugin for Grafana",
"private": true,
"version": "11.1.1",
"version": "11.1.3",
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "workspace:*",
+72 -72
View File
@@ -2571,13 +2571,13 @@ __metadata:
resolution: "@grafana-plugins/grafana-azure-monitor-datasource@workspace:public/app/plugins/datasource/azuremonitor"
dependencies:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.1.1"
"@grafana/e2e-selectors": "npm:11.1.1"
"@grafana/data": "npm:11.1.3"
"@grafana/e2e-selectors": "npm:11.1.3"
"@grafana/experimental": "npm:1.7.11"
"@grafana/plugin-configs": "npm:11.1.1"
"@grafana/runtime": "npm:11.1.1"
"@grafana/schema": "npm:11.1.1"
"@grafana/ui": "npm:11.1.1"
"@grafana/plugin-configs": "npm:11.1.3"
"@grafana/runtime": "npm:11.1.3"
"@grafana/schema": "npm:11.1.3"
"@grafana/ui": "npm:11.1.3"
"@kusto/monaco-kusto": "npm:^10.0.0"
"@testing-library/dom": "npm:10.0.0"
"@testing-library/react": "npm:15.0.2"
@@ -2615,13 +2615,13 @@ __metadata:
resolution: "@grafana-plugins/grafana-postgresql-datasource@workspace:public/app/plugins/datasource/grafana-postgresql-datasource"
dependencies:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.1.1"
"@grafana/e2e-selectors": "npm:11.1.1"
"@grafana/data": "npm:11.1.3"
"@grafana/e2e-selectors": "npm:11.1.3"
"@grafana/experimental": "npm:1.7.11"
"@grafana/plugin-configs": "npm:11.1.1"
"@grafana/runtime": "npm:11.1.1"
"@grafana/sql": "npm:11.1.1"
"@grafana/ui": "npm:11.1.1"
"@grafana/plugin-configs": "npm:11.1.3"
"@grafana/runtime": "npm:11.1.3"
"@grafana/sql": "npm:11.1.3"
"@grafana/ui": "npm:11.1.3"
"@testing-library/react": "npm:15.0.2"
"@testing-library/user-event": "npm:14.5.2"
"@types/jest": "npm:29.5.12"
@@ -2646,11 +2646,11 @@ __metadata:
resolution: "@grafana-plugins/grafana-pyroscope-datasource@workspace:public/app/plugins/datasource/grafana-pyroscope-datasource"
dependencies:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.1.1"
"@grafana/plugin-configs": "npm:11.1.1"
"@grafana/runtime": "npm:11.1.1"
"@grafana/schema": "npm:11.1.1"
"@grafana/ui": "npm:11.1.1"
"@grafana/data": "npm:11.1.3"
"@grafana/plugin-configs": "npm:11.1.3"
"@grafana/runtime": "npm:11.1.3"
"@grafana/schema": "npm:11.1.3"
"@grafana/ui": "npm:11.1.3"
"@testing-library/dom": "npm:10.0.0"
"@testing-library/jest-dom": "npm:6.4.2"
"@testing-library/react": "npm:15.0.2"
@@ -2687,13 +2687,13 @@ __metadata:
resolution: "@grafana-plugins/grafana-testdata-datasource@workspace:public/app/plugins/datasource/grafana-testdata-datasource"
dependencies:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.1.1"
"@grafana/e2e-selectors": "npm:11.1.1"
"@grafana/data": "npm:11.1.3"
"@grafana/e2e-selectors": "npm:11.1.3"
"@grafana/experimental": "npm:1.7.11"
"@grafana/plugin-configs": "npm:11.1.1"
"@grafana/runtime": "npm:11.1.1"
"@grafana/schema": "npm:11.1.1"
"@grafana/ui": "npm:11.1.1"
"@grafana/plugin-configs": "npm:11.1.3"
"@grafana/runtime": "npm:11.1.3"
"@grafana/schema": "npm:11.1.3"
"@grafana/ui": "npm:11.1.3"
"@testing-library/dom": "npm:10.0.0"
"@testing-library/react": "npm:15.0.2"
"@testing-library/user-event": "npm:14.5.2"
@@ -2770,13 +2770,13 @@ __metadata:
resolution: "@grafana-plugins/mysql@workspace:public/app/plugins/datasource/mysql"
dependencies:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.1.1"
"@grafana/e2e-selectors": "npm:11.1.1"
"@grafana/data": "npm:11.1.3"
"@grafana/e2e-selectors": "npm:11.1.3"
"@grafana/experimental": "npm:1.7.11"
"@grafana/plugin-configs": "npm:11.1.1"
"@grafana/runtime": "npm:11.1.1"
"@grafana/sql": "npm:11.1.1"
"@grafana/ui": "npm:11.1.1"
"@grafana/plugin-configs": "npm:11.1.3"
"@grafana/runtime": "npm:11.1.3"
"@grafana/sql": "npm:11.1.3"
"@grafana/ui": "npm:11.1.3"
"@testing-library/react": "npm:15.0.2"
"@testing-library/user-event": "npm:14.5.2"
"@types/jest": "npm:29.5.12"
@@ -2801,11 +2801,11 @@ __metadata:
resolution: "@grafana-plugins/parca@workspace:public/app/plugins/datasource/parca"
dependencies:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.1.1"
"@grafana/plugin-configs": "npm:11.1.1"
"@grafana/runtime": "npm:11.1.1"
"@grafana/schema": "npm:11.1.1"
"@grafana/ui": "npm:11.1.1"
"@grafana/data": "npm:11.1.3"
"@grafana/plugin-configs": "npm:11.1.3"
"@grafana/runtime": "npm:11.1.3"
"@grafana/schema": "npm:11.1.3"
"@grafana/ui": "npm:11.1.3"
"@testing-library/dom": "npm:10.0.0"
"@testing-library/react": "npm:15.0.2"
"@testing-library/user-event": "npm:14.5.2"
@@ -2833,14 +2833,14 @@ __metadata:
resolution: "@grafana-plugins/stackdriver@workspace:public/app/plugins/datasource/cloud-monitoring"
dependencies:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.1.1"
"@grafana/e2e-selectors": "npm:11.1.1"
"@grafana/data": "npm:11.1.3"
"@grafana/e2e-selectors": "npm:11.1.3"
"@grafana/experimental": "npm:1.7.11"
"@grafana/google-sdk": "npm:0.1.2"
"@grafana/plugin-configs": "npm:11.1.1"
"@grafana/runtime": "npm:11.1.1"
"@grafana/schema": "npm:11.1.1"
"@grafana/ui": "npm:11.1.1"
"@grafana/plugin-configs": "npm:11.1.3"
"@grafana/runtime": "npm:11.1.3"
"@grafana/schema": "npm:11.1.3"
"@grafana/ui": "npm:11.1.3"
"@testing-library/dom": "npm:10.0.0"
"@testing-library/react": "npm:15.0.2"
"@testing-library/user-event": "npm:14.5.2"
@@ -2888,7 +2888,7 @@ __metadata:
"@grafana/lezer-traceql": "npm:0.0.17"
"@grafana/monaco-logql": "npm:^0.0.7"
"@grafana/o11y-ds-frontend": "workspace:*"
"@grafana/plugin-configs": "npm:11.1.1"
"@grafana/plugin-configs": "npm:11.1.3"
"@grafana/runtime": "workspace:*"
"@grafana/schema": "workspace:*"
"@grafana/ui": "workspace:*"
@@ -2998,12 +2998,12 @@ __metadata:
languageName: node
linkType: hard
"@grafana/data@npm:11.1.1, @grafana/data@workspace:*, @grafana/data@workspace:packages/grafana-data":
"@grafana/data@npm:11.1.3, @grafana/data@workspace:*, @grafana/data@workspace:packages/grafana-data":
version: 0.0.0-use.local
resolution: "@grafana/data@workspace:packages/grafana-data"
dependencies:
"@braintree/sanitize-url": "npm:7.0.1"
"@grafana/schema": "npm:11.1.1"
"@grafana/schema": "npm:11.1.3"
"@grafana/tsconfig": "npm:^1.3.0-rc1"
"@rollup/plugin-node-resolve": "npm:15.2.3"
"@types/d3-interpolate": "npm:^3.0.0"
@@ -3051,7 +3051,7 @@ __metadata:
languageName: unknown
linkType: soft
"@grafana/e2e-selectors@npm:11.1.1, @grafana/e2e-selectors@npm:^11.0.0, @grafana/e2e-selectors@workspace:*, @grafana/e2e-selectors@workspace:packages/grafana-e2e-selectors":
"@grafana/e2e-selectors@npm:11.1.3, @grafana/e2e-selectors@npm:^11.0.0, @grafana/e2e-selectors@workspace:*, @grafana/e2e-selectors@workspace:packages/grafana-e2e-selectors":
version: 0.0.0-use.local
resolution: "@grafana/e2e-selectors@workspace:packages/grafana-e2e-selectors"
dependencies:
@@ -3176,9 +3176,9 @@ __metadata:
"@babel/preset-env": "npm:7.24.7"
"@babel/preset-react": "npm:7.24.7"
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.1.1"
"@grafana/data": "npm:11.1.3"
"@grafana/tsconfig": "npm:^1.3.0-rc1"
"@grafana/ui": "npm:11.1.1"
"@grafana/ui": "npm:11.1.3"
"@leeoniya/ufuzzy": "npm:1.0.14"
"@rollup/plugin-node-resolve": "npm:15.2.3"
"@testing-library/dom": "npm:10.0.0"
@@ -3260,13 +3260,13 @@ __metadata:
resolution: "@grafana/o11y-ds-frontend@workspace:packages/grafana-o11y-ds-frontend"
dependencies:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.1.1"
"@grafana/e2e-selectors": "npm:11.1.1"
"@grafana/data": "npm:11.1.3"
"@grafana/e2e-selectors": "npm:11.1.3"
"@grafana/experimental": "npm:1.7.11"
"@grafana/runtime": "npm:11.1.1"
"@grafana/schema": "npm:11.1.1"
"@grafana/runtime": "npm:11.1.3"
"@grafana/schema": "npm:11.1.3"
"@grafana/tsconfig": "npm:^1.3.0-rc1"
"@grafana/ui": "npm:11.1.1"
"@grafana/ui": "npm:11.1.3"
"@testing-library/dom": "npm:10.0.0"
"@testing-library/jest-dom": "npm:^6.1.2"
"@testing-library/react": "npm:15.0.2"
@@ -3291,7 +3291,7 @@ __metadata:
languageName: unknown
linkType: soft
"@grafana/plugin-configs@npm:11.1.1, @grafana/plugin-configs@workspace:*, @grafana/plugin-configs@workspace:packages/grafana-plugin-configs":
"@grafana/plugin-configs@npm:11.1.3, @grafana/plugin-configs@workspace:*, @grafana/plugin-configs@workspace:packages/grafana-plugin-configs":
version: 0.0.0-use.local
resolution: "@grafana/plugin-configs@workspace:packages/grafana-plugin-configs"
dependencies:
@@ -3331,14 +3331,14 @@ __metadata:
"@emotion/css": "npm:11.11.2"
"@emotion/eslint-plugin": "npm:11.11.0"
"@floating-ui/react": "npm:0.26.16"
"@grafana/data": "npm:11.1.1"
"@grafana/e2e-selectors": "npm:11.1.1"
"@grafana/data": "npm:11.1.3"
"@grafana/e2e-selectors": "npm:11.1.3"
"@grafana/experimental": "npm:1.7.11"
"@grafana/faro-web-sdk": "npm:1.7.3"
"@grafana/runtime": "npm:11.1.1"
"@grafana/schema": "npm:11.1.1"
"@grafana/runtime": "npm:11.1.3"
"@grafana/schema": "npm:11.1.3"
"@grafana/tsconfig": "npm:^1.3.0-rc1"
"@grafana/ui": "npm:11.1.1"
"@grafana/ui": "npm:11.1.3"
"@leeoniya/ufuzzy": "npm:1.0.14"
"@lezer/common": "npm:1.2.1"
"@lezer/highlight": "npm:1.2.0"
@@ -3436,16 +3436,16 @@ __metadata:
languageName: unknown
linkType: soft
"@grafana/runtime@npm:11.1.1, @grafana/runtime@workspace:*, @grafana/runtime@workspace:packages/grafana-runtime":
"@grafana/runtime@npm:11.1.3, @grafana/runtime@workspace:*, @grafana/runtime@workspace:packages/grafana-runtime":
version: 0.0.0-use.local
resolution: "@grafana/runtime@workspace:packages/grafana-runtime"
dependencies:
"@grafana/data": "npm:11.1.1"
"@grafana/e2e-selectors": "npm:11.1.1"
"@grafana/data": "npm:11.1.3"
"@grafana/e2e-selectors": "npm:11.1.3"
"@grafana/faro-web-sdk": "npm:^1.3.6"
"@grafana/schema": "npm:11.1.1"
"@grafana/schema": "npm:11.1.3"
"@grafana/tsconfig": "npm:^1.3.0-rc1"
"@grafana/ui": "npm:11.1.1"
"@grafana/ui": "npm:11.1.3"
"@rollup/plugin-node-resolve": "npm:15.2.3"
"@rollup/plugin-terser": "npm:0.4.4"
"@testing-library/dom": "npm:10.0.0"
@@ -3534,7 +3534,7 @@ __metadata:
languageName: node
linkType: hard
"@grafana/schema@npm:11.1.1, @grafana/schema@workspace:*, @grafana/schema@workspace:packages/grafana-schema":
"@grafana/schema@npm:11.1.3, @grafana/schema@workspace:*, @grafana/schema@workspace:packages/grafana-schema":
version: 0.0.0-use.local
resolution: "@grafana/schema@workspace:packages/grafana-schema"
dependencies:
@@ -3552,17 +3552,17 @@ __metadata:
languageName: unknown
linkType: soft
"@grafana/sql@npm:11.1.1, @grafana/sql@workspace:*, @grafana/sql@workspace:packages/grafana-sql":
"@grafana/sql@npm:11.1.3, @grafana/sql@workspace:*, @grafana/sql@workspace:packages/grafana-sql":
version: 0.0.0-use.local
resolution: "@grafana/sql@workspace:packages/grafana-sql"
dependencies:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.1.1"
"@grafana/e2e-selectors": "npm:11.1.1"
"@grafana/data": "npm:11.1.3"
"@grafana/e2e-selectors": "npm:11.1.3"
"@grafana/experimental": "npm:1.7.11"
"@grafana/runtime": "npm:11.1.1"
"@grafana/runtime": "npm:11.1.3"
"@grafana/tsconfig": "npm:^1.3.0-rc1"
"@grafana/ui": "npm:11.1.1"
"@grafana/ui": "npm:11.1.3"
"@react-awesome-query-builder/ui": "npm:6.5.2"
"@testing-library/dom": "npm:10.0.0"
"@testing-library/jest-dom": "npm:^6.1.2"
@@ -3605,7 +3605,7 @@ __metadata:
languageName: node
linkType: hard
"@grafana/ui@npm:11.1.1, @grafana/ui@workspace:*, @grafana/ui@workspace:packages/grafana-ui":
"@grafana/ui@npm:11.1.3, @grafana/ui@workspace:*, @grafana/ui@workspace:packages/grafana-ui":
version: 0.0.0-use.local
resolution: "@grafana/ui@workspace:packages/grafana-ui"
dependencies:
@@ -3614,10 +3614,10 @@ __metadata:
"@emotion/react": "npm:11.11.4"
"@faker-js/faker": "npm:^8.4.1"
"@floating-ui/react": "npm:0.26.16"
"@grafana/data": "npm:11.1.1"
"@grafana/e2e-selectors": "npm:11.1.1"
"@grafana/data": "npm:11.1.3"
"@grafana/e2e-selectors": "npm:11.1.3"
"@grafana/faro-web-sdk": "npm:^1.3.6"
"@grafana/schema": "npm:11.1.1"
"@grafana/schema": "npm:11.1.3"
"@grafana/tsconfig": "npm:^1.3.0-rc1"
"@leeoniya/ufuzzy": "npm:1.0.14"
"@monaco-editor/react": "npm:4.6.0"