[Security Solution][Alerts] fixes new terms multi fields timeline issue (#146185)

## Summary

- fixes https://github.com/elastic/kibana/issues/146131

### Before

https://user-images.githubusercontent.com/92328789/203600097-589d4b8b-c238-48e4-bf72-2f2efcc39ac2.mp4

### After

https://user-images.githubusercontent.com/92328789/203599864-37a4ccc3-12b8-4c48-87ea-559d15582ef9.mov


### For maintainers




- [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
This commit is contained in:
Vitalii Dmyterko 2022-11-28 17:26:07 +00:00 committed by GitHub
parent ab8dd04073
commit 0f31951235
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 18 deletions

View file

@ -7,6 +7,8 @@
import sinon from 'sinon';
import moment from 'moment';
import set from 'lodash/set';
import cloneDeep from 'lodash/cloneDeep';
import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types';
import type { Filter } from '@kbn/es-query';
@ -16,6 +18,7 @@ import {
sendAlertToTimelineAction,
sendBulkEventsToTimelineAction,
determineToAndFrom,
getNewTermsData,
} from './actions';
import {
defaultTimelineProps,
@ -933,6 +936,63 @@ describe('alert actions', () => {
});
});
describe('New terms', () => {
describe('getNewTermsData', () => {
it('should return new terms data correctly for single value field', () => {
const newTermsEcsMock = cloneDeep(ecsDataMockWithNoTemplateTimeline[0]);
set(newTermsEcsMock, 'kibana.alert.new_terms', ['host-0']);
set(newTermsEcsMock, 'kibana.alert.rule.parameters.new_terms_fields', ['host.name']);
expect(getNewTermsData(newTermsEcsMock).dataProviders).toEqual([
{
and: [],
enabled: true,
excluded: false,
id: 'send-alert-to-timeline-action-default-draggable-event-details-value-formatted-field-value-timeline-1-host-name-host-0',
kqlQuery: '',
name: 'host.name',
queryMatch: { field: 'host.name', operator: ':', value: 'host-0' },
},
]);
});
it('should return new terms data as AND query for multiple values field', () => {
const newTermsEcsMock = cloneDeep(ecsDataMockWithNoTemplateTimeline[0]);
set(newTermsEcsMock, 'kibana.alert.new_terms', ['host-0', '127.0.0.1']);
set(newTermsEcsMock, 'kibana.alert.rule.parameters.new_terms_fields', [
'host.name',
'host.ip',
]);
expect(getNewTermsData(newTermsEcsMock).dataProviders).toEqual([
{
and: [
{
and: [],
enabled: true,
excluded: false,
id: 'send-alert-to-timeline-action-default-draggable-event-details-value-formatted-field-value-timeline-1-host-ip-127.0.0.1',
kqlQuery: '',
name: 'host.ip',
queryMatch: {
field: 'host.ip',
operator: ':',
value: '127.0.0.1',
},
},
],
enabled: true,
excluded: false,
id: 'send-alert-to-timeline-action-default-draggable-event-details-value-formatted-field-value-timeline-1-host-name-host-0',
kqlQuery: '',
name: 'host.name',
queryMatch: { field: 'host.name', operator: ':', value: 'host-0' },
},
]);
});
});
});
describe('determineToAndFrom', () => {
beforeEach(() => {
fetchMock.mockResolvedValue({

View file

@ -560,29 +560,38 @@ const createThresholdTimeline = async (
}
};
const getNewTermsData = (ecsData: Ecs | Ecs[]) => {
export const getNewTermsData = (ecsData: Ecs | Ecs[]) => {
const normalizedEcsData: Ecs = Array.isArray(ecsData) ? ecsData[0] : ecsData;
const originalTimeValue = getField(normalizedEcsData, ALERT_ORIGINAL_TIME);
const newTermsField = getField(normalizedEcsData, `${ALERT_RULE_PARAMETERS}.new_terms_fields`)[0];
const newTermsValue = getField(normalizedEcsData, ALERT_NEW_TERMS)[0];
const newTermsFieldId = newTermsField.replace('.', '-');
const dataProviderPartial = {
id: `send-alert-to-timeline-action-default-draggable-event-details-value-formatted-field-value-${TimelineId.active}-${newTermsFieldId}-${newTermsValue}`,
name: newTermsField,
enabled: true,
excluded: false,
kqlQuery: '',
queryMatch: {
field: newTermsField,
value: newTermsValue,
operator: ':' as const,
},
and: [],
};
const newTermsFields: string[] =
getField(normalizedEcsData, `${ALERT_RULE_PARAMETERS}.new_terms_fields`) ?? [];
const dataProviderPartials = newTermsFields.map((newTermsField, index) => {
const newTermsFieldId = newTermsField.replace('.', '-');
const newTermsValue = getField(normalizedEcsData, ALERT_NEW_TERMS)[index];
return {
id: `send-alert-to-timeline-action-default-draggable-event-details-value-formatted-field-value-${TimelineId.active}-${newTermsFieldId}-${newTermsValue}`,
name: newTermsField,
enabled: true,
excluded: false,
kqlQuery: '',
queryMatch: {
field: newTermsField,
value: newTermsValue,
operator: ':' as const,
},
and: [],
};
});
const dataProviders = dataProviderPartials.length
? [{ ...dataProviderPartials[0], and: dataProviderPartials.slice(1) }]
: [];
return {
from: originalTimeValue,
to: moment().toISOString(),
dataProviders: [dataProviderPartial],
dataProviders,
};
};