Skip to content

Commit 75eda66

Browse files
[SIEM] Fixes toaster errors when siemDefault index is an empty or empty spaces (#73991)
## Summary Fixes fully this issue: #49753 If you go to advanced settings and configure siemDefaultIndex to be an empty string or have empty spaces: <img width="1291" alt="Screen Shot 2020-07-31 at 12 52 00 PM" src="https://user-images.githubusercontent.com/1151048/89067511-a9434000-d32c-11ea-9106-e2079a5db317.png"> You shouldn't get any toaster errors when going to any of the pages such as overview, detections, etc... This fixes that and adds both unit and integration tests around those areas. The fix is to add a filter which will filter all the patterns out that are either empty strings or have the _all within them rather than just looking for a single value to exist. ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios
1 parent 5aca964 commit 75eda66

File tree

4 files changed

+168
-42
lines changed

4 files changed

+168
-42
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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 { filterIndexes } from './resolvers';
8+
9+
describe('resolvers', () => {
10+
test('it should filter single index that has an empty string', () => {
11+
const emptyArray = filterIndexes(['']);
12+
expect(emptyArray).toEqual([]);
13+
});
14+
15+
test('it should filter single index that has blanks within it', () => {
16+
const emptyArray = filterIndexes([' ']);
17+
expect(emptyArray).toEqual([]);
18+
});
19+
20+
test('it should filter indexes that has an empty string and a valid index', () => {
21+
const emptyArray = filterIndexes(['', 'valid-index']);
22+
expect(emptyArray).toEqual(['valid-index']);
23+
});
24+
25+
test('it should filter indexes that have blanks within them and a valid index', () => {
26+
const emptyArray = filterIndexes([' ', 'valid-index']);
27+
expect(emptyArray).toEqual(['valid-index']);
28+
});
29+
30+
test('it should filter single index that has _all within it', () => {
31+
const emptyArray = filterIndexes(['_all']);
32+
expect(emptyArray).toEqual([]);
33+
});
34+
35+
test('it should filter single index that has _all within it surrounded by spaces', () => {
36+
const emptyArray = filterIndexes([' _all ']);
37+
expect(emptyArray).toEqual([]);
38+
});
39+
40+
test('it should filter indexes that _all within them and a valid index', () => {
41+
const emptyArray = filterIndexes(['_all', 'valid-index']);
42+
expect(emptyArray).toEqual(['valid-index']);
43+
});
44+
45+
test('it should filter indexes that _all surrounded with spaces within them and a valid index', () => {
46+
const emptyArray = filterIndexes([' _all ', 'valid-index']);
47+
expect(emptyArray).toEqual(['valid-index']);
48+
});
49+
});

x-pack/plugins/security_solution/server/graphql/source_status/resolvers.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,34 @@ export const createSourceStatusResolvers = (libs: {
3232
};
3333
} => ({
3434
SourceStatus: {
35-
async indicesExist(source, args, { req }) {
36-
if (
37-
args.defaultIndex.length === 1 &&
38-
(args.defaultIndex[0] === '' || args.defaultIndex[0] === '_all')
39-
) {
35+
async indicesExist(_, args, { req }) {
36+
const indexes = filterIndexes(args.defaultIndex);
37+
if (indexes.length !== 0) {
38+
return libs.sourceStatus.hasIndices(req, indexes);
39+
} else {
4040
return false;
4141
}
42-
return libs.sourceStatus.hasIndices(req, args.defaultIndex);
4342
},
44-
async indexFields(source, args, { req }) {
45-
if (
46-
args.defaultIndex.length === 1 &&
47-
(args.defaultIndex[0] === '' || args.defaultIndex[0] === '_all')
48-
) {
43+
async indexFields(_, args, { req }) {
44+
const indexes = filterIndexes(args.defaultIndex);
45+
if (indexes.length !== 0) {
46+
return libs.fields.getFields(req, indexes);
47+
} else {
4948
return [];
5049
}
51-
return libs.fields.getFields(req, args.defaultIndex);
5250
},
5351
},
5452
});
5553

54+
/**
55+
* Given a set of indexes this will remove anything that is:
56+
* - blank or empty strings are removed as not valid indexes
57+
* - _all is removed as that is not a valid index
58+
* @param indexes Indexes with invalid values removed
59+
*/
60+
export const filterIndexes = (indexes: string[]): string[] =>
61+
indexes.filter((index) => index.trim() !== '' && index.trim() !== '_all');
62+
5663
export const toIFieldSubTypeNonNullableScalar = new GraphQLScalarType({
5764
name: 'IFieldSubType',
5865
description: 'Represents value in index pattern field item',

x-pack/plugins/security_solution/server/lib/index_fields/elasticsearch_adapter.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,21 @@ import {
1717
import { FrameworkAdapter, FrameworkRequest } from '../framework';
1818
import { FieldsAdapter, IndexFieldDescriptor } from './types';
1919

20-
type IndexesAliasIndices = Record<string, string[]>;
21-
2220
export class ElasticsearchIndexFieldAdapter implements FieldsAdapter {
2321
constructor(private readonly framework: FrameworkAdapter) {}
2422

2523
public async getIndexFields(request: FrameworkRequest, indices: string[]): Promise<IndexField[]> {
2624
const indexPatternsService = this.framework.getIndexPatternsService(request);
27-
const indexesAliasIndices: IndexesAliasIndices = indices.reduce(
28-
(accumulator: IndexesAliasIndices, indice: string) => {
29-
const key = getIndexAlias(indices, indice);
25+
const indexesAliasIndices = indices.reduce<Record<string, string[]>>((accumulator, indice) => {
26+
const key = getIndexAlias(indices, indice);
3027

31-
if (get(key, accumulator)) {
32-
accumulator[key] = [...accumulator[key], indice];
33-
} else {
34-
accumulator[key] = [indice];
35-
}
36-
return accumulator;
37-
},
38-
{} as IndexesAliasIndices
39-
);
28+
if (get(key, accumulator)) {
29+
accumulator[key] = [...accumulator[key], indice];
30+
} else {
31+
accumulator[key] = [indice];
32+
}
33+
return accumulator;
34+
}, {});
4035
const responsesIndexFields: IndexFieldDescriptor[][] = await Promise.all(
4136
Object.values(indexesAliasIndices).map((indicesByGroup) =>
4237
indexPatternsService.getFieldsForWildcard({

x-pack/test/api_integration/apis/security_solution/sources.ts

Lines changed: 91 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,97 @@ export default function ({ getService }: FtrProviderContext) {
1818
before(() => esArchiver.load('auditbeat/default'));
1919
after(() => esArchiver.unload('auditbeat/default'));
2020

21-
it('Make sure that we get source information when auditbeat indices is there', () => {
22-
return client
23-
.query<SourceQuery.Query>({
24-
query: sourceQuery,
25-
variables: {
26-
sourceId: 'default',
27-
defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
28-
docValueFields: [],
29-
},
30-
})
31-
.then((resp) => {
32-
const sourceStatus = resp.data.source.status;
33-
// test data in x-pack/test/functional/es_archives/auditbeat_test_data/data.json.gz
34-
expect(sourceStatus.indexFields.length).to.be(397);
35-
expect(sourceStatus.indicesExist).to.be(true);
36-
});
21+
it('Make sure that we get source information when auditbeat indices is there', async () => {
22+
const resp = await client.query<SourceQuery.Query>({
23+
query: sourceQuery,
24+
variables: {
25+
sourceId: 'default',
26+
defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
27+
docValueFields: [],
28+
},
29+
});
30+
const sourceStatus = resp.data.source.status;
31+
// test data in x-pack/test/functional/es_archives/auditbeat_test_data/data.json.gz
32+
expect(sourceStatus.indexFields.length).to.be(397);
33+
expect(sourceStatus.indicesExist).to.be(true);
34+
});
35+
36+
it('should find indexes as being available when they exist', async () => {
37+
const resp = await client.query<SourceQuery.Query>({
38+
query: sourceQuery,
39+
variables: {
40+
sourceId: 'default',
41+
defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
42+
docValueFields: [],
43+
},
44+
});
45+
const sourceStatus = resp.data.source.status;
46+
expect(sourceStatus.indicesExist).to.be(true);
47+
});
48+
49+
it('should not find indexes as existing when there is an empty array of them', async () => {
50+
const resp = await client.query<SourceQuery.Query>({
51+
query: sourceQuery,
52+
variables: {
53+
sourceId: 'default',
54+
defaultIndex: [],
55+
docValueFields: [],
56+
},
57+
});
58+
const sourceStatus = resp.data.source.status;
59+
expect(sourceStatus.indicesExist).to.be(false);
60+
});
61+
62+
it('should not find indexes as existing when there is a _all within it', async () => {
63+
const resp = await client.query<SourceQuery.Query>({
64+
query: sourceQuery,
65+
variables: {
66+
sourceId: 'default',
67+
defaultIndex: ['_all'],
68+
docValueFields: [],
69+
},
70+
});
71+
const sourceStatus = resp.data.source.status;
72+
expect(sourceStatus.indicesExist).to.be(false);
73+
});
74+
75+
it('should not find indexes as existing when there are empty strings within it', async () => {
76+
const resp = await client.query<SourceQuery.Query>({
77+
query: sourceQuery,
78+
variables: {
79+
sourceId: 'default',
80+
defaultIndex: [''],
81+
docValueFields: [],
82+
},
83+
});
84+
const sourceStatus = resp.data.source.status;
85+
expect(sourceStatus.indicesExist).to.be(false);
86+
});
87+
88+
it('should not find indexes as existing when there are blank spaces within it', async () => {
89+
const resp = await client.query<SourceQuery.Query>({
90+
query: sourceQuery,
91+
variables: {
92+
sourceId: 'default',
93+
defaultIndex: [' '],
94+
docValueFields: [],
95+
},
96+
});
97+
const sourceStatus = resp.data.source.status;
98+
expect(sourceStatus.indicesExist).to.be(false);
99+
});
100+
101+
it('should find indexes when one is an empty index but the others are valid', async () => {
102+
const resp = await client.query<SourceQuery.Query>({
103+
query: sourceQuery,
104+
variables: {
105+
sourceId: 'default',
106+
defaultIndex: ['', 'auditbeat-*'],
107+
docValueFields: [],
108+
},
109+
});
110+
const sourceStatus = resp.data.source.status;
111+
expect(sourceStatus.indicesExist).to.be(true);
37112
});
38113
});
39114
}

0 commit comments

Comments
 (0)