Skip to content

Commit 0997040

Browse files
authored
[Security Solution][Detections] Fixes bulk alert status update to only update alerts within the defined daterange (#82071) (#82541)
## Summary Addresses #82004 where updating an alerts status would result in all alerts being updated as the request is sent without the necessary daterange filter. ##### Before: <details><summary>Query</summary> <p> ``` json { "conflicts": "proceed", "status": "open", "query": { "bool": { "must": [], "filter": [ { "match_all": {} }, { "term": { "signal.status": "closed" } } ], "should": [], "must_not": [ { "exists": { "field": "signal.rule.building_block_type" } } ] } } } ``` </p> </details> <p align="center"> <img width="500" src="https://user-images.githubusercontent.com/2946766/97628470-5db73580-19f2-11eb-8e51-61e428e7804f.gif" /> </p> ##### After: <details><summary>Query</summary> <p> ``` json { "conflicts": "proceed", "status": "closed", "query": { "bool": { "must": [], "filter": [ { "bool": { "filter": [ { "bool": { "should": [ { "range": { "@timestamp": { "gte": "2020-10-29T20:17:23.357Z" } } } ], "minimum_should_match": 1 } }, { "bool": { "should": [ { "range": { "@timestamp": { "lte": "2020-10-29T20:17:40.097Z" } } } ], "minimum_should_match": 1 } } ] } }, { "term": { "signal.status": "open" } } ], "should": [], "must_not": [ { "exists": { "field": "signal.rule.building_block_type" } } ] } } } ``` </p> </details> <p align="center"> <img width="500" src="https://user-images.githubusercontent.com/2946766/97628955-0796c200-19f3-11eb-9ec3-2a6ace17160b.gif" /> </p> ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
1 parent 9571427 commit 0997040

File tree

9 files changed

+79
-56
lines changed

9 files changed

+79
-56
lines changed

x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,6 @@ const EventsViewerComponent: React.FC<Props> = ({
177177
filters,
178178
kqlQuery: query,
179179
kqlMode,
180-
start,
181-
end,
182180
isEventViewer: true,
183181
});
184182

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

-2
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,13 @@ const StatefulTopNComponent: React.FC<Props> = ({
117117
browserFields,
118118
config: esQuery.getEsQueryConfig(kibana.services.uiSettings),
119119
dataProviders,
120-
end: activeTimelineTo,
121120
filters: activeTimelineFilters,
122121
indexPattern,
123122
kqlMode,
124123
kqlQuery: {
125124
language: 'kuery',
126125
query: activeTimelineKqlQueryExpression ?? '',
127126
},
128-
start: activeTimelineFrom,
129127
})?.filterQuery
130128
: undefined
131129
}

x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ const AlertsUtilityBarComponent: React.FC<AlertsUtilityBarProps> = ({
195195
</UtilityBarAction>
196196

197197
<UtilityBarAction
198+
aria-label="selectAllAlerts"
199+
dataTestSubj="selectAllAlertsButton"
198200
iconType={showClearSelection ? 'cross' : 'pagesSelect'}
199201
onClick={() => {
200202
if (!showClearSelection) {

x-pack/plugins/security_solution/public/detections/components/alerts_table/helpers.test.ts

+36-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
import { TimelineType } from '../../../../common/types/timeline';
8-
import { Filter } from '../../../../../../../src/plugins/data/public';
8+
import { esFilters, Filter } from '../../../../../../../src/plugins/data/public';
99
import {
1010
DataProvider,
1111
DataProviderType,
@@ -17,6 +17,7 @@ import {
1717
replaceTemplateFieldFromQuery,
1818
replaceTemplateFieldFromMatchFilters,
1919
reformatDataProviderWithNewValue,
20+
buildTimeRangeFilter,
2021
} from './helpers';
2122
import { mockTimelineDetails } from '../../../common/mock';
2223

@@ -530,4 +531,38 @@ describe('helpers', () => {
530531
});
531532
});
532533
});
534+
535+
describe('buildTimeRangeFilter', () => {
536+
test('time range filter is created with from and to', () => {
537+
const from = '2020-10-29T21:06:10.192Z';
538+
const to = '2020-10-29T21:07:38.774Z';
539+
const timeRangeFilter = buildTimeRangeFilter(from, to);
540+
expect(timeRangeFilter).toEqual([
541+
{
542+
range: {
543+
'@timestamp': {
544+
gte: '2020-10-29T21:06:10.192Z',
545+
lt: '2020-10-29T21:07:38.774Z',
546+
format: 'strict_date_optional_time',
547+
},
548+
},
549+
meta: {
550+
type: 'range',
551+
disabled: false,
552+
negate: false,
553+
alias: null,
554+
key: '@timestamp',
555+
params: {
556+
gte: from,
557+
lt: to,
558+
format: 'strict_date_optional_time',
559+
},
560+
},
561+
$state: {
562+
store: esFilters.FilterStateStore.APP_STATE,
563+
},
564+
},
565+
]);
566+
});
567+
});
533568
});

x-pack/plugins/security_solution/public/detections/components/alerts_table/helpers.ts

+33-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
*/
66

77
import { isEmpty } from 'lodash/fp';
8-
import { Filter, esKuery, KueryNode } from '../../../../../../../src/plugins/data/public';
8+
import {
9+
Filter,
10+
esKuery,
11+
KueryNode,
12+
esFilters,
13+
} from '../../../../../../../src/plugins/data/public';
914
import {
1015
DataProvider,
1116
DataProviderType,
@@ -214,3 +219,30 @@ export const replaceTemplateFieldFromDataProviders = (
214219
}
215220
return newDataProvider;
216221
});
222+
223+
export const buildTimeRangeFilter = (from: string, to: string): Filter[] => [
224+
{
225+
range: {
226+
'@timestamp': {
227+
gte: from,
228+
lt: to,
229+
format: 'strict_date_optional_time',
230+
},
231+
},
232+
meta: {
233+
type: 'range',
234+
disabled: false,
235+
negate: false,
236+
alias: null,
237+
key: '@timestamp',
238+
params: {
239+
gte: from,
240+
lt: to,
241+
format: 'strict_date_optional_time',
242+
},
243+
},
244+
$state: {
245+
store: esFilters.FilterStateStore.APP_STATE,
246+
},
247+
} as Filter,
248+
];

x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx

+7-5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import {
4646
} from '../../../common/components/toasters';
4747
import { SourcererScopeName } from '../../../common/store/sourcerer/model';
4848
import { useSourcererScope } from '../../../common/containers/sourcerer';
49+
import { buildTimeRangeFilter } from './helpers';
4950

5051
interface OwnProps {
5152
timelineId: TimelineIdLiteral;
@@ -105,13 +106,14 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
105106
dataProviders: [],
106107
indexPattern: indexPatterns,
107108
browserFields,
108-
filters: isEmpty(defaultFilters)
109-
? [...globalFilters, ...customFilters]
110-
: [...(defaultFilters ?? []), ...globalFilters, ...customFilters],
109+
filters: [
110+
...(defaultFilters ?? []),
111+
...globalFilters,
112+
...customFilters,
113+
...buildTimeRangeFilter(from, to),
114+
],
111115
kqlQuery: globalQuery,
112116
kqlMode: globalQuery.language,
113-
start: from,
114-
end: to,
115117
isEventViewer: true,
116118
});
117119
}

x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.test.tsx

-28
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ import { mockBrowserFields } from '../../../common/containers/source/mock';
1414
import { EsQueryConfig, Filter, esFilters } from '../../../../../../../src/plugins/data/public';
1515

1616
const cleanUpKqlQuery = (str: string) => str.replace(/\n/g, '').replace(/\s\s+/g, ' ');
17-
const startDate = '2018-03-23T18:49:23.132Z';
18-
const endDate = '2018-03-24T03:33:52.253Z';
1917

2018
describe('Build KQL Query', () => {
2119
test('Build KQL query with one data provider', () => {
@@ -238,8 +236,6 @@ describe('Combined Queries', () => {
238236
filters: [],
239237
kqlQuery: { query: '', language: 'kuery' },
240238
kqlMode: 'search',
241-
start: startDate,
242-
end: endDate,
243239
})
244240
).toBeNull();
245241
});
@@ -255,8 +251,6 @@ describe('Combined Queries', () => {
255251
filters: [],
256252
kqlQuery: { query: '', language: 'kuery' },
257253
kqlMode: 'search',
258-
start: startDate,
259-
end: endDate,
260254
isEventViewer,
261255
})
262256
).toEqual({
@@ -300,8 +294,6 @@ describe('Combined Queries', () => {
300294
],
301295
kqlQuery: { query: '', language: 'kuery' },
302296
kqlMode: 'search',
303-
start: startDate,
304-
end: endDate,
305297
isEventViewer,
306298
})
307299
).toEqual({
@@ -320,8 +312,6 @@ describe('Combined Queries', () => {
320312
filters: [],
321313
kqlQuery: { query: '', language: 'kuery' },
322314
kqlMode: 'search',
323-
start: startDate,
324-
end: endDate,
325315
})!;
326316
expect(filterQuery).toEqual(
327317
'{"bool":{"must":[],"filter":[{"bool":{"should":[{"match_phrase":{"name":"Provider 1"}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}'
@@ -340,8 +330,6 @@ describe('Combined Queries', () => {
340330
filters: [],
341331
kqlQuery: { query: '', language: 'kuery' },
342332
kqlMode: 'search',
343-
start: startDate,
344-
end: endDate,
345333
})!;
346334
expect(filterQuery).toEqual(
347335
'{"bool":{"must":[],"filter":[{"bool":{"should":[{"range":{"@timestamp":{"gte":1521848183232,"lte":1521848183232}}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}'
@@ -360,8 +348,6 @@ describe('Combined Queries', () => {
360348
filters: [],
361349
kqlQuery: { query: '', language: 'kuery' },
362350
kqlMode: 'search',
363-
start: startDate,
364-
end: endDate,
365351
})!;
366352
expect(filterQuery).toEqual(
367353
'{"bool":{"must":[],"filter":[{"bool":{"should":[{"range":{"@timestamp":{"gte":1521848183232,"lte":1521848183232}}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}'
@@ -380,8 +366,6 @@ describe('Combined Queries', () => {
380366
filters: [],
381367
kqlQuery: { query: '', language: 'kuery' },
382368
kqlMode: 'search',
383-
start: startDate,
384-
end: endDate,
385369
})!;
386370
expect(filterQuery).toEqual(
387371
'{"bool":{"must":[],"filter":[{"bool":{"should":[{"match":{"event.end":1521848183232}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}'
@@ -400,8 +384,6 @@ describe('Combined Queries', () => {
400384
filters: [],
401385
kqlQuery: { query: '', language: 'kuery' },
402386
kqlMode: 'search',
403-
start: startDate,
404-
end: endDate,
405387
})!;
406388
expect(filterQuery).toEqual(
407389
'{"bool":{"must":[],"filter":[{"bool":{"should":[{"match":{"event.end":1521848183232}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}'
@@ -417,8 +399,6 @@ describe('Combined Queries', () => {
417399
filters: [],
418400
kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' },
419401
kqlMode: 'search',
420-
start: startDate,
421-
end: endDate,
422402
})!;
423403
expect(filterQuery).toEqual(
424404
'{"bool":{"must":[],"filter":[{"bool":{"should":[{"match_phrase":{"host.name":"host-1"}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}'
@@ -435,8 +415,6 @@ describe('Combined Queries', () => {
435415
filters: [],
436416
kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' },
437417
kqlMode: 'search',
438-
start: startDate,
439-
end: endDate,
440418
})!;
441419
expect(filterQuery).toEqual(
442420
'{"bool":{"must":[],"filter":[{"bool":{"should":[{"bool":{"should":[{"match_phrase":{"name":"Provider 1"}}],"minimum_should_match":1}},{"bool":{"should":[{"match_phrase":{"host.name":"host-1"}}],"minimum_should_match":1}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}'
@@ -453,8 +431,6 @@ describe('Combined Queries', () => {
453431
filters: [],
454432
kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' },
455433
kqlMode: 'filter',
456-
start: startDate,
457-
end: endDate,
458434
})!;
459435
expect(filterQuery).toEqual(
460436
'{"bool":{"must":[],"filter":[{"bool":{"filter":[{"bool":{"should":[{"match_phrase":{"name":"Provider 1"}}],"minimum_should_match":1}},{"bool":{"should":[{"match_phrase":{"host.name":"host-1"}}],"minimum_should_match":1}}]}}],"should":[],"must_not":[]}}'
@@ -473,8 +449,6 @@ describe('Combined Queries', () => {
473449
filters: [],
474450
kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' },
475451
kqlMode: 'search',
476-
start: startDate,
477-
end: endDate,
478452
})!;
479453
expect(filterQuery).toEqual(
480454
'{"bool":{"must":[],"filter":[{"bool":{"should":[{"bool":{"should":[{"bool":{"filter":[{"bool":{"should":[{"match_phrase":{"name":"Provider 1"}}],"minimum_should_match":1}},{"bool":{"filter":[{"bool":{"should":[{"match_phrase":{"name":"Provider 3"}}],"minimum_should_match":1}},{"bool":{"should":[{"match_phrase":{"name":"Provider 4"}}],"minimum_should_match":1}}]}}]}},{"bool":{"filter":[{"bool":{"should":[{"match_phrase":{"name":"Provider 2"}}],"minimum_should_match":1}},{"bool":{"should":[{"match_phrase":{"name":"Provider 5"}}],"minimum_should_match":1}}]}}],"minimum_should_match":1}},{"bool":{"should":[{"match_phrase":{"host.name":"host-1"}}],"minimum_should_match":1}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}'
@@ -493,8 +467,6 @@ describe('Combined Queries', () => {
493467
filters: [],
494468
kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' },
495469
kqlMode: 'filter',
496-
start: startDate,
497-
end: endDate,
498470
})!;
499471
expect(filterQuery).toEqual(
500472
'{"bool":{"must":[],"filter":[{"bool":{"filter":[{"bool":{"should":[{"bool":{"filter":[{"bool":{"should":[{"match_phrase":{"name":"Provider 1"}}],"minimum_should_match":1}},{"bool":{"filter":[{"bool":{"should":[{"match_phrase":{"name":"Provider 3"}}],"minimum_should_match":1}},{"bool":{"should":[{"match_phrase":{"name":"Provider 4"}}],"minimum_should_match":1}}]}}]}},{"bool":{"filter":[{"bool":{"should":[{"match_phrase":{"name":"Provider 2"}}],"minimum_should_match":1}},{"bool":{"should":[{"match_phrase":{"name":"Provider 5"}}],"minimum_should_match":1}}]}}],"minimum_should_match":1}},{"bool":{"should":[{"match_phrase":{"host.name":"host-1"}}],"minimum_should_match":1}}]}}],"should":[],"must_not":[]}}'

x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx

-4
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,6 @@ export const combineQueries = ({
104104
filters = [],
105105
kqlQuery,
106106
kqlMode,
107-
start,
108-
end,
109107
isEventViewer,
110108
}: {
111109
config: EsQueryConfig;
@@ -115,8 +113,6 @@ export const combineQueries = ({
115113
filters: Filter[];
116114
kqlQuery: Query;
117115
kqlMode: string;
118-
start: string;
119-
end: string;
120116
isEventViewer?: boolean;
121117
}): { filterQuery: string } | null => {
122118
const kuery: Query = { query: '', language: kqlQuery.language };

x-pack/plugins/security_solution/public/timelines/components/timeline/timeline.tsx

+1-13
Original file line numberDiff line numberDiff line change
@@ -164,20 +164,8 @@ export const TimelineComponent: React.FC<Props> = ({
164164
filters,
165165
kqlQuery,
166166
kqlMode,
167-
start,
168-
end,
169167
}),
170-
[
171-
browserFields,
172-
dataProviders,
173-
esQueryConfig,
174-
start,
175-
end,
176-
filters,
177-
indexPattern,
178-
kqlMode,
179-
kqlQuery,
180-
]
168+
[browserFields, dataProviders, esQueryConfig, filters, indexPattern, kqlMode, kqlQuery]
181169
);
182170

183171
const canQueryTimeline = useMemo(

0 commit comments

Comments
 (0)