diff --git a/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_tags_items.test.tsx b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_tags_items.test.tsx index 3cbc54cf24f12..c49e1cf133dd4 100644 --- a/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_tags_items.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_tags_items.test.tsx @@ -19,6 +19,12 @@ import { useUiSetting$ } from '../../../lib/kibana'; jest.mock('./use_set_alert_tags'); jest.mock('../../../lib/kibana'); +jest.mock( + '../../../../detections/containers/detection_engine/alerts/use_alerts_privileges', + () => ({ + useAlertsPrivileges: jest.fn().mockReturnValue({ hasIndexWrite: true }), + }) +); const defaultProps: UseBulkAlertTagsItemsProps = { refetch: () => {}, diff --git a/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_tags_items.tsx b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_tags_items.tsx index df4d5c37aeeaf..977cb0bf8b315 100644 --- a/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_tags_items.tsx +++ b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_tags_items.tsx @@ -8,6 +8,7 @@ import { EuiFlexGroup, EuiIconTip, EuiFlexItem } from '@elastic/eui'; import type { RenderContentPanelProps } from '@kbn/triggers-actions-ui-plugin/public/types'; import React, { useCallback, useMemo } from 'react'; +import { useAlertsPrivileges } from '../../../../detections/containers/detection_engine/alerts/use_alerts_privileges'; import { BulkAlertTagsPanel } from './alert_bulk_tags'; import * as i18n from './translations'; import { useSetAlertTags } from './use_set_alert_tags'; @@ -24,6 +25,7 @@ export interface UseBulkAlertTagsPanel { } export const useBulkAlertTagsItems = ({ refetch }: UseBulkAlertTagsItemsProps) => { + const { hasIndexWrite } = useAlertsPrivileges(); const setAlertTags = useSetAlertTags(); const handleOnAlertTagsSubmit = useCallback( async (tags, ids, onSuccess, setIsLoading) => { @@ -34,16 +36,22 @@ export const useBulkAlertTagsItems = ({ refetch }: UseBulkAlertTagsItemsProps) = [setAlertTags] ); - const alertTagsItems = [ - { - key: 'manage-alert-tags', - 'data-test-subj': 'alert-tags-context-menu-item', - name: i18n.ALERT_TAGS_CONTEXT_MENU_ITEM_TITLE, - panel: 1, - label: i18n.ALERT_TAGS_CONTEXT_MENU_ITEM_TITLE, - disableOnQuery: true, - }, - ]; + const alertTagsItems = useMemo( + () => + hasIndexWrite + ? [ + { + key: 'manage-alert-tags', + 'data-test-subj': 'alert-tags-context-menu-item', + name: i18n.ALERT_TAGS_CONTEXT_MENU_ITEM_TITLE, + panel: 1, + label: i18n.ALERT_TAGS_CONTEXT_MENU_ITEM_TITLE, + disableOnQuery: true, + }, + ] + : [], + [hasIndexWrite] + ); const TitleContent = useMemo( () => ( @@ -79,15 +87,18 @@ export const useBulkAlertTagsItems = ({ refetch }: UseBulkAlertTagsItemsProps) = ); const alertTagsPanels: UseBulkAlertTagsPanel[] = useMemo( - () => [ - { - id: 1, - title: TitleContent, - 'data-test-subj': 'alert-tags-context-menu-panel', - renderContent, - }, - ], - [TitleContent, renderContent] + () => + hasIndexWrite + ? [ + { + id: 1, + title: TitleContent, + 'data-test-subj': 'alert-tags-context-menu-panel', + renderContent, + }, + ] + : [], + [TitleContent, hasIndexWrite, renderContent] ); return { diff --git a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_alert_actions.tsx b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_alert_actions.tsx index 5ac7628f5376f..decc2cb159b5c 100644 --- a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_alert_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_alert_actions.tsx @@ -19,6 +19,7 @@ import type { AlertWorkflowStatus } from '../../../common/types'; import { FILTER_CLOSED, FILTER_OPEN, FILTER_ACKNOWLEDGED } from '../../../../common/types'; import * as i18n from '../translations'; import { buildTimeRangeFilter } from '../../components/alerts_table/helpers'; +import { useAlertsPrivileges } from '../../containers/detection_engine/alerts/use_alerts_privileges'; interface UseBulkAlertActionItemsArgs { /* Table ID for which this hook is being used */ @@ -41,6 +42,7 @@ export const useBulkAlertActionItems = ({ to, refetch: refetchProp, }: UseBulkAlertActionItemsArgs) => { + const { hasIndexWrite } = useAlertsPrivileges(); const { startTransaction } = useStartTransaction(); const { addSuccess, addError, addWarning } = useAppToasts(); @@ -172,7 +174,9 @@ export const useBulkAlertActionItems = ({ [getOnAction] ); - return [FILTER_OPEN, FILTER_CLOSED, FILTER_ACKNOWLEDGED].map((status) => - getUpdateAlertStatusAction(status as AlertWorkflowStatus) - ); + return hasIndexWrite + ? [FILTER_OPEN, FILTER_CLOSED, FILTER_ACKNOWLEDGED].map((status) => + getUpdateAlertStatusAction(status as AlertWorkflowStatus) + ) + : []; }; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts index ca90e9b72efd1..c55c8f62dc4a9 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts @@ -5,8 +5,16 @@ * 2.0. */ +import { ROLES } from '@kbn/security-solution-plugin/common/test'; import { getNewRule } from '../../../objects/rule'; -import { ALERTS_COUNT, SELECTED_ALERTS } from '../../../screens/alerts'; +import { + ALERTS_COUNT, + CLOSE_SELECTED_ALERTS_BTN, + MARK_ALERT_ACKNOWLEDGED_BTN, + SELECTED_ALERTS, + TAKE_ACTION_POPOVER_BTN, + TIMELINE_CONTEXT_MENU_BTN, +} from '../../../screens/alerts'; import { selectNumberOfAlerts, @@ -30,12 +38,12 @@ import { visit } from '../../../tasks/navigation'; import { ALERTS_URL } from '../../../urls/navigation'; // FLAKY: https://github.com/elastic/kibana/issues/169091 -describe('Changing alert status', { tags: ['@ess', '@serverless'] }, () => { +describe('Changing alert status', () => { before(() => { cy.task('esArchiverLoad', { archiveName: 'auditbeat_big' }); }); - context('Opening alerts', () => { + context('Opening alerts', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { login(); deleteAlertsAndRules(); @@ -116,7 +124,7 @@ describe('Changing alert status', { tags: ['@ess', '@serverless'] }, () => { }); }); - context('Marking alerts as acknowledged', () => { + context('Marking alerts as acknowledged', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { login(); deleteAlertsAndRules(); @@ -167,7 +175,7 @@ describe('Changing alert status', { tags: ['@ess', '@serverless'] }, () => { }); }); - context('Closing alerts', () => { + context('Closing alerts', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { login(); deleteAlertsAndRules(); @@ -228,4 +236,32 @@ describe('Changing alert status', { tags: ['@ess', '@serverless'] }, () => { }); }); }); + + // This test is unable to be run in serverless as `reader` is not available and viewer is currently reserved + // https://github.com/elastic/kibana/pull/169723#issuecomment-1793191007 + // https://github.com/elastic/kibana/issues/170583 + context('User is readonly', { tags: ['@ess', '@brokenInServerless'] }, () => { + beforeEach(() => { + login(); + visit(ALERTS_URL); + deleteAlertsAndRules(); + createRule(getNewRule()); + login(ROLES.reader); + visit(ALERTS_URL, { role: ROLES.reader }); + waitForAlertsToPopulate(); + }); + it('should not allow users to change a single alert status', () => { + // This is due to the reader role which makes everything in security 'read only' + cy.get(TIMELINE_CONTEXT_MENU_BTN).should('not.exist'); + }); + + it('should not allow users to bulk change the alert status', () => { + selectNumberOfAlerts(2); + cy.get(TAKE_ACTION_POPOVER_BTN).first().click(); + cy.get(TAKE_ACTION_POPOVER_BTN).should('be.visible'); + + cy.get(CLOSE_SELECTED_ALERTS_BTN).should('not.exist'); + cy.get(MARK_ALERT_ACKNOWLEDGED_BTN).should('not.exist'); + }); + }); });