diff --git a/packages/grafana-data/src/types/config.ts b/packages/grafana-data/src/types/config.ts index 04ebffbb4cf..a9d55ee2e07 100644 --- a/packages/grafana-data/src/types/config.ts +++ b/packages/grafana-data/src/types/config.ts @@ -181,6 +181,7 @@ export interface GrafanaConfig { autoAssignOrg: boolean; verifyEmailEnabled: boolean; oauth: OAuthSettings; + /** @deprecated always set to true. */ rbacEnabled: boolean; disableUserSignUp: boolean; loginHint: string; diff --git a/public/app/core/services/context_srv.ts b/public/app/core/services/context_srv.ts index b1a63b0d381..f76ca6b5c00 100644 --- a/public/app/core/services/context_srv.ts +++ b/public/app/core/services/context_srv.ts @@ -97,11 +97,9 @@ export class ContextSrv { async fetchUserPermissions() { try { - if (this.accessControlEnabled()) { - this.user.permissions = await getBackendSrv().get('/api/access-control/user/actions', { - reloadcache: true, - }); - } + this.user.permissions = await getBackendSrv().get('/api/access-control/user/actions', { + reloadcache: true, + }); } catch (e) { console.error(e); } @@ -125,31 +123,17 @@ export class ContextSrv { } } - accessControlEnabled(): boolean { - return config.rbacEnabled; - } - licensedAccessControlEnabled(): boolean { - return featureEnabled('accesscontrol') && config.rbacEnabled; + return featureEnabled('accesscontrol'); } // Checks whether user has required permission hasPermissionInMetadata(action: AccessControlAction | string, object: WithAccessControlMetadata): boolean { - // Fallback if access control disabled - if (!this.accessControlEnabled()) { - return true; - } - return !!object.accessControl?.[action]; } // Checks whether user has required permission hasPermission(action: AccessControlAction | string): boolean { - // Fallback if access control disabled - if (!this.accessControlEnabled()) { - return true; - } - return !!this.user.permissions?.[action]; } @@ -180,23 +164,14 @@ export class ContextSrv { } hasAccessToExplore() { - if (this.accessControlEnabled()) { - return this.hasPermission(AccessControlAction.DataSourcesExplore) && config.exploreEnabled; - } - return (this.isEditor || config.viewersCanEdit) && config.exploreEnabled; + return this.hasPermission(AccessControlAction.DataSourcesExplore) && config.exploreEnabled; } hasAccess(action: string, fallBack: boolean): boolean { - if (!this.accessControlEnabled()) { - return fallBack; - } return this.hasPermission(action); } hasAccessInMetadata(action: string, object: WithAccessControlMetadata, fallBack: boolean): boolean { - if (!this.accessControlEnabled()) { - return fallBack; - } return this.hasPermissionInMetadata(action, object); } diff --git a/public/app/core/utils/accessControl.ts b/public/app/core/utils/accessControl.ts index e31b4a75717..47bc51f9ccc 100644 --- a/public/app/core/utils/accessControl.ts +++ b/public/app/core/utils/accessControl.ts @@ -1,9 +1,4 @@ -import config from '../../core/config'; - // accessControlQueryParam adds an additional accesscontrol=true param to params when accesscontrol is enabled export function accessControlQueryParam(params = {}) { - if (!config.rbacEnabled) { - return params; - } return { ...params, accesscontrol: true }; } diff --git a/public/app/features/admin/UserOrgs.tsx b/public/app/features/admin/UserOrgs.tsx index 4e2865e764d..31379631d01 100644 --- a/public/app/features/admin/UserOrgs.tsx +++ b/public/app/features/admin/UserOrgs.tsx @@ -377,21 +377,17 @@ export class AddToOrgModal extends PureComponent - {contextSrv.accessControlEnabled() ? ( - - ) : ( - - )} + diff --git a/public/app/features/alerting/unified/MuteTimings.test.tsx b/public/app/features/alerting/unified/MuteTimings.test.tsx index 53d91ce4dc3..e87db13b33c 100644 --- a/public/app/features/alerting/unified/MuteTimings.test.tsx +++ b/public/app/features/alerting/unified/MuteTimings.test.tsx @@ -6,10 +6,11 @@ import { byRole, byTestId, byText } from 'testing-library-selector'; import { locationService, setDataSourceSrv } from '@grafana/runtime'; import { AlertManagerCortexConfig, MuteTimeInterval } from 'app/plugins/datasource/alertmanager/types'; +import { AccessControlAction } from 'app/types'; import MuteTimings from './MuteTimings'; import { fetchAlertManagerConfig, updateAlertManagerConfig } from './api/alertmanager'; -import { disableRBAC, mockDataSource, MockDataSourceSrv } from './mocks'; +import { grantUserPermissions, mockDataSource, MockDataSourceSrv } from './mocks'; import { DataSourceType } from './utils/datasource'; jest.mock('./api/alertmanager'); @@ -105,10 +106,11 @@ describe('Mute timings', () => { beforeEach(() => { setDataSourceSrv(new MockDataSourceSrv(dataSources)); resetMocks(); + // FIXME: scope down + grantUserPermissions(Object.values(AccessControlAction)); }); it('creates a new mute timing', async () => { - disableRBAC(); renderMuteTimings(); await waitFor(() => expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalled()); diff --git a/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx b/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx index 8d33c54e6a8..add93de4b69 100644 --- a/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx +++ b/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx @@ -13,13 +13,14 @@ import { toKeyedAction } from 'app/features/variables/state/keyedVariablesReduce import { PrometheusDatasource } from 'app/plugins/datasource/prometheus/datasource'; import { PromOptions } from 'app/plugins/datasource/prometheus/types'; import { configureStore } from 'app/store/configureStore'; +import { AccessControlAction } from 'app/types'; import { AlertQuery } from 'app/types/unified-alerting-dto'; import { PanelAlertTabContent } from './PanelAlertTabContent'; import { fetchRules } from './api/prometheus'; import { fetchRulerRules } from './api/ruler'; import { - disableRBAC, + grantUserPermissions, mockDataSource, MockDataSourceSrv, mockPromAlertingRule, @@ -180,6 +181,14 @@ const ui = { describe('PanelAlertTabContent', () => { beforeEach(() => { jest.resetAllMocks(); + grantUserPermissions([ + AccessControlAction.AlertingRuleRead, + AccessControlAction.AlertingRuleUpdate, + AccessControlAction.AlertingRuleDelete, + AccessControlAction.AlertingRuleCreate, + AccessControlAction.AlertingRuleExternalRead, + AccessControlAction.AlertingRuleExternalWrite, + ]); mocks.getAllDataSources.mockReturnValue(Object.values(dataSources)); const dsService = new MockDataSourceSrv(dataSources); dsService.datasources[dataSources.prometheus.uid] = new PrometheusDatasource( @@ -187,7 +196,6 @@ describe('PanelAlertTabContent', () => { ) as DataSourceApi; dsService.datasources[dataSources.default.uid] = new PrometheusDatasource(dataSources.default) as DataSourceApi; setDataSourceSrv(dsService); - disableRBAC(); }); it('Will take into account panel maxDataPoints', async () => { diff --git a/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx b/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx index 61e2e3d576e..8c335a5a007 100644 --- a/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx +++ b/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx @@ -6,6 +6,7 @@ import { byRole, byText } from 'testing-library-selector'; import { setDataSourceSrv } from '@grafana/runtime'; import { contextSrv } from 'app/core/services/context_srv'; +import { AccessControlAction } from 'app/types'; import { PromApiFeatures, PromApplication } from 'app/types/unified-alerting-dto'; import { searchFolders } from '../../manage-dashboards/state/actions'; @@ -13,7 +14,7 @@ import { searchFolders } from '../../manage-dashboards/state/actions'; import { discoverFeatures } from './api/buildInfo'; import { fetchRulerRules, fetchRulerRulesGroup, fetchRulerRulesNamespace, setRulerRuleGroup } from './api/ruler'; import { ExpressionEditorProps } from './components/rule-editor/ExpressionEditor'; -import { disableRBAC, mockDataSource, MockDataSourceSrv } from './mocks'; +import { grantUserPermissions, mockDataSource, MockDataSourceSrv } from './mocks'; import { fetchRulerRulesIfNotFetchedYet } from './state/actions'; import * as config from './utils/config'; import { DataSourceType } from './utils/datasource'; @@ -139,10 +140,10 @@ describe('RuleEditor cloud: checking editable data sources', () => { jest.clearAllMocks(); contextSrv.isEditor = true; contextSrv.hasEditPermissionInFolders = true; + // grant all permissions in AccessControlActionEnum + grantUserPermissions(Object.values(AccessControlAction)); }); - disableRBAC(); - it('for cloud alerts, should only allow to select editable rules sources', async () => { mocks.api.discoverFeatures.mockImplementation(async (dataSourceName) => { if (dataSourceName === 'loki with ruler' || dataSourceName === 'cortex with ruler') { diff --git a/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx b/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx index 4925613526d..e89c9c033c1 100644 --- a/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx +++ b/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx @@ -6,13 +6,14 @@ import { clickSelectOption } from 'test/helpers/selectOptionInTest'; import { byRole } from 'testing-library-selector'; import { contextSrv } from 'app/core/services/context_srv'; +import { AccessControlAction } from 'app/types'; import { searchFolders } from '../../manage-dashboards/state/actions'; import { fetchRulerRules, fetchRulerRulesGroup, fetchRulerRulesNamespace, setRulerRuleGroup } from './api/ruler'; import { ExpressionEditorProps } from './components/rule-editor/ExpressionEditor'; import { mockApi, mockFeatureDiscoveryApi, setupMswServer } from './mockApi'; -import { disableRBAC, mockDataSource } from './mocks'; +import { grantUserPermissions, mockDataSource } from './mocks'; import { defaultAlertmanagerChoiceResponse, emptyExternalAlertmanagersResponse, @@ -82,10 +83,19 @@ describe('RuleEditor cloud', () => { jest.clearAllMocks(); contextSrv.isEditor = true; contextSrv.hasEditPermissionInFolders = true; + grantUserPermissions([ + AccessControlAction.AlertingRuleRead, + AccessControlAction.AlertingRuleUpdate, + AccessControlAction.AlertingRuleDelete, + AccessControlAction.AlertingRuleCreate, + AccessControlAction.DataSourcesRead, + AccessControlAction.DataSourcesWrite, + AccessControlAction.DataSourcesCreate, + AccessControlAction.AlertingRuleExternalRead, + AccessControlAction.AlertingRuleExternalWrite, + ]); }); - disableRBAC(); - it('can create a new cloud alert', async () => { mocks.api.setRulerRuleGroup.mockResolvedValue(); mocks.api.fetchRulerRulesNamespace.mockResolvedValue([]); diff --git a/public/app/features/alerting/unified/RuleEditorExisting.test.tsx b/public/app/features/alerting/unified/RuleEditorExisting.test.tsx index fa85b62d952..a3ecbbfcb6f 100644 --- a/public/app/features/alerting/unified/RuleEditorExisting.test.tsx +++ b/public/app/features/alerting/unified/RuleEditorExisting.test.tsx @@ -18,7 +18,7 @@ import RuleEditor from './RuleEditor'; import { discoverFeatures } from './api/buildInfo'; import { fetchRulerRules, fetchRulerRulesGroup, fetchRulerRulesNamespace, setRulerRuleGroup } from './api/ruler'; import { ExpressionEditorProps } from './components/rule-editor/ExpressionEditor'; -import { disableRBAC, mockDataSource, MockDataSourceSrv, mockFolder } from './mocks'; +import { grantUserPermissions, mockDataSource, MockDataSourceSrv, mockFolder } from './mocks'; import { fetchRulerRulesIfNotFetchedYet } from './state/actions'; import * as config from './utils/config'; import { GRAFANA_RULES_SOURCE_NAME } from './utils/datasource'; @@ -79,9 +79,21 @@ describe('RuleEditor grafana managed rules', () => { jest.clearAllMocks(); contextSrv.isEditor = true; contextSrv.hasEditPermissionInFolders = true; - }); - disableRBAC(); + grantUserPermissions([ + AccessControlAction.AlertingRuleRead, + AccessControlAction.AlertingRuleUpdate, + AccessControlAction.AlertingRuleDelete, + AccessControlAction.AlertingRuleCreate, + AccessControlAction.DataSourcesRead, + AccessControlAction.DataSourcesWrite, + AccessControlAction.DataSourcesCreate, + AccessControlAction.FoldersWrite, + AccessControlAction.FoldersRead, + AccessControlAction.AlertingRuleExternalRead, + AccessControlAction.AlertingRuleExternalWrite, + ]); + }); it('can edit grafana managed rule', async () => { const uid = 'FOOBAR123'; diff --git a/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx b/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx index f14e44b7bbd..cc15a0c61d1 100644 --- a/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx +++ b/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx @@ -8,6 +8,7 @@ import { byRole } from 'testing-library-selector'; import { setDataSourceSrv } from '@grafana/runtime'; import { contextSrv } from 'app/core/services/context_srv'; import { DashboardSearchHit } from 'app/features/search/types'; +import { AccessControlAction } from 'app/types'; import { GrafanaAlertStateDecision, PromApplication } from 'app/types/unified-alerting-dto'; import { searchFolders } from '../../../../app/features/manage-dashboards/state/actions'; @@ -15,7 +16,7 @@ import { searchFolders } from '../../../../app/features/manage-dashboards/state/ import { discoverFeatures } from './api/buildInfo'; import { fetchRulerRules, fetchRulerRulesGroup, fetchRulerRulesNamespace, setRulerRuleGroup } from './api/ruler'; import { ExpressionEditorProps } from './components/rule-editor/ExpressionEditor'; -import { disableRBAC, mockDataSource, MockDataSourceSrv } from './mocks'; +import { grantUserPermissions, mockDataSource, MockDataSourceSrv } from './mocks'; import { fetchRulerRulesIfNotFetchedYet } from './state/actions'; import * as config from './utils/config'; import { GRAFANA_RULES_SOURCE_NAME } from './utils/datasource'; @@ -66,10 +67,21 @@ describe('RuleEditor grafana managed rules', () => { jest.clearAllMocks(); contextSrv.isEditor = true; contextSrv.hasEditPermissionInFolders = true; + grantUserPermissions([ + AccessControlAction.AlertingRuleRead, + AccessControlAction.AlertingRuleUpdate, + AccessControlAction.AlertingRuleDelete, + AccessControlAction.AlertingRuleCreate, + AccessControlAction.DataSourcesRead, + AccessControlAction.DataSourcesWrite, + AccessControlAction.DataSourcesCreate, + AccessControlAction.FoldersWrite, + AccessControlAction.FoldersRead, + AccessControlAction.AlertingRuleExternalRead, + AccessControlAction.AlertingRuleExternalWrite, + ]); }); - disableRBAC(); - it('can create new grafana managed alert', async () => { const dataSources = { default: mockDataSource( diff --git a/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx b/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx index 8e189c291a5..681a84611b1 100644 --- a/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx +++ b/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx @@ -7,6 +7,7 @@ import { byRole, byText } from 'testing-library-selector'; import { setDataSourceSrv } from '@grafana/runtime'; import { contextSrv } from 'app/core/services/context_srv'; +import { AccessControlAction } from 'app/types'; import { PromApplication } from 'app/types/unified-alerting-dto'; import { searchFolders } from '../../manage-dashboards/state/actions'; @@ -14,7 +15,7 @@ import { searchFolders } from '../../manage-dashboards/state/actions'; import { discoverFeatures } from './api/buildInfo'; import { fetchRulerRules, fetchRulerRulesGroup, fetchRulerRulesNamespace, setRulerRuleGroup } from './api/ruler'; import { RecordingRuleEditorProps } from './components/rule-editor/RecordingRuleEditor'; -import { disableRBAC, mockDataSource, MockDataSourceSrv } from './mocks'; +import { grantUserPermissions, mockDataSource, MockDataSourceSrv } from './mocks'; import { fetchRulerRulesIfNotFetchedYet } from './state/actions'; import * as config from './utils/config'; @@ -96,9 +97,21 @@ describe('RuleEditor recording rules', () => { jest.clearAllMocks(); contextSrv.isEditor = true; contextSrv.hasEditPermissionInFolders = true; + grantUserPermissions([ + AccessControlAction.AlertingRuleRead, + AccessControlAction.AlertingRuleUpdate, + AccessControlAction.AlertingRuleDelete, + AccessControlAction.AlertingRuleCreate, + AccessControlAction.DataSourcesRead, + AccessControlAction.DataSourcesWrite, + AccessControlAction.DataSourcesCreate, + AccessControlAction.FoldersWrite, + AccessControlAction.FoldersRead, + AccessControlAction.AlertingRuleExternalRead, + AccessControlAction.AlertingRuleExternalWrite, + ]); }); - disableRBAC(); it('can create a new cloud recording rule', async () => { setDataSourceSrv(new MockDataSourceSrv(dataSources)); mocks.getAllDataSources.mockReturnValue(Object.values(dataSources)); diff --git a/public/app/features/alerting/unified/RuleList.test.tsx b/public/app/features/alerting/unified/RuleList.test.tsx index 54a5f82af68..07de53cb27a 100644 --- a/public/app/features/alerting/unified/RuleList.test.tsx +++ b/public/app/features/alerting/unified/RuleList.test.tsx @@ -18,7 +18,6 @@ import { discoverFeatures } from './api/buildInfo'; import { fetchRules } from './api/prometheus'; import { deleteNamespace, deleteRulerRulesGroup, fetchRulerRules, setRulerRuleGroup } from './api/ruler'; import { - enableRBAC, grantUserPermissions, mockDataSource, MockDataSourceSrv, @@ -686,8 +685,6 @@ describe('RuleList', () => { describe('RBAC Enabled', () => { describe('Export button', () => { it('Export button should be visible when the user has alert provisioning read permissions', async () => { - enableRBAC(); - grantUserPermissions([AccessControlAction.AlertingProvisioningRead]); mocks.getAllDataSourcesMock.mockReturnValue([]); @@ -701,8 +698,6 @@ describe('RuleList', () => { expect(ui.exportButton.get()).toBeInTheDocument(); }); it('Export button should be visible when the user has alert provisioning read secrets permissions', async () => { - enableRBAC(); - grantUserPermissions([AccessControlAction.AlertingProvisioningReadSecrets]); mocks.getAllDataSourcesMock.mockReturnValue([]); @@ -716,8 +711,6 @@ describe('RuleList', () => { expect(ui.exportButton.get()).toBeInTheDocument(); }); it('Export button should not be visible when the user has no alert provisioning read permissions', async () => { - enableRBAC(); - grantUserPermissions([AccessControlAction.AlertingRuleCreate, AccessControlAction.FoldersRead]); mocks.getAllDataSourcesMock.mockReturnValue([]); @@ -733,8 +726,6 @@ describe('RuleList', () => { }); describe('Grafana Managed Alerts', () => { it('New alert button should be visible when the user has alert rule create and folder read permissions and no rules exists', async () => { - enableRBAC(); - grantUserPermissions([ AccessControlAction.FoldersRead, AccessControlAction.AlertingRuleCreate, @@ -753,8 +744,6 @@ describe('RuleList', () => { }); it('New alert button should be visible when the user has alert rule create and folder read permissions and rules already exists', async () => { - enableRBAC(); - grantUserPermissions([ AccessControlAction.FoldersRead, AccessControlAction.AlertingRuleCreate, @@ -775,8 +764,6 @@ describe('RuleList', () => { describe('Cloud Alerts', () => { it('New alert button should be visible when the user has the alert rule external write and datasource read permissions and no rules exists', async () => { - enableRBAC(); - grantUserPermissions([ // AccessControlAction.AlertingRuleRead, AccessControlAction.DataSourcesRead, @@ -803,8 +790,6 @@ describe('RuleList', () => { }); it('New alert button should be visible when the user has the alert rule external write and data source read permissions and rules already exists', async () => { - enableRBAC(); - grantUserPermissions([ AccessControlAction.DataSourcesRead, AccessControlAction.AlertingRuleExternalRead, @@ -833,8 +818,6 @@ describe('RuleList', () => { describe('Analytics', () => { it('Sends log info when creating an alert rule from a scratch', async () => { - enableRBAC(); - grantUserPermissions([ AccessControlAction.FoldersRead, AccessControlAction.AlertingRuleCreate, diff --git a/public/app/features/alerting/unified/components/admin/AlertmanagerConfig.test.tsx b/public/app/features/alerting/unified/components/admin/AlertmanagerConfig.test.tsx index e8e02d2d341..61860be1322 100644 --- a/public/app/features/alerting/unified/components/admin/AlertmanagerConfig.test.tsx +++ b/public/app/features/alerting/unified/components/admin/AlertmanagerConfig.test.tsx @@ -12,6 +12,7 @@ import { AlertManagerDataSourceJsonData, AlertManagerImplementation, } from 'app/plugins/datasource/alertmanager/types'; +import { AccessControlAction } from 'app/types'; import { fetchAlertManagerConfig, @@ -20,7 +21,7 @@ import { fetchStatus, } from '../../api/alertmanager'; import { - disableRBAC, + grantUserPermissions, mockDataSource, MockDataSourceSrv, someCloudAlertManagerConfig, @@ -88,11 +89,12 @@ const ui = { describe('Admin config', () => { beforeEach(() => { jest.resetAllMocks(); + // FIXME: scope down + grantUserPermissions(Object.values(AccessControlAction)); mocks.getAllDataSources.mockReturnValue(Object.values(dataSources)); setDataSourceSrv(new MockDataSourceSrv(dataSources)); contextSrv.isGrafanaAdmin = true; store.delete(ALERTMANAGER_NAME_LOCAL_STORAGE_KEY); - disableRBAC(); }); it('Reset alertmanager config', async () => { diff --git a/public/app/features/alerting/unified/components/receivers/ReceiversTable.test.tsx b/public/app/features/alerting/unified/components/receivers/ReceiversTable.test.tsx index fd999810e01..7195e2b70fb 100644 --- a/public/app/features/alerting/unified/components/receivers/ReceiversTable.test.tsx +++ b/public/app/features/alerting/unified/components/receivers/ReceiversTable.test.tsx @@ -17,7 +17,7 @@ import { AccessControlAction, ContactPointsState, NotifierDTO, NotifierType } fr import { backendSrv } from '../../../../../core/services/backend_srv'; import * as receiversApi from '../../api/receiversApi'; import { mockProvisioningApi, setupMswServer } from '../../mockApi'; -import { enableRBAC, grantUserPermissions } from '../../mocks'; +import { grantUserPermissions } from '../../mocks'; import { AlertmanagerProvider } from '../../state/AlertmanagerContext'; import { fetchGrafanaNotifiersAction } from '../../state/actions'; import { GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource'; @@ -184,7 +184,6 @@ describe('ReceiversTable', () => { const notifiers: NotifierDTO[] = [mockNotifier('googlechat', 'Google Chat'), mockNotifier('sensugo', 'Sensu Go')]; it('should be visible when user has permissions to read provisioning', async () => { - enableRBAC(); grantUserPermissions([AccessControlAction.AlertingProvisioningRead]); await renderReceieversTable(receivers, notifiers, GRAFANA_RULES_SOURCE_NAME); @@ -193,7 +192,6 @@ describe('ReceiversTable', () => { expect(buttons).toHaveLength(2); }); it('should be visible when user has permissions to read provisioning with secrets', async () => { - enableRBAC(); grantUserPermissions([AccessControlAction.AlertingProvisioningReadSecrets]); await renderReceieversTable(receivers, notifiers, GRAFANA_RULES_SOURCE_NAME); @@ -202,7 +200,6 @@ describe('ReceiversTable', () => { expect(buttons).toHaveLength(2); }); it('should not be visible when user has no provisioning permissions', async () => { - enableRBAC(); grantUserPermissions([AccessControlAction.AlertingNotificationsRead]); await renderReceieversTable(receivers, [], GRAFANA_RULES_SOURCE_NAME); @@ -235,7 +232,6 @@ describe('ReceiversTable', () => { const notifiers: NotifierDTO[] = [mockNotifier('googlechat', 'Google Chat'), mockNotifier('sensugo', 'Sensu Go')]; - enableRBAC(); grantUserPermissions([AccessControlAction.AlertingProvisioningRead]); // Act diff --git a/public/app/features/alerting/unified/components/rules/RuleDetails.test.tsx b/public/app/features/alerting/unified/components/rules/RuleDetails.test.tsx index bed1ad3b75a..d8b07efe7dc 100644 --- a/public/app/features/alerting/unified/components/rules/RuleDetails.test.tsx +++ b/public/app/features/alerting/unified/components/rules/RuleDetails.test.tsx @@ -34,8 +34,6 @@ const ui = { }, }; -jest.spyOn(contextSrv, 'accessControlEnabled').mockReturnValue(true); - const server = setupServer(); const alertmanagerChoiceMockedResponse: AlertmanagersChoiceResponse = { diff --git a/public/app/features/alerting/unified/components/rules/RuleListGroupView.test.tsx b/public/app/features/alerting/unified/components/rules/RuleListGroupView.test.tsx index 38c0a829e3f..7649000f67c 100644 --- a/public/app/features/alerting/unified/components/rules/RuleListGroupView.test.tsx +++ b/public/app/features/alerting/unified/components/rules/RuleListGroupView.test.tsx @@ -31,8 +31,6 @@ const ui = { describe('RuleListGroupView', () => { describe('RBAC', () => { - jest.spyOn(contextSrv, 'accessControlEnabled').mockReturnValue(true); - it('Should display Grafana rules when the user has the alert rule read permission', async () => { const grafanaNamespace = getGrafanaNamespace(); const namespaces: CombinedRuleNamespace[] = [grafanaNamespace]; diff --git a/public/app/features/alerting/unified/components/rules/RulesGroup.test.tsx b/public/app/features/alerting/unified/components/rules/RulesGroup.test.tsx index cd299760040..044e358d278 100644 --- a/public/app/features/alerting/unified/components/rules/RulesGroup.test.tsx +++ b/public/app/features/alerting/unified/components/rules/RulesGroup.test.tsx @@ -8,12 +8,13 @@ import { byRole, byTestId, byText } from 'testing-library-selector'; import { logInfo } from '@grafana/runtime'; import { contextSrv } from 'app/core/services/context_srv'; import { configureStore } from 'app/store/configureStore'; +import { AccessControlAction } from 'app/types'; import { CombinedRuleGroup, CombinedRuleNamespace } from 'app/types/unified-alerting'; import { LogMessages } from '../../Analytics'; import { useHasRuler } from '../../hooks/useHasRuler'; import { mockFolderApi, mockProvisioningApi, setupMswServer } from '../../mockApi'; -import { disableRBAC, mockCombinedRule, mockDataSource, mockFolder, mockGrafanaRulerRule } from '../../mocks'; +import { grantUserPermissions, mockCombinedRule, mockDataSource, mockFolder, mockGrafanaRulerRule } from '../../mocks'; import { RulesGroup } from './RulesGroup'; @@ -46,6 +47,8 @@ function mockUseHasRuler(hasRuler: boolean, rulerRulesLoaded: boolean) { beforeEach(() => { mocks.useHasRuler.mockReset(); + // FIXME: scope down + grantUserPermissions(Object.values(AccessControlAction)); }); const ui = { @@ -164,8 +167,6 @@ describe('Rules group tests', () => { groups: [group], }; - disableRBAC(); - it('When ruler enabled should display delete and edit group buttons', () => { // Arrange mockUseHasRuler(true, true); @@ -223,8 +224,6 @@ describe('Rules group tests', () => { groups: [group], }; - disableRBAC(); - it('Should log info when closing the edit group rule modal without saving', async () => { mockUseHasRuler(true, true); renderRulesGroup(namespace, group); diff --git a/public/app/features/alerting/unified/components/rules/RulesTable.test.tsx b/public/app/features/alerting/unified/components/rules/RulesTable.test.tsx index f5283c8fd6e..da7cccf7a55 100644 --- a/public/app/features/alerting/unified/components/rules/RulesTable.test.tsx +++ b/public/app/features/alerting/unified/components/rules/RulesTable.test.tsx @@ -5,7 +5,6 @@ import { Provider } from 'react-redux'; import { MemoryRouter } from 'react-router-dom'; import { byRole } from 'testing-library-selector'; -import { contextSrv } from 'app/core/services/context_srv'; import { configureStore } from 'app/store/configureStore'; import { CombinedRule } from 'app/types/unified-alerting'; @@ -31,8 +30,6 @@ const ui = { }, }; -jest.spyOn(contextSrv, 'accessControlEnabled').mockReturnValue(true); - function renderRulesTable(rule: CombinedRule) { const store = configureStore(); diff --git a/public/app/features/alerting/unified/hooks/useIsRuleEditable.test.tsx b/public/app/features/alerting/unified/hooks/useIsRuleEditable.test.tsx index c94d79a21f5..f58f2c24f58 100644 --- a/public/app/features/alerting/unified/hooks/useIsRuleEditable.test.tsx +++ b/public/app/features/alerting/unified/hooks/useIsRuleEditable.test.tsx @@ -5,14 +5,7 @@ import { Provider } from 'react-redux'; import { contextSrv } from 'app/core/services/context_srv'; import { AccessControlAction, FolderDTO, StoreState } from 'app/types'; -import { - disableRBAC, - enableRBAC, - mockFolder, - mockRulerAlertingRule, - mockRulerGrafanaRule, - mockUnifiedAlertingStore, -} from '../mocks'; +import { mockFolder, mockRulerAlertingRule, mockRulerGrafanaRule, mockUnifiedAlertingStore } from '../mocks'; import { useFolder } from './useFolder'; import { useIsRuleEditable } from './useIsRuleEditable'; @@ -27,7 +20,6 @@ const mocks = { describe('useIsRuleEditable', () => { describe('RBAC enabled', () => { - beforeEach(enableRBAC); describe('Grafana rules', () => { // When RBAC is enabled we require appropriate alerting permissions in the folder scope it('Should allow editing when the user has the alert rule update permission in the folder', async () => { @@ -130,35 +122,6 @@ describe('useIsRuleEditable', () => { }); }); }); - - describe('RBAC disabled', () => { - beforeEach(disableRBAC); - describe('Grafana rules', () => { - it('Should allow editing and deleting when the user has folder canSave permission', async () => { - mockUseFolder({ canSave: true }); - - const wrapper = getProviderWrapper(); - - const { result } = renderHook(() => useIsRuleEditable('grafana', mockRulerGrafanaRule()), { wrapper }); - - await waitFor(() => expect(result.current.loading).toBe(false)); - expect(result.current.isEditable).toBe(true); - expect(result.current.isRemovable).toBe(true); - }); - - it('Should forbid editing and deleting when the user has no folder canSave permission', async () => { - mockUseFolder({ canSave: false }); - - const wrapper = getProviderWrapper(); - - const { result } = renderHook(() => useIsRuleEditable('grafana', mockRulerGrafanaRule()), { wrapper }); - - await waitFor(() => expect(result.current.loading).toBe(false)); - expect(result.current.isEditable).toBe(false); - expect(result.current.isRemovable).toBe(false); - }); - }); - }); }); function mockUseFolder(partial?: Partial) { diff --git a/public/app/features/alerting/unified/mocks.ts b/public/app/features/alerting/unified/mocks.ts index b7c78a7c1e2..132aba7d0a7 100644 --- a/public/app/features/alerting/unified/mocks.ts +++ b/public/app/features/alerting/unified/mocks.ts @@ -595,14 +595,6 @@ export const mockFolder = (partial?: Partial): FolderDTO => { }; }; -export const enableRBAC = () => { - jest.spyOn(contextSrv, 'accessControlEnabled').mockReturnValue(true); -}; - -export const disableRBAC = () => { - jest.spyOn(contextSrv, 'accessControlEnabled').mockReturnValue(false); -}; - export const grantUserPermissions = (permissions: AccessControlAction[]) => { jest .spyOn(contextSrv, 'hasPermission') diff --git a/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx index 4cbf1393b14..1f42955fe5b 100644 --- a/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx +++ b/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx @@ -17,7 +17,6 @@ import { DashboardMetaChangedEvent } from 'app/types/events'; import { VariableEditorContainer } from '../../../variables/editor/VariableEditorContainer'; import { DashboardModel } from '../../state/DashboardModel'; import { AccessControlDashboardPermissions } from '../DashboardPermissions/AccessControlDashboardPermissions'; -import { DashboardPermissions } from '../DashboardPermissions/DashboardPermissions'; import { SaveDashboardAsButton, SaveDashboardButton } from '../SaveDashboard/SaveDashboardButton'; import { AnnotationsSettings } from './AnnotationsSettings'; @@ -148,14 +147,7 @@ function getSettingsPages(dashboard: DashboardModel) { const permissionsTitle = t('dashboard-settings.permissions.title', 'Permissions'); if (dashboard.id && dashboard.meta.canAdmin) { - if (!config.rbacEnabled) { - pages.push({ - title: permissionsTitle, - id: 'permissions', - icon: 'lock', - component: DashboardPermissions, - }); - } else if (contextSrv.hasPermission(AccessControlAction.DashboardsPermissionsRead)) { + if (contextSrv.hasPermission(AccessControlAction.DashboardsPermissionsRead)) { pages.push({ title: permissionsTitle, id: 'permissions', diff --git a/public/app/features/dashboard/state/DashboardModel.test.ts b/public/app/features/dashboard/state/DashboardModel.test.ts index 8d764aa671b..58e14ca32bd 100644 --- a/public/app/features/dashboard/state/DashboardModel.test.ts +++ b/public/app/features/dashboard/state/DashboardModel.test.ts @@ -2,7 +2,6 @@ import { keys as _keys } from 'lodash'; import { dateTime, TimeRange, VariableHide } from '@grafana/data'; import { Dashboard, defaultVariableModel } from '@grafana/schema'; -import { contextSrv } from 'app/core/services/context_srv'; import { getDashboardModel } from '../../../../test/helpers/getDashboardModel'; import { variableAdapters } from '../../variables/adapters'; @@ -22,8 +21,6 @@ import { jest.mock('app/core/services/context_srv'); -const mockContextSrv = jest.mocked(contextSrv); - variableAdapters.setInit(() => [ createQueryVariableAdapter(), createAdHocVariableAdapter(), @@ -950,7 +947,6 @@ describe('DashboardModel', () => { dashboard.meta.canEdit = canEdit; dashboard.meta.canMakeEditable = canMakeEditable; - mockContextSrv.accessControlEnabled.mockReturnValue(true); const result = dashboard.canAddAnnotations(); expect(result).toBe(expected); } @@ -983,7 +979,6 @@ describe('DashboardModel', () => { dashboard.meta.canEdit = canEdit; dashboard.meta.canMakeEditable = canMakeEditable; - mockContextSrv.accessControlEnabled.mockReturnValue(true); const result = dashboard.canEditAnnotations(); expect(result).toBe(expected); } @@ -1014,7 +1009,6 @@ describe('DashboardModel', () => { dashboard.meta.canEdit = canEdit; dashboard.meta.canMakeEditable = canMakeEditable; - mockContextSrv.accessControlEnabled.mockReturnValue(true); const result = dashboard.canEditAnnotations('testDashboardUID'); expect(result).toBe(expected); } @@ -1047,7 +1041,6 @@ describe('DashboardModel', () => { dashboard.meta.canEdit = canEdit; dashboard.meta.canMakeEditable = canMakeEditable; - mockContextSrv.accessControlEnabled.mockReturnValue(true); const result = dashboard.canDeleteAnnotations(); expect(result).toBe(expected); } @@ -1078,7 +1071,6 @@ describe('DashboardModel', () => { dashboard.meta.canEdit = canEdit; dashboard.meta.canMakeEditable = canMakeEditable; - mockContextSrv.accessControlEnabled.mockReturnValue(true); const result = dashboard.canDeleteAnnotations('testDashboardUID'); expect(result).toBe(expected); } diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts index f10718649dd..d99b0f89628 100644 --- a/public/app/features/dashboard/state/DashboardModel.ts +++ b/public/app/features/dashboard/state/DashboardModel.ts @@ -1186,14 +1186,11 @@ export class DashboardModel implements TimeModel { canEditAnnotations(dashboardUID?: string) { let canEdit = true; - // if RBAC is enabled there are additional conditions to check - if (contextSrv.accessControlEnabled()) { - // dashboardUID is falsy when it is an organizational annotation - if (!dashboardUID) { - canEdit = !!this.meta.annotationsPermissions?.organization.canEdit; - } else { - canEdit = !!this.meta.annotationsPermissions?.dashboard.canEdit; - } + // dashboardUID is falsy when it is an organizational annotation + if (!dashboardUID) { + canEdit = !!this.meta.annotationsPermissions?.organization.canEdit; + } else { + canEdit = !!this.meta.annotationsPermissions?.dashboard.canEdit; } return this.canEditDashboard() && canEdit; } @@ -1201,13 +1198,11 @@ export class DashboardModel implements TimeModel { canDeleteAnnotations(dashboardUID?: string) { let canDelete = true; - if (contextSrv.accessControlEnabled()) { - // dashboardUID is falsy when it is an organizational annotation - if (!dashboardUID) { - canDelete = !!this.meta.annotationsPermissions?.organization.canDelete; - } else { - canDelete = !!this.meta.annotationsPermissions?.dashboard.canDelete; - } + // dashboardUID is falsy when it is an organizational annotation + if (!dashboardUID) { + canDelete = !!this.meta.annotationsPermissions?.organization.canDelete; + } else { + canDelete = !!this.meta.annotationsPermissions?.dashboard.canDelete; } return canDelete && this.canEditDashboard(); } @@ -1220,7 +1215,7 @@ export class DashboardModel implements TimeModel { } // If RBAC is enabled there are additional conditions to check. - return !contextSrv.accessControlEnabled() || Boolean(this.meta.annotationsPermissions?.dashboard.canAdd); + return Boolean(this.meta.annotationsPermissions?.dashboard.canAdd); } canEditDashboard() { diff --git a/public/app/features/query/state/DashboardQueryRunner/UnifiedAlertStatesWorker.test.ts b/public/app/features/query/state/DashboardQueryRunner/UnifiedAlertStatesWorker.test.ts index 2b7ab9064ab..9d401a130b2 100644 --- a/public/app/features/query/state/DashboardQueryRunner/UnifiedAlertStatesWorker.test.ts +++ b/public/app/features/query/state/DashboardQueryRunner/UnifiedAlertStatesWorker.test.ts @@ -3,7 +3,7 @@ import { lastValueFrom } from 'rxjs'; import { AlertState, getDefaultTimeRange, TimeRange } from '@grafana/data'; import { config } from '@grafana/runtime'; import { backendSrv } from 'app/core/services/backend_srv'; -import { disableRBAC, enableRBAC, grantUserPermissions } from 'app/features/alerting/unified/mocks'; +import { grantUserPermissions } from 'app/features/alerting/unified/mocks'; import { Annotation } from 'app/features/alerting/unified/utils/constants'; import { createDashboardModelFixture } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures'; import { AccessControlAction } from 'app/types/accessControl'; @@ -47,10 +47,7 @@ describe('UnifiedAlertStatesWorker', () => { beforeEach(() => { config.publicDashboardAccessToken = ''; - }); - - beforeAll(() => { - disableRBAC(); + grantUserPermissions(Object.values(AccessControlAction)); }); describe('when canWork is called with correct props', () => { @@ -231,7 +228,6 @@ describe('UnifiedAlertStatesWorker', () => { describe('UnifiedAlertStateWorker with RBAC', () => { beforeAll(() => { - enableRBAC(); grantUserPermissions([]); }); diff --git a/public/app/features/teams/TeamPages.tsx b/public/app/features/teams/TeamPages.tsx index e8f0f56e53c..240a113dda5 100644 --- a/public/app/features/teams/TeamPages.tsx +++ b/public/app/features/teams/TeamPages.tsx @@ -41,11 +41,9 @@ function mapStateToProps(state: StoreState, props: OwnProps) { const teamId = parseInt(props.match.params.id, 10); const team = getTeam(state.team, teamId); let defaultPage = 'members'; - if (contextSrv.accessControlEnabled()) { - // With RBAC the settings page will always be available - if (!team || !contextSrv.hasPermissionInMetadata(AccessControlAction.ActionTeamsPermissionsRead, team)) { - defaultPage = 'settings'; - } + // With RBAC the settings page will always be available + if (!team || !contextSrv.hasPermissionInMetadata(AccessControlAction.ActionTeamsPermissionsRead, team)) { + defaultPage = 'settings'; } const pageName = props.match.params.page ?? defaultPage; const teamLoadingNav = getTeamLoadingNav(pageName); diff --git a/public/app/plugins/panel/graph/event_editor.ts b/public/app/plugins/panel/graph/event_editor.ts index c64b2c9e2b1..886d7d698c7 100644 --- a/public/app/plugins/panel/graph/event_editor.ts +++ b/public/app/plugins/panel/graph/event_editor.ts @@ -4,7 +4,6 @@ import { AnnotationEvent, dateTime } from '@grafana/data'; import { coreModule } from 'app/angular/core_module'; import { MetricsPanelCtrl } from 'app/angular/panel/metrics_panel_ctrl'; -import { contextSrv } from '../../../core/services/context_srv'; import { deleteAnnotation, saveAnnotation, updateAnnotation } from '../../../features/annotations/api'; import { getDashboardQueryRunner } from '../../../features/query/state/DashboardQueryRunner/DashboardQueryRunner'; @@ -34,13 +33,10 @@ export class EventEditorCtrl { } canDelete(): boolean { - if (contextSrv.accessControlEnabled()) { - if (this.event.source?.type === 'dashboard') { - return !!this.panelCtrl.dashboard.meta.annotationsPermissions?.dashboard.canDelete; - } - return !!this.panelCtrl.dashboard.meta.annotationsPermissions?.organization.canDelete; + if (this.event.source?.type === 'dashboard') { + return !!this.panelCtrl.dashboard.meta.annotationsPermissions?.dashboard.canDelete; } - return true; + return !!this.panelCtrl.dashboard.meta.annotationsPermissions?.organization.canDelete; } async save(): Promise {