Skip to content

Commit

Permalink
[SIEM] Fixes toaster errors when siemDefault index is an empty or emp…
Browse files Browse the repository at this point in the history
…ty spaces (elastic#73991)

## Summary

Fixes fully this issue: elastic#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
  • Loading branch information
FrankHassanabad authored Jul 31, 2020
1 parent 5aca964 commit 75eda66
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { filterIndexes } from './resolvers';

describe('resolvers', () => {
test('it should filter single index that has an empty string', () => {
const emptyArray = filterIndexes(['']);
expect(emptyArray).toEqual([]);
});

test('it should filter single index that has blanks within it', () => {
const emptyArray = filterIndexes([' ']);
expect(emptyArray).toEqual([]);
});

test('it should filter indexes that has an empty string and a valid index', () => {
const emptyArray = filterIndexes(['', 'valid-index']);
expect(emptyArray).toEqual(['valid-index']);
});

test('it should filter indexes that have blanks within them and a valid index', () => {
const emptyArray = filterIndexes([' ', 'valid-index']);
expect(emptyArray).toEqual(['valid-index']);
});

test('it should filter single index that has _all within it', () => {
const emptyArray = filterIndexes(['_all']);
expect(emptyArray).toEqual([]);
});

test('it should filter single index that has _all within it surrounded by spaces', () => {
const emptyArray = filterIndexes([' _all ']);
expect(emptyArray).toEqual([]);
});

test('it should filter indexes that _all within them and a valid index', () => {
const emptyArray = filterIndexes(['_all', 'valid-index']);
expect(emptyArray).toEqual(['valid-index']);
});

test('it should filter indexes that _all surrounded with spaces within them and a valid index', () => {
const emptyArray = filterIndexes([' _all ', 'valid-index']);
expect(emptyArray).toEqual(['valid-index']);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,34 @@ export const createSourceStatusResolvers = (libs: {
};
} => ({
SourceStatus: {
async indicesExist(source, args, { req }) {
if (
args.defaultIndex.length === 1 &&
(args.defaultIndex[0] === '' || args.defaultIndex[0] === '_all')
) {
async indicesExist(_, args, { req }) {
const indexes = filterIndexes(args.defaultIndex);
if (indexes.length !== 0) {
return libs.sourceStatus.hasIndices(req, indexes);
} else {
return false;
}
return libs.sourceStatus.hasIndices(req, args.defaultIndex);
},
async indexFields(source, args, { req }) {
if (
args.defaultIndex.length === 1 &&
(args.defaultIndex[0] === '' || args.defaultIndex[0] === '_all')
) {
async indexFields(_, args, { req }) {
const indexes = filterIndexes(args.defaultIndex);
if (indexes.length !== 0) {
return libs.fields.getFields(req, indexes);
} else {
return [];
}
return libs.fields.getFields(req, args.defaultIndex);
},
},
});

/**
* Given a set of indexes this will remove anything that is:
* - blank or empty strings are removed as not valid indexes
* - _all is removed as that is not a valid index
* @param indexes Indexes with invalid values removed
*/
export const filterIndexes = (indexes: string[]): string[] =>
indexes.filter((index) => index.trim() !== '' && index.trim() !== '_all');

export const toIFieldSubTypeNonNullableScalar = new GraphQLScalarType({
name: 'IFieldSubType',
description: 'Represents value in index pattern field item',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,21 @@ import {
import { FrameworkAdapter, FrameworkRequest } from '../framework';
import { FieldsAdapter, IndexFieldDescriptor } from './types';

type IndexesAliasIndices = Record<string, string[]>;

export class ElasticsearchIndexFieldAdapter implements FieldsAdapter {
constructor(private readonly framework: FrameworkAdapter) {}

public async getIndexFields(request: FrameworkRequest, indices: string[]): Promise<IndexField[]> {
const indexPatternsService = this.framework.getIndexPatternsService(request);
const indexesAliasIndices: IndexesAliasIndices = indices.reduce(
(accumulator: IndexesAliasIndices, indice: string) => {
const key = getIndexAlias(indices, indice);
const indexesAliasIndices = indices.reduce<Record<string, string[]>>((accumulator, indice) => {
const key = getIndexAlias(indices, indice);

if (get(key, accumulator)) {
accumulator[key] = [...accumulator[key], indice];
} else {
accumulator[key] = [indice];
}
return accumulator;
},
{} as IndexesAliasIndices
);
if (get(key, accumulator)) {
accumulator[key] = [...accumulator[key], indice];
} else {
accumulator[key] = [indice];
}
return accumulator;
}, {});
const responsesIndexFields: IndexFieldDescriptor[][] = await Promise.all(
Object.values(indexesAliasIndices).map((indicesByGroup) =>
indexPatternsService.getFieldsForWildcard({
Expand Down
107 changes: 91 additions & 16 deletions x-pack/test/api_integration/apis/security_solution/sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,97 @@ export default function ({ getService }: FtrProviderContext) {
before(() => esArchiver.load('auditbeat/default'));
after(() => esArchiver.unload('auditbeat/default'));

it('Make sure that we get source information when auditbeat indices is there', () => {
return client
.query<SourceQuery.Query>({
query: sourceQuery,
variables: {
sourceId: 'default',
defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
docValueFields: [],
},
})
.then((resp) => {
const sourceStatus = resp.data.source.status;
// test data in x-pack/test/functional/es_archives/auditbeat_test_data/data.json.gz
expect(sourceStatus.indexFields.length).to.be(397);
expect(sourceStatus.indicesExist).to.be(true);
});
it('Make sure that we get source information when auditbeat indices is there', async () => {
const resp = await client.query<SourceQuery.Query>({
query: sourceQuery,
variables: {
sourceId: 'default',
defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
docValueFields: [],
},
});
const sourceStatus = resp.data.source.status;
// test data in x-pack/test/functional/es_archives/auditbeat_test_data/data.json.gz
expect(sourceStatus.indexFields.length).to.be(397);
expect(sourceStatus.indicesExist).to.be(true);
});

it('should find indexes as being available when they exist', async () => {
const resp = await client.query<SourceQuery.Query>({
query: sourceQuery,
variables: {
sourceId: 'default',
defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
docValueFields: [],
},
});
const sourceStatus = resp.data.source.status;
expect(sourceStatus.indicesExist).to.be(true);
});

it('should not find indexes as existing when there is an empty array of them', async () => {
const resp = await client.query<SourceQuery.Query>({
query: sourceQuery,
variables: {
sourceId: 'default',
defaultIndex: [],
docValueFields: [],
},
});
const sourceStatus = resp.data.source.status;
expect(sourceStatus.indicesExist).to.be(false);
});

it('should not find indexes as existing when there is a _all within it', async () => {
const resp = await client.query<SourceQuery.Query>({
query: sourceQuery,
variables: {
sourceId: 'default',
defaultIndex: ['_all'],
docValueFields: [],
},
});
const sourceStatus = resp.data.source.status;
expect(sourceStatus.indicesExist).to.be(false);
});

it('should not find indexes as existing when there are empty strings within it', async () => {
const resp = await client.query<SourceQuery.Query>({
query: sourceQuery,
variables: {
sourceId: 'default',
defaultIndex: [''],
docValueFields: [],
},
});
const sourceStatus = resp.data.source.status;
expect(sourceStatus.indicesExist).to.be(false);
});

it('should not find indexes as existing when there are blank spaces within it', async () => {
const resp = await client.query<SourceQuery.Query>({
query: sourceQuery,
variables: {
sourceId: 'default',
defaultIndex: [' '],
docValueFields: [],
},
});
const sourceStatus = resp.data.source.status;
expect(sourceStatus.indicesExist).to.be(false);
});

it('should find indexes when one is an empty index but the others are valid', async () => {
const resp = await client.query<SourceQuery.Query>({
query: sourceQuery,
variables: {
sourceId: 'default',
defaultIndex: ['', 'auditbeat-*'],
docValueFields: [],
},
});
const sourceStatus = resp.data.source.status;
expect(sourceStatus.indicesExist).to.be(true);
});
});
}

0 comments on commit 75eda66

Please sign in to comment.