[Security Solution] expandable flyout - fix prevalence query not taking into account fields with multiple values (#166891)

This commit is contained in:
Philippe Oberti 2023-09-27 22:26:36 +02:00 committed by GitHub
parent 7b4e6a6775
commit af51e26333
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 87 additions and 42 deletions

View file

@ -79,7 +79,7 @@ describe('PrevalenceDetails', () => {
data: [
{
field: field1,
value: 'value1',
values: ['value1'],
alertCount: 1,
docCount: 1,
hostPrevalence: 0.05,
@ -87,7 +87,7 @@ describe('PrevalenceDetails', () => {
},
{
field: field2,
value: 'value2',
values: ['value2'],
alertCount: 1,
docCount: 1,
hostPrevalence: 0.5,
@ -124,7 +124,7 @@ describe('PrevalenceDetails', () => {
data: [
{
field: 'field1',
value: 'value1',
values: ['value1'],
alertCount: 1000,
docCount: 2000000,
hostPrevalence: 0.05,
@ -154,6 +154,35 @@ describe('PrevalenceDetails', () => {
);
});
it('should render multiple values in value column', () => {
(usePrevalence as jest.Mock).mockReturnValue({
loading: false,
error: false,
data: [
{
field: 'field1',
values: ['value1', 'value2'],
alertCount: 1000,
docCount: 2000000,
hostPrevalence: 0.05,
userPrevalence: 0.1,
},
],
});
const { getByTestId } = render(
<TestProviders>
<LeftPanelContext.Provider value={panelContextValue}>
<PrevalenceDetails />
</LeftPanelContext.Provider>
</TestProviders>
);
expect(getByTestId(PREVALENCE_DETAILS_TABLE_TEST_ID)).toBeInTheDocument();
expect(getByTestId(PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID)).toHaveTextContent('value1');
expect(getByTestId(PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID)).toHaveTextContent('value2');
});
it('should render the table with only basic columns if license is not platinum', () => {
const field1 = 'field1';
const field2 = 'field2';
@ -163,7 +192,7 @@ describe('PrevalenceDetails', () => {
data: [
{
field: field1,
value: 'value1',
values: ['value1'],
alertCount: 1,
docCount: 1,
hostPrevalence: 0.05,
@ -171,7 +200,7 @@ describe('PrevalenceDetails', () => {
},
{
field: field2,
value: 'value2',
values: ['value2'],
alertCount: 1,
docCount: 1,
hostPrevalence: 0.5,

View file

@ -74,7 +74,7 @@ const columns: Array<EuiBasicTableColumn<PrevalenceDetailsRow>> = [
width: '20%',
},
{
field: 'value',
field: 'values',
name: (
<FormattedMessage
id="xpack.securitySolution.flyout.left.insights.prevalence.valueColumnLabel"
@ -82,7 +82,15 @@ const columns: Array<EuiBasicTableColumn<PrevalenceDetailsRow>> = [
/>
),
'data-test-subj': PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID,
render: (value: string) => <EuiText size="xs">{value}</EuiText>,
render: (values: string[]) => (
<EuiFlexGroup direction="column" gutterSize="none">
{values.map((value) => (
<EuiFlexItem key={value}>
<EuiText size="xs">{value}</EuiText>
</EuiFlexItem>
))}
</EuiFlexGroup>
),
width: '20%',
},
{
@ -113,9 +121,9 @@ const columns: Array<EuiBasicTableColumn<PrevalenceDetailsRow>> = [
),
'data-test-subj': PREVALENCE_DETAILS_TABLE_ALERT_COUNT_CELL_TEST_ID,
render: (data: PrevalenceDetailsRow) => {
const dataProviders = [
getDataProvider(data.field, `timeline-indicator-${data.field}-${data.value}`, data.value),
];
const dataProviders = data.values.map((value) =>
getDataProvider(data.field, `timeline-indicator-${data.field}-${value}`, value)
);
return data.alertCount > 0 ? (
<InvestigateInTimelineButton
asEmptyButton={true}
@ -159,24 +167,18 @@ const columns: Array<EuiBasicTableColumn<PrevalenceDetailsRow>> = [
),
'data-test-subj': PREVALENCE_DETAILS_TABLE_DOC_COUNT_CELL_TEST_ID,
render: (data: PrevalenceDetailsRow) => {
const dataProviders = [
{
...getDataProvider(
data.field,
`timeline-indicator-${data.field}-${data.value}`,
data.value
const dataProviders = data.values.map((value) => ({
...getDataProvider(data.field, `timeline-indicator-${data.field}-${value}`, value),
and: [
getDataProviderAnd(
'event.kind',
`timeline-indicator-event.kind-not-signal`,
'signal',
IS_OPERATOR,
true
),
and: [
getDataProviderAnd(
'event.kind',
`timeline-indicator-event.kind-not-signal`,
'signal',
IS_OPERATOR,
true
),
],
},
];
],
}));
return data.docCount > 0 ? (
<InvestigateInTimelineButton
asEmptyButton={true}

View file

@ -91,13 +91,14 @@ describe('<PrevalenceOverview />', () => {
it('should render only data with prevalence less than 10%', () => {
const field1 = 'field1';
const field2 = 'field2';
const field3 = 'field3';
(usePrevalence as jest.Mock).mockReturnValue({
loading: false,
error: false,
data: [
{
field: field1,
value: 'value1',
values: ['value1'],
alertCount: 1,
docCount: 1,
hostPrevalence: 0.05,
@ -105,7 +106,15 @@ describe('<PrevalenceOverview />', () => {
},
{
field: field2,
value: 'value2',
values: ['value2', 'value22'],
alertCount: 1,
docCount: 1,
hostPrevalence: 0.06,
userPrevalence: 0.2,
},
{
field: field3,
values: ['value3'],
alertCount: 1,
docCount: 1,
hostPrevalence: 0.5,
@ -126,8 +135,14 @@ describe('<PrevalenceOverview />', () => {
const iconDataTestSubj2 = `${PREVALENCE_TEST_ID}${field2}Icon`;
const valueDataTestSubj2 = `${PREVALENCE_TEST_ID}${field2}Value`;
expect(queryByTestId(iconDataTestSubj2)).not.toBeInTheDocument();
expect(queryByTestId(valueDataTestSubj2)).not.toBeInTheDocument();
expect(getByTestId(iconDataTestSubj2)).toBeInTheDocument();
expect(getByTestId(valueDataTestSubj2)).toBeInTheDocument();
expect(getByTestId(valueDataTestSubj2)).toHaveTextContent('field2, value2,value22 is uncommon');
const iconDataTestSubj3 = `${PREVALENCE_TEST_ID}${field3}Icon`;
const valueDataTestSubj3 = `${PREVALENCE_TEST_ID}${field3}Value`;
expect(queryByTestId(iconDataTestSubj3)).not.toBeInTheDocument();
expect(queryByTestId(valueDataTestSubj3)).not.toBeInTheDocument();
expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument();
});
@ -139,7 +154,7 @@ describe('<PrevalenceOverview />', () => {
data: [
{
field: 'field1',
value: 'value1',
values: ['value1'],
alertCount: 1,
docCount: 1,
hostPrevalence: 0.05,

View file

@ -99,7 +99,7 @@ export const PrevalenceOverview: FC = () => {
<FormattedMessage
id="xpack.securitySolution.flyout.right.insights.prevalence.rowDescription"
defaultMessage="{field}, {value} is uncommon"
values={{ field: d.field, value: d.value }}
values={{ field: d.field, value: d.values.toString() }}
/>
}
data-test-subj={`${PREVALENCE_TEST_ID}${d.field}`}

View file

@ -124,7 +124,7 @@ describe('usePrevalence', () => {
expect(hookResult.result.current.data).toEqual([
{
field: 'host.name',
value: 'host-1',
values: ['host-1'],
alertCount: 1,
docCount: 1,
hostPrevalence: 0.1,

View file

@ -6,7 +6,6 @@
*/
import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common';
import { isArray } from 'lodash/fp';
import { useMemo } from 'react';
import { useHighlightedFields } from './use_highlighted_fields';
import { convertHighlightedFieldsToPrevalenceFilters } from '../utils/highlighted_fields_helpers';
@ -24,7 +23,7 @@ import { EventKind } from '../constants/event_kinds';
export interface PrevalenceData {
field: string;
value: string;
values: string[];
alertCount: number;
docCount: number;
hostPrevalence: number;
@ -91,7 +90,7 @@ export const usePrevalence = ({
const fieldNames = Object.keys(data.aggregations[FIELD_NAMES_AGG_KEY].buckets);
fieldNames.forEach((fieldName: string) => {
const fieldValue = highlightedFields[fieldName].values;
const fieldValues = highlightedFields[fieldName].values;
// retrieves the number of signals for the current field/value pair
const alertCount =
@ -131,7 +130,7 @@ export const usePrevalence = ({
items.push({
field: fieldName,
value: isArray(fieldValue) ? fieldValue[0] : fieldValue,
values: fieldValues,
alertCount,
docCount,
hostPrevalence,

View file

@ -58,12 +58,12 @@ describe('convertHighlightedFieldsToPrevalenceFilters', () => {
values: ['host-1'],
},
'user.name': {
values: ['user-1'],
values: ['user-1', 'user-2'],
},
};
expect(convertHighlightedFieldsToPrevalenceFilters(highlightedFields)).toEqual({
'host.name': { match: { 'host.name': 'host-1' } },
'user.name': { match: { 'user.name': 'user-1' } },
'host.name': { terms: { 'host.name': ['host-1'] } },
'user.name': { terms: { 'user.name': ['user-1', 'user-2'] } },
});
});
});

View file

@ -48,7 +48,7 @@ export const convertHighlightedFieldsToPrevalenceFilters = (
return {
...acc,
[curr]: { match: { [curr]: Array.isArray(values) ? values[0] : values } },
[curr]: { terms: { [curr]: values } },
};
}, []) as unknown as Record<string, QueryDslQueryContainer>;
};