From c73b1787ecc34383ebc4feab207834fa05eece38 Mon Sep 17 00:00:00 2001 From: "Grot (@grafanabot)" <43478413+grafanabot@users.noreply.github.com> Date: Tue, 31 May 2022 08:41:35 -0400 Subject: [PATCH] [v9.0.x] Alerting: Add fgac support to alert list panel (#49912) Co-authored-by: gillesdemey Co-authored-by: Konrad Lalik --- .../UnifiedAlertStatesWorker.test.ts | 28 +++++++++++++++++++ .../UnifiedAlertStatesWorker.ts | 10 +++++++ .../panel/alertlist/UnifiedAlertList.tsx | 13 ++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/public/app/features/query/state/DashboardQueryRunner/UnifiedAlertStatesWorker.test.ts b/public/app/features/query/state/DashboardQueryRunner/UnifiedAlertStatesWorker.test.ts index f2d1c4eaf8c..744885d9526 100644 --- a/public/app/features/query/state/DashboardQueryRunner/UnifiedAlertStatesWorker.test.ts +++ b/public/app/features/query/state/DashboardQueryRunner/UnifiedAlertStatesWorker.test.ts @@ -2,7 +2,9 @@ import { lastValueFrom } from 'rxjs'; import { AlertState, getDefaultTimeRange, TimeRange } from '@grafana/data'; import { backendSrv } from 'app/core/services/backend_srv'; +import { disableRBAC, enableRBAC, grantUserPermissions } from 'app/features/alerting/unified/mocks'; import { Annotation } from 'app/features/alerting/unified/utils/constants'; +import { AccessControlAction } from 'app/types/accessControl'; import { PromAlertingRuleState, PromRuleDTO, PromRulesResponse, PromRuleType } from 'app/types/unified-alerting-dto'; import { silenceConsoleOutput } from '../../../../../test/core/utils/silenceConsoleOutput'; @@ -35,6 +37,10 @@ function getTestContext() { describe('UnifiedAlertStatesWorker', () => { const worker = new UnifiedAlertStatesWorker(); + beforeAll(() => { + disableRBAC(); + }); + describe('when canWork is called with correct props', () => { it('then it should return true', () => { const options = getDefaultOptions(); @@ -200,3 +206,25 @@ describe('UnifiedAlertStatesWorker', () => { }); }); }); + +describe('UnifiedAlertStateWorker with RBAC', () => { + beforeAll(() => { + enableRBAC(); + grantUserPermissions([]); + }); + + it('should not do work with insufficient permissions', () => { + const worker = new UnifiedAlertStatesWorker(); + const options = getDefaultOptions(); + + expect(worker.canWork(options)).toBe(false); + }); + + it('should do work with correct permissions', () => { + grantUserPermissions([AccessControlAction.AlertingRuleRead, AccessControlAction.AlertingRuleExternalRead]); + const workerWithPermissions = new UnifiedAlertStatesWorker(); + + const options = getDefaultOptions(); + expect(workerWithPermissions.canWork(options)).toBe(true); + }); +}); diff --git a/public/app/features/query/state/DashboardQueryRunner/UnifiedAlertStatesWorker.ts b/public/app/features/query/state/DashboardQueryRunner/UnifiedAlertStatesWorker.ts index a9100ce3e60..335b1cd20ca 100644 --- a/public/app/features/query/state/DashboardQueryRunner/UnifiedAlertStatesWorker.ts +++ b/public/app/features/query/state/DashboardQueryRunner/UnifiedAlertStatesWorker.ts @@ -3,8 +3,10 @@ import { catchError, map } from 'rxjs/operators'; import { AlertState, AlertStateInfo } from '@grafana/data'; import { getBackendSrv } from '@grafana/runtime'; +import { contextSrv } from 'app/core/services/context_srv'; import { Annotation } from 'app/features/alerting/unified/utils/constants'; import { isAlertingRule } from 'app/features/alerting/unified/utils/rules'; +import { AccessControlAction } from 'app/types'; import { PromAlertingRuleState, PromRulesResponse } from 'app/types/unified-alerting-dto'; import { DashboardQueryRunnerOptions, DashboardQueryRunnerWorker, DashboardQueryRunnerWorkerResult } from './types'; @@ -29,6 +31,14 @@ export class UnifiedAlertStatesWorker implements DashboardQueryRunnerWorker { return false; } + const hasRuleReadPermission = + contextSrv.hasPermission(AccessControlAction.AlertingRuleRead) && + contextSrv.hasPermission(AccessControlAction.AlertingRuleExternalRead); + + if (!hasRuleReadPermission) { + return false; + } + return true; } diff --git a/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx b/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx index da0feae77c7..194b7ceea09 100644 --- a/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx +++ b/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx @@ -4,7 +4,8 @@ import React, { useEffect, useMemo } from 'react'; import { useDispatch } from 'react-redux'; import { GrafanaTheme2, PanelProps } from '@grafana/data'; -import { CustomScrollbar, LoadingPlaceholder, useStyles2 } from '@grafana/ui'; +import { Alert, CustomScrollbar, LoadingPlaceholder, useStyles2 } from '@grafana/ui'; +import { contextSrv } from 'app/core/services/context_srv'; import alertDef from 'app/features/alerting/state/alertDef'; import { useUnifiedAlertingSelector } from 'app/features/alerting/unified/hooks/useUnifiedAlertingSelector'; import { fetchAllPromRulesAction } from 'app/features/alerting/unified/state/actions'; @@ -17,6 +18,7 @@ import { } from 'app/features/alerting/unified/utils/datasource'; import { flattenRules, getFirstActiveAt } from 'app/features/alerting/unified/utils/rules'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; +import { AccessControlAction } from 'app/types'; import { PromRuleWithLocation } from 'app/types/unified-alerting'; import { PromAlertingRuleState } from 'app/types/unified-alerting-dto'; @@ -60,6 +62,15 @@ export function UnifiedAlertList(props: PanelProps) { const noAlertsMessage = rules.length ? '' : 'No alerts'; + if ( + !contextSrv.hasPermission(AccessControlAction.AlertingRuleRead) && + !contextSrv.hasPermission(AccessControlAction.AlertingRuleExternalRead) + ) { + return ( + Sorry, you do not have the required permissions to read alert rules + ); + } + return (