mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Security Solution] [Platform] Update bulk edit rules to remove data view id from rule if bulk adding index (#136560)
This commit is contained in:
parent
96e284fdf4
commit
0027f63783
5 changed files with 60 additions and 358 deletions
|
@ -161,13 +161,15 @@ const IndexPatternsFormComponent = ({
|
|||
</EuiCallOut>
|
||||
</EuiFormRow>
|
||||
)}
|
||||
<CommonUseField
|
||||
path="overwriteDataViews"
|
||||
componentProps={{
|
||||
idAria: 'bulkEditRulesOverwriteRulesWithDataViews',
|
||||
'data-test-subj': 'bulkEditRulesOverwriteRulesWithDataViews',
|
||||
}}
|
||||
/>
|
||||
{editAction === BulkActionEditType.add_index_patterns && (
|
||||
<CommonUseField
|
||||
path="overwriteDataViews"
|
||||
componentProps={{
|
||||
idAria: 'bulkEditRulesOverwriteRulesWithDataViews',
|
||||
'data-test-subj': 'bulkEditRulesOverwriteRulesWithDataViews',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{overwriteDataViews && (
|
||||
<EuiFormRow fullWidth>
|
||||
<EuiCallOut color="warning" size="s" data-test-subj="bulkEditRulesDataViewsWarning">
|
||||
|
@ -178,6 +180,16 @@ const IndexPatternsFormComponent = ({
|
|||
</EuiCallOut>
|
||||
</EuiFormRow>
|
||||
)}
|
||||
{editAction === BulkActionEditType.delete_index_patterns && (
|
||||
<EuiFormRow fullWidth>
|
||||
<EuiCallOut color="warning" size="s" data-test-subj="bulkEditRulesDataViewsWarning">
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.deleteIndexPattnersDataViewsOverwriteWarningCallout"
|
||||
defaultMessage="If you have selected rules which depend on a data view this action will not have any effect on those rules."
|
||||
/>
|
||||
</EuiCallOut>
|
||||
</EuiFormRow>
|
||||
)}
|
||||
</BulkEditFormWrapper>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,249 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
addItemsToArray,
|
||||
deleteItemsFromArray,
|
||||
applyBulkActionEditToRule,
|
||||
} from './bulk_action_edit';
|
||||
import { BulkActionEditType } from '../../../../common/detection_engine/schemas/common/schemas';
|
||||
import type { RuleAlertType } from './types';
|
||||
describe('bulk_action_edit', () => {
|
||||
describe('addItemsToArray', () => {
|
||||
test('should add single item to array', () => {
|
||||
expect(addItemsToArray(['a', 'b', 'c'], ['d'])).toEqual(['a', 'b', 'c', 'd']);
|
||||
});
|
||||
|
||||
test('should add multiple items to array', () => {
|
||||
expect(addItemsToArray(['a', 'b', 'c'], ['d', 'e'])).toEqual(['a', 'b', 'c', 'd', 'e']);
|
||||
});
|
||||
|
||||
test('should not allow to add duplicated items', () => {
|
||||
expect(addItemsToArray(['a', 'c'], ['b', 'c'])).toEqual(['a', 'c', 'b']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteItemsFromArray', () => {
|
||||
test('should remove single item from array', () => {
|
||||
expect(deleteItemsFromArray(['a', 'b', 'c'], ['c'])).toEqual(['a', 'b']);
|
||||
});
|
||||
|
||||
test('should remove multiple items from array', () => {
|
||||
expect(deleteItemsFromArray(['a', 'b', 'c'], ['b', 'c'])).toEqual(['a']);
|
||||
});
|
||||
|
||||
test('should return array unchanged if items to remove absent in array', () => {
|
||||
expect(deleteItemsFromArray(['a', 'c'], ['x', 'z'])).toEqual(['a', 'c']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('applyBulkActionEditToRule', () => {
|
||||
const getRuleMock = (params = {}) => ({
|
||||
tags: ['tag1', 'tag2'],
|
||||
params: { type: 'query', index: ['initial-index-*'], ...params },
|
||||
});
|
||||
describe('tags', () => {
|
||||
test('should add new tags to rule', () => {
|
||||
const editedRule = applyBulkActionEditToRule(getRuleMock() as RuleAlertType, {
|
||||
type: BulkActionEditType.add_tags,
|
||||
value: ['new_tag'],
|
||||
});
|
||||
expect(editedRule.tags).toEqual(['tag1', 'tag2', 'new_tag']);
|
||||
});
|
||||
test('should remove tag from rule', () => {
|
||||
const editedRule = applyBulkActionEditToRule(getRuleMock() as RuleAlertType, {
|
||||
type: BulkActionEditType.delete_tags,
|
||||
value: ['tag1'],
|
||||
});
|
||||
expect(editedRule.tags).toEqual(['tag2']);
|
||||
});
|
||||
|
||||
test('should rewrite tags in rule', () => {
|
||||
const editedRule = applyBulkActionEditToRule(getRuleMock() as RuleAlertType, {
|
||||
type: BulkActionEditType.set_tags,
|
||||
value: ['tag_r_1', 'tag_r_2'],
|
||||
});
|
||||
expect(editedRule.tags).toEqual(['tag_r_1', 'tag_r_2']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('index_patterns', () => {
|
||||
test('should add new index pattern to rule', () => {
|
||||
const editedRule = applyBulkActionEditToRule(getRuleMock() as RuleAlertType, {
|
||||
type: BulkActionEditType.add_index_patterns,
|
||||
value: ['my-index-*'],
|
||||
});
|
||||
expect(editedRule.params).toHaveProperty('index', ['initial-index-*', 'my-index-*']);
|
||||
});
|
||||
test('should remove index pattern from rule', () => {
|
||||
const editedRule = applyBulkActionEditToRule(
|
||||
{ params: { index: ['initial-index-*', 'index-2-*'] } } as RuleAlertType,
|
||||
{
|
||||
type: BulkActionEditType.delete_index_patterns,
|
||||
value: ['index-2-*'],
|
||||
}
|
||||
);
|
||||
expect(editedRule.params).toHaveProperty('index', ['initial-index-*']);
|
||||
});
|
||||
|
||||
test('should rewrite index pattern in rule', () => {
|
||||
const editedRule = applyBulkActionEditToRule(getRuleMock() as RuleAlertType, {
|
||||
type: BulkActionEditType.set_index_patterns,
|
||||
value: ['index'],
|
||||
});
|
||||
expect(editedRule.params).toHaveProperty('index', ['index']);
|
||||
});
|
||||
|
||||
test('should throw error on adding index pattern if rule is of machine learning type', () => {
|
||||
expect(() =>
|
||||
applyBulkActionEditToRule({ params: { type: 'machine_learning' } } as RuleAlertType, {
|
||||
type: BulkActionEditType.add_index_patterns,
|
||||
value: ['my-index-*'],
|
||||
})
|
||||
).toThrow(
|
||||
"Index patterns can't be added. Machine learning rule doesn't have index patterns property"
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw error on deleting index pattern if rule is of machine learning type', () => {
|
||||
expect(() =>
|
||||
applyBulkActionEditToRule({ params: { type: 'machine_learning' } } as RuleAlertType, {
|
||||
type: BulkActionEditType.delete_index_patterns,
|
||||
value: ['my-index-*'],
|
||||
})
|
||||
).toThrow(
|
||||
"Index patterns can't be deleted. Machine learning rule doesn't have index patterns property"
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw error on overwriting index pattern if rule is of machine learning type', () => {
|
||||
expect(() =>
|
||||
applyBulkActionEditToRule({ params: { type: 'machine_learning' } } as RuleAlertType, {
|
||||
type: BulkActionEditType.set_index_patterns,
|
||||
value: ['my-index-*'],
|
||||
})
|
||||
).toThrow(
|
||||
"Index patterns can't be overwritten. Machine learning rule doesn't have index patterns property"
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw error if all index patterns are deleted', () => {
|
||||
expect(() =>
|
||||
applyBulkActionEditToRule({ params: { index: ['my-index-*'] } } as RuleAlertType, {
|
||||
type: BulkActionEditType.delete_index_patterns,
|
||||
value: ['my-index-*'],
|
||||
})
|
||||
).toThrow("Can't delete all index patterns. At least one index pattern must be left");
|
||||
});
|
||||
|
||||
test('should throw error if all index patterns are rewritten with empty list', () => {
|
||||
expect(() =>
|
||||
applyBulkActionEditToRule({ params: { index: ['my-index-*'] } } as RuleAlertType, {
|
||||
type: BulkActionEditType.set_index_patterns,
|
||||
value: [],
|
||||
})
|
||||
).toThrow("Index patterns can't be overwritten with empty list");
|
||||
});
|
||||
|
||||
describe('overwriteDataViews', () => {
|
||||
describe('overwriteDataViews is true', () => {
|
||||
test('should add new index pattern to rule', () => {
|
||||
const editedRule = applyBulkActionEditToRule(
|
||||
getRuleMock({ dataViewId: 'logs-*', index: [] }) as RuleAlertType,
|
||||
{
|
||||
type: BulkActionEditType.add_index_patterns,
|
||||
value: ['my-index-*'],
|
||||
overwriteDataViews: true,
|
||||
}
|
||||
);
|
||||
expect(editedRule.params).toHaveProperty('index', ['my-index-*']);
|
||||
expect(editedRule.params).toHaveProperty('dataViewId', undefined);
|
||||
});
|
||||
|
||||
test('should remove index pattern from rule', () => {
|
||||
const editedRule = applyBulkActionEditToRule(
|
||||
getRuleMock({ dataViewId: 'logs-*', index: ['index', 'index-2-*'] }) as RuleAlertType,
|
||||
{
|
||||
type: BulkActionEditType.delete_index_patterns,
|
||||
value: ['index-2-*'],
|
||||
overwriteDataViews: true,
|
||||
}
|
||||
);
|
||||
expect(editedRule.params).toHaveProperty('index', ['index']);
|
||||
expect(editedRule.params).toHaveProperty('dataViewId', undefined);
|
||||
});
|
||||
|
||||
test('should rewrite index pattern in rule', () => {
|
||||
const editedRule = applyBulkActionEditToRule(
|
||||
getRuleMock({ dataViewId: 'logs-*', index: ['index', 'index-1'] }) as RuleAlertType,
|
||||
{
|
||||
type: BulkActionEditType.set_index_patterns,
|
||||
value: ['index'],
|
||||
overwriteDataViews: true,
|
||||
}
|
||||
);
|
||||
expect(editedRule.params).toHaveProperty('index', ['index']);
|
||||
expect(editedRule.params).toHaveProperty('dataViewId', undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('overwriteDataViews is false', () => {
|
||||
test('should NOT remove dataViewId from rule if adding index pattern', () => {
|
||||
const editedRule = applyBulkActionEditToRule(
|
||||
getRuleMock({ dataViewId: 'logs-*', index: [] }) as RuleAlertType,
|
||||
{
|
||||
type: BulkActionEditType.add_index_patterns,
|
||||
value: ['my-index-*'],
|
||||
overwriteDataViews: false,
|
||||
}
|
||||
);
|
||||
expect(editedRule.params).toHaveProperty('dataViewId', 'logs-*');
|
||||
});
|
||||
|
||||
test('should NOT remove dataViewId from rule if deleting index pattern', () => {
|
||||
const editedRule = applyBulkActionEditToRule(
|
||||
getRuleMock({ dataViewId: 'logs-*', index: ['index', 'index-2-*'] }) as RuleAlertType,
|
||||
{
|
||||
type: BulkActionEditType.delete_index_patterns,
|
||||
value: ['index-2-*'],
|
||||
overwriteDataViews: false,
|
||||
}
|
||||
);
|
||||
expect(editedRule.params).toHaveProperty('dataViewId', 'logs-*');
|
||||
});
|
||||
|
||||
test('should NOT remove dataViewId from rule if setting index pattern', () => {
|
||||
const editedRule = applyBulkActionEditToRule(
|
||||
getRuleMock({ dataViewId: 'logs-*', index: [] }) as RuleAlertType,
|
||||
{
|
||||
type: BulkActionEditType.set_index_patterns,
|
||||
value: ['index'],
|
||||
overwriteDataViews: false,
|
||||
}
|
||||
);
|
||||
expect(editedRule.params).toHaveProperty('dataViewId', 'logs-*');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('timeline', () => {
|
||||
test('should set timeline', () => {
|
||||
const editedRule = applyBulkActionEditToRule(getRuleMock() as RuleAlertType, {
|
||||
type: BulkActionEditType.set_timeline,
|
||||
value: {
|
||||
timeline_id: '91832785-286d-4ebe-b884-1a208d111a70',
|
||||
timeline_title: 'Test timeline',
|
||||
},
|
||||
});
|
||||
|
||||
expect(editedRule.params.timelineId).toBe('91832785-286d-4ebe-b884-1a208d111a70');
|
||||
expect(editedRule.params.timelineTitle).toBe('Test timeline');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { RuleAlertType } from './types';
|
||||
|
||||
import type { BulkActionEditPayload } from '../../../../common/detection_engine/schemas/common/schemas';
|
||||
import { BulkActionEditType } from '../../../../common/detection_engine/schemas/common/schemas';
|
||||
|
||||
import { invariant } from '../../../../common/utils/invariant';
|
||||
import { isMachineLearningParams } from '../signals/utils';
|
||||
|
||||
export const addItemsToArray = <T>(arr: T[], items: T[]): T[] =>
|
||||
Array.from(new Set([...arr, ...items]));
|
||||
|
||||
export const deleteItemsFromArray = <T>(arr: T[], items: T[]): T[] => {
|
||||
const itemsSet = new Set(items);
|
||||
return arr.filter((item) => !itemsSet.has(item));
|
||||
};
|
||||
|
||||
export const applyBulkActionEditToRule = (
|
||||
existingRule: RuleAlertType,
|
||||
action: BulkActionEditPayload
|
||||
): RuleAlertType => {
|
||||
const rule = { ...existingRule, params: { ...existingRule.params } };
|
||||
|
||||
switch (action.type) {
|
||||
// tags actions
|
||||
case BulkActionEditType.add_tags:
|
||||
rule.tags = addItemsToArray(rule.tags ?? [], action.value);
|
||||
break;
|
||||
|
||||
case BulkActionEditType.delete_tags:
|
||||
rule.tags = deleteItemsFromArray(rule.tags ?? [], action.value);
|
||||
break;
|
||||
|
||||
case BulkActionEditType.set_tags:
|
||||
rule.tags = action.value;
|
||||
break;
|
||||
|
||||
// index_patterns actions
|
||||
// index pattern is not present in machine learning rule type, so we throw error on it
|
||||
case BulkActionEditType.add_index_patterns:
|
||||
invariant(
|
||||
rule.params.type !== 'machine_learning',
|
||||
"Index patterns can't be added. Machine learning rule doesn't have index patterns property"
|
||||
);
|
||||
|
||||
if (!isMachineLearningParams(rule.params) && action.overwriteDataViews) {
|
||||
rule.params.dataViewId = undefined;
|
||||
}
|
||||
rule.params.index = addItemsToArray(rule.params.index ?? [], action.value);
|
||||
|
||||
break;
|
||||
|
||||
case BulkActionEditType.delete_index_patterns:
|
||||
invariant(
|
||||
rule.params.type !== 'machine_learning',
|
||||
"Index patterns can't be deleted. Machine learning rule doesn't have index patterns property"
|
||||
);
|
||||
|
||||
if (!isMachineLearningParams(rule.params) && action.overwriteDataViews) {
|
||||
rule.params.dataViewId = undefined;
|
||||
}
|
||||
rule.params.index = deleteItemsFromArray(rule.params.index ?? [], action.value);
|
||||
|
||||
invariant(
|
||||
rule.params.index.length !== 0,
|
||||
"Can't delete all index patterns. At least one index pattern must be left"
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case BulkActionEditType.set_index_patterns:
|
||||
invariant(
|
||||
rule.params.type !== 'machine_learning',
|
||||
"Index patterns can't be overwritten. Machine learning rule doesn't have index patterns property"
|
||||
);
|
||||
invariant(action.value.length !== 0, "Index patterns can't be overwritten with empty list");
|
||||
|
||||
if (!isMachineLearningParams(rule.params) && action.overwriteDataViews) {
|
||||
rule.params.dataViewId = undefined;
|
||||
}
|
||||
rule.params.index = action.value;
|
||||
|
||||
break;
|
||||
|
||||
// timeline actions
|
||||
case BulkActionEditType.set_timeline:
|
||||
const timelineId = action.value.timeline_id.trim() || undefined;
|
||||
const timelineTitle = timelineId ? action.value.timeline_title : undefined;
|
||||
|
||||
rule.params.timelineId = timelineId;
|
||||
rule.params.timelineTitle = timelineTitle;
|
||||
break;
|
||||
}
|
||||
|
||||
return rule;
|
||||
};
|
|
@ -11,6 +11,7 @@ import type { BulkActionEditForRuleParams } from '../../../../../common/detectio
|
|||
import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas';
|
||||
|
||||
import { invariant } from '../../../../../common/utils/invariant';
|
||||
import { isMachineLearningParams } from '../../signals/utils';
|
||||
|
||||
export const addItemsToArray = <T>(arr: T[], items: T[]): T[] =>
|
||||
Array.from(new Set([...arr, ...items]));
|
||||
|
@ -35,6 +36,10 @@ const applyBulkActionEditToRuleParams = (
|
|||
"Index patterns can't be added. Machine learning rule doesn't have index patterns property"
|
||||
);
|
||||
|
||||
if (!isMachineLearningParams(ruleParams) && action.overwriteDataViews) {
|
||||
ruleParams.dataViewId = undefined;
|
||||
}
|
||||
|
||||
ruleParams.index = addItemsToArray(ruleParams.index ?? [], action.value);
|
||||
break;
|
||||
|
||||
|
|
|
@ -562,6 +562,42 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
expect(deleteIndexRule.index).to.eql(['initial-index-*', 'index2-*']);
|
||||
});
|
||||
|
||||
it('should add an index pattern to a rule and overwrite the data view', async () => {
|
||||
const ruleId = 'ruleId';
|
||||
const dataViewId = 'index1-*';
|
||||
const simpleRule = {
|
||||
...getSimpleRule(ruleId),
|
||||
index: undefined,
|
||||
data_view_id: dataViewId,
|
||||
};
|
||||
await createRule(supertest, log, simpleRule);
|
||||
|
||||
const { body: setIndexBody } = await postBulkAction()
|
||||
.send({
|
||||
query: '',
|
||||
action: BulkAction.edit,
|
||||
[BulkAction.edit]: [
|
||||
{
|
||||
type: BulkActionEditType.add_index_patterns,
|
||||
value: ['initial-index-*'],
|
||||
overwriteDataViews: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(setIndexBody.attributes.summary).to.eql({ failed: 0, succeeded: 1, total: 1 });
|
||||
|
||||
// Check that the updated rule is returned with the response
|
||||
expect(setIndexBody.attributes.results.updated[0].index).to.eql(['initial-index-*']);
|
||||
expect(setIndexBody.attributes.results.updated[0].data_view_id).to.eql(undefined);
|
||||
|
||||
// Check that the updates have been persisted
|
||||
const { body: setIndexRule } = await fetchRule(ruleId).expect(200);
|
||||
|
||||
expect(setIndexRule.index).to.eql(['initial-index-*']);
|
||||
});
|
||||
|
||||
it('should set timeline values in rule', async () => {
|
||||
const ruleId = 'ruleId';
|
||||
const timelineId = '91832785-286d-4ebe-b884-1a208d111a70';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue