Skip to content

Commit

Permalink
[Security Solution][Exceptions] - Exceptions modal pt 2 (#70886) (#71354
Browse files Browse the repository at this point in the history
)

* makes comment updates

* adds tests

* adds back non ecs data to timeline

* comments

* fixes jest tests

* fixes typo

Co-authored-by: Davis Plumlee <[email protected]>
  • Loading branch information
peluja1012 and dplumlee authored Jul 10, 2020
1 parent c37931c commit be75ab0
Show file tree
Hide file tree
Showing 11 changed files with 429 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
SetEventsLoadingProps,
UpdateTimelineLoading,
} from './types';
import { Ecs } from '../../../graphql/types';
import { Ecs, TimelineNonEcsData } from '../../../graphql/types';
import { AddExceptionOnClick } from '../../../common/components/exceptions/add_exception_modal';
import { getMappedNonEcsValue } from '../../../common/components/exceptions/helpers';

Expand Down Expand Up @@ -174,6 +174,8 @@ export const requiredFieldsForActions = [
'signal.rule.query',
'signal.rule.to',
'signal.rule.id',
'signal.original_event.kind',
'signal.original_event.module',

// Endpoint exception fields
'file.path',
Expand All @@ -189,6 +191,7 @@ interface AlertActionArgs {
createTimeline: CreateTimeline;
dispatch: Dispatch;
ecsRowData: Ecs;
nonEcsRowData: TimelineNonEcsData[];
hasIndexWrite: boolean;
onAlertStatusUpdateFailure: (status: Status, error: Error) => void;
onAlertStatusUpdateSuccess: (count: number, status: Status) => void;
Expand All @@ -211,6 +214,7 @@ export const getAlertActions = ({
createTimeline,
dispatch,
ecsRowData,
nonEcsRowData,
hasIndexWrite,
onAlertStatusUpdateFailure,
onAlertStatusUpdateSuccess,
Expand Down Expand Up @@ -281,6 +285,18 @@ export const getAlertActions = ({
width: DEFAULT_ICON_BUTTON_WIDTH,
};

const isEndpointAlert = () => {
const [module] = getMappedNonEcsValue({
data: nonEcsRowData,
fieldName: 'signal.original_event.module',
});
const [kind] = getMappedNonEcsValue({
data: nonEcsRowData,
fieldName: 'signal.original_event.kind',
});
return module === 'endpoint' && kind === 'alert';
};

return [
{
...getInvestigateInResolverAction({ dispatch, timelineId }),
Expand All @@ -305,15 +321,14 @@ export const getAlertActions = ({
...(FILTER_OPEN !== status ? [openAlertActionComponent] : []),
...(FILTER_CLOSED !== status ? [closeAlertActionComponent] : []),
...(FILTER_IN_PROGRESS !== status ? [inProgressAlertActionComponent] : []),
// TODO: disable this option if the alert is not an Endpoint alert
{
onClick: ({ ecsData, data }: TimelineRowActionOnClick) => {
const ruleNameValue = getMappedNonEcsValue({ data, fieldName: 'signal.rule.name' });
const ruleId = getMappedNonEcsValue({ data, fieldName: 'signal.rule.id' });
if (ruleId !== undefined && ruleId.length > 0) {
const [ruleName] = getMappedNonEcsValue({ data, fieldName: 'signal.rule.name' });
const [ruleId] = getMappedNonEcsValue({ data, fieldName: 'signal.rule.id' });
if (ruleId !== undefined) {
openAddExceptionModal({
ruleName: ruleNameValue ? ruleNameValue[0] : '',
ruleId: ruleId[0],
ruleName: ruleName ?? '',
ruleId,
exceptionListType: 'endpoint',
alertData: {
ecsData,
Expand All @@ -323,20 +338,20 @@ export const getAlertActions = ({
}
},
id: 'addEndpointException',
isActionDisabled: () => !canUserCRUD || !hasIndexWrite,
isActionDisabled: () => !canUserCRUD || !hasIndexWrite || !isEndpointAlert(),
dataTestSubj: 'add-endpoint-exception-menu-item',
ariaLabel: 'Add Endpoint Exception',
content: <EuiText size="m">{i18n.ACTION_ADD_ENDPOINT_EXCEPTION}</EuiText>,
displayType: 'contextMenu',
},
{
onClick: ({ ecsData, data }: TimelineRowActionOnClick) => {
const ruleNameValue = getMappedNonEcsValue({ data, fieldName: 'signal.rule.name' });
const ruleId = getMappedNonEcsValue({ data, fieldName: 'signal.rule.id' });
if (ruleId !== undefined && ruleId.length > 0) {
const [ruleName] = getMappedNonEcsValue({ data, fieldName: 'signal.rule.name' });
const [ruleId] = getMappedNonEcsValue({ data, fieldName: 'signal.rule.id' });
if (ruleId !== undefined) {
openAddExceptionModal({
ruleName: ruleNameValue ? ruleNameValue[0] : '',
ruleId: ruleId[0],
ruleName: ruleName ?? '',
ruleId,
exceptionListType: 'detection',
alertData: {
ecsData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ import { inputsSelectors, State, inputsModel } from '../../../common/store';
import { timelineActions, timelineSelectors } from '../../../timelines/store/timeline';
import { TimelineModel } from '../../../timelines/store/timeline/model';
import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
import { useManageTimeline } from '../../../timelines/components/manage_timeline';
import {
useManageTimeline,
TimelineRowActionArgs,
} from '../../../timelines/components/manage_timeline';
import { useApolloClient } from '../../../common/utils/apollo_context';

import { updateAlertStatusAction } from './actions';
Expand All @@ -48,7 +51,6 @@ import {
displaySuccessToast,
displayErrorToast,
} from '../../../common/components/toasters';
import { Ecs } from '../../../graphql/types';
import { getInvestigateInResolverAction } from '../../../timelines/components/timeline/body/helpers';
import {
AddExceptionModal,
Expand Down Expand Up @@ -321,12 +323,13 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({

// Send to Timeline / Update Alert Status Actions for each table row
const additionalActions = useMemo(
() => (ecsRowData: Ecs) =>
() => ({ ecsData, nonEcsData }: TimelineRowActionArgs) =>
getAlertActions({
apolloClient,
canUserCRUD,
createTimeline: createTimelineCallback,
ecsRowData,
ecsRowData: ecsData,
nonEcsRowData: nonEcsData,
dispatch,
hasIndexWrite,
onAlertStatusUpdateFailure,
Expand Down Expand Up @@ -401,9 +404,12 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
closeAddExceptionModal();
}, [closeAddExceptionModal]);

const onAddExceptionConfirm = useCallback(() => {
closeAddExceptionModal();
}, [closeAddExceptionModal]);
const onAddExceptionConfirm = useCallback(
(didCloseAlert: boolean) => {
closeAddExceptionModal();
},
[closeAddExceptionModal]
);

if (loading || isEmpty(signalsIndex)) {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
defaultEndpointExceptionItems,
entryHasListType,
entryHasNonEcsType,
getMappedNonEcsValue,
} from '../helpers';
import { useFetchIndexPatterns } from '../../../../alerts/containers/detection_engine/rules';

Expand All @@ -65,7 +66,7 @@ interface AddExceptionModalProps {
nonEcsData: TimelineNonEcsData[];
};
onCancel: () => void;
onConfirm: () => void;
onConfirm: (didCloseAlert: boolean) => void;
}

const Modal = styled(EuiModal)`
Expand Down Expand Up @@ -130,8 +131,8 @@ export const AddExceptionModal = memo(function AddExceptionModal({
);
const onSuccess = useCallback(() => {
displaySuccessToast(i18n.ADD_EXCEPTION_SUCCESS, dispatchToaster);
onConfirm();
}, [dispatchToaster, onConfirm]);
onConfirm(shouldCloseAlert);
}, [dispatchToaster, onConfirm, shouldCloseAlert]);

const [{ isLoading: addExceptionIsLoading }, addOrUpdateExceptionItems] = useAddOrUpdateException(
{
Expand Down Expand Up @@ -193,6 +194,12 @@ export const AddExceptionModal = memo(function AddExceptionModal({
indexPatterns,
]);

useEffect(() => {
if (shouldDisableBulkClose === true) {
setShouldBulkCloseAlert(false);
}
}, [shouldDisableBulkClose]);

const onCommentChange = useCallback(
(value: string) => {
setComment(value);
Expand All @@ -214,18 +221,33 @@ export const AddExceptionModal = memo(function AddExceptionModal({
[setShouldBulkCloseAlert]
);

const retrieveAlertOsTypes = useCallback(() => {
const osDefaults = ['windows', 'macos', 'linux'];
if (alertData) {
const osTypes = getMappedNonEcsValue({
data: alertData.nonEcsData,
fieldName: 'host.os.family',
});
if (osTypes.length === 0) {
return osDefaults;
}
return osTypes;
}
return osDefaults;
}, [alertData]);

const enrichExceptionItems = useCallback(() => {
let enriched: Array<ExceptionListItemSchema | CreateExceptionListItemSchema> = [];
enriched =
comment !== ''
? enrichExceptionItemsWithComments(exceptionItemsToAdd, [{ comment }])
: exceptionItemsToAdd;
if (exceptionListType === 'endpoint') {
const osTypes = alertData ? ['windows'] : ['windows', 'macos', 'linux'];
const osTypes = retrieveAlertOsTypes();
enriched = enrichExceptionItemsWithOS(enriched, osTypes);
}
return enriched;
}, [comment, exceptionItemsToAdd, exceptionListType, alertData]);
}, [comment, exceptionItemsToAdd, exceptionListType, retrieveAlertOsTypes]);

const onAddExceptionConfirm = useCallback(() => {
if (addOrUpdateExceptionItems !== null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { AddExceptionComments } from '../add_exception_comments';
import {
enrichExceptionItemsWithComments,
enrichExceptionItemsWithOS,
getOsTagValues,
getOperatingSystems,
entryHasListType,
entryHasNonEcsType,
} from '../helpers';
Expand Down Expand Up @@ -135,6 +135,12 @@ export const EditExceptionModal = memo(function EditExceptionModal({
indexPatterns,
]);

useEffect(() => {
if (shouldDisableBulkClose === true) {
setShouldBulkCloseAlert(false);
}
}, [shouldDisableBulkClose]);

const handleBuilderOnChange = useCallback(
({
exceptionItems,
Expand Down Expand Up @@ -167,7 +173,7 @@ export const EditExceptionModal = memo(function EditExceptionModal({
...(comment !== '' ? [{ comment }] : []),
]);
if (exceptionListType === 'endpoint') {
const osTypes = exceptionItem._tags ? getOsTagValues(exceptionItem._tags) : ['windows'];
const osTypes = exceptionItem._tags ? getOperatingSystems(exceptionItem._tags) : [];
enriched = enrichExceptionItemsWithOS(enriched, osTypes);
}
return enriched;
Expand Down Expand Up @@ -199,6 +205,8 @@ export const EditExceptionModal = memo(function EditExceptionModal({
{!isSignalIndexLoading && (
<>
<ModalBodySection className="builder-section">
<EuiText>{i18n.EXCEPTION_BUILDER_INFO}</EuiText>
<EuiSpacer />
<ExceptionBuilder
exceptionListItems={[exceptionItem]}
listType={exceptionListType}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const ENDPOINT_QUARANTINE_TEXT = i18n.translate(
);

export const EXCEPTION_BUILDER_INFO = i18n.translate(
'xpack.securitySolution.exceptions.addException.infoLabel',
'xpack.securitySolution.exceptions.editException.infoLabel',
{
defaultMessage: "Alerts are generated when the rule's conditions are met, except when:",
}
Expand Down
Loading

0 comments on commit be75ab0

Please sign in to comment.