mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
165b4c3f66
commit
28c0fb1cfd
@ -181,6 +181,7 @@ export interface GrafanaConfig {
|
||||
autoAssignOrg: boolean;
|
||||
verifyEmailEnabled: boolean;
|
||||
oauth: OAuthSettings;
|
||||
/** @deprecated always set to true. */
|
||||
rbacEnabled: boolean;
|
||||
disableUserSignUp: boolean;
|
||||
loginHint: string;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 };
|
||||
}
|
||||
|
@ -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">
|
||||
|
@ -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());
|
||||
|
@ -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 () => {
|
||||
|
@ -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') {
|
||||
|
@ -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([]);
|
||||
|
@ -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';
|
||||
|
@ -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(
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
|
@ -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 () => {
|
||||
|
@ -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
|
||||
|
@ -34,8 +34,6 @@ const ui = {
|
||||
},
|
||||
};
|
||||
|
||||
jest.spyOn(contextSrv, 'accessControlEnabled').mockReturnValue(true);
|
||||
|
||||
const server = setupServer();
|
||||
|
||||
const alertmanagerChoiceMockedResponse: AlertmanagersChoiceResponse = {
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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>) {
|
||||
|
@ -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')
|
||||
|
@ -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',
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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([]);
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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> {
|
||||
|
Loading…
Reference in New Issue
Block a user