AccessControl: Remove legacy frontend AC checks (#76187)

* remove legacy ac checks

* fix RBAC disabled tests

* add permissions for tests to work

* fix unifiedalertstatesworker test
This commit is contained in:
Jo 2023-10-09 18:10:06 +02:00 committed by GitHub
parent 165b4c3f66
commit 28c0fb1cfd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 123 additions and 201 deletions

View File

@ -181,6 +181,7 @@ export interface GrafanaConfig {
autoAssignOrg: boolean;
verifyEmailEnabled: boolean;
oauth: OAuthSettings;
/** @deprecated always set to true. */
rbacEnabled: boolean;
disableUserSignUp: boolean;
loginHint: string;

View File

@ -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);
}

View File

@ -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 };
}

View File

@ -377,21 +377,17 @@ export class AddToOrgModal extends PureComponent<AddToOrgModalProps, AddToOrgMod
<OrgPicker inputId="new-org-input" onSelected={this.onOrgSelect} excludeOrgs={userOrgs} autoFocus />
</Field>
<Field label="Role" disabled={selectedOrg === null}>
{contextSrv.accessControlEnabled() ? (
<UserRolePicker
userId={user?.id || 0}
orgId={selectedOrg?.id}
basicRole={role}
onBasicRoleChange={this.onOrgRoleChange}
basicRoleDisabled={false}
roleOptions={roleOptions}
apply={true}
onApplyRoles={this.onRoleUpdate}
pendingRoles={this.state.pendingRoles}
/>
) : (
<OrgRolePicker inputId="new-org-role-input" value={role} onChange={this.onOrgRoleChange} />
)}
<UserRolePicker
userId={user?.id || 0}
orgId={selectedOrg?.id}
basicRole={role}
onBasicRoleChange={this.onOrgRoleChange}
basicRoleDisabled={false}
roleOptions={roleOptions}
apply={true}
onApplyRoles={this.onRoleUpdate}
pendingRoles={this.state.pendingRoles}
/>
</Field>
<Modal.ButtonRow>
<HorizontalGroup spacing="md" justify="center">

View File

@ -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());

View File

@ -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 () => {

View File

@ -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') {

View File

@ -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([]);

View File

@ -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';

View File

@ -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(

View File

@ -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));

View File

@ -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,

View File

@ -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 () => {

View File

@ -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

View File

@ -34,8 +34,6 @@ const ui = {
},
};
jest.spyOn(contextSrv, 'accessControlEnabled').mockReturnValue(true);
const server = setupServer();
const alertmanagerChoiceMockedResponse: AlertmanagersChoiceResponse = {

View File

@ -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];

View File

@ -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);

View File

@ -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();

View File

@ -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<FolderDTO>) {

View File

@ -595,14 +595,6 @@ export const mockFolder = (partial?: Partial<FolderDTO>): 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')

View File

@ -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',

View File

@ -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);
}

View File

@ -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() {

View File

@ -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([]);
});

View File

@ -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);

View File

@ -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<void> {