diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.test.tsx index a0fa1f6683964..ecc4f7954460d 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.test.tsx @@ -160,11 +160,11 @@ describe('Alert table context menu', () => { ecsRowData: { ...ecsRowData, agent: { type: ['endpoint'] }, event: { kind: ['event'] } }, }; - describe('when users can access endpoint management', () => { + describe('when users has write event filters privilege', () => { beforeEach(() => { (useUserPrivileges as jest.Mock).mockReturnValue({ ...mockInitialUserPrivilegesState(), - endpointPrivileges: { loading: false, canAccessEndpointManagement: true }, + endpointPrivileges: { loading: false, canWriteEventFilters: true }, }); }); @@ -246,15 +246,15 @@ describe('Alert table context menu', () => { }); }); - describe('when users can NOT access endpoint management', () => { + describe("when users don't have write event filters privilege", () => { beforeEach(() => { (useUserPrivileges as jest.Mock).mockReturnValue({ ...mockInitialUserPrivilegesState(), - endpointPrivileges: { loading: false, canAccessEndpointManagement: false }, + endpointPrivileges: { loading: false, canWriteEventFilters: false }, }); }); - test('it disables AddEndpointEventFilter when timeline id is host events page but cannot acces endpoint management', () => { + test('it removes AddEndpointEventFilter option when timeline id is host events page but does not has write event filters privilege', () => { const wrapper = mount( , { @@ -262,12 +262,11 @@ describe('Alert table context menu', () => { } ); - wrapper.find(actionMenuButton).simulate('click'); - expect(wrapper.find(addEndpointEventFilterButton).first().exists()).toEqual(true); - expect(wrapper.find(addEndpointEventFilterButton).first().props().disabled).toEqual(true); + // Entire actionMenuButton is removed as there is no option available + expect(wrapper.find(actionMenuButton).first().exists()).toEqual(false); }); - test('it disables AddEndpointEventFilter when timeline id is user events page but cannot acces endpoint management', () => { + test('it removes AddEndpointEventFilter option when timeline id is user events page but does not has write event filters privilege', () => { const wrapper = mount( , { @@ -275,9 +274,8 @@ describe('Alert table context menu', () => { } ); - wrapper.find(actionMenuButton).simulate('click'); - expect(wrapper.find(addEndpointEventFilterButton).first().exists()).toEqual(true); - expect(wrapper.find(addEndpointEventFilterButton).first().props().disabled).toEqual(true); + // Entire actionMenuButton is removed as there is no option available + expect(wrapper.find(actionMenuButton).first().exists()).toEqual(false); }); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx index 31a548e2ced9c..9d8aac03daea3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx @@ -90,11 +90,11 @@ const AlertContextMenuComponent: React.FC !canAccessEndpointManagementLoading && canAccessEndpointManagement, - [canAccessEndpointManagement, canAccessEndpointManagementLoading] + () => !endpointPrivilegesLoading && canWriteEventFilters, + [canWriteEventFilters, endpointPrivilegesLoading] ); const alertStatus = get(0, ecsRowData?.kibana?.alert?.workflow_status) as Status | undefined; @@ -194,8 +194,7 @@ const AlertContextMenuComponent: React.FC { setAlertDetailsDataMockToEvent(); }); - test('should enable the "Add Endpoint event filter" button if provided endpoint event', async () => { + test('should enable the "Add Endpoint event filter" button if provided endpoint event and has right privileges', async () => { + (useUserPrivileges as jest.Mock).mockReturnValue({ + ...mockInitialUserPrivilegesState(), + endpointPrivileges: { loading: false, canWriteEventFilters: true }, + }); wrapper = mount( @@ -334,10 +338,10 @@ describe('take action dropdown', () => { }); }); - test('should disable the "Add Endpoint event filter" button if no endpoint management privileges', async () => { + test('should hide the "Add Endpoint event filter" button if no write event filters privileges', async () => { (useUserPrivileges as jest.Mock).mockReturnValue({ ...mockInitialUserPrivilegesState(), - endpointPrivileges: { loading: false, canAccessEndpointManagement: false }, + endpointPrivileges: { loading: false, canWriteEventFilters: false }, }); wrapper = mount( @@ -346,9 +350,7 @@ describe('take action dropdown', () => { ); wrapper.find('button[data-test-subj="take-action-dropdown-btn"]').simulate('click'); await waitFor(() => { - expect( - wrapper.find('[data-test-subj="add-event-filter-menu-item"]').first().getDOMNode() - ).toBeDisabled(); + expect(wrapper.exists('[data-test-subj="add-event-filter-menu-item"]')).toBeFalsy(); }); }); @@ -473,10 +475,10 @@ describe('take action dropdown', () => { }); }); - it('should not display the button if user is not allowed to manage endpoints', async () => { + it('should not display the button if user is not allowed to write event filters', async () => { (useUserPrivileges as jest.Mock).mockReturnValue({ ...mockInitialUserPrivilegesState(), - endpointPrivileges: { loading: false, canAccessEndpointManagement: false }, + endpointPrivileges: { loading: false, canWriteEventFilters: false }, }); render(); diff --git a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx index 059a1c0c4b64f..c5f33d34b1997 100644 --- a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx @@ -75,12 +75,12 @@ export const TakeActionDropdown = React.memo( scopeId, }: TakeActionDropdownProps) => { const tGridEnabled = useIsExperimentalFeatureEnabled('tGridEnabled'); - const { loading: canAccessEndpointManagementLoading, canAccessEndpointManagement } = + const { loading: endpointPrivilegesLoading, canWriteEventFilters } = useUserPrivileges().endpointPrivileges; const canCreateEndpointEventFilters = useMemo( - () => !canAccessEndpointManagementLoading && canAccessEndpointManagement, - [canAccessEndpointManagement, canAccessEndpointManagementLoading] + () => !endpointPrivilegesLoading && canWriteEventFilters, + [canWriteEventFilters, endpointPrivilegesLoading] ); const { osquery } = useKibana().services; @@ -168,7 +168,6 @@ export const TakeActionDropdown = React.memo( const { eventFilterActionItems } = useEventFilterAction({ onAddEventFilterClick: handleOnAddEventFilterClick, - disabled: !isEndpointEvent || !canCreateEndpointEventFilters, }); const onMenuItemClick = useCallback(() => { @@ -210,12 +209,13 @@ export const TakeActionDropdown = React.memo( () => !isEvent && actionsData.ruleId ? [...statusActionItems, ...exceptionActionItems] - : isEndpointEvent + : isEndpointEvent && canCreateEndpointEventFilters ? eventFilterActionItems : [], [ eventFilterActionItems, isEndpointEvent, + canCreateEndpointEventFilters, exceptionActionItems, statusActionItems, isEvent, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx index e34227f0bfe8f..dce89dc199d9e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx @@ -19,8 +19,11 @@ import { GuidedOnboardingTourStep, SecurityTourStep, } from '../../../../../common/components/guided_onboarding_tour/tour_step'; +import { initialUserPrivilegesState as mockInitialUserPrivilegesState } from '../../../../../common/components/user_privileges/user_privileges_context'; +import { useUserPrivileges } from '../../../../../common/components/user_privileges'; import { SecurityStepId } from '../../../../../common/components/guided_onboarding_tour/tour_config'; +jest.mock('../../../../../common/components/user_privileges'); jest.mock('../../../../../common/components/guided_onboarding_tour'); jest.mock('../../../../../detections/components/user_info', () => ({ useUserData: jest.fn().mockReturnValue([{ canUserCRUD: true, hasIndexWrite: true }]), @@ -268,6 +271,12 @@ describe('Actions', () => { }); describe('Alert context menu enabled?', () => { + beforeEach(() => { + (useUserPrivileges as jest.Mock).mockReturnValue({ + ...mockInitialUserPrivilegesState(), + endpointPrivileges: { loading: false, canWriteEventFilters: true }, + }); + }); test('it disables for eventType=raw', () => { const wrapper = mount(