Skip to content

Commit 040c309

Browse files
authored
[SIEM] Tests for search_after and bulk index (#50129)
* tests for detection engine get/put utils * increases unit test code statement coverage to 100% for search_after / bulk index reindexer * removes mockLogger declaration from individual test cases - clears mock counts before each test case runs so as to not accumulate method calls after each test case * resets default paging size to 1000 - typo from when I was working through my tests * updates tests after rebase with master * fixes type check after fixing test from rebase with master * removes undefined from maxSignals in type definition, updates tests with pure jest function implementations of logger and services - modifying only the return values or creating a mock implementation when necessary, removed some overlapping test cases * fixes type issue * replaces mock implementation with mock return value for unit test * removes mock logger expected counts, just check if error logs are called, don't care about debug / warn etc. * fixes more type checks after rebase with master
1 parent bbb9421 commit 040c309

File tree

7 files changed

+656
-21
lines changed

7 files changed

+656
-21
lines changed

x-pack/legacy/plugins/siem/common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const DEFAULT_TIME_RANGE = 'timepicker:timeDefaults';
1515
export const DEFAULT_REFRESH_RATE_INTERVAL = 'timepicker:refreshIntervalDefaults';
1616
export const DEFAULT_SIEM_TIME_RANGE = 'siem:timeDefaults';
1717
export const DEFAULT_SIEM_REFRESH_INTERVAL = 'siem:refreshIntervalDefaults';
18+
export const DEFAULT_SIGNALS_INDEX = '.siem-signals';
1819
export const DEFAULT_ANOMALY_SCORE = 'siem:defaultAnomalyScore';
1920
export const DEFAULT_MAX_TABLE_QUERY_SIZE = 10000;
2021
export const DEFAULT_SCALE_DATE_FORMAT = 'dateFormat:scaled';
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { SignalSourceHit, SignalSearchResponse, SignalAlertParams } from '../types';
8+
9+
export const sampleSignalAlertParams = (maxSignals: number | undefined): SignalAlertParams => ({
10+
id: 'rule-1',
11+
description: 'Detecting root and admin users',
12+
falsePositives: [],
13+
immutable: false,
14+
index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
15+
interval: '5m',
16+
name: 'Detect Root/Admin Users',
17+
type: 'query',
18+
from: 'now-6m',
19+
tags: ['some fake tag'],
20+
to: 'now',
21+
severity: 'high',
22+
query: 'user.name: root or user.name: admin',
23+
language: 'kuery',
24+
references: ['http://google.com'],
25+
maxSignals: maxSignals ? maxSignals : 10000,
26+
enabled: true,
27+
filter: undefined,
28+
filters: undefined,
29+
savedId: undefined,
30+
size: 1000,
31+
});
32+
33+
export const sampleDocNoSortId: SignalSourceHit = {
34+
_index: 'myFakeSignalIndex',
35+
_type: 'doc',
36+
_score: 100,
37+
_version: 1,
38+
_id: 'someFakeId',
39+
_source: {
40+
someKey: 'someValue',
41+
'@timestamp': 'someTimeStamp',
42+
},
43+
};
44+
45+
export const sampleDocWithSortId: SignalSourceHit = {
46+
_index: 'myFakeSignalIndex',
47+
_type: 'doc',
48+
_score: 100,
49+
_version: 1,
50+
_id: 'someFakeId',
51+
_source: {
52+
someKey: 'someValue',
53+
'@timestamp': 'someTimeStamp',
54+
},
55+
sort: ['1234567891111'],
56+
};
57+
58+
export const sampleEmptyDocSearchResults: SignalSearchResponse = {
59+
took: 10,
60+
timed_out: false,
61+
_shards: {
62+
total: 10,
63+
successful: 10,
64+
failed: 0,
65+
skipped: 0,
66+
},
67+
hits: {
68+
total: 0,
69+
max_score: 100,
70+
hits: [],
71+
},
72+
};
73+
74+
export const sampleDocSearchResultsNoSortId: SignalSearchResponse = {
75+
took: 10,
76+
timed_out: false,
77+
_shards: {
78+
total: 10,
79+
successful: 10,
80+
failed: 0,
81+
skipped: 0,
82+
},
83+
hits: {
84+
total: 100,
85+
max_score: 100,
86+
hits: [
87+
{
88+
...sampleDocNoSortId,
89+
},
90+
],
91+
},
92+
};
93+
94+
export const sampleDocSearchResultsNoSortIdNoHits: SignalSearchResponse = {
95+
took: 10,
96+
timed_out: false,
97+
_shards: {
98+
total: 10,
99+
successful: 10,
100+
failed: 0,
101+
skipped: 0,
102+
},
103+
hits: {
104+
total: 0,
105+
max_score: 100,
106+
hits: [
107+
{
108+
...sampleDocNoSortId,
109+
},
110+
],
111+
},
112+
};
113+
114+
export const repeatedSearchResultsWithSortId = (repeat: number) => ({
115+
took: 10,
116+
timed_out: false,
117+
_shards: {
118+
total: 10,
119+
successful: 10,
120+
failed: 0,
121+
skipped: 0,
122+
},
123+
hits: {
124+
total: repeat,
125+
max_score: 100,
126+
hits: Array.from({ length: repeat }).map(x => ({
127+
...sampleDocWithSortId,
128+
})),
129+
},
130+
});
131+
132+
export const sampleDocSearchResultsWithSortId: SignalSearchResponse = {
133+
took: 10,
134+
timed_out: false,
135+
_shards: {
136+
total: 10,
137+
successful: 10,
138+
failed: 0,
139+
skipped: 0,
140+
},
141+
hits: {
142+
total: 1,
143+
max_score: 100,
144+
hits: [
145+
{
146+
...sampleDocWithSortId,
147+
},
148+
],
149+
},
150+
};

x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/build_events_query.test.ts

Lines changed: 146 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ describe('create_signals', () => {
6666
],
6767
},
6868
},
69-
track_total_hits: true,
69+
7070
sort: [
7171
{
7272
'@timestamp': {
@@ -136,14 +136,158 @@ describe('create_signals', () => {
136136
],
137137
},
138138
},
139-
track_total_hits: true,
139+
140+
sort: [
141+
{
142+
'@timestamp': {
143+
order: 'asc',
144+
},
145+
},
146+
],
147+
},
148+
});
149+
});
150+
test('if searchAfterSortId is a valid sortId string', () => {
151+
const fakeSortId = '123456789012';
152+
const query = buildEventsSearchQuery({
153+
index: ['auditbeat-*'],
154+
from: 'now-5m',
155+
to: 'today',
156+
filter: {},
157+
size: 100,
158+
searchAfterSortId: fakeSortId,
159+
});
160+
expect(query).toEqual({
161+
allowNoIndices: true,
162+
index: ['auditbeat-*'],
163+
size: 100,
164+
ignoreUnavailable: true,
165+
body: {
166+
query: {
167+
bool: {
168+
filter: [
169+
{},
170+
{
171+
bool: {
172+
filter: [
173+
{
174+
bool: {
175+
should: [
176+
{
177+
range: {
178+
'@timestamp': {
179+
gte: 'now-5m',
180+
},
181+
},
182+
},
183+
],
184+
minimum_should_match: 1,
185+
},
186+
},
187+
{
188+
bool: {
189+
should: [
190+
{
191+
range: {
192+
'@timestamp': {
193+
lte: 'today',
194+
},
195+
},
196+
},
197+
],
198+
minimum_should_match: 1,
199+
},
200+
},
201+
],
202+
},
203+
},
204+
{
205+
match_all: {},
206+
},
207+
],
208+
},
209+
},
210+
211+
sort: [
212+
{
213+
'@timestamp': {
214+
order: 'asc',
215+
},
216+
},
217+
],
218+
search_after: [fakeSortId],
219+
},
220+
});
221+
});
222+
test('if searchAfterSortId is a valid sortId number', () => {
223+
const fakeSortIdNumber = 123456789012;
224+
const query = buildEventsSearchQuery({
225+
index: ['auditbeat-*'],
226+
from: 'now-5m',
227+
to: 'today',
228+
filter: {},
229+
size: 100,
230+
searchAfterSortId: fakeSortIdNumber,
231+
});
232+
expect(query).toEqual({
233+
allowNoIndices: true,
234+
index: ['auditbeat-*'],
235+
size: 100,
236+
ignoreUnavailable: true,
237+
body: {
238+
query: {
239+
bool: {
240+
filter: [
241+
{},
242+
{
243+
bool: {
244+
filter: [
245+
{
246+
bool: {
247+
should: [
248+
{
249+
range: {
250+
'@timestamp': {
251+
gte: 'now-5m',
252+
},
253+
},
254+
},
255+
],
256+
minimum_should_match: 1,
257+
},
258+
},
259+
{
260+
bool: {
261+
should: [
262+
{
263+
range: {
264+
'@timestamp': {
265+
lte: 'today',
266+
},
267+
},
268+
},
269+
],
270+
minimum_should_match: 1,
271+
},
272+
},
273+
],
274+
},
275+
},
276+
{
277+
match_all: {},
278+
},
279+
],
280+
},
281+
},
282+
140283
sort: [
141284
{
142285
'@timestamp': {
143286
order: 'asc',
144287
},
145288
},
146289
],
290+
search_after: [fakeSortIdNumber],
147291
},
148292
});
149293
});

x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/build_events_query.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ interface BuildEventsSearchQuery {
1010
to: string;
1111
filter: unknown;
1212
size: number;
13-
searchAfterSortId?: string;
13+
searchAfterSortId: string | number | undefined;
1414
}
1515

1616
export const buildEventsSearchQuery = ({
@@ -74,7 +74,6 @@ export const buildEventsSearchQuery = ({
7474
],
7575
},
7676
},
77-
track_total_hits: true,
7877
sort: [
7978
{
8079
'@timestamp': {

x-pack/legacy/plugins/siem/server/lib/detection_engine/alerts/signals_alert_type.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
*/
66

77
import { schema } from '@kbn/config-schema';
8-
import { SIGNALS_ID } from '../../../../common/constants';
8+
import { SIGNALS_ID, DEFAULT_SIGNALS_INDEX } from '../../../../common/constants';
99
import { Logger } from '../../../../../../../../src/core/server';
10-
1110
// TODO: Remove this for the build_events_query call eventually
1211
import { buildEventsReIndex } from './build_events_reindex';
1312

@@ -34,7 +33,7 @@ export const signalsAlertType = ({ logger }: { logger: Logger }): SignalAlertTyp
3433
savedId: schema.nullable(schema.string()),
3534
query: schema.nullable(schema.string()),
3635
filters: schema.nullable(schema.arrayOf(schema.object({}, { allowUnknowns: true }))),
37-
maxSignals: schema.number({ defaultValue: 100 }),
36+
maxSignals: schema.number({ defaultValue: 10000 }),
3837
severity: schema.string(),
3938
tags: schema.arrayOf(schema.string(), { defaultValue: [] }),
4039
to: schema.string(),
@@ -82,6 +81,7 @@ export const signalsAlertType = ({ logger }: { logger: Logger }): SignalAlertTyp
8281
to,
8382
filter: esFilter,
8483
size: searchAfterSize,
84+
searchAfterSortId: undefined,
8585
});
8686

8787
try {
@@ -93,7 +93,7 @@ export const signalsAlertType = ({ logger }: { logger: Logger }): SignalAlertTyp
9393
to,
9494
// TODO: Change this out once we have solved
9595
// https://github.com/elastic/kibana/issues/47002
96-
signalsIndex: process.env.SIGNALS_INDEX || '.siem-signals-10-01-2019',
96+
signalsIndex: process.env.SIGNALS_INDEX || DEFAULT_SIGNALS_INDEX,
9797
severity,
9898
description,
9999
name,

0 commit comments

Comments
 (0)