mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Fix folder permissions (#48189)
* Use the folder view permission in alerting * Add tests
This commit is contained in:
parent
3b4d237ade
commit
5f594addbf
@ -8,20 +8,23 @@ import { byLabelText, byRole, byTestId, byText } from 'testing-library-selector'
|
||||
|
||||
import { locationService, setDataSourceSrv } from '@grafana/runtime';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
import { AccessControlAction } from 'app/types';
|
||||
import { PromAlertingRuleState, PromApplication } from 'app/types/unified-alerting-dto';
|
||||
|
||||
import RuleList from './RuleList';
|
||||
import { fetchBuildInfo } from './api/buildInfo';
|
||||
import { fetchRules } from './api/prometheus';
|
||||
import { fetchRulerRules, deleteRulerRulesGroup, deleteNamespace, setRulerRuleGroup } from './api/ruler';
|
||||
import { deleteNamespace, deleteRulerRulesGroup, fetchRulerRules, setRulerRuleGroup } from './api/ruler';
|
||||
import {
|
||||
enableRBAC,
|
||||
grantUserPermissions,
|
||||
mockDataSource,
|
||||
MockDataSourceSrv,
|
||||
mockPromAlert,
|
||||
mockPromAlertingRule,
|
||||
mockPromRecordingRule,
|
||||
mockPromRuleGroup,
|
||||
mockPromRuleNamespace,
|
||||
MockDataSourceSrv,
|
||||
somePromRules,
|
||||
someRulerRules,
|
||||
} from './mocks';
|
||||
@ -101,6 +104,8 @@ const ui = {
|
||||
moreErrorsButton: byRole('button', { name: /more errors/ }),
|
||||
editCloudGroupIcon: byTestId('edit-group'),
|
||||
|
||||
newRuleButton: byRole('link', { name: 'New alert rule' }),
|
||||
|
||||
editGroupModal: {
|
||||
namespaceInput: byLabelText('Namespace'),
|
||||
ruleGroupInput: byLabelText('Rule group'),
|
||||
@ -631,4 +636,105 @@ describe('RuleList', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('RBAC Enabled', () => {
|
||||
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,
|
||||
AccessControlAction.AlertingRuleRead,
|
||||
]);
|
||||
|
||||
mocks.getAllDataSourcesMock.mockReturnValue([]);
|
||||
setDataSourceSrv(new MockDataSourceSrv({}));
|
||||
mocks.api.fetchRules.mockResolvedValue([]);
|
||||
mocks.api.fetchRulerRules.mockResolvedValue({});
|
||||
|
||||
renderRuleList();
|
||||
|
||||
await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(1));
|
||||
expect(ui.newRuleButton.get()).toBeInTheDocument();
|
||||
});
|
||||
|
||||
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,
|
||||
AccessControlAction.AlertingRuleRead,
|
||||
]);
|
||||
|
||||
mocks.getAllDataSourcesMock.mockReturnValue([]);
|
||||
setDataSourceSrv(new MockDataSourceSrv({}));
|
||||
mocks.api.fetchRules.mockResolvedValue(somePromRules('grafana'));
|
||||
mocks.api.fetchRulerRules.mockResolvedValue(someRulerRules);
|
||||
|
||||
renderRuleList();
|
||||
|
||||
await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(1));
|
||||
expect(ui.newRuleButton.get()).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
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,
|
||||
AccessControlAction.AlertingRuleExternalRead,
|
||||
AccessControlAction.AlertingRuleExternalWrite,
|
||||
]);
|
||||
|
||||
mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]);
|
||||
setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom }));
|
||||
mocks.api.fetchBuildInfo.mockResolvedValue({
|
||||
application: PromApplication.Cortex,
|
||||
features: {
|
||||
rulerApiEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
mocks.api.fetchRules.mockResolvedValue([]);
|
||||
mocks.api.fetchRulerRules.mockResolvedValue({});
|
||||
|
||||
renderRuleList();
|
||||
|
||||
await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(1));
|
||||
expect(ui.newRuleButton.get()).toBeInTheDocument();
|
||||
});
|
||||
|
||||
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,
|
||||
AccessControlAction.AlertingRuleExternalWrite,
|
||||
]);
|
||||
|
||||
mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]);
|
||||
setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom }));
|
||||
mocks.api.fetchBuildInfo.mockResolvedValue({
|
||||
application: PromApplication.Cortex,
|
||||
features: {
|
||||
rulerApiEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
mocks.api.fetchRules.mockResolvedValue(somePromRules('Cortex'));
|
||||
mocks.api.fetchRulerRules.mockResolvedValue(someRulerRules);
|
||||
|
||||
renderRuleList();
|
||||
|
||||
await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(1));
|
||||
expect(ui.newRuleButton.get()).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { FC } from 'react';
|
||||
|
||||
import { FolderPicker, Props as FolderPickerProps } from 'app/core/components/Select/FolderPicker';
|
||||
import { PermissionLevelString } from 'app/types';
|
||||
|
||||
export interface Folder {
|
||||
title: string;
|
||||
@ -12,5 +13,12 @@ export interface Props extends Omit<FolderPickerProps, 'initialTitle' | 'initial
|
||||
}
|
||||
|
||||
export const RuleFolderPicker: FC<Props> = ({ value, ...props }) => (
|
||||
<FolderPicker showRoot={false} allowEmpty={true} initialTitle={value?.title} initialFolderId={value?.id} {...props} />
|
||||
<FolderPicker
|
||||
showRoot={false}
|
||||
allowEmpty={true}
|
||||
initialTitle={value?.title}
|
||||
initialFolderId={value?.id}
|
||||
{...props}
|
||||
permissionLevel={PermissionLevelString.View}
|
||||
/>
|
||||
);
|
||||
|
@ -6,7 +6,8 @@ import {
|
||||
DataSourceRef,
|
||||
ScopedVars,
|
||||
} from '@grafana/data';
|
||||
import { DataSourceSrv, GetDataSourceListFilters, config } from '@grafana/runtime';
|
||||
import { config, DataSourceSrv, GetDataSourceListFilters } from '@grafana/runtime';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { DatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import {
|
||||
AlertmanagerAlert,
|
||||
@ -18,8 +19,8 @@ import {
|
||||
Silence,
|
||||
SilenceState,
|
||||
} from 'app/plugins/datasource/alertmanager/types';
|
||||
import { FolderDTO } from 'app/types';
|
||||
import { AlertingRule, Alert, RecordingRule, RuleGroup, RuleNamespace, CombinedRule } from 'app/types/unified-alerting';
|
||||
import { AccessControlAction, FolderDTO } from 'app/types';
|
||||
import { Alert, AlertingRule, CombinedRule, RecordingRule, RuleGroup, RuleNamespace } from 'app/types/unified-alerting';
|
||||
import {
|
||||
GrafanaAlertStateDecision,
|
||||
GrafanaRuleDefinition,
|
||||
@ -465,3 +466,13 @@ export const mockFolder = (partial?: Partial<FolderDTO>): FolderDTO => {
|
||||
...partial,
|
||||
};
|
||||
};
|
||||
|
||||
export const enableRBAC = () => {
|
||||
jest.spyOn(contextSrv, 'accessControlEnabled').mockReturnValue(true);
|
||||
};
|
||||
|
||||
export const grantUserPermissions = (permissions: AccessControlAction[]) => {
|
||||
jest
|
||||
.spyOn(contextSrv, 'hasPermission')
|
||||
.mockImplementation((action) => permissions.includes(action as AccessControlAction));
|
||||
};
|
||||
|
@ -108,9 +108,11 @@ export function evaluateAccess(actions: AccessControlAction[], fallBackUserRoles
|
||||
export function getRulesAccess() {
|
||||
return {
|
||||
canCreateGrafanaRules:
|
||||
contextSrv.hasEditPermissionInFolders &&
|
||||
contextSrv.hasAccess(AccessControlAction.FoldersRead, contextSrv.isEditor) &&
|
||||
contextSrv.hasAccess(rulesPermissions.create.grafana, contextSrv.isEditor),
|
||||
canCreateCloudRules: contextSrv.hasAccess(rulesPermissions.create.external, contextSrv.isEditor),
|
||||
canCreateCloudRules:
|
||||
contextSrv.hasAccess(AccessControlAction.DataSourcesRead, contextSrv.isEditor) &&
|
||||
contextSrv.hasAccess(rulesPermissions.create.external, contextSrv.isEditor),
|
||||
canEditRules: (rulesSourceName: string) =>
|
||||
contextSrv.hasAccess(getRulesPermissions(rulesSourceName).update, contextSrv.isEditor),
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user