[SIEM] Fix for removal of first filter clearing remaining filters (#37135) (#37144)

## Summary

As outlined in https://github.com/elastic/ingest-dev/issues/419, clearing the first filter within the Timeline Query Builder would result in all the remaining `and`'d filters being cleared as well. This PR fixes that issues, and adds testing to catch a future regressions.

Before:
![filter_query_clear_bug](https://user-images.githubusercontent.com/2946766/58357586-a26f9200-7e38-11e9-8c5e-11bbdfcabfef.gif)


After:
![filter_clear_fix](https://user-images.githubusercontent.com/2946766/58357436-05145e00-7e38-11e9-8a51-b90481afb9b9.gif)


### Checklist

Use ~~strikethroughs~~ to remove checklist items you don't feel are applicable to this PR.

- [x] This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) 
  - IE11 needs this fix to be applicable: https://github.com/elastic/ingest-dev/issues/263
- [ ] ~Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/master/packages/kbn-i18n/README.md)~
- [ ] ~[Documentation](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#writing-documentation) was added for features that require explanation or tutorials~
- [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
- [ ] ~This was checked for [keyboard-only and screenreader accessibility](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Accessibility_testing_checklist)~

### For maintainers

- [ ] ~This was checked for breaking API changes and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~
- [ ] ~This includes a feature addition or change that requires a release note and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~
This commit is contained in:
Garrett Spong 2019-05-28 08:47:39 -06:00 committed by GitHub
parent b403fe3d22
commit acf4b798cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 358 additions and 1 deletions

View file

@ -1000,6 +1000,14 @@ const removeProvider = (providerId: string, timeline: TimelineModel) => {
const providerIndex = timeline.dataProviders.findIndex(p => p.id === providerId);
return [
...timeline.dataProviders.slice(0, providerIndex),
...(timeline.dataProviders[providerIndex].and.length
? [
{
...timeline.dataProviders[providerIndex].and.slice(0, 1)[0],
and: [...timeline.dataProviders[providerIndex].and.slice(1)],
},
]
: []),
...timeline.dataProviders.slice(providerIndex + 1),
];
};

View file

@ -7,7 +7,11 @@
import { cloneDeep, set } from 'lodash/fp';
import { ColumnHeader } from '../../components/timeline/body/column_headers/column_header';
import { IS_OPERATOR, DataProvider } from '../../components/timeline/data_providers/data_provider';
import {
IS_OPERATOR,
DataProvider,
DataProvidersAnd,
} from '../../components/timeline/data_providers/data_provider';
import { defaultColumnHeaderType } from '../../components/timeline/body/column_headers/default_headers';
import {
DEFAULT_COLUMN_MIN_WIDTH,
@ -1706,5 +1710,350 @@ describe('Timeline', () => {
};
expect(update).toEqual(expected);
});
test('should remove only first provider and not nested andProvider', () => {
const dataProviders: DataProvider[] = [
{
and: [],
id: '111',
name: 'data provider 1',
enabled: true,
queryMatch: {
field: '',
value: '',
operator: IS_OPERATOR,
},
excluded: false,
kqlQuery: '',
},
{
and: [],
id: '222',
name: 'data provider 2',
enabled: true,
queryMatch: {
field: '',
value: '',
operator: IS_OPERATOR,
},
excluded: false,
kqlQuery: '',
},
{
and: [],
id: '333',
name: 'data provider 3',
enabled: true,
queryMatch: {
field: '',
value: '',
operator: IS_OPERATOR,
},
excluded: false,
kqlQuery: '',
},
];
const multiDataProviderMock = set('foo.dataProviders', dataProviders, timelineByIdMock);
const andDataProvider: DataProvidersAnd = {
id: '211',
name: 'And Data Provider',
enabled: true,
queryMatch: {
field: '',
value: '',
operator: IS_OPERATOR,
},
excluded: false,
kqlQuery: '',
};
const nestedMultiAndDataProviderMock = set(
'foo.dataProviders[1].and',
[andDataProvider],
multiDataProviderMock
);
const update = removeTimelineProvider({
id: 'foo',
providerId: '222',
timelineById: nestedMultiAndDataProviderMock,
});
expect(update).toEqual(
set(
'foo.dataProviders',
[
nestedMultiAndDataProviderMock.foo.dataProviders[0],
{ ...andDataProvider, and: [] },
nestedMultiAndDataProviderMock.foo.dataProviders[2],
],
timelineByIdMock
)
);
});
test('should remove only the first provider and keep multiple nested andProviders', () => {
const multiDataProvider: DataProvider[] = [
{
and: [
{
enabled: true,
id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root',
name: 'root',
excluded: false,
kqlQuery: '',
queryMatch: {
field: 'user.name',
value: 'root',
operator: ':',
},
},
{
enabled: true,
id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success',
name: 'success',
excluded: false,
kqlQuery: '',
queryMatch: {
field: 'auditd.result',
value: 'success',
operator: ':',
},
},
],
enabled: true,
excluded: false,
id: 'hosts-table-hostName-suricata-iowa',
name: 'suricata-iowa',
kqlQuery: '',
queryMatch: {
field: 'host.name',
value: 'suricata-iowa',
operator: ':',
},
},
];
const multiDataProviderMock = set('foo.dataProviders', multiDataProvider, timelineByIdMock);
const update = removeTimelineProvider({
id: 'foo',
providerId: 'hosts-table-hostName-suricata-iowa',
timelineById: multiDataProviderMock,
});
expect(update).toEqual(
set(
'foo.dataProviders',
[
{
enabled: true,
id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root',
name: 'root',
excluded: false,
kqlQuery: '',
queryMatch: {
field: 'user.name',
value: 'root',
operator: ':',
},
and: [
{
enabled: true,
id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success',
name: 'success',
excluded: false,
kqlQuery: '',
queryMatch: {
field: 'auditd.result',
value: 'success',
operator: ':',
},
},
],
},
],
timelineByIdMock
)
);
});
test('should remove only the first AND provider when the first AND is deleted, and there are multiple andProviders', () => {
const multiDataProvider: DataProvider[] = [
{
and: [
{
enabled: true,
id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root',
name: 'root',
excluded: false,
kqlQuery: '',
queryMatch: {
field: 'user.name',
value: 'root',
operator: ':',
},
},
{
enabled: true,
id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success',
name: 'success',
excluded: false,
kqlQuery: '',
queryMatch: {
field: 'auditd.result',
value: 'success',
operator: ':',
},
},
],
enabled: true,
excluded: false,
id: 'hosts-table-hostName-suricata-iowa',
name: 'suricata-iowa',
kqlQuery: '',
queryMatch: {
field: 'host.name',
value: 'suricata-iowa',
operator: ':',
},
},
];
const multiDataProviderMock = set('foo.dataProviders', multiDataProvider, timelineByIdMock);
const update = removeTimelineProvider({
andProviderId: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root',
id: 'foo',
providerId: 'hosts-table-hostName-suricata-iowa',
timelineById: multiDataProviderMock,
});
expect(update).toEqual(
set(
'foo.dataProviders',
[
{
and: [
{
enabled: true,
id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success',
name: 'success',
excluded: false,
kqlQuery: '',
queryMatch: {
field: 'auditd.result',
value: 'success',
operator: ':',
},
},
],
enabled: true,
excluded: false,
id: 'hosts-table-hostName-suricata-iowa',
name: 'suricata-iowa',
kqlQuery: '',
queryMatch: {
field: 'host.name',
value: 'suricata-iowa',
operator: ':',
},
},
],
timelineByIdMock
)
);
});
test('should remove only the second AND provider when the second AND is deleted, and there are multiple andProviders', () => {
const multiDataProvider: DataProvider[] = [
{
and: [
{
enabled: true,
id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root',
name: 'root',
excluded: false,
kqlQuery: '',
queryMatch: {
field: 'user.name',
value: 'root',
operator: ':',
},
},
{
enabled: true,
id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success',
name: 'success',
excluded: false,
kqlQuery: '',
queryMatch: {
field: 'auditd.result',
value: 'success',
operator: ':',
},
},
],
enabled: true,
excluded: false,
id: 'hosts-table-hostName-suricata-iowa',
name: 'suricata-iowa',
kqlQuery: '',
queryMatch: {
field: 'host.name',
value: 'suricata-iowa',
operator: ':',
},
},
];
const multiDataProviderMock = set('foo.dataProviders', multiDataProvider, timelineByIdMock);
const update = removeTimelineProvider({
andProviderId: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success',
id: 'foo',
providerId: 'hosts-table-hostName-suricata-iowa',
timelineById: multiDataProviderMock,
});
expect(update).toEqual(
set(
'foo.dataProviders',
[
{
and: [
{
enabled: true,
id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root',
name: 'root',
excluded: false,
kqlQuery: '',
queryMatch: {
field: 'user.name',
value: 'root',
operator: ':',
},
},
],
enabled: true,
excluded: false,
id: 'hosts-table-hostName-suricata-iowa',
name: 'suricata-iowa',
kqlQuery: '',
queryMatch: {
field: 'host.name',
value: 'suricata-iowa',
operator: ':',
},
},
],
timelineByIdMock
)
);
});
});
});