Skip to content

Commit

Permalink
disable "add endpoint exception" action from alert
Browse files Browse the repository at this point in the history
  • Loading branch information
ashokaditya committed Aug 11, 2023
1 parent 12dd2c1 commit 7f14fec
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ import { initialUserPrivilegesState as mockInitialUserPrivilegesState } from '..
import { useUserPrivileges } from '../../../../common/components/user_privileges';
import { TableId } from '@kbn/securitysolution-data-table';
import { TimelineId } from '../../../../../common/types/timeline';
import { useListsConfig } from '../../../containers/detection_engine/lists/use_lists_config';

jest.mock('../../../containers/detection_engine/lists/use_lists_config');

const mockUseHasSecurityCapability = jest.fn().mockReturnValue(false);
jest.mock('../../../../helper_hooks', () => ({
useHasSecurityCapability: () => mockUseHasSecurityCapability(),
}));

jest.mock('../../../../common/components/user_privileges');

Expand Down Expand Up @@ -98,6 +106,14 @@ const openAlertDetailsPageButton = '[data-test-subj="open-alert-details-page-men
const applyAlertTagsButton = '[data-test-subj="alert-tags-context-menu-item"]';

describe('Alert table context menu', () => {
beforeEach(() => {
(useListsConfig as jest.Mock).mockImplementation(() => ({
loading: false,
needsConfiguration: false,
}));
mockUseHasSecurityCapability.mockReturnValue(true);
});

describe('Case actions', () => {
test('it render AddToCase context menu item if timelineId === TimelineId.detectionsPage', () => {
const wrapper = mount(<AlertContextMenu {...props} scopeId={TableId.alertsOnAlertsPage} />, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { useSignalIndex } from '../../../containers/detection_engine/alerts/use_
import { EventFiltersFlyout } from '../../../../management/pages/event_filters/view/components/event_filters_flyout';
import { useAlertsActions } from './use_alerts_actions';
import { useExceptionFlyout } from './use_add_exception_flyout';
import { useExceptionActions } from './use_add_exception_actions';
import { useAlertExceptionActions } from './use_add_exception_actions';
import { useEventFilterModal } from './use_event_filter_modal';
import type { Status } from '../../../../../common/api/detection_engine';
import { ATTACH_ALERT_TO_CASE_FOR_ROW } from '../../../../timelines/components/timeline/body/translations';
Expand Down Expand Up @@ -195,7 +195,7 @@ const AlertContextMenuComponent: React.FC<AlertContextMenuProps & PropsFromRedux
closePopover();
}, [closePopover, onAddEventFilterClick]);

const { exceptionActionItems } = useExceptionActions({
const { exceptionActionItems } = useAlertExceptionActions({
isEndpointAlert: isAlertFromEndpointAlert({ ecsData: ecsRowData }),
onAddExceptionTypeClick: handleOnAddExceptionTypeClick,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import { useCallback, useMemo } from 'react';
import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types';

import { useListsConfig } from '../../../containers/detection_engine/lists/use_lists_config';
import { useUserData } from '../../user_info';
import { ACTION_ADD_ENDPOINT_EXCEPTION, ACTION_ADD_EXCEPTION } from '../translations';
import type { AlertTableContextMenuItem } from '../types';
import { useHasSecurityCapability } from '../../../../helper_hooks';

interface UseExceptionActionProps {
isEndpointAlert: boolean;
Expand Down Expand Up @@ -64,3 +66,37 @@ export const useExceptionActions = ({

return { exceptionActionItems };
};

export const useAlertExceptionActions = ({
isEndpointAlert,
onAddExceptionTypeClick,
}: UseExceptionActionProps) => {
const { exceptionActionItems } = useExceptionActions({
isEndpointAlert,
onAddExceptionTypeClick,
});

const { loading: listsConfigLoading, needsConfiguration: needsListsConfiguration } =
useListsConfig();
const canReadEndpointExceptions = useHasSecurityCapability('writeEndpointExceptions');

const canAccessRuleExceptions = useMemo(
() => !listsConfigLoading && !needsListsConfiguration && canReadEndpointExceptions,
[canReadEndpointExceptions, listsConfigLoading, needsListsConfiguration]
);
// Endpoint exceptions are available for:
// Serverless Endpoint Essentials/Complete PLI and
// on ESS Security Kibana sub-feature Endpoint Exceptions (enabled when Security feature is enabled)
if (canAccessRuleExceptions) {
return { exceptionActionItems };
}

return {
exceptionActionItems: exceptionActionItems.map((item) => {
if (item.name === ACTION_ADD_ENDPOINT_EXCEPTION) {
item.disabled = true;
}
return item;
}),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import type { TakeActionDropdownProps } from '.';
import { TakeActionDropdown } from '.';
import { generateAlertDetailsDataMock } from '../../../common/components/event_details/__mocks__';
import { getDetectionAlertMock } from '../../../common/mock/mock_detection_alerts';
import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy';
import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common';
import { TimelineId } from '../../../../common/types/timeline';
import { TestProviders } from '../../../common/mock';
import { mockTimelines } from '../../../common/mock/mock_timelines_plugin';
import { createStartServicesMock } from '../../../common/lib/kibana/kibana_react.mock';
import { useKibana, useGetUserCasesPermissions, useHttp } from '../../../common/lib/kibana';
import { useGetUserCasesPermissions, useHttp, useKibana } from '../../../common/lib/kibana';
import { mockCasesContract } from '@kbn/cases-plugin/public/mocks';
import { initialUserPrivilegesState as mockInitialUserPrivilegesState } from '../../../common/components/user_privileges/user_privileges_context';
import { useUserPrivileges } from '../../../common/components/user_privileges';
Expand All @@ -30,15 +30,17 @@ import {
import { endpointMetadataHttpMocks } from '../../../management/pages/endpoint_hosts/mocks';
import type { HttpSetup } from '@kbn/core/public';
import {
isAlertFromEndpointEvent,
isAlertFromEndpointAlert,
isAlertFromEndpointEvent,
} from '../../../common/utils/endpoint_alert_check';
import { getUserPrivilegesMockDefaultValue } from '../../../common/components/user_privileges/__mocks__';
import { allCasesPermissions } from '../../../cases_test_utils';
import { HostStatus } from '../../../../common/endpoint/types';
import { ENDPOINT_CAPABILITIES } from '../../../../common/endpoint/service/response_actions/constants';
import { ALERT_TAGS_CONTEXT_MENU_ITEM_TITLE } from '../../../common/components/toolbar/bulk_actions/translations';
import { useListsConfig } from '../../containers/detection_engine/lists/use_lists_config';

jest.mock('../../containers/detection_engine/lists/use_lists_config');
jest.mock('../../../common/components/user_privileges');

jest.mock('../user_info', () => ({
Expand Down Expand Up @@ -92,6 +94,11 @@ jest.mock('../../containers/detection_engine/alerts/use_host_isolation_status',

jest.mock('../../../common/components/user_privileges');

const mockUseHasSecurityCapability = jest.fn().mockReturnValue(false);
jest.mock('../../../helper_hooks', () => ({
useHasSecurityCapability: () => mockUseHasSecurityCapability(),
}));

describe('take action dropdown', () => {
let defaultProps: TakeActionDropdownProps;
let mockStartServicesMock: ReturnType<typeof createStartServicesMock>;
Expand Down Expand Up @@ -131,6 +138,12 @@ describe('take action dropdown', () => {
});

(useHttp as jest.Mock).mockReturnValue(mockStartServicesMock.http);

(useListsConfig as jest.Mock).mockImplementation(() => ({
loading: false,
needsConfiguration: false,
}));
mockUseHasSecurityCapability.mockReturnValue(true);
});

afterEach(() => {
Expand Down Expand Up @@ -206,6 +219,7 @@ describe('take action dropdown', () => {
).toEqual('Add Endpoint exception');
});
});

test('should render "Add rule exception"', async () => {
await waitFor(() => {
expect(wrapper.find('[data-test-subj="add-exception-menu-item"]').first().text()).toEqual(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import { EuiButton, EuiContextMenu, EuiPopover } from '@elastic/eui';
import type { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types';
import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs';
import { TableId } from '@kbn/securitysolution-data-table';
import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common';
import { GuidedOnboardingTourStep } from '../../../common/components/guided_onboarding_tour/tour_step';
import {
AlertsCasesTourSteps,
SecurityStepId,
} from '../../../common/components/guided_onboarding_tour/tour_config';
import { isActiveTimeline } from '../../../helpers';
import { useResponderActionItem } from '../endpoint_responder';
import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy';
import { TAKE_ACTION } from '../alerts_table/additional_filters_action/translations';
import { useExceptionActions } from '../alerts_table/timeline_actions/use_add_exception_actions';
import { useAlertExceptionActions } from '../alerts_table/timeline_actions/use_add_exception_actions';
import { useAlertsActions } from '../alerts_table/timeline_actions/use_alerts_actions';
import { useInvestigateInTimeline } from '../alerts_table/timeline_actions/use_investigate_in_timeline';

Expand Down Expand Up @@ -157,7 +157,7 @@ export const TakeActionDropdown = React.memo(
[onAddExceptionTypeClick]
);

const { exceptionActionItems } = useExceptionActions({
const { exceptionActionItems } = useAlertExceptionActions({
isEndpointAlert: isAlertFromEndpointAlert({ ecsData }),
onAddExceptionTypeClick: handleOnAddExceptionTypeClick,
});
Expand Down

0 comments on commit 7f14fec

Please sign in to comment.