Skip to content

Commit 4efc8e9

Browse files
peluja1012spong
authored andcommitted
[Security Solution][Exceptions] Exception modal bulk close option only closes alerts generated by same rule (#77402)
* Exception modal bulk close option only closes alerts generated by same rule * update modal text
1 parent b6be6e9 commit 4efc8e9

6 files changed

Lines changed: 52 additions & 18 deletions

File tree

x-pack/plugins/security_solution/public/common/components/exceptions/add_exception_modal/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,10 +309,11 @@ export const AddExceptionModal = memo(function AddExceptionModal({
309309
const alertIdToClose = shouldCloseAlert && alertData ? alertData.ecsData._id : undefined;
310310
const bulkCloseIndex =
311311
shouldBulkCloseAlert && signalIndexName !== null ? [signalIndexName] : undefined;
312-
addOrUpdateExceptionItems(enrichExceptionItems(), alertIdToClose, bulkCloseIndex);
312+
addOrUpdateExceptionItems(ruleId, enrichExceptionItems(), alertIdToClose, bulkCloseIndex);
313313
}
314314
}, [
315315
addOrUpdateExceptionItems,
316+
ruleId,
316317
enrichExceptionItems,
317318
shouldCloseAlert,
318319
shouldBulkCloseAlert,

x-pack/plugins/security_solution/public/common/components/exceptions/add_exception_modal/translations.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,15 @@ export const ENDPOINT_QUARANTINE_TEXT = i18n.translate(
6363
export const BULK_CLOSE_LABEL = i18n.translate(
6464
'xpack.securitySolution.exceptions.addException.bulkCloseLabel',
6565
{
66-
defaultMessage:
67-
'Close all alerts that match this exception, including alerts generated by other rules',
66+
defaultMessage: 'Close all alerts that match this exception and were generated by this rule',
6867
}
6968
);
7069

7170
export const BULK_CLOSE_LABEL_DISABLED = i18n.translate(
7271
'xpack.securitySolution.exceptions.addException.bulkCloseLabel.disabled',
7372
{
7473
defaultMessage:
75-
'Close all alerts that match attributes in this exception (Lists and non-ECS fields are not supported)',
74+
'Close all alerts that match this exception and were generated by this rule (Lists and non-ECS fields are not supported)',
7675
}
7776
);
7877

x-pack/plugins/security_solution/public/common/components/exceptions/edit_exception_modal/index.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,15 @@ export const EditExceptionModal = memo(function EditExceptionModal({
240240
if (addOrUpdateExceptionItems !== null) {
241241
const bulkCloseIndex =
242242
shouldBulkCloseAlert && signalIndexName !== null ? [signalIndexName] : undefined;
243-
addOrUpdateExceptionItems(enrichExceptionItems(), undefined, bulkCloseIndex);
243+
addOrUpdateExceptionItems(ruleId, enrichExceptionItems(), undefined, bulkCloseIndex);
244244
}
245-
}, [addOrUpdateExceptionItems, enrichExceptionItems, shouldBulkCloseAlert, signalIndexName]);
245+
}, [
246+
addOrUpdateExceptionItems,
247+
ruleId,
248+
enrichExceptionItems,
249+
shouldBulkCloseAlert,
250+
signalIndexName,
251+
]);
246252

247253
return (
248254
<EuiOverlayMask onClick={onCancel}>

x-pack/plugins/security_solution/public/common/components/exceptions/edit_exception_modal/translations.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,15 @@ export const EDIT_EXCEPTION_SUCCESS = i18n.translate(
4848
export const BULK_CLOSE_LABEL = i18n.translate(
4949
'xpack.securitySolution.exceptions.editException.bulkCloseLabel',
5050
{
51-
defaultMessage:
52-
'Close all alerts that match this exception, including alerts generated by other rules',
51+
defaultMessage: 'Close all alerts that match this exception and were generated by this rule',
5352
}
5453
);
5554

5655
export const BULK_CLOSE_LABEL_DISABLED = i18n.translate(
5756
'xpack.securitySolution.exceptions.editException.bulkCloseLabel.disabled',
5857
{
5958
defaultMessage:
60-
'Close all alerts that match attributes in this exception (Lists and non-ECS fields are not supported)',
59+
'Close all alerts that match this exception and were generated by this rule (Lists and non-ECS fields are not supported)',
6160
}
6261
);
6362

x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.test.tsx

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { KibanaServices } from '../../../common/lib/kibana';
1111
import * as alertsApi from '../../../detections/containers/detection_engine/alerts/api';
1212
import * as listsApi from '../../../../../lists/public/exceptions/api';
1313
import * as getQueryFilterHelper from '../../../../common/detection_engine/get_query_filter';
14-
import * as buildAlertStatusFilterHelper from '../../../detections/components/alerts_table/default_config';
14+
import * as buildFilterHelpers from '../../../detections/components/alerts_table/default_config';
1515
import { getExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_item_schema.mock';
1616
import { getCreateExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/request/create_exception_list_item_schema.mock';
1717
import { getUpdateExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/request/update_exception_list_item_schema.mock';
@@ -42,12 +42,16 @@ describe('useAddOrUpdateException', () => {
4242
>>;
4343
let getQueryFilter: jest.SpyInstance<ReturnType<typeof getQueryFilterHelper.getQueryFilter>>;
4444
let buildAlertStatusFilter: jest.SpyInstance<ReturnType<
45-
typeof buildAlertStatusFilterHelper.buildAlertStatusFilter
45+
typeof buildFilterHelpers.buildAlertStatusFilter
46+
>>;
47+
let buildAlertsRuleIdFilter: jest.SpyInstance<ReturnType<
48+
typeof buildFilterHelpers.buildAlertsRuleIdFilter
4649
>>;
4750
let addOrUpdateItemsArgs: Parameters<AddOrUpdateExceptionItemsFunc>;
4851
let render: () => RenderHookResult<UseAddOrUpdateExceptionProps, ReturnUseAddOrUpdateException>;
4952
const onError = jest.fn();
5053
const onSuccess = jest.fn();
54+
const ruleId = 'rule-id';
5155
const alertIdToClose = 'idToClose';
5256
const bulkCloseIndex = ['.custom'];
5357
const itemsToAdd: CreateExceptionListItemSchema[] = [
@@ -122,9 +126,11 @@ describe('useAddOrUpdateException', () => {
122126

123127
getQueryFilter = jest.spyOn(getQueryFilterHelper, 'getQueryFilter');
124128

125-
buildAlertStatusFilter = jest.spyOn(buildAlertStatusFilterHelper, 'buildAlertStatusFilter');
129+
buildAlertStatusFilter = jest.spyOn(buildFilterHelpers, 'buildAlertStatusFilter');
130+
131+
buildAlertsRuleIdFilter = jest.spyOn(buildFilterHelpers, 'buildAlertsRuleIdFilter');
126132

127-
addOrUpdateItemsArgs = [itemsToAddOrUpdate];
133+
addOrUpdateItemsArgs = [ruleId, itemsToAddOrUpdate];
128134
render = () =>
129135
renderHook<UseAddOrUpdateExceptionProps, ReturnUseAddOrUpdateException>(() =>
130136
useAddOrUpdateException({
@@ -247,7 +253,7 @@ describe('useAddOrUpdateException', () => {
247253

248254
describe('when alertIdToClose is passed in', () => {
249255
beforeEach(() => {
250-
addOrUpdateItemsArgs = [itemsToAddOrUpdate, alertIdToClose];
256+
addOrUpdateItemsArgs = [ruleId, itemsToAddOrUpdate, alertIdToClose];
251257
});
252258
it('should update the alert status', async () => {
253259
await act(async () => {
@@ -302,7 +308,7 @@ describe('useAddOrUpdateException', () => {
302308

303309
describe('when bulkCloseIndex is passed in', () => {
304310
beforeEach(() => {
305-
addOrUpdateItemsArgs = [itemsToAddOrUpdate, undefined, bulkCloseIndex];
311+
addOrUpdateItemsArgs = [ruleId, itemsToAddOrUpdate, undefined, bulkCloseIndex];
306312
});
307313
it('should update the status of only alerts that are open', async () => {
308314
await act(async () => {
@@ -320,6 +326,22 @@ describe('useAddOrUpdateException', () => {
320326
expect(buildAlertStatusFilter.mock.calls[0][0]).toEqual('open');
321327
});
322328
});
329+
it('should update the status of only alerts generated by the provided rule', async () => {
330+
await act(async () => {
331+
const { rerender, result, waitForNextUpdate } = render();
332+
const addOrUpdateItems = await waitForAddOrUpdateFunc({
333+
rerender,
334+
result,
335+
waitForNextUpdate,
336+
});
337+
if (addOrUpdateItems) {
338+
addOrUpdateItems(...addOrUpdateItemsArgs);
339+
}
340+
await waitForNextUpdate();
341+
expect(buildAlertsRuleIdFilter).toHaveBeenCalledTimes(1);
342+
expect(buildAlertsRuleIdFilter.mock.calls[0][0]).toEqual(ruleId);
343+
});
344+
});
323345
it('should generate the query filter using exceptions', async () => {
324346
await act(async () => {
325347
const { rerender, result, waitForNextUpdate } = render();

x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,25 @@ import {
1717
} from '../../../lists_plugin_deps';
1818
import { updateAlertStatus } from '../../../detections/containers/detection_engine/alerts/api';
1919
import { getUpdateAlertsQuery } from '../../../detections/components/alerts_table/actions';
20-
import { buildAlertStatusFilter } from '../../../detections/components/alerts_table/default_config';
20+
import {
21+
buildAlertStatusFilter,
22+
buildAlertsRuleIdFilter,
23+
} from '../../../detections/components/alerts_table/default_config';
2124
import { getQueryFilter } from '../../../../common/detection_engine/get_query_filter';
2225
import { Index } from '../../../../common/detection_engine/schemas/common/schemas';
2326
import { formatExceptionItemForUpdate, prepareExceptionItemsForBulkClose } from './helpers';
2427

2528
/**
2629
* Adds exception items to the list. Also optionally closes alerts.
2730
*
31+
* @param ruleId id of the rule where the exception updates will be applied
2832
* @param exceptionItemsToAddOrUpdate array of ExceptionListItemSchema to add or update
2933
* @param alertIdToClose - optional string representing alert to close
3034
* @param bulkCloseIndex - optional index used to create bulk close query
3135
*
3236
*/
3337
export type AddOrUpdateExceptionItemsFunc = (
38+
ruleId: string,
3439
exceptionItemsToAddOrUpdate: Array<ExceptionListItemSchema | CreateExceptionListItemSchema>,
3540
alertIdToClose?: string,
3641
bulkCloseIndex?: Index
@@ -63,9 +68,10 @@ export const useAddOrUpdateException = ({
6368
const [isLoading, setIsLoading] = useState(false);
6469
const addOrUpdateExceptionRef = useRef<AddOrUpdateExceptionItemsFunc | null>(null);
6570
const addOrUpdateException = useCallback<AddOrUpdateExceptionItemsFunc>(
66-
async (exceptionItemsToAddOrUpdate, alertIdToClose, bulkCloseIndex) => {
71+
async (ruleId, exceptionItemsToAddOrUpdate, alertIdToClose, bulkCloseIndex) => {
6772
if (addOrUpdateExceptionRef.current !== null) {
6873
addOrUpdateExceptionRef.current(
74+
ruleId,
6975
exceptionItemsToAddOrUpdate,
7076
alertIdToClose,
7177
bulkCloseIndex
@@ -117,6 +123,7 @@ export const useAddOrUpdateException = ({
117123
};
118124

119125
const addOrUpdateExceptionItems: AddOrUpdateExceptionItemsFunc = async (
126+
ruleId,
120127
exceptionItemsToAddOrUpdate,
121128
alertIdToClose,
122129
bulkCloseIndex
@@ -137,7 +144,7 @@ export const useAddOrUpdateException = ({
137144
const filter = getQueryFilter(
138145
'',
139146
'kuery',
140-
buildAlertStatusFilter('open'),
147+
[...buildAlertsRuleIdFilter(ruleId), ...buildAlertStatusFilter('open')],
141148
bulkCloseIndex,
142149
prepareExceptionItemsForBulkClose(exceptionItemsToAddOrUpdate),
143150
false

0 commit comments

Comments
 (0)