Skip to content

Commit b4dfab0

Browse files
[SIEM] Fix timeline buildGlobalQuery
1 parent 3602f0f commit b4dfab0

2 files changed

Lines changed: 83 additions & 44 deletions

File tree

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

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const endDate = new Date('2018-03-24T03:33:52.253Z').valueOf();
1818

1919
describe('Build KQL Query', () => {
2020
test('Build KQL query with one data provider', () => {
21-
const dataProviders = mockDataProviders.slice(0, 1);
21+
const dataProviders = cloneDeep(mockDataProviders.slice(0, 1));
2222
const kqlQuery = buildGlobalQuery(dataProviders, mockBrowserFields);
2323
expect(cleanUpKqlQuery(kqlQuery)).toEqual('name : "Provider 1"');
2424
});
@@ -56,18 +56,40 @@ describe('Build KQL Query', () => {
5656
});
5757

5858
test('Build KQL query with two data provider', () => {
59-
const dataProviders = mockDataProviders.slice(0, 2);
59+
const dataProviders = cloneDeep(mockDataProviders.slice(0, 2));
60+
const kqlQuery = buildGlobalQuery(dataProviders, mockBrowserFields);
61+
expect(cleanUpKqlQuery(kqlQuery)).toEqual('(name : "Provider 1") or (name : "Provider 2")');
62+
});
63+
64+
test('Build KQL query with two data provider and first is disabled', () => {
65+
const dataProviders = cloneDeep(mockDataProviders.slice(0, 2));
66+
dataProviders[0].enabled = false;
67+
const kqlQuery = buildGlobalQuery(dataProviders, mockBrowserFields);
68+
expect(cleanUpKqlQuery(kqlQuery)).toEqual('name : "Provider 2"');
69+
});
70+
71+
test('Build KQL query with two data provider and second is disabled', () => {
72+
const dataProviders = cloneDeep(mockDataProviders.slice(0, 2));
73+
dataProviders[1].enabled = false;
6074
const kqlQuery = buildGlobalQuery(dataProviders, mockBrowserFields);
61-
expect(cleanUpKqlQuery(kqlQuery)).toEqual('(name : "Provider 1" ) or (name : "Provider 2" )');
75+
expect(cleanUpKqlQuery(kqlQuery)).toEqual('name : "Provider 1"');
6276
});
6377

6478
test('Build KQL query with one data provider and one and', () => {
6579
const dataProviders = cloneDeep(mockDataProviders.slice(0, 1));
66-
dataProviders[0].and = mockDataProviders.slice(1, 2);
80+
dataProviders[0].and = cloneDeep(mockDataProviders.slice(1, 2));
6781
const kqlQuery = buildGlobalQuery(dataProviders, mockBrowserFields);
6882
expect(cleanUpKqlQuery(kqlQuery)).toEqual('name : "Provider 1" and name : "Provider 2"');
6983
});
7084

85+
test('Build KQL query with one disabled data provider and one and', () => {
86+
const dataProviders = cloneDeep(mockDataProviders.slice(0, 1));
87+
dataProviders[0].enabled = false;
88+
dataProviders[0].and = cloneDeep(mockDataProviders.slice(1, 2));
89+
const kqlQuery = buildGlobalQuery(dataProviders, mockBrowserFields);
90+
expect(cleanUpKqlQuery(kqlQuery)).toEqual('name : "Provider 2"');
91+
});
92+
7193
test('Build KQL query with one data provider and one and as timestamp (string input)', () => {
7294
const dataProviders = cloneDeep(mockDataProviders.slice(0, 1));
7395
dataProviders[0].and = cloneDeep(mockDataProviders.slice(1, 2));
@@ -106,28 +128,50 @@ describe('Build KQL Query', () => {
106128

107129
test('Build KQL query with two data provider and multiple and', () => {
108130
const dataProviders = cloneDeep(mockDataProviders.slice(0, 2));
109-
dataProviders[0].and = mockDataProviders.slice(2, 4);
110-
dataProviders[1].and = mockDataProviders.slice(4, 5);
131+
dataProviders[0].and = cloneDeep(mockDataProviders.slice(2, 4));
132+
dataProviders[1].and = cloneDeep(mockDataProviders.slice(4, 5));
111133
const kqlQuery = buildGlobalQuery(dataProviders, mockBrowserFields);
112134
expect(cleanUpKqlQuery(kqlQuery)).toEqual(
113135
'(name : "Provider 1" and name : "Provider 3" and name : "Provider 4") or (name : "Provider 2" and name : "Provider 5")'
114136
);
115137
});
116138

139+
test('Build KQL query with two data provider and multiple and and first data provider is disabled', () => {
140+
const dataProviders = cloneDeep(mockDataProviders.slice(0, 2));
141+
dataProviders[0].enabled = false;
142+
dataProviders[0].and = cloneDeep(mockDataProviders.slice(2, 4));
143+
dataProviders[1].and = cloneDeep(mockDataProviders.slice(4, 5));
144+
const kqlQuery = buildGlobalQuery(dataProviders, mockBrowserFields);
145+
expect(cleanUpKqlQuery(kqlQuery)).toEqual(
146+
'(name : "Provider 3" and name : "Provider 4") or (name : "Provider 2" and name : "Provider 5")'
147+
);
148+
});
149+
150+
test('Build KQL query with two data provider and multiple and and first and provider is disabled', () => {
151+
const dataProviders = cloneDeep(mockDataProviders.slice(0, 2));
152+
dataProviders[0].and = cloneDeep(mockDataProviders.slice(2, 4));
153+
dataProviders[0].and[0].enabled = false;
154+
dataProviders[1].and = cloneDeep(mockDataProviders.slice(4, 5));
155+
const kqlQuery = buildGlobalQuery(dataProviders, mockBrowserFields);
156+
expect(cleanUpKqlQuery(kqlQuery)).toEqual(
157+
'(name : "Provider 1" and name : "Provider 4") or (name : "Provider 2" and name : "Provider 5")'
158+
);
159+
});
160+
117161
test('Build KQL query with all data provider', () => {
118162
const kqlQuery = buildGlobalQuery(mockDataProviders, mockBrowserFields);
119163
expect(cleanUpKqlQuery(kqlQuery)).toEqual(
120-
'(name : "Provider 1" ) or (name : "Provider 2" ) or (name : "Provider 3" ) or (name : "Provider 4" ) or (name : "Provider 5" ) or (name : "Provider 6" ) or (name : "Provider 7" ) or (name : "Provider 8" ) or (name : "Provider 9" ) or (name : "Provider 10" )'
164+
'(name : "Provider 1") or (name : "Provider 2") or (name : "Provider 3") or (name : "Provider 4") or (name : "Provider 5") or (name : "Provider 6") or (name : "Provider 7") or (name : "Provider 8") or (name : "Provider 9") or (name : "Provider 10")'
121165
);
122166
});
123167

124168
test('Build complex KQL query with and and or', () => {
125169
const dataProviders = cloneDeep(mockDataProviders);
126-
dataProviders[0].and = mockDataProviders.slice(2, 4);
127-
dataProviders[1].and = mockDataProviders.slice(4, 5);
170+
dataProviders[0].and = cloneDeep(mockDataProviders.slice(2, 4));
171+
dataProviders[1].and = cloneDeep(mockDataProviders.slice(4, 5));
128172
const kqlQuery = buildGlobalQuery(dataProviders, mockBrowserFields);
129173
expect(cleanUpKqlQuery(kqlQuery)).toEqual(
130-
'(name : "Provider 1" and name : "Provider 3" and name : "Provider 4") or (name : "Provider 2" and name : "Provider 5") or (name : "Provider 3" ) or (name : "Provider 4" ) or (name : "Provider 5" ) or (name : "Provider 6" ) or (name : "Provider 7" ) or (name : "Provider 8" ) or (name : "Provider 9" ) or (name : "Provider 10" )'
174+
'(name : "Provider 1" and name : "Provider 3" and name : "Provider 4") or (name : "Provider 2" and name : "Provider 5") or (name : "Provider 3") or (name : "Provider 4") or (name : "Provider 5") or (name : "Provider 6") or (name : "Provider 7") or (name : "Provider 8") or (name : "Provider 9") or (name : "Provider 10")'
131175
);
132176
});
133177
});
@@ -223,7 +267,7 @@ describe('Combined Queries', () => {
223267
});
224268

225269
test('Only Data Provider', () => {
226-
const dataProviders = mockDataProviders.slice(0, 1);
270+
const dataProviders = cloneDeep(mockDataProviders.slice(0, 1));
227271
const { filterQuery } = combineQueries({
228272
config,
229273
dataProviders,
@@ -338,7 +382,7 @@ describe('Combined Queries', () => {
338382
});
339383

340384
test('Data Provider & KQL search query', () => {
341-
const dataProviders = mockDataProviders.slice(0, 1);
385+
const dataProviders = cloneDeep(mockDataProviders.slice(0, 1));
342386
const { filterQuery } = combineQueries({
343387
config,
344388
dataProviders,
@@ -356,7 +400,7 @@ describe('Combined Queries', () => {
356400
});
357401

358402
test('Data Provider & KQL filter query', () => {
359-
const dataProviders = mockDataProviders.slice(0, 1);
403+
const dataProviders = cloneDeep(mockDataProviders.slice(0, 1));
360404
const { filterQuery } = combineQueries({
361405
config,
362406
dataProviders,
@@ -375,8 +419,8 @@ describe('Combined Queries', () => {
375419

376420
test('Data Provider & KQL search query multiple', () => {
377421
const dataProviders = cloneDeep(mockDataProviders.slice(0, 2));
378-
dataProviders[0].and = mockDataProviders.slice(2, 4);
379-
dataProviders[1].and = mockDataProviders.slice(4, 5);
422+
dataProviders[0].and = cloneDeep(mockDataProviders.slice(2, 4));
423+
dataProviders[1].and = cloneDeep(mockDataProviders.slice(4, 5));
380424
const { filterQuery } = combineQueries({
381425
config,
382426
dataProviders,
@@ -395,8 +439,8 @@ describe('Combined Queries', () => {
395439

396440
test('Data Provider & KQL filter query multiple', () => {
397441
const dataProviders = cloneDeep(mockDataProviders.slice(0, 2));
398-
dataProviders[0].and = mockDataProviders.slice(2, 4);
399-
dataProviders[1].and = mockDataProviders.slice(4, 5);
442+
dataProviders[0].and = cloneDeep(mockDataProviders.slice(2, 4));
443+
dataProviders[1].and = cloneDeep(mockDataProviders.slice(4, 5));
400444
const { filterQuery } = combineQueries({
401445
config,
402446
dataProviders,

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

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -63,35 +63,30 @@ const buildQueryMatch = (
6363
: `${dataProvider.queryMatch.field} ${EXISTS_OPERATOR}`
6464
}`.trim();
6565

66-
const buildQueryForAndProvider = (
67-
dataAndProviders: DataProvidersAnd[],
68-
browserFields: BrowserFields
69-
) =>
70-
dataAndProviders
71-
.reduce((andQuery, andDataProvider) => {
72-
const prepend = (q: string) => `${q !== '' ? `${q} and ` : ''}`;
73-
return andDataProvider.enabled
74-
? `${prepend(andQuery)} ${buildQueryMatch(andDataProvider, browserFields)}`
75-
: andQuery;
76-
}, '')
77-
.trim();
78-
7966
export const buildGlobalQuery = (dataProviders: DataProvider[], browserFields: BrowserFields) =>
8067
dataProviders
81-
.reduce((query, dataProvider: DataProvider, i) => {
82-
const prepend = (q: string) => `${q !== '' ? `${q} or ` : ''}`;
83-
const openParen = i >= 0 && dataProviders.length > 1 ? '(' : '';
84-
const closeParen = i >= 0 && dataProviders.length > 1 ? ')' : '';
85-
return dataProvider.enabled
86-
? `${prepend(query)}${openParen}${buildQueryMatch(dataProvider, browserFields)}
87-
${
88-
dataProvider.and.length > 0
89-
? ` and ${buildQueryForAndProvider(dataProvider.and, browserFields)}`
90-
: ''
91-
}${closeParen}`.trim()
92-
: query;
93-
}, '')
94-
.trim();
68+
.reduce((queries: string[], dataProvider: DataProvider) => {
69+
const flatDataProviders = [dataProvider, ...dataProvider.and];
70+
const activeDataProviders = flatDataProviders.filter(
71+
(flatDataProvider) => flatDataProvider.enabled
72+
);
73+
74+
if (!activeDataProviders.length) return queries;
75+
76+
const activeDataProvidersQueries = activeDataProviders.map((activeDataProvider) =>
77+
buildQueryMatch(activeDataProvider, browserFields)
78+
);
79+
80+
const activeDataProvidersQueryMatch = activeDataProvidersQueries.join(' and ');
81+
82+
return [...queries, `${activeDataProvidersQueryMatch}`];
83+
}, [])
84+
.filter((queriesItem) => !isEmpty(queriesItem))
85+
.reduce((globalQuery: string, queryMatch: string, index: number, queries: string[]) => {
86+
if (queries.length <= 1) return queryMatch;
87+
88+
return !index ? `(${queryMatch})` : `${globalQuery} or (${queryMatch})`;
89+
}, '');
9590

9691
export const combineQueries = ({
9792
config,

0 commit comments

Comments
 (0)