Skip to content

Commit

Permalink
[8.13] [Security Solution] Add dataViewId to filter actions (#177946) (
Browse files Browse the repository at this point in the history
…#178081)

# Backport

This will backport the following commits from `main` to `8.13`:
- [[Security Solution] Add dataViewId to filter actions
(#177946)](#177946)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Sergi
Massaneda","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-03-06T10:57:41Z","message":"[Security
Solution] Add dataViewId to filter actions (#177946)\n\n##
Summary\r\n\r\nThis PR fixes a bug related to the filter
edition:\r\nhttps://github.com//issues/164406\r\n\r\nFilter
actions were missing the `meta.index` value, which needs to
be\r\nassigned to the dataView id being used. When the filter is edited,
the\r\nfilter component retrieves the index pattern from the dataView
saved\r\nobject.\r\n\r\nThe `meta.index` value has been added to all the
\"Filter in/out\" actions\r\nusing the `CellActions` metadata
object.\r\n\r\nThanks @angorayc for catching this and implementing the
fix\r\n\r\n###
Screenshots\r\n\r\nBefore:\r\n\r\n\r\n![before](https://github.com/elastic/kibana/assets/17747913/6e60cc1f-7811-4c97-8da0-95b688dd3d96)\r\n\r\nAfter:\r\n\r\n\r\n![after](https://github.com/elastic/kibana/assets/17747913/abaf740f-6ec0-4263-8455-d9f14dc3e423)\r\n\r\n---------\r\n\r\nCo-authored-by:
Angela Chuang <[email protected]>\r\nCo-authored-by:
kibanamachine
<[email protected]>\r\nCo-authored-by:
Angela Chuang
<[email protected]>","sha":"406b24c6a8758fc82218ad5dbaf048677454d0d9","branchLabelMapping":{"^v8.14.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:fix","Team:Threat
Hunting","Team:Threat
Hunting:Explore","v8.13.0","v8.14.0","v8.12.3"],"title":"[Security
Solution] Add dataViewId to filter
actions","number":177946,"url":"https://github.com/elastic/kibana/pull/177946","mergeCommit":{"message":"[Security
Solution] Add dataViewId to filter actions (#177946)\n\n##
Summary\r\n\r\nThis PR fixes a bug related to the filter
edition:\r\nhttps://github.com//issues/164406\r\n\r\nFilter
actions were missing the `meta.index` value, which needs to
be\r\nassigned to the dataView id being used. When the filter is edited,
the\r\nfilter component retrieves the index pattern from the dataView
saved\r\nobject.\r\n\r\nThe `meta.index` value has been added to all the
\"Filter in/out\" actions\r\nusing the `CellActions` metadata
object.\r\n\r\nThanks @angorayc for catching this and implementing the
fix\r\n\r\n###
Screenshots\r\n\r\nBefore:\r\n\r\n\r\n![before](https://github.com/elastic/kibana/assets/17747913/6e60cc1f-7811-4c97-8da0-95b688dd3d96)\r\n\r\nAfter:\r\n\r\n\r\n![after](https://github.com/elastic/kibana/assets/17747913/abaf740f-6ec0-4263-8455-d9f14dc3e423)\r\n\r\n---------\r\n\r\nCo-authored-by:
Angela Chuang <[email protected]>\r\nCo-authored-by:
kibanamachine
<[email protected]>\r\nCo-authored-by:
Angela Chuang
<[email protected]>","sha":"406b24c6a8758fc82218ad5dbaf048677454d0d9"}},"sourceBranch":"main","suggestedTargetBranches":["8.13","8.12"],"targetPullRequestStates":[{"branch":"8.13","label":"v8.13.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.14.0","branchLabelMappingKey":"^v8.14.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/177946","number":177946,"mergeCommit":{"message":"[Security
Solution] Add dataViewId to filter actions (#177946)\n\n##
Summary\r\n\r\nThis PR fixes a bug related to the filter
edition:\r\nhttps://github.com//issues/164406\r\n\r\nFilter
actions were missing the `meta.index` value, which needs to
be\r\nassigned to the dataView id being used. When the filter is edited,
the\r\nfilter component retrieves the index pattern from the dataView
saved\r\nobject.\r\n\r\nThe `meta.index` value has been added to all the
\"Filter in/out\" actions\r\nusing the `CellActions` metadata
object.\r\n\r\nThanks @angorayc for catching this and implementing the
fix\r\n\r\n###
Screenshots\r\n\r\nBefore:\r\n\r\n\r\n![before](https://github.com/elastic/kibana/assets/17747913/6e60cc1f-7811-4c97-8da0-95b688dd3d96)\r\n\r\nAfter:\r\n\r\n\r\n![after](https://github.com/elastic/kibana/assets/17747913/abaf740f-6ec0-4263-8455-d9f14dc3e423)\r\n\r\n---------\r\n\r\nCo-authored-by:
Angela Chuang <[email protected]>\r\nCo-authored-by:
kibanamachine
<[email protected]>\r\nCo-authored-by:
Angela Chuang
<[email protected]>","sha":"406b24c6a8758fc82218ad5dbaf048677454d0d9"}},{"branch":"8.12","label":"v8.12.3","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

---------

Co-authored-by: Sergi Massaneda <[email protected]>
  • Loading branch information
kibanamachine and semd authored Mar 6, 2024
1 parent ae7c4da commit d4ec567
Show file tree
Hide file tree
Showing 53 changed files with 364 additions and 928 deletions.
20 changes: 13 additions & 7 deletions packages/kbn-cell-actions/src/actions/filter/create_filter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,23 @@ const field = 'field.name';
const value = 'the-value';
const numberValue = 123;
const booleanValue = true;
const dataViewId = 'mock-data-view-id';

describe('createFilter', () => {
it.each([
{ caseName: 'string array', caseValue: [value] },
{ caseName: 'number array', caseValue: [numberValue], query: numberValue.toString() },
{ caseName: 'boolean array', caseValue: [booleanValue], query: booleanValue.toString() },
])('should return filter with $caseName value', ({ caseValue, query = value }) => {
expect(createFilter({ key: field, value: caseValue, negate: false })).toEqual({
expect(createFilter({ key: field, value: caseValue, negate: false, dataViewId })).toEqual({
meta: {
type: 'phrase',
key: field,
negate: false,
params: {
query,
},
index: dataViewId,
},
query: {
match_phrase: {
Expand All @@ -43,14 +45,15 @@ describe('createFilter', () => {
{ caseName: 'number array', caseValue: [numberValue], query: numberValue.toString() },
{ caseName: 'boolean array', caseValue: [booleanValue], query: booleanValue.toString() },
])('should return negate filter with $caseName value', ({ caseValue, query = value }) => {
expect(createFilter({ key: field, value: caseValue, negate: true })).toEqual({
expect(createFilter({ key: field, value: caseValue, negate: true, dataViewId })).toEqual({
meta: {
type: 'phrase',
key: field,
negate: true,
params: {
query,
},
index: dataViewId,
},
query: {
match_phrase: {
Expand All @@ -67,19 +70,20 @@ describe('createFilter', () => {
{ caseName: 'negated', negate: true },
])('should return combined filter with multiple $caseName values', ({ negate }) => {
const value2 = 'the-value2';
expect(createFilter({ key: field, value: [value, value2], negate })).toEqual({
expect(createFilter({ key: field, value: [value, value2], negate, dataViewId })).toEqual({
meta: {
type: 'combined',
relation: 'AND',
key: field,
negate,
index: dataViewId,
params: [
{
meta: { type: 'phrase', key: field, params: { query: value } },
meta: { type: 'phrase', key: field, params: { query: value }, index: dataViewId },
query: { match_phrase: { [field]: { query: value } } },
},
{
meta: { type: 'phrase', key: field, params: { query: value2 } },
meta: { type: 'phrase', key: field, params: { query: value2 }, index: dataViewId },
query: { match_phrase: { [field]: { query: value2 } } },
},
],
Expand All @@ -90,13 +94,14 @@ describe('createFilter', () => {
it.each([{ caseName: 'empty array', caseValue: [] }])(
'should return exist filter with $caseName value',
({ caseValue }) => {
expect(createFilter({ key: field, value: caseValue, negate: false })).toEqual({
expect(createFilter({ key: field, value: caseValue, negate: false, dataViewId })).toEqual({
query: {
exists: {
field,
},
},
meta: {
index: dataViewId,
key: field,
negate: false,
type: 'exists',
Expand All @@ -109,13 +114,14 @@ describe('createFilter', () => {
it.each([{ caseName: 'empty array', caseValue: [] }])(
'should return negate exist filter with $caseName value',
({ caseValue }) => {
expect(createFilter({ key: field, value: caseValue, negate: true })).toEqual({
expect(createFilter({ key: field, value: caseValue, negate: true, dataViewId })).toEqual({
query: {
exists: {
field,
},
},
meta: {
index: dataViewId,
key: field,
negate: true,
type: 'exists',
Expand Down
28 changes: 22 additions & 6 deletions packages/kbn-cell-actions/src/actions/filter/create_filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,32 @@ import { DefaultActionsSupportedValue } from '../types';
export const isEmptyFilterValue = (value: Array<string | number | boolean>) =>
value.length === 0 || value.every((v) => v === '');

const createExistsFilter = ({ key, negate }: { key: string; negate: boolean }): ExistsFilter => ({
meta: { key, negate, type: FILTERS.EXISTS, value: 'exists' },
const createExistsFilter = ({
key,
negate,
dataViewId,
}: {
key: string;
negate: boolean;
dataViewId?: string;
}): ExistsFilter => ({
meta: { key, negate, type: FILTERS.EXISTS, value: 'exists', index: dataViewId },
query: { exists: { field: key } },
});

const createPhraseFilter = ({
key,
negate,
value,
dataViewId,
}: {
value: string | number | boolean;
key: string;
negate?: boolean;
dataViewId?: string;
}): PhraseFilter => ({
meta: {
index: dataViewId,
key,
negate,
type: FILTERS.PHRASE,
Expand All @@ -45,36 +56,41 @@ const createCombinedFilter = ({
values,
key,
negate,
dataViewId,
}: {
values: DefaultActionsSupportedValue;
key: string;
negate: boolean;
dataViewId?: string;
}): CombinedFilter => ({
meta: {
index: dataViewId,
key,
negate,
type: FILTERS.COMBINED,
relation: BooleanRelation.AND,
params: values.map((value) => createPhraseFilter({ key, value })),
params: values.map((value) => createPhraseFilter({ key, value, dataViewId })),
},
});

export const createFilter = ({
key,
value,
negate,
dataViewId,
}: {
key: string;
value: DefaultActionsSupportedValue;
negate: boolean;
dataViewId?: string;
}): Filter => {
if (value.length === 0) {
return createExistsFilter({ key, negate });
return createExistsFilter({ key, negate, dataViewId });
}

if (value.length > 1) {
return createCombinedFilter({ key, negate, values: value });
return createCombinedFilter({ key, negate, values: value, dataViewId });
} else {
return createPhraseFilter({ key, negate, value: value[0] });
return createPhraseFilter({ key, negate, value: value[0], dataViewId });
}
};
25 changes: 22 additions & 3 deletions packages/kbn-cell-actions/src/actions/filter/filter_in.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jest.mock('./create_filter', () => ({

const fieldName = 'user.name';
const value = 'the value';
const dataViewId = 'mockDataViewId';

const mockWarningToast = jest.fn();

Expand Down Expand Up @@ -96,6 +97,7 @@ describe('createFilterInActionFactory', () => {
key: fieldName,
value: [value],
negate: false,
dataViewId,
});
});

Expand All @@ -113,6 +115,7 @@ describe('createFilterInActionFactory', () => {
key: fieldName,
value: [value],
negate: false,
dataViewId,
});
});

Expand All @@ -126,7 +129,12 @@ describe('createFilterInActionFactory', () => {
},
],
});
expect(mockCreateFilter).toHaveBeenCalledWith({ key: fieldName, value: [], negate: true });
expect(mockCreateFilter).toHaveBeenCalledWith({
key: fieldName,
value: [],
negate: true,
dataViewId,
});
});

it('should create negate filter query with undefined value', async () => {
Expand All @@ -143,6 +151,7 @@ describe('createFilterInActionFactory', () => {
key: fieldName,
value: [],
negate: true,
dataViewId,
});
});

Expand All @@ -156,7 +165,12 @@ describe('createFilterInActionFactory', () => {
},
],
});
expect(mockCreateFilter).toHaveBeenCalledWith({ key: fieldName, value: [''], negate: true });
expect(mockCreateFilter).toHaveBeenCalledWith({
key: fieldName,
value: [''],
negate: true,
dataViewId,
});
});

it('should create negate filter query with empty array value', async () => {
Expand All @@ -169,7 +183,12 @@ describe('createFilterInActionFactory', () => {
},
],
});
expect(mockCreateFilter).toHaveBeenCalledWith({ key: fieldName, value: [], negate: true });
expect(mockCreateFilter).toHaveBeenCalledWith({
key: fieldName,
value: [],
negate: true,
dataViewId,
});
});

it('should notify the user when value type is unsupported', async () => {
Expand Down
10 changes: 8 additions & 2 deletions packages/kbn-cell-actions/src/actions/filter/filter_in.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { i18n } from '@kbn/i18n';
import type { FilterManager, KBN_FIELD_TYPES } from '@kbn/data-plugin/public';
import { NotificationsStart } from '@kbn/core-notifications-browser';

import { createFilter, isEmptyFilterValue } from './create_filter';
import { FILTER_CELL_ACTION_TYPE } from '../../constants';
import { createCellActionFactory } from '../factory';
Expand Down Expand Up @@ -46,13 +47,15 @@ export const createFilterInActionFactory = createCellActionFactory(
isTypeSupportedByDefaultActions(field.type as KBN_FIELD_TYPES)
);
},
execute: async ({ data }) => {
execute: async ({ data, metadata }) => {
const field = data[0]?.field;
const rawValue = data[0]?.value;
const dataViewId = typeof metadata?.dataViewId === 'string' ? metadata.dataViewId : undefined;

const value = filterOutNullableValues(valueToArray(rawValue));

if (isValueSupportedByDefaultActions(value)) {
addFilterIn({ filterManager, fieldName: field.name, value });
addFilterIn({ filterManager, fieldName: field.name, value, dataViewId });
} else {
toasts.addWarning({
title: ACTION_INCOMPATIBLE_VALUE_WARNING,
Expand All @@ -66,16 +69,19 @@ export const addFilterIn = ({
filterManager,
fieldName,
value,
dataViewId,
}: {
filterManager: FilterManager | undefined;
fieldName: string;
value: DefaultActionsSupportedValue;
dataViewId?: string;
}) => {
if (filterManager != null) {
const filter = createFilter({
key: fieldName,
value,
negate: isEmptyFilterValue(value),
dataViewId,
});
filterManager.addFilters(filter);
}
Expand Down
25 changes: 22 additions & 3 deletions packages/kbn-cell-actions/src/actions/filter/filter_out.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jest.mock('./create_filter', () => ({

const fieldName = 'user.name';
const value = 'the value';
const dataViewId = 'mockDataViewId';

const mockWarningToast = jest.fn();

Expand Down Expand Up @@ -95,6 +96,7 @@ describe('createFilterOutAction', () => {
key: fieldName,
value: [value],
negate: true,
dataViewId,
});
});

Expand All @@ -112,6 +114,7 @@ describe('createFilterOutAction', () => {
key: fieldName,
value: [value],
negate: true,
dataViewId,
});
});

Expand All @@ -125,7 +128,12 @@ describe('createFilterOutAction', () => {
},
],
});
expect(mockCreateFilter).toHaveBeenCalledWith({ key: fieldName, value: [], negate: false });
expect(mockCreateFilter).toHaveBeenCalledWith({
key: fieldName,
value: [],
negate: false,
dataViewId,
});
});

it('should create filter query with undefined value', async () => {
Expand All @@ -142,6 +150,7 @@ describe('createFilterOutAction', () => {
key: fieldName,
value: [],
negate: false,
dataViewId,
});
});

Expand All @@ -155,7 +164,12 @@ describe('createFilterOutAction', () => {
},
],
});
expect(mockCreateFilter).toHaveBeenCalledWith({ key: fieldName, value: [''], negate: false });
expect(mockCreateFilter).toHaveBeenCalledWith({
key: fieldName,
value: [''],
negate: false,
dataViewId,
});
});

it('should create negate filter query with empty array value', async () => {
Expand All @@ -168,7 +182,12 @@ describe('createFilterOutAction', () => {
},
],
});
expect(mockCreateFilter).toHaveBeenCalledWith({ key: fieldName, value: [], negate: false });
expect(mockCreateFilter).toHaveBeenCalledWith({
key: fieldName,
value: [],
negate: false,
dataViewId,
});
});

it('should notify the user when value type is unsupported', async () => {
Expand Down
Loading

0 comments on commit d4ec567

Please sign in to comment.