From 2d2cf84ddbf2dcb99e8efc6adedae510b4bf334c Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Mon, 15 Aug 2022 13:06:42 +0100 Subject: [PATCH 01/41] init bulk actions --- .../lib/retry_if_bulk_edit_conflicts.ts | 3 + .../schemas/common/schemas.ts | 41 +++++++++- .../action_to_rules_client_operation.ts | 75 +++++++++++++++---- .../bulk_actions/split_bulk_edit_actions.ts | 2 + .../detection_engine/rules/bulk_edit_rules.ts | 2 +- 5 files changed, 105 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.ts b/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.ts index 9e1e60acb768f..2cdea69c094e9 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.ts @@ -76,6 +76,9 @@ export const retryIfBulkEditConflicts = async ( if (item.type === 'alert' && item?.error?.statusCode === 409) { return acc.set(item.id, { message: item.error.message }); } + if (item?.error) { + acc.set(item.id, { message: item.error.message }); + } return acc; }, new Map() diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts index c0975925d480c..5523b6efd40aa 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts @@ -16,6 +16,12 @@ import { UUID, LimitedSizeArray, } from '@kbn/securitysolution-io-ts-types'; +import { + throttle, + action_group as actionGroup, + action_params as actionParams, + action_id as actionId, +} from '@kbn/securitysolution-io-ts-alerting-types'; import * as t from 'io-ts'; export const author = t.array(t.string); @@ -379,6 +385,8 @@ export enum BulkActionEditType { 'delete_index_patterns' = 'delete_index_patterns', 'set_index_patterns' = 'set_index_patterns', 'set_timeline' = 'set_timeline', + 'add_actions' = 'add_actions', + 'set_actions' = 'set_actions', } const bulkActionEditPayloadTags = t.type({ @@ -418,16 +426,47 @@ const bulkActionEditPayloadTimeline = t.type({ export type BulkActionEditPayloadTimeline = t.TypeOf; +const bulkActionEditPayloadActions = t.type({ + type: t.union([ + t.literal(BulkActionEditType.add_actions), + t.literal(BulkActionEditType.set_actions), + ]), + value: t.type({ + throttle, + // actions: t.array(t.UnknownRecord), + actions: t.array( + t.exact( + t.type({ + group: actionGroup, + id: actionId, + params: actionParams, + }) + ) + ), + }), +}); + +export type BulkActionEditPayloadSActions = t.TypeOf; + export const bulkActionEditPayload = t.union([ bulkActionEditPayloadTags, bulkActionEditPayloadIndexPatterns, bulkActionEditPayloadTimeline, + bulkActionEditPayloadActions, ]); export type BulkActionEditPayload = t.TypeOf; -export type BulkActionEditForRuleAttributes = BulkActionEditPayloadTags; +/** + * actions that modifies rules attributes + */ +export type BulkActionEditForRuleAttributes = + | BulkActionEditPayloadTags + | BulkActionEditPayloadSActions; +/** + * actions that modifies rules params + */ export type BulkActionEditForRuleParams = | BulkActionEditPayloadIndexPatterns | BulkActionEditPayloadTimeline; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts index c75f7d0943e52..35a8f35a23b79 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts @@ -11,6 +11,20 @@ import type { BulkActionEditForRuleAttributes } from '../../../../../common/dete import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; import { assertUnreachable } from '../../../../../common/utility_types'; +import { transformToAlertThrottle, transformToNotifyWhen } from '../utils'; + +const getThrottleOperation = (throttle: string) => ({ + field: 'throttle', + operation: 'set', + value: transformToAlertThrottle(throttle), +}); + +const getNotifyWhenOperation = (throttle: string) => ({ + field: 'notifyWhen', + operation: 'set', + value: transformToNotifyWhen(throttle), +}); + /** * converts bulk edit action to format of rulesClient.bulkEdit operation * @param action BulkActionEditForRuleAttributes @@ -18,29 +32,58 @@ import { assertUnreachable } from '../../../../../common/utility_types'; */ export const bulkEditActionToRulesClientOperation = ( action: BulkActionEditForRuleAttributes -): BulkEditOperation => { +): BulkEditOperation[] => { switch (action.type) { // tags actions case BulkActionEditType.add_tags: - return { - field: 'tags', - operation: 'add', - value: action.value, - }; + return [ + { + field: 'tags', + operation: 'add', + value: action.value, + }, + ]; case BulkActionEditType.delete_tags: - return { - field: 'tags', - operation: 'delete', - value: action.value, - }; + return [ + { + field: 'tags', + operation: 'delete', + value: action.value, + }, + ]; case BulkActionEditType.set_tags: - return { - field: 'tags', - operation: 'set', - value: action.value, - }; + return [ + { + field: 'tags', + operation: 'set', + value: action.value, + }, + ]; + + // rule actions + case BulkActionEditType.add_actions: + return [ + { + field: 'actions', + operation: 'add', + value: action.value.actions, + }, + getThrottleOperation(action.value.throttle), + getNotifyWhenOperation(action.value.throttle), + ]; + + case BulkActionEditType.set_actions: + return [ + { + field: 'actions', + operation: 'set', + value: action.value.actions, + }, + getThrottleOperation(action.value.throttle), + getNotifyWhenOperation(action.value.throttle), + ]; default: return assertUnreachable(action.type); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts index e1ba96390d538..87d38f7578628 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts @@ -32,6 +32,8 @@ export const splitBulkEditActions = (actions: BulkActionEditPayload[]) => { case BulkActionEditType.add_tags: case BulkActionEditType.set_tags: case BulkActionEditType.delete_tags: + case BulkActionEditType.add_actions: + case BulkActionEditType.set_actions: acc.attributesActions.push(action); break; default: diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts index 587d7d539caa6..059e67e9a90e2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts @@ -43,7 +43,7 @@ export const bulkEditRules = ({ return rulesClient.bulkEdit({ ...(ids ? { ids } : { filter: enrichFilterWithRuleTypeMapping(filter) }), - operations: attributesActions.map(bulkEditActionToRulesClientOperation), + operations: attributesActions.map(bulkEditActionToRulesClientOperation).flat(), paramsModifier: async (ruleParams: RuleAlertType['params']) => { await validateBulkEditRule({ mlAuthz, ruleType: ruleParams.type }); return ruleParamsModifier(ruleParams, paramsActions); From e23d690e5492564ba7a790b44a1b4d5131ba0b26 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Tue, 16 Aug 2022 13:19:42 +0100 Subject: [PATCH 02/41] bulk edit rules --- .../schemas/common/schemas.ts | 4 +- .../action_to_rules_client_operation.ts | 22 +- .../detection_engine/rules/bulk_edit_rules.ts | 49 +- .../group1/perform_bulk_action.ts | 418 +++++++++++++++++- 4 files changed, 477 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts index 5523b6efd40aa..c238bb065f6d2 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts @@ -446,7 +446,7 @@ const bulkActionEditPayloadActions = t.type({ }), }); -export type BulkActionEditPayloadSActions = t.TypeOf; +export type BulkActionEditPayloadActions = t.TypeOf; export const bulkActionEditPayload = t.union([ bulkActionEditPayloadTags, @@ -462,7 +462,7 @@ export type BulkActionEditPayload = t.TypeOf; */ export type BulkActionEditForRuleAttributes = | BulkActionEditPayloadTags - | BulkActionEditPayloadSActions; + | BulkActionEditPayloadActions; /** * actions that modifies rules params diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts index 35a8f35a23b79..2504afa2afbc1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts @@ -13,17 +13,19 @@ import { assertUnreachable } from '../../../../../common/utility_types'; import { transformToAlertThrottle, transformToNotifyWhen } from '../utils'; -const getThrottleOperation = (throttle: string) => ({ - field: 'throttle', - operation: 'set', - value: transformToAlertThrottle(throttle), -}); +const getThrottleOperation = (throttle: string) => + ({ + field: 'throttle', + operation: 'set', + value: transformToAlertThrottle(throttle), + } as const); -const getNotifyWhenOperation = (throttle: string) => ({ - field: 'notifyWhen', - operation: 'set', - value: transformToNotifyWhen(throttle), -}); +const getNotifyWhenOperation = (throttle: string) => + ({ + field: 'notifyWhen', + operation: 'set', + value: transformToNotifyWhen(throttle), + } as const); /** * converts bulk edit action to format of rulesClient.bulkEdit operation diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts index 059e67e9a90e2..ef7ae7eca490e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts @@ -5,8 +5,12 @@ * 2.0. */ +import pMap from 'p-map'; import type { RulesClient } from '@kbn/alerting-plugin/server'; -import type { BulkActionEditPayload } from '../../../../common/detection_engine/schemas/common'; +import type { + BulkActionEditPayload, + BulkActionEditPayloadActions, +} from '../../../../common/detection_engine/schemas/common'; import { enrichFilterWithRuleTypeMapping } from './enrich_filter_with_rule_type_mappings'; import type { MlAuthz } from '../../machine_learning/authz'; @@ -14,6 +18,9 @@ import { ruleParamsModifier } from './bulk_actions/rule_params_modifier'; import { splitBulkEditActions } from './bulk_actions/split_bulk_edit_actions'; import { validateBulkEditRule } from './bulk_actions/validations'; import { bulkEditActionToRulesClientOperation } from './bulk_actions/action_to_rules_client_operation'; +import { NOTIFICATION_THROTTLE_NO_ACTIONS } from '../../../../common/constants'; +import { BulkActionEditType } from '../../../../common/detection_engine/schemas/common/schemas'; +import { readRules } from './read_rules'; import type { RuleAlertType } from './types'; @@ -32,7 +39,7 @@ export interface BulkEditRulesArguments { * @param BulkEditRulesArguments * @returns edited rules and caught errors */ -export const bulkEditRules = ({ +export const bulkEditRules = async ({ rulesClient, ids, actions, @@ -41,7 +48,7 @@ export const bulkEditRules = ({ }: BulkEditRulesArguments) => { const { attributesActions, paramsActions } = splitBulkEditActions(actions); - return rulesClient.bulkEdit({ + const result = await rulesClient.bulkEdit({ ...(ids ? { ids } : { filter: enrichFilterWithRuleTypeMapping(filter) }), operations: attributesActions.map(bulkEditActionToRulesClientOperation).flat(), paramsModifier: async (ruleParams: RuleAlertType['params']) => { @@ -49,4 +56,40 @@ export const bulkEditRules = ({ return ruleParamsModifier(ruleParams, paramsActions); }, }); + + // rulesClient bulkEdit currently doesn't support bulk mute/unmute. + // this is a workaround to mitigate this + // if rule actions has been applied: + // - we go through each rule + // - mute/unmute if needed, refetch rule + // calling mute for rule needed only when rule was unmuted before and throttle value is NOTIFICATION_THROTTLE_NO_ACTIONS + // calling unmute needed only if rule was muted and throttle value is not NOTIFICATION_THROTTLE_NO_ACTIONS + // TODO: error handlers (?) + const rulesAction = attributesActions.find(({ type }) => + [BulkActionEditType.set_actions, BulkActionEditType.add_actions].includes(type) + ) as BulkActionEditPayloadActions; + if (rulesAction) { + const rules = await pMap( + result.rules, + async (rule) => { + if (rule.muteAll && rulesAction.value.throttle !== NOTIFICATION_THROTTLE_NO_ACTIONS) { + await rulesClient.unmuteAll({ id: rule.id }); + return readRules({ rulesClient, id: rule.id, ruleId: undefined }); + } else if ( + !rule.muteAll && + rulesAction.value.throttle === NOTIFICATION_THROTTLE_NO_ACTIONS + ) { + await rulesClient.muteAll({ id: rule.id }); + return readRules({ rulesClient, id: rule.id, ruleId: undefined }); + } + + return rule; + }, + { concurrency: 50 } + ); + + return { ...result, rules }; + } + + return result; }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts index 21e89b2d214b7..8fd0637b6f457 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts @@ -10,7 +10,10 @@ import expect from '@kbn/expect'; import { DETECTION_ENGINE_RULES_BULK_ACTION, DETECTION_ENGINE_RULES_URL, + NOTIFICATION_THROTTLE_NO_ACTIONS, + NOTIFICATION_THROTTLE_RULE, } from '@kbn/security-solution-plugin/common/constants'; + import { BulkAction, BulkActionEditType, @@ -30,6 +33,7 @@ import { getLegacyActionSO, installPrePackagedRules, getSimpleMlRule, + getWebHookAction, } from '../../utils'; // eslint-disable-next-line import/no-default-export @@ -42,8 +46,22 @@ export default ({ getService }: FtrProviderContext): void => { supertest.post(DETECTION_ENGINE_RULES_BULK_ACTION).set('kbn-xsrf', 'true'); const fetchRule = (ruleId: string) => supertest.get(`${DETECTION_ENGINE_RULES_URL}?rule_id=${ruleId}`).set('kbn-xsrf', 'true'); + /** + * allows to get access to internal property: notifyWhen + */ + const fetchRuleByAlertApi = (ruleId: string) => + supertest.get(`/api/alerting/rule/${ruleId}`).set('kbn-xsrf', 'true'); + + const createWebHookAction = async () => + ( + await supertest + .post('/api/actions/action') + .set('kbn-xsrf', 'true') + .send(getWebHookAction()) + .expect(200) + ).body; - describe('perform_bulk_action', () => { + describe.only('perform_bulk_action', () => { beforeEach(async () => { await createSignalsIndex(supertest, log); }); @@ -1022,6 +1040,404 @@ export default ({ getService }: FtrProviderContext): void => { }); }); + describe('rule actions', () => { + const webHookActionMock = { + group: 'default', + params: { + body: '{}', + }, + }; + + describe('add_actions', () => { + it('should set action correctly', async () => { + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); + + // create a new action + const hookAction = await createWebHookAction(); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.set_actions, + value: { + throttle: '1h', + actions: [ + { + ...webHookActionMock, + id: hookAction.id, + }, + ], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].actions).to.eql([ + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + + // Check that the updates have been persisted + const { body: readRule } = await fetchRule(ruleId).expect(200); + + expect(readRule.actions).to.eql([ + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + }); + + it('should set actions to empty if list of action is empty in payload', async () => { + // create a new action + const hookAction = await createWebHookAction(); + + const defaultRuleAction = { + id: hookAction.id, + action_type_id: '.webhook', + group: 'default', + params: { + body: '{"test":"a default action"}', + }, + }; + + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, { + ...getSimpleRule(ruleId), + actions: [defaultRuleAction], + throttle: '1d', + }); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.set_actions, + value: { + throttle: '1h', + actions: [], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].actions).to.eql([]); + + // Check that the updates have been persisted + const { body: readRule } = await fetchRule(ruleId).expect(200); + + expect(readRule.actions).to.eql([]); + }); + }); + + describe('add_actions', () => { + it('should add action correctly to empty actions list', async () => { + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); + + // create a new action + const hookAction = await createWebHookAction(); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.add_actions, + value: { + throttle: '1h', + actions: [ + { + ...webHookActionMock, + id: hookAction.id, + }, + ], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].actions).to.eql([ + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + + // Check that the updates have been persisted + const { body: readRule } = await fetchRule(ruleId).expect(200); + + expect(readRule.actions).to.eql([ + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + }); + + it('should add action correctly to non empty actions list', async () => { + // create a new action + const hookAction = await createWebHookAction(); + + const defaultRuleAction = { + id: hookAction.id, + action_type_id: '.webhook', + group: 'default', + params: { + body: '{"test":"a default action"}', + }, + }; + + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, { + ...getSimpleRule(ruleId), + actions: [defaultRuleAction], + throttle: '1d', + }); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.add_actions, + value: { + throttle: '1h', + actions: [ + { + ...webHookActionMock, + id: hookAction.id, + }, + ], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].actions).to.eql([ + defaultRuleAction, + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + + // Check that the updates have been persisted + const { body: readRule } = await fetchRule(ruleId).expect(200); + + expect(readRule.actions).to.eql([ + defaultRuleAction, + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + }); + + it('should not change actions of rule if empty list of actions added', async () => { + // create a new action + const hookAction = await createWebHookAction(); + + const defaultRuleAction = { + id: hookAction.id, + action_type_id: '.webhook', + group: 'default', + params: { + body: '{"test":"a default action"}', + }, + }; + + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, { + ...getSimpleRule(ruleId), + actions: [defaultRuleAction], + throttle: '1d', + }); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.add_actions, + value: { + throttle: '1h', + actions: [], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].actions).to.eql([defaultRuleAction]); + + // Check that the updates have been persisted + const { body: readRule } = await fetchRule(ruleId).expect(200); + + expect(readRule.actions).to.eql([defaultRuleAction]); + }); + }); + + describe('throttle', () => { + const casesForEmptyActions = [ + { + payload: { throttle: NOTIFICATION_THROTTLE_NO_ACTIONS }, + }, + { + payload: { throttle: NOTIFICATION_THROTTLE_RULE }, + }, + { + payload: { throttle: '1h' }, + }, + ]; + casesForEmptyActions.forEach(({ payload }) => { + it(`is set correctly, if payload throttle="${payload.throttle}" and actions empty`, async () => { + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.set_actions, + value: { + throttle: payload.throttle, + actions: [], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].throttle).to.eql( + NOTIFICATION_THROTTLE_NO_ACTIONS + ); + + // Check that the updates have been persisted + const { body: rule } = await fetchRule(ruleId).expect(200); + + expect(rule.throttle).to.eql(NOTIFICATION_THROTTLE_NO_ACTIONS); + }); + }); + + // const casesForNonEmptyActions = [ + // { + // payload: { throttle: NOTIFICATION_THROTTLE_NO_ACTIONS }, + // }, + // { + // payload: { throttle: NOTIFICATION_THROTTLE_RULE }, + // }, + // { + // payload: { throttle: '1h' }, + // }, + // ]; + // casesForNonEmptyActions.forEach(({ payload, expected }) => { + // it.only(`is set correctly, if payload throttle="${payload.throttle}" and actions empty`, async () => { + // const ruleId = 'ruleId'; + // const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); + + // const { body } = await postBulkAction() + // .send({ + // ids: [createdRule.id], + // action: BulkAction.edit, + // [BulkAction.edit]: [ + // { + // type: BulkActionEditType.set_actions, + // value: { + // throttle: payload.throttle, + // actions: [], + // }, + // }, + // ], + // }) + // .expect(200); + + // // Check that the updated rule is returned with the response + // expect(body.attributes.results.updated[0].throttle).to.eql(expected.throttle); + + // // Check that the updates have been persisted + // const { body: rule } = await fetchRule(ruleId).expect(200); + + // console.log('>>>>>', JSON.stringify(rule, null, 2)); + // expect(rule.throttle).to.eql(expected.throttle); + // }); + // }); + }); + + describe('notifyWhen', () => { + const cases = [ + { + payload: { throttle: NOTIFICATION_THROTTLE_NO_ACTIONS }, + // keeps existing default value which is onActiveAlert + expected: { notifyWhen: 'onActiveAlert' }, + }, + { + payload: { throttle: '1d' }, + expected: { notifyWhen: 'onThrottleInterval' }, + }, + { + payload: { throttle: NOTIFICATION_THROTTLE_RULE }, + expected: { notifyWhen: 'onActiveAlert' }, + }, + ]; + cases.forEach(({ payload, expected }) => { + it(`is set correctly, if payload throttle="${payload.throttle}"`, async () => { + const createdRule = await createRule(supertest, log, getSimpleRule('ruleId')); + + await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.set_actions, + value: { + throttle: payload.throttle, + actions: [], + }, + }, + ], + }) + .expect(200); + + // Check whether notifyWhen set correctly + const { body: rule } = await fetchRuleByAlertApi(createdRule.id).expect(200); + + expect(rule.notify_when).to.eql(expected.notifyWhen); + }); + }); + }); + }); + it('should limit concurrent requests to 5', async () => { const ruleId = 'ruleId'; const timelineId = '91832785-286d-4ebe-b884-1a208d111a70'; From cc113410d6c9d2707cf75851851395586491691d Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:21:59 +0100 Subject: [PATCH 03/41] [RAM] revisit later --- .../server/rules_client/lib/retry_if_bulk_edit_conflicts.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.ts b/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.ts index 2cdea69c094e9..9e1e60acb768f 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/retry_if_bulk_edit_conflicts.ts @@ -76,9 +76,6 @@ export const retryIfBulkEditConflicts = async ( if (item.type === 'alert' && item?.error?.statusCode === 409) { return acc.set(item.id, { message: item.error.message }); } - if (item?.error) { - acc.set(item.id, { message: item.error.message }); - } return acc; }, new Map() From e5cddafd4ea4c913799708a450788e84d8a8dd19 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Tue, 16 Aug 2022 13:26:12 +0100 Subject: [PATCH 04/41] remove .only --- .../security_and_spaces/group1/perform_bulk_action.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts index 8fd0637b6f457..6162419e051ca 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts @@ -61,7 +61,7 @@ export default ({ getService }: FtrProviderContext): void => { .expect(200) ).body; - describe.only('perform_bulk_action', () => { + describe('perform_bulk_action', () => { beforeEach(async () => { await createSignalsIndex(supertest, log); }); From eebaa87dc46053e337fb9a8203973a21970bcfbf Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Tue, 16 Aug 2022 13:35:36 +0100 Subject: [PATCH 05/41] fix eslint --- .../rules/bulk_actions/action_to_rules_client_operation.ts | 2 +- .../server/lib/detection_engine/rules/bulk_edit_rules.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts index 2504afa2afbc1..ee13c4c780db6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts @@ -88,6 +88,6 @@ export const bulkEditActionToRulesClientOperation = ( ]; default: - return assertUnreachable(action.type); + return assertUnreachable(action); } }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts index ef7ae7eca490e..5cf9cd117bad2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts @@ -74,13 +74,13 @@ export const bulkEditRules = async ({ async (rule) => { if (rule.muteAll && rulesAction.value.throttle !== NOTIFICATION_THROTTLE_NO_ACTIONS) { await rulesClient.unmuteAll({ id: rule.id }); - return readRules({ rulesClient, id: rule.id, ruleId: undefined }); + return (await readRules({ rulesClient, id: rule.id, ruleId: undefined })) ?? rule; } else if ( !rule.muteAll && rulesAction.value.throttle === NOTIFICATION_THROTTLE_NO_ACTIONS ) { await rulesClient.muteAll({ id: rule.id }); - return readRules({ rulesClient, id: rule.id, ruleId: undefined }); + return (await readRules({ rulesClient, id: rule.id, ruleId: undefined })) ?? rule; } return rule; From d0f6b6169299a8306875dafd4c04c0c2ed39cfbb Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Wed, 17 Aug 2022 12:56:26 +0100 Subject: [PATCH 06/41] it's alive! --- .../all/bulk_actions/bulk_edit_flyout.tsx | 5 + .../forms/bulk_edit_form_wrapper.tsx | 5 +- .../bulk_actions/forms/rule_actions_form.tsx | 185 ++++++++++++++++++ .../rules/all/bulk_actions/translations.tsx | 46 +++++ .../all/bulk_actions/use_bulk_actions.tsx | 10 + .../utils/compute_dry_run_payload.ts | 13 ++ .../pages/detection_engine/rules/helpers.tsx | 69 ++++--- .../detection_engine/rules/translations.ts | 7 + 8 files changed, 311 insertions(+), 29 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx index 4a4d33c358b0e..17e225dc827a9 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx @@ -13,6 +13,7 @@ import { BulkActionEditType } from '../../../../../../../common/detection_engine import { IndexPatternsForm } from './forms/index_patterns_form'; import { TagsForm } from './forms/tags_form'; import { TimelineTemplateForm } from './forms/timeline_template_form'; +import { RuleActionsForm } from './forms/rule_actions_form'; interface BulkEditFlyoutProps { onClose: () => void; @@ -37,6 +38,10 @@ const BulkEditFlyoutComponent = ({ editAction, tags, ...props }: BulkEditFlyoutP case BulkActionEditType.set_timeline: return ; + case BulkActionEditType.add_actions: + case BulkActionEditType.set_actions: + return ; + default: return null; } diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/bulk_edit_form_wrapper.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/bulk_edit_form_wrapper.tsx index 26a555b7de335..a4fafd8d21bfd 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/bulk_edit_form_wrapper.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/bulk_edit_form_wrapper.tsx @@ -7,6 +7,7 @@ import type { FC } from 'react'; import React from 'react'; +import type { EuiFlyoutSize } from '@elastic/eui'; import { useGeneratedHtmlId, EuiFlyout, @@ -32,6 +33,7 @@ interface BulkEditFormWrapperProps { children: React.ReactNode; onClose: () => void; onSubmit: () => void; + flyoutSize?: EuiFlyoutSize; } const BulkEditFormWrapperComponent: FC = ({ @@ -41,6 +43,7 @@ const BulkEditFormWrapperComponent: FC = ({ children, onClose, onSubmit, + flyoutSize = 's', }) => { const simpleFlyoutTitleId = useGeneratedHtmlId({ prefix: 'RulesBulkEditForm', @@ -48,7 +51,7 @@ const BulkEditFormWrapperComponent: FC = ({ const { isValid } = form; return ( - +

{title}

diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx new file mode 100644 index 0000000000000..d8431b49b07bd --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -0,0 +1,185 @@ +/* + * 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 React, { useCallback, useMemo } from 'react'; +import { EuiCallOut, EuiSpacer } from '@elastic/eui'; + +import type { + RuleAction, + ActionTypeRegistryContract, +} from '@kbn/triggers-actions-ui-plugin/public'; +import type { FormSchema } from '../../../../../../../shared_imports'; +import { + useForm, + UseField, + FIELD_TYPES, + useFormData, + getUseField, + Field, +} from '../../../../../../../shared_imports'; +import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; +import { NOTIFICATION_THROTTLE_NO_ACTIONS } from '../../../../../../../../common/constants'; + +import { BulkEditFormWrapper } from './bulk_edit_form_wrapper'; +import { bulkAddRuleActions as i18n } from '../translations'; + +import { useKibana } from '../../../../../../../common/lib/kibana'; + +import { + ThrottleSelectField, + THROTTLE_OPTIONS, +} from '../../../../../../components/rules/throttle_select_field'; +import { allActionMessageParams } from '../../../helpers'; + +import { RuleActionsField } from '../../../../../../components/rules/rule_actions_field'; +import { validateRuleActionsField } from '../../../../../../components/rules/step_rule_actions/schema'; + +const CommonUseField = getUseField({ component: Field }); + +export interface RuleActionsFormData { + throttle: string; + actions: RuleAction[]; + overwrite: boolean; +} + +const getFormSchema = ( + actionTypeRegistry: ActionTypeRegistryContract +): FormSchema => ({ + throttle: { + label: i18n.THROTTLE_LABEL, + helpText: i18n.THROTTLE_HELP_TEXT, + }, + actions: { + validations: [ + { + validator: validateRuleActionsField(actionTypeRegistry), + }, + ], + }, + overwrite: { + type: FIELD_TYPES.CHECKBOX, + label: i18n.OVERWRITE_LABEL, + }, +}); + +const defaultFormData: RuleActionsFormData = { + throttle: NOTIFICATION_THROTTLE_NO_ACTIONS, + actions: [], + overwrite: false, +}; + +interface RuleActionsFormProps { + rulesCount: number; + onClose: () => void; + onConfirm: (bulkActionEditPayload: BulkActionEditPayload) => void; +} + +const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleActionsFormProps) => { + const { + services: { + triggersActionsUi: { actionTypeRegistry }, + }, + } = useKibana(); + + const formSchema = useMemo(() => getFormSchema(actionTypeRegistry), [actionTypeRegistry]); + + const { form } = useForm({ + schema: formSchema, + defaultValue: defaultFormData, + }); + + const [{ overwrite, throttle }] = useFormData({ form, watch: ['overwrite', 'throttle'] }); + + const handleSubmit = useCallback(async () => { + const { data, isValid } = await form.submit(); + if (!isValid) { + return; + } + + const editAction = data.overwrite + ? BulkActionEditType.set_actions + : BulkActionEditType.add_actions; + + onConfirm({ + type: editAction, + value: { + actions: data.actions.map(({ actionTypeId, ...action }) => action), + throttle: data.throttle, + }, + }); + }, [form, onConfirm]); + + const throttleFieldComponentProps = useMemo( + () => ({ + idAria: 'bulkEditRulesRuleActionThrottle', + isLoading: true, + dataTestSubj: 'bulkEditRulesRuleActionThrottle', + hasNoInitialSelection: false, + euiFieldProps: { + options: THROTTLE_OPTIONS, + }, + }), + [] + ); + + const showActionsSelect = throttle !== defaultFormData.throttle; + + return ( + + {overwrite && ( + <> + + {i18n.warningCalloutMessage(rulesCount)} + + + + )} + + + {i18n.infoCalloutMessage(rulesCount)} + + + + + + + {showActionsSelect && ( + <> + + + + )} + + + + ); +}; + +export const RuleActionsForm = React.memo(RuleActionsFormComponent); +RuleActionsForm.displayName = 'RuleActionsForm'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx index cce2d3e032a83..27cb27a15f4e2 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx @@ -55,3 +55,49 @@ export const bulkApplyTimelineTemplate = { /> ), }; + +export const bulkAddRuleActions = { + FORM_TITLE: i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.edit.addRuleActions.formTitle', + { + defaultMessage: 'Add rule actions', + } + ), + + OVERWRITE_LABEL: i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.edit.addRuleActions.overwriteCheckboxLabel', + { + defaultMessage: 'Overwrite all selected rules actions', + } + ), + + THROTTLE_LABEL: i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.edit.addRuleActions.throttleLabel', + { + defaultMessage: 'Actions frequency', + } + ), + THROTTLE_HELP_TEXT: i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.edit.addRuleActions.throttleHelpText', + { + defaultMessage: + 'Select when automated actions should be performed if a rule evaluates as true.', + } + ), + + warningCalloutMessage: (rulesCount: number): JSX.Element => ( + + ), + + infoCalloutMessage: (rulesCount: number): JSX.Element => ( + + ), +}; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx index 9c5383dc1a693..61a6e4407478d 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx @@ -360,6 +360,16 @@ export const useBulkActions = ({ disabled: isEditDisabled, panel: 1, }, + { + key: i18n.BULK_ACTION_ADD_RULE_ACTIONS, + name: i18n.BULK_ACTION_ADD_RULE_ACTIONS, + 'data-test-subj': 'addRuleActionsBulk', + disabled: isEditDisabled, + onClick: handleBulkEdit(BulkActionEditType.add_actions), + toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipPosition: 'right', + icon: undefined, + }, { key: i18n.BULK_ACTION_APPLY_TIMELINE_TEMPLATE, name: i18n.BULK_ACTION_APPLY_TIMELINE_TEMPLATE, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts index d50d6840e899a..6fa66ed606a2f 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts @@ -10,6 +10,7 @@ import { BulkAction, BulkActionEditType, } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; +import { assertUnreachable } from '../../../../../../../../common/utility_types'; /** * helper utility that creates payload for _bulk_action API in dry mode @@ -53,5 +54,17 @@ export const computeDryRunPayload = ( value: { timeline_id: '', timeline_title: '' }, }, ]; + + case BulkActionEditType.add_actions: + case BulkActionEditType.set_actions: + return [ + { + type: editAction, + value: { throttle: '1h', actions: [] }, + }, + ]; + + default: + assertUnreachable(editAction); } }; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx index 86a54e099e7b2..648d257ae3eb9 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx @@ -361,14 +361,39 @@ export const redirectToDetections = ( hasEncryptionKey === false || needsListsConfiguration; -const getRuleSpecificRuleParamKeys = (ruleType: Type) => { - const queryRuleParams = ['index', 'filters', 'language', 'query', 'saved_id']; +const commonRuleParamsKeys = [ + 'id', + 'name', + 'description', + 'false_positives', + 'rule_id', + 'max_signals', + 'risk_score', + 'output_index', + 'references', + 'severity', + 'timeline_id', + 'timeline_title', + 'threat', + 'type', + 'version', +]; +const queryRuleParams = ['index', 'filters', 'language', 'query', 'saved_id']; +const machineLearningRuleParams = ['anomaly_threshold', 'machine_learning_job_id']; +const thresholdRuleParams = ['threshold', ...queryRuleParams]; +const allRuleParamsKeys = [ + ...commonRuleParamsKeys, + ...queryRuleParams, + ...machineLearningRuleParams, + ...thresholdRuleParams, +].sort(); +const getRuleSpecificRuleParamKeys = (ruleType: Type) => { switch (ruleType) { case 'machine_learning': - return ['anomaly_threshold', 'machine_learning_job_id']; + return machineLearningRuleParams; case 'threshold': - return ['threshold', ...queryRuleParams]; + return thresholdRuleParams; case 'new_terms': case 'threat_match': case 'query': @@ -380,24 +405,6 @@ const getRuleSpecificRuleParamKeys = (ruleType: Type) => { }; export const getActionMessageRuleParams = (ruleType: Type): string[] => { - const commonRuleParamsKeys = [ - 'id', - 'name', - 'description', - 'false_positives', - 'rule_id', - 'max_signals', - 'risk_score', - 'output_index', - 'references', - 'severity', - 'timeline_id', - 'timeline_title', - 'threat', - 'type', - 'version', - ]; - const ruleParamsKeys = [ ...commonRuleParamsKeys, ...getRuleSpecificRuleParamKeys(ruleType), @@ -406,12 +413,7 @@ export const getActionMessageRuleParams = (ruleType: Type): string[] => { return ruleParamsKeys; }; -export const getActionMessageParams = memoizeOne((ruleType: Type | undefined): ActionVariables => { - if (!ruleType) { - return { state: [], params: [] }; - } - const actionMessageRuleParams = getActionMessageRuleParams(ruleType); - // Prefixes are being added automatically by the ActionTypeForm +const transformRuleKeysToActionVariables = (actionMessageRuleParams: string[]): ActionVariables => { return { state: [{ name: 'signals_count', description: 'state.signals_count' }], params: [], @@ -428,8 +430,19 @@ export const getActionMessageParams = memoizeOne((ruleType: Type | undefined): A }), ], }; +}; + +export const getActionMessageParams = memoizeOne((ruleType: Type | undefined): ActionVariables => { + if (!ruleType) { + return { state: [], params: [] }; + } + const actionMessageRuleParams = getActionMessageRuleParams(ruleType); + + return transformRuleKeysToActionVariables(actionMessageRuleParams); }); +export const allActionMessageParams = transformRuleKeysToActionVariables(allRuleParamsKeys); + // typed as null not undefined as the initial state for this value is null. export const userHasPermissions = (canUserCRUD: boolean | null): boolean => canUserCRUD != null ? canUserCRUD : true; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts index b4f25d1b5ff2f..d345fe02f683e 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts @@ -180,6 +180,13 @@ export const BULK_ACTION_APPLY_TIMELINE_TEMPLATE = i18n.translate( } ); +export const BULK_ACTION_ADD_RULE_ACTIONS = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.addRuleActionsTitle', + { + defaultMessage: 'Add rule actions', + } +); + export const BULK_ACTION_MENU_TITLE = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.contextMenuTitle', { From afab2821fcab12fabc61908efe817aa83d0d72d8 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Wed, 17 Aug 2022 13:47:48 +0100 Subject: [PATCH 07/41] additonal tests --- .../perform_bulk_action_schema.test.ts | 170 +++++++++++++++++- 1 file changed, 164 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts index a1f6122a2ef35..5d09518c237ea 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts @@ -343,12 +343,12 @@ describe('perform_bulk_action_schema', () => { const message = retrieveValidationMessage(payload); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "edit" supplied to "action"', - 'Invalid value "set_timeline" supplied to "edit,type"', - 'Invalid value "{"timeline_title":"Test timeline title"}" supplied to "edit,value"', - 'Invalid value "undefined" supplied to "edit,value,timeline_id"', - ]); + expect(getPaths(left(message.errors))).toEqual( + expect.arrayContaining([ + 'Invalid value "{"timeline_title":"Test timeline title"}" supplied to "edit,value"', + 'Invalid value "undefined" supplied to "edit,value,timeline_id"', + ]) + ); expect(message.schema).toEqual({}); }); @@ -373,5 +373,163 @@ describe('perform_bulk_action_schema', () => { expect(message.schema).toEqual(payload); }); }); + + describe('rule actions', () => { + test('invalid request: invalid rule actions payload', () => { + const payload = { + query: 'name: test', + action: BulkAction.edit, + [BulkAction.edit]: [{ type: BulkActionEditType.add_actions, value: [] }], + }; + + const message = retrieveValidationMessage(payload); + + expect(getPaths(left(message.errors))).toEqual( + expect.arrayContaining(['Invalid value "[]" supplied to "edit,value"']) + ); + expect(message.schema).toEqual({}); + }); + + test('invalid request: missing throttle in payload', () => { + const payload = { + query: 'name: test', + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.add_actions, + value: { + actions: [], + }, + }, + ], + }; + + const message = retrieveValidationMessage(payload); + + expect(getPaths(left(message.errors))).toEqual( + expect.arrayContaining(['Invalid value "undefined" supplied to "edit,value,throttle"']) + ); + expect(message.schema).toEqual({}); + }); + + test('invalid request: missing actions in payload', () => { + const payload = { + query: 'name: test', + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.add_actions, + value: { + throttle: '1h', + }, + }, + ], + }; + + const message = retrieveValidationMessage(payload); + + expect(getPaths(left(message.errors))).toEqual( + expect.arrayContaining(['Invalid value "undefined" supplied to "edit,value,actions"']) + ); + expect(message.schema).toEqual({}); + }); + + test('invalid request: invalid action_type_id property in actions array', () => { + const payload = { + query: 'name: test', + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.add_actions, + value: { + throttle: '1h', + actions: [ + { + action_type_id: '.webhook', + group: 'default', + id: '458a50e0-1a28-11ed-9098-47fd8e1f3345', + params: { + body: { + rule_id: '{{rule.id}}', + }, + }, + }, + ], + }, + }, + ], + }; + + const message = retrieveValidationMessage(payload); + expect(getPaths(left(message.errors))).toEqual( + expect.arrayContaining(['invalid keys "action_type_id"']) + ); + expect(message.schema).toEqual({}); + }); + + test('valid request: add_actions edit action', () => { + const payload: PerformBulkActionSchema = { + query: 'name: test', + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.add_actions, + value: { + throttle: '1h', + actions: [ + { + group: 'default', + id: '458a50e0-1a28-11ed-9098-47fd8e1f3345', + params: { + body: { + rule_id: '{{rule.id}}', + }, + }, + }, + ], + }, + }, + ], + }; + + const message = retrieveValidationMessage(payload); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('valid request: set_actions edit action', () => { + const payload: PerformBulkActionSchema = { + query: 'name: test', + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.set_actions, + value: { + throttle: '1h', + actions: [ + { + group: 'default', + id: '458a50e0-1a28-11ed-9098-47fd8e1f3345', + params: { + documents: [ + { + rule_id: '{{rule.id}}', + }, + ], + }, + }, + ], + }, + }, + ], + }; + + const message = retrieveValidationMessage(payload); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + }); }); }); From 4e5311132779b1c37bef779e9206842a25c9225d Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Wed, 17 Aug 2022 14:52:39 +0100 Subject: [PATCH 08/41] rename actims --- .../schemas/common/schemas.ts | 17 ++++++++-------- .../perform_bulk_action_schema.test.ts | 16 +++++++-------- .../all/bulk_actions/bulk_edit_flyout.tsx | 4 ++-- .../bulk_actions/forms/rule_actions_form.tsx | 4 ++-- .../all/bulk_actions/use_bulk_actions.tsx | 2 +- .../utils/compute_dry_run_payload.ts | 4 ++-- .../action_to_rules_client_operation.ts | 4 ++-- .../bulk_actions/split_bulk_edit_actions.ts | 4 ++-- .../detection_engine/rules/bulk_edit_rules.ts | 6 +++--- .../group1/perform_bulk_action.ts | 20 +++++++++---------- 10 files changed, 40 insertions(+), 41 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts index c238bb065f6d2..d747c86281414 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts @@ -385,8 +385,8 @@ export enum BulkActionEditType { 'delete_index_patterns' = 'delete_index_patterns', 'set_index_patterns' = 'set_index_patterns', 'set_timeline' = 'set_timeline', - 'add_actions' = 'add_actions', - 'set_actions' = 'set_actions', + 'add_rule_actions' = 'add_rule_actions', + 'set_rule_actions' = 'set_rule_actions', } const bulkActionEditPayloadTags = t.type({ @@ -426,14 +426,13 @@ const bulkActionEditPayloadTimeline = t.type({ export type BulkActionEditPayloadTimeline = t.TypeOf; -const bulkActionEditPayloadActions = t.type({ +const bulkActionEditPayloadRuleActions = t.type({ type: t.union([ - t.literal(BulkActionEditType.add_actions), - t.literal(BulkActionEditType.set_actions), + t.literal(BulkActionEditType.add_rule_actions), + t.literal(BulkActionEditType.set_rule_actions), ]), value: t.type({ throttle, - // actions: t.array(t.UnknownRecord), actions: t.array( t.exact( t.type({ @@ -446,13 +445,13 @@ const bulkActionEditPayloadActions = t.type({ }), }); -export type BulkActionEditPayloadActions = t.TypeOf; +export type bulkActionEditPayloadRuleActions = t.TypeOf; export const bulkActionEditPayload = t.union([ bulkActionEditPayloadTags, bulkActionEditPayloadIndexPatterns, bulkActionEditPayloadTimeline, - bulkActionEditPayloadActions, + bulkActionEditPayloadRuleActions, ]); export type BulkActionEditPayload = t.TypeOf; @@ -462,7 +461,7 @@ export type BulkActionEditPayload = t.TypeOf; */ export type BulkActionEditForRuleAttributes = | BulkActionEditPayloadTags - | BulkActionEditPayloadActions; + | bulkActionEditPayloadRuleActions; /** * actions that modifies rules params diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts index 5d09518c237ea..f9bb01e4bf5fa 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts @@ -379,7 +379,7 @@ describe('perform_bulk_action_schema', () => { const payload = { query: 'name: test', action: BulkAction.edit, - [BulkAction.edit]: [{ type: BulkActionEditType.add_actions, value: [] }], + [BulkAction.edit]: [{ type: BulkActionEditType.add_rule_actions, value: [] }], }; const message = retrieveValidationMessage(payload); @@ -396,7 +396,7 @@ describe('perform_bulk_action_schema', () => { action: BulkAction.edit, [BulkAction.edit]: [ { - type: BulkActionEditType.add_actions, + type: BulkActionEditType.add_rule_actions, value: { actions: [], }, @@ -418,7 +418,7 @@ describe('perform_bulk_action_schema', () => { action: BulkAction.edit, [BulkAction.edit]: [ { - type: BulkActionEditType.add_actions, + type: BulkActionEditType.add_rule_actions, value: { throttle: '1h', }, @@ -440,7 +440,7 @@ describe('perform_bulk_action_schema', () => { action: BulkAction.edit, [BulkAction.edit]: [ { - type: BulkActionEditType.add_actions, + type: BulkActionEditType.add_rule_actions, value: { throttle: '1h', actions: [ @@ -467,13 +467,13 @@ describe('perform_bulk_action_schema', () => { expect(message.schema).toEqual({}); }); - test('valid request: add_actions edit action', () => { + test('valid request: add_rule_actions edit action', () => { const payload: PerformBulkActionSchema = { query: 'name: test', action: BulkAction.edit, [BulkAction.edit]: [ { - type: BulkActionEditType.add_actions, + type: BulkActionEditType.add_rule_actions, value: { throttle: '1h', actions: [ @@ -498,13 +498,13 @@ describe('perform_bulk_action_schema', () => { expect(message.schema).toEqual(payload); }); - test('valid request: set_actions edit action', () => { + test('valid request: set_rule_actions edit action', () => { const payload: PerformBulkActionSchema = { query: 'name: test', action: BulkAction.edit, [BulkAction.edit]: [ { - type: BulkActionEditType.set_actions, + type: BulkActionEditType.set_rule_actions, value: { throttle: '1h', actions: [ diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx index 17e225dc827a9..0d6ff3c5a8655 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx @@ -38,8 +38,8 @@ const BulkEditFlyoutComponent = ({ editAction, tags, ...props }: BulkEditFlyoutP case BulkActionEditType.set_timeline: return ; - case BulkActionEditType.add_actions: - case BulkActionEditType.set_actions: + case BulkActionEditType.add_rule_actions: + case BulkActionEditType.set_rule_actions: return ; default: diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index d8431b49b07bd..84ae12f08bd1f 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -101,8 +101,8 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction } const editAction = data.overwrite - ? BulkActionEditType.set_actions - : BulkActionEditType.add_actions; + ? BulkActionEditType.set_rule_actions + : BulkActionEditType.add_rule_actions; onConfirm({ type: editAction, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx index 61a6e4407478d..6bfc119ad1b0c 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx @@ -365,7 +365,7 @@ export const useBulkActions = ({ name: i18n.BULK_ACTION_ADD_RULE_ACTIONS, 'data-test-subj': 'addRuleActionsBulk', disabled: isEditDisabled, - onClick: handleBulkEdit(BulkActionEditType.add_actions), + onClick: handleBulkEdit(BulkActionEditType.add_rule_actions), toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, toolTipPosition: 'right', icon: undefined, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts index 6fa66ed606a2f..86b429ca4b552 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts @@ -55,8 +55,8 @@ export const computeDryRunPayload = ( }, ]; - case BulkActionEditType.add_actions: - case BulkActionEditType.set_actions: + case BulkActionEditType.add_rule_actions: + case BulkActionEditType.set_rule_actions: return [ { type: editAction, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts index ee13c4c780db6..74cce4f995a74 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts @@ -65,7 +65,7 @@ export const bulkEditActionToRulesClientOperation = ( ]; // rule actions - case BulkActionEditType.add_actions: + case BulkActionEditType.add_rule_actions: return [ { field: 'actions', @@ -76,7 +76,7 @@ export const bulkEditActionToRulesClientOperation = ( getNotifyWhenOperation(action.value.throttle), ]; - case BulkActionEditType.set_actions: + case BulkActionEditType.set_rule_actions: return [ { field: 'actions', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts index 87d38f7578628..ee42304aec0eb 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts @@ -32,8 +32,8 @@ export const splitBulkEditActions = (actions: BulkActionEditPayload[]) => { case BulkActionEditType.add_tags: case BulkActionEditType.set_tags: case BulkActionEditType.delete_tags: - case BulkActionEditType.add_actions: - case BulkActionEditType.set_actions: + case BulkActionEditType.add_rule_actions: + case BulkActionEditType.set_rule_actions: acc.attributesActions.push(action); break; default: diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts index 5cf9cd117bad2..965754f771cdd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts @@ -9,7 +9,7 @@ import pMap from 'p-map'; import type { RulesClient } from '@kbn/alerting-plugin/server'; import type { BulkActionEditPayload, - BulkActionEditPayloadActions, + bulkActionEditPayloadRuleActions, } from '../../../../common/detection_engine/schemas/common'; import { enrichFilterWithRuleTypeMapping } from './enrich_filter_with_rule_type_mappings'; import type { MlAuthz } from '../../machine_learning/authz'; @@ -66,8 +66,8 @@ export const bulkEditRules = async ({ // calling unmute needed only if rule was muted and throttle value is not NOTIFICATION_THROTTLE_NO_ACTIONS // TODO: error handlers (?) const rulesAction = attributesActions.find(({ type }) => - [BulkActionEditType.set_actions, BulkActionEditType.add_actions].includes(type) - ) as BulkActionEditPayloadActions; + [BulkActionEditType.set_rule_actions, BulkActionEditType.add_rule_actions].includes(type) + ) as bulkActionEditPayloadRuleActions; if (rulesAction) { const rules = await pMap( result.rules, diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts index 6162419e051ca..cf409252b750c 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts @@ -1048,7 +1048,7 @@ export default ({ getService }: FtrProviderContext): void => { }, }; - describe('add_actions', () => { + describe('add_rule_actions', () => { it('should set action correctly', async () => { const ruleId = 'ruleId'; const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); @@ -1062,7 +1062,7 @@ export default ({ getService }: FtrProviderContext): void => { action: BulkAction.edit, [BulkAction.edit]: [ { - type: BulkActionEditType.set_actions, + type: BulkActionEditType.set_rule_actions, value: { throttle: '1h', actions: [ @@ -1124,7 +1124,7 @@ export default ({ getService }: FtrProviderContext): void => { action: BulkAction.edit, [BulkAction.edit]: [ { - type: BulkActionEditType.set_actions, + type: BulkActionEditType.set_rule_actions, value: { throttle: '1h', actions: [], @@ -1144,7 +1144,7 @@ export default ({ getService }: FtrProviderContext): void => { }); }); - describe('add_actions', () => { + describe('add_rule_actions', () => { it('should add action correctly to empty actions list', async () => { const ruleId = 'ruleId'; const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); @@ -1158,7 +1158,7 @@ export default ({ getService }: FtrProviderContext): void => { action: BulkAction.edit, [BulkAction.edit]: [ { - type: BulkActionEditType.add_actions, + type: BulkActionEditType.add_rule_actions, value: { throttle: '1h', actions: [ @@ -1220,7 +1220,7 @@ export default ({ getService }: FtrProviderContext): void => { action: BulkAction.edit, [BulkAction.edit]: [ { - type: BulkActionEditType.add_actions, + type: BulkActionEditType.add_rule_actions, value: { throttle: '1h', actions: [ @@ -1284,7 +1284,7 @@ export default ({ getService }: FtrProviderContext): void => { action: BulkAction.edit, [BulkAction.edit]: [ { - type: BulkActionEditType.add_actions, + type: BulkActionEditType.add_rule_actions, value: { throttle: '1h', actions: [], @@ -1327,7 +1327,7 @@ export default ({ getService }: FtrProviderContext): void => { action: BulkAction.edit, [BulkAction.edit]: [ { - type: BulkActionEditType.set_actions, + type: BulkActionEditType.set_rule_actions, value: { throttle: payload.throttle, actions: [], @@ -1371,7 +1371,7 @@ export default ({ getService }: FtrProviderContext): void => { // action: BulkAction.edit, // [BulkAction.edit]: [ // { - // type: BulkActionEditType.set_actions, + // type: BulkActionEditType.set_rule_actions, // value: { // throttle: payload.throttle, // actions: [], @@ -1419,7 +1419,7 @@ export default ({ getService }: FtrProviderContext): void => { action: BulkAction.edit, [BulkAction.edit]: [ { - type: BulkActionEditType.set_actions, + type: BulkActionEditType.set_rule_actions, value: { throttle: payload.throttle, actions: [], From 7cb4a078a8c8c3655c034d2f5f5fd862475a069b Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Wed, 17 Aug 2022 14:57:31 +0100 Subject: [PATCH 09/41] fix tests --- .../action_to_rules_client_operation.test.ts | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.test.ts index 8646a79d3d070..90336cc195edb 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.test.ts @@ -10,29 +10,35 @@ import { BulkActionEditType } from '../../../../../common/detection_engine/schem import { bulkEditActionToRulesClientOperation } from './action_to_rules_client_operation'; describe('bulkEditActionToRulesClientOperation', () => { - test('should transform tags bulk edit actions correctly f', () => { + test('should transform tags bulk edit actions correctly', () => { expect( bulkEditActionToRulesClientOperation({ type: BulkActionEditType.add_tags, value: ['test'] }) - ).toEqual({ - field: 'tags', - operation: 'add', - value: ['test'], - }); + ).toEqual([ + { + field: 'tags', + operation: 'add', + value: ['test'], + }, + ]); }); expect( bulkEditActionToRulesClientOperation({ type: BulkActionEditType.set_tags, value: ['test'] }) - ).toEqual({ - field: 'tags', - operation: 'set', - value: ['test'], - }); + ).toEqual([ + { + field: 'tags', + operation: 'set', + value: ['test'], + }, + ]); expect( bulkEditActionToRulesClientOperation({ type: BulkActionEditType.delete_tags, value: ['test'] }) - ).toEqual({ - field: 'tags', - operation: 'delete', - value: ['test'], - }); + ).toEqual([ + { + field: 'tags', + operation: 'delete', + value: ['test'], + }, + ]); }); From 32a73a3425d5eeea88c66815697088e14d3e28bd Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Wed, 17 Aug 2022 16:17:24 +0100 Subject: [PATCH 10/41] services.application.capabilities.actions.show; --- .../rules/all/bulk_actions/use_bulk_actions.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx index 6bfc119ad1b0c..58812ff98431c 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx @@ -40,6 +40,7 @@ import { } from '../../../../../containers/detection_engine/rules/use_find_rules_query'; import { BULK_RULE_ACTIONS } from '../../../../../../common/lib/apm/user_actions'; import { useStartTransaction } from '../../../../../../common/lib/apm/use_start_transaction'; +import { useKibana } from '../../../../../../common/lib/kibana'; import { useInvalidatePrePackagedRulesStatus } from '../../../../../containers/detection_engine/rules/use_pre_packaged_rules_status'; import type { DryRunResult, BulkActionForConfirmation } from './types'; @@ -76,6 +77,9 @@ export const useBulkActions = ({ const getIsMounted = useIsMounted(); const filterQuery = convertRulesFilterToKQL(filterOptions); const { startTransaction } = useStartTransaction(); + const { services } = useKibana(); + + const hasUserAccessToActions = services.application.capabilities.actions.show; // refetch tags if edit action is related to tags: add_tags/delete_tags/set_tags const resolveTagsRefetch = useCallback( @@ -364,7 +368,7 @@ export const useBulkActions = ({ key: i18n.BULK_ACTION_ADD_RULE_ACTIONS, name: i18n.BULK_ACTION_ADD_RULE_ACTIONS, 'data-test-subj': 'addRuleActionsBulk', - disabled: isEditDisabled, + disabled: !hasUserAccessToActions || isEditDisabled, onClick: handleBulkEdit(BulkActionEditType.add_rule_actions), toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, toolTipPosition: 'right', @@ -491,6 +495,7 @@ export const useBulkActions = ({ completeBulkEditForm, getIsMounted, resolveTagsRefetch, + hasUserAccessToActions, ] ); From 85ead17f52c76a42d0dedd37ab863ff398ce845f Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Wed, 17 Aug 2022 16:17:41 +0100 Subject: [PATCH 11/41] trying to fix bundle --- .../detection_engine/schemas/common/schemas.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts index d747c86281414..3d92520190b14 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts @@ -16,12 +16,6 @@ import { UUID, LimitedSizeArray, } from '@kbn/securitysolution-io-ts-types'; -import { - throttle, - action_group as actionGroup, - action_params as actionParams, - action_id as actionId, -} from '@kbn/securitysolution-io-ts-alerting-types'; import * as t from 'io-ts'; export const author = t.array(t.string); @@ -432,13 +426,13 @@ const bulkActionEditPayloadRuleActions = t.type({ t.literal(BulkActionEditType.set_rule_actions), ]), value: t.type({ - throttle, + throttle: t.string, actions: t.array( t.exact( t.type({ - group: actionGroup, - id: actionId, - params: actionParams, + group: t.string, + id: t.string, + params: t.UnknownRecord, }) ) ), From 3a8f591a6b6e9a246d7bd7e917f08e02f0235f4b Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Wed, 17 Aug 2022 18:51:08 +0100 Subject: [PATCH 12/41] immutability fix --- .../rule_types/eql/create_eql_alert_type.ts | 3 +- .../create_indicator_match_alert_type.ts | 3 +- .../rule_types/ml/create_ml_alert_type.ts | 12 - .../new_terms/create_new_terms_alert_type.ts | 3 +- .../query/create_query_alert_type.ts | 3 +- .../create_saved_query_alert_type.ts | 3 +- .../threshold/create_threshold_alert_type.ts | 3 +- .../utils/validate_mutated_params.ts | 6 - .../rules/bulk_actions/validations.ts | 34 +- .../detection_engine/rules/bulk_edit_rules.ts | 7 +- .../group1/perform_bulk_action.ts | 959 ++++++++++-------- 11 files changed, 588 insertions(+), 448 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts index abfdc5fe491a7..16db4e4955538 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts @@ -13,7 +13,7 @@ import type { EqlRuleParams } from '../../schemas/rule_schemas'; import { eqlRuleParams } from '../../schemas/rule_schemas'; import { eqlExecutor } from '../../signals/executors/eql'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; -import { validateImmutable, validateIndexPatterns } from '../utils'; +import { validateIndexPatterns } from '../utils'; export const createEqlAlertType = ( createOptions: CreateRuleOptions @@ -41,7 +41,6 @@ export const createEqlAlertType = ( * @returns mutatedRuleParams */ validateMutatedParams: (mutatedRuleParams) => { - validateImmutable(mutatedRuleParams.immutable); validateIndexPatterns(mutatedRuleParams.index); return mutatedRuleParams; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/create_indicator_match_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/create_indicator_match_alert_type.ts index 94fc6d78965bb..6a370b381acd1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/create_indicator_match_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/create_indicator_match_alert_type.ts @@ -13,7 +13,7 @@ import type { ThreatRuleParams } from '../../schemas/rule_schemas'; import { threatRuleParams } from '../../schemas/rule_schemas'; import { threatMatchExecutor } from '../../signals/executors/threat_match'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; -import { validateImmutable, validateIndexPatterns } from '../utils'; +import { validateIndexPatterns } from '../utils'; export const createIndicatorMatchAlertType = ( createOptions: CreateRuleOptions @@ -42,7 +42,6 @@ export const createIndicatorMatchAlertType = ( * @returns mutatedRuleParams */ validateMutatedParams: (mutatedRuleParams) => { - validateImmutable(mutatedRuleParams.immutable); validateIndexPatterns(mutatedRuleParams.index); return mutatedRuleParams; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/create_ml_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/create_ml_alert_type.ts index 926615fc8d176..c24e9c5af8d4f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/create_ml_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/create_ml_alert_type.ts @@ -13,7 +13,6 @@ import type { MachineLearningRuleParams } from '../../schemas/rule_schemas'; import { machineLearningRuleParams } from '../../schemas/rule_schemas'; import { mlExecutor } from '../../signals/executors/ml'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; -import { validateImmutable } from '../utils'; export const createMlAlertType = ( createOptions: CreateRuleOptions @@ -34,17 +33,6 @@ export const createMlAlertType = ( } return validated; }, - /** - * validate rule params when rule is bulk edited (update and created in future as well) - * returned params can be modified (useful in case of version increment) - * @param mutatedRuleParams - * @returns mutatedRuleParams - */ - validateMutatedParams: (mutatedRuleParams) => { - validateImmutable(mutatedRuleParams.immutable); - - return mutatedRuleParams; - }, }, }, actionGroups: [ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts index 213f22720a9dd..c49a523bdde1a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts @@ -29,7 +29,7 @@ import { buildNewTermsAgg, } from './build_new_terms_aggregation'; import type { SignalSource } from '../../signals/types'; -import { validateImmutable, validateIndexPatterns } from '../utils'; +import { validateIndexPatterns } from '../utils'; import { parseDateString, validateHistoryWindowStart } from './utils'; interface BulkCreateResults { @@ -90,7 +90,6 @@ export const createNewTermsAlertType = ( * @returns mutatedRuleParams */ validateMutatedParams: (mutatedRuleParams) => { - validateImmutable(mutatedRuleParams.immutable); validateIndexPatterns(mutatedRuleParams.index); return mutatedRuleParams; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.ts index 14e309a83c959..5a940ebe364c5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.ts @@ -13,7 +13,7 @@ import type { QueryRuleParams } from '../../schemas/rule_schemas'; import { queryRuleParams } from '../../schemas/rule_schemas'; import { queryExecutor } from '../../signals/executors/query'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; -import { validateImmutable, validateIndexPatterns } from '../utils'; +import { validateIndexPatterns } from '../utils'; export const createQueryAlertType = ( createOptions: CreateRuleOptions ): SecurityAlertType => { @@ -40,7 +40,6 @@ export const createQueryAlertType = ( * @returns mutatedRuleParams */ validateMutatedParams: (mutatedRuleParams) => { - validateImmutable(mutatedRuleParams.immutable); validateIndexPatterns(mutatedRuleParams.index); return mutatedRuleParams; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/saved_query/create_saved_query_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/saved_query/create_saved_query_alert_type.ts index f8009220581e1..325d9adfb1bda 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/saved_query/create_saved_query_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/saved_query/create_saved_query_alert_type.ts @@ -13,7 +13,7 @@ import type { CompleteRule, SavedQueryRuleParams } from '../../schemas/rule_sche import { savedQueryRuleParams } from '../../schemas/rule_schemas'; import { queryExecutor } from '../../signals/executors/query'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; -import { validateImmutable, validateIndexPatterns } from '../utils'; +import { validateIndexPatterns } from '../utils'; export const createSavedQueryAlertType = ( createOptions: CreateRuleOptions ): SecurityAlertType => { @@ -40,7 +40,6 @@ export const createSavedQueryAlertType = ( * @returns mutatedRuleParams */ validateMutatedParams: (mutatedRuleParams) => { - validateImmutable(mutatedRuleParams.immutable); validateIndexPatterns(mutatedRuleParams.index); return mutatedRuleParams; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/create_threshold_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/create_threshold_alert_type.ts index cacc2f91a925f..1a419ddfd09c6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/create_threshold_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/create_threshold_alert_type.ts @@ -14,7 +14,7 @@ import { thresholdRuleParams } from '../../schemas/rule_schemas'; import { thresholdExecutor } from '../../signals/executors/threshold'; import type { ThresholdAlertState } from '../../signals/types'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; -import { validateImmutable, validateIndexPatterns } from '../utils'; +import { validateIndexPatterns } from '../utils'; export const createThresholdAlertType = ( createOptions: CreateRuleOptions @@ -42,7 +42,6 @@ export const createThresholdAlertType = ( * @returns mutatedRuleParams */ validateMutatedParams: (mutatedRuleParams) => { - validateImmutable(mutatedRuleParams.immutable); validateIndexPatterns(mutatedRuleParams.index); return mutatedRuleParams; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/validate_mutated_params.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/validate_mutated_params.ts index 0aac2fc709588..f8a696f0c7f68 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/validate_mutated_params.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/validate_mutated_params.ts @@ -5,12 +5,6 @@ * 2.0. */ -export const validateImmutable = (immutable: boolean) => { - if (immutable === true) { - throw new Error("Elastic rule can't be edited"); - } -}; - export const validateIndexPatterns = (indices: string[] | undefined) => { if (indices?.length === 0) { throw new Error("Index patterns can't be empty"); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts index 28793f9fe9c88..5c2b5c0fb478a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts @@ -10,6 +10,7 @@ import { invariant } from '../../../../../common/utils/invariant'; import { isMlRule } from '../../../../../common/machine_learning/helpers'; import { BulkActionsDryRunErrCode } from '../../../../../common/constants'; import type { BulkActionEditPayload } from '../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; import type { RuleAlertType } from '../types'; import { isIndexPatternsBulkEditAction } from './utils'; import { throwDryRunError } from './dry_run'; @@ -24,6 +25,8 @@ interface BulkActionsValidationArgs { interface BulkEditBulkActionsValidationArgs { ruleType: RuleType; mlAuthz: MlAuthz; + edit: BulkActionEditPayload[]; + immutable: boolean; } interface DryRunBulkEditBulkActionsValidationArgs { @@ -78,8 +81,26 @@ export const validateBulkDuplicateRule = async ({ rule, mlAuthz }: BulkActionsVa export const validateBulkEditRule = async ({ ruleType, mlAuthz, + edit, + immutable, }: BulkEditBulkActionsValidationArgs) => { await throwMlAuthError(mlAuthz, ruleType); + + // if rule can't be edited error will be thrown + const canRuleBeEdited = !immutable || istEditApplicableToImmutableRule(edit); + await throwDryRunError( + () => invariant(canRuleBeEdited, "Elastic rule can't be edited"), + BulkActionsDryRunErrCode.IMMUTABLE + ); +}; + +/** + * add_rule_actions, set_rule_actions can be applied to prebuilt/immutable rules + */ +const istEditApplicableToImmutableRule = (edit: BulkActionEditPayload[]): boolean => { + return edit.every(({ type }) => + [BulkActionEditType.set_rule_actions, BulkActionEditType.add_rule_actions].includes(type) + ); }; /** @@ -91,13 +112,12 @@ export const dryRunValidateBulkEditRule = async ({ edit, mlAuthz, }: DryRunBulkEditBulkActionsValidationArgs) => { - await validateBulkEditRule({ ruleType: rule.params.type, mlAuthz }); - - // if rule is immutable, it can't be edited - await throwDryRunError( - () => invariant(rule.params.immutable === false, "Elastic rule can't be edited"), - BulkActionsDryRunErrCode.IMMUTABLE - ); + await validateBulkEditRule({ + ruleType: rule.params.type, + mlAuthz, + edit, + immutable: rule.params.immutable, + }); // if rule is machine_learning, index pattern action can't be applied to it await throwDryRunError( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts index 965754f771cdd..f435e59f60fb3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts @@ -52,7 +52,12 @@ export const bulkEditRules = async ({ ...(ids ? { ids } : { filter: enrichFilterWithRuleTypeMapping(filter) }), operations: attributesActions.map(bulkEditActionToRulesClientOperation).flat(), paramsModifier: async (ruleParams: RuleAlertType['params']) => { - await validateBulkEditRule({ mlAuthz, ruleType: ruleParams.type }); + await validateBulkEditRule({ + mlAuthz, + ruleType: ruleParams.type, + edit: actions, + immutable: ruleParams.immutable, + }); return ruleParamsModifier(ruleParams, paramsActions); }, }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts index cf409252b750c..9d4e8dd94fec7 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts @@ -46,6 +46,17 @@ export default ({ getService }: FtrProviderContext): void => { supertest.post(DETECTION_ENGINE_RULES_BULK_ACTION).set('kbn-xsrf', 'true'); const fetchRule = (ruleId: string) => supertest.get(`${DETECTION_ENGINE_RULES_URL}?rule_id=${ruleId}`).set('kbn-xsrf', 'true'); + + const fetchPrebuiltRule = async () => { + const { body: findBody } = await supertest + .get( + `${DETECTION_ENGINE_RULES_URL}/_find?per_page=1&filter=alert.attributes.params.immutable: true` + ) + .set('kbn-xsrf', 'true'); + + return findBody.data[0]; + }; + /** * allows to get access to internal property: notifyWhen */ @@ -658,19 +669,13 @@ export default ({ getService }: FtrProviderContext): void => { expect(rule.timeline_title).to.be(undefined); }); - it('should return error when trying to bulk edit immutable rule', async () => { + it('should return error when trying to bulk edit prebuilt rule', async () => { await installPrePackagedRules(supertest, log); - const { body: findBody } = await supertest - .get( - `${DETECTION_ENGINE_RULES_URL}/_find?per_page=1&filter=alert.attributes.params.immutable: true` - ) - .set('kbn-xsrf', 'true') - .send(); - const immutableRule = findBody.data[0]; + const prebuiltRule = await fetchPrebuiltRule(); const { body } = await postBulkAction() .send({ - ids: [immutableRule.id], + ids: [prebuiltRule.id], action: BulkAction.edit, [BulkAction.edit]: [ { @@ -683,12 +688,12 @@ export default ({ getService }: FtrProviderContext): void => { expect(body.attributes.summary).to.eql({ failed: 1, succeeded: 0, total: 1 }); expect(body.attributes.errors[0]).to.eql({ - message: "Mutated params invalid: Elastic rule can't be edited", + message: "Elastic rule can't be edited", status_code: 500, rules: [ { - id: immutableRule.id, - name: immutableRule.name, + id: prebuiltRule.id, + name: prebuiltRule.name, }, ], }); @@ -779,6 +784,538 @@ export default ({ getService }: FtrProviderContext): void => { expect(updatedRule.version).to.be(rule.version + 1); }); + + describe('prebuilt rules', () => { + const cases = [ + { + type: BulkActionEditType.add_tags, + value: ['new-tag'], + }, + { + type: BulkActionEditType.set_tags, + value: ['new-tag'], + }, + { + type: BulkActionEditType.delete_tags, + value: ['new-tag'], + }, + { + type: BulkActionEditType.add_index_patterns, + value: ['test-*'], + }, + { + type: BulkActionEditType.set_index_patterns, + value: ['test-*'], + }, + { + type: BulkActionEditType.delete_index_patterns, + value: ['test-*'], + }, + { + type: BulkActionEditType.set_timeline, + value: { timeline_id: 'mock-id', timeline_title: 'mock-title' }, + }, + ]; + cases.forEach(({ type, value }) => { + it(`should return error when trying to apply "${type}" edit action to prebuilt rule`, async () => { + await installPrePackagedRules(supertest, log); + const prebuiltRule = await fetchPrebuiltRule(); + + const { body } = await postBulkAction() + .send({ + ids: [prebuiltRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type, + value, + }, + ], + }) + .expect(500); + + expect(body.attributes.summary).to.eql({ failed: 1, succeeded: 0, total: 1 }); + expect(body.attributes.errors[0]).to.eql({ + message: "Elastic rule can't be edited", + status_code: 500, + rules: [ + { + id: prebuiltRule.id, + name: prebuiltRule.name, + }, + ], + }); + }); + }); + }); + + describe('rule actions', () => { + const webHookActionMock = { + group: 'default', + params: { + body: '{}', + }, + }; + + describe('set_rule_actions', () => { + it('should set action correctly', async () => { + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); + + // create a new action + const hookAction = await createWebHookAction(); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.set_rule_actions, + value: { + throttle: '1h', + actions: [ + { + ...webHookActionMock, + id: hookAction.id, + }, + ], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].actions).to.eql([ + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + + // Check that the updates have been persisted + const { body: readRule } = await fetchRule(ruleId).expect(200); + + expect(readRule.actions).to.eql([ + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + }); + + it('should set actions to empty if list of action is empty in payload', async () => { + // create a new action + const hookAction = await createWebHookAction(); + + const defaultRuleAction = { + id: hookAction.id, + action_type_id: '.webhook', + group: 'default', + params: { + body: '{"test":"a default action"}', + }, + }; + + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, { + ...getSimpleRule(ruleId), + actions: [defaultRuleAction], + throttle: '1d', + }); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.set_rule_actions, + value: { + throttle: '1h', + actions: [], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].actions).to.eql([]); + + // Check that the updates have been persisted + const { body: readRule } = await fetchRule(ruleId).expect(200); + + expect(readRule.actions).to.eql([]); + }); + }); + + describe('add_rule_actions', () => { + it('should add action correctly to empty actions list', async () => { + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); + + // create a new action + const hookAction = await createWebHookAction(); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.add_rule_actions, + value: { + throttle: '1h', + actions: [ + { + ...webHookActionMock, + id: hookAction.id, + }, + ], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].actions).to.eql([ + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + + // Check that the updates have been persisted + const { body: readRule } = await fetchRule(ruleId).expect(200); + + expect(readRule.actions).to.eql([ + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + }); + + it('should add action correctly to non empty actions list', async () => { + // create a new action + const hookAction = await createWebHookAction(); + + const defaultRuleAction = { + id: hookAction.id, + action_type_id: '.webhook', + group: 'default', + params: { + body: '{"test":"a default action"}', + }, + }; + + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, { + ...getSimpleRule(ruleId), + actions: [defaultRuleAction], + throttle: '1d', + }); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.add_rule_actions, + value: { + throttle: '1h', + actions: [ + { + ...webHookActionMock, + id: hookAction.id, + }, + ], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].actions).to.eql([ + defaultRuleAction, + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + + // Check that the updates have been persisted + const { body: readRule } = await fetchRule(ruleId).expect(200); + + expect(readRule.actions).to.eql([ + defaultRuleAction, + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + }); + + it('should not change actions of rule if empty list of actions added', async () => { + // create a new action + const hookAction = await createWebHookAction(); + + const defaultRuleAction = { + id: hookAction.id, + action_type_id: '.webhook', + group: 'default', + params: { + body: '{"test":"a default action"}', + }, + }; + + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, { + ...getSimpleRule(ruleId), + actions: [defaultRuleAction], + throttle: '1d', + }); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.add_rule_actions, + value: { + throttle: '1h', + actions: [], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].actions).to.eql([defaultRuleAction]); + + // Check that the updates have been persisted + const { body: readRule } = await fetchRule(ruleId).expect(200); + + expect(readRule.actions).to.eql([defaultRuleAction]); + }); + }); + + describe('prebuilt rules', () => { + const cases = [ + { + type: BulkActionEditType.set_rule_actions, + }, + { + type: BulkActionEditType.add_rule_actions, + }, + ]; + cases.forEach(({ type }) => { + it(`should apply "${type}" rule action to prebuilt rule`, async () => { + await installPrePackagedRules(supertest, log); + const prebuiltRule = await fetchPrebuiltRule(); + const hookAction = await createWebHookAction(); + + const { body } = await postBulkAction() + .send({ + ids: [prebuiltRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type, + value: { + throttle: '1h', + actions: [ + { + ...webHookActionMock, + id: hookAction.id, + }, + ], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].actions).to.eql([ + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + + // Check that the updates have been persisted + const { body: readRule } = await fetchRule(prebuiltRule.rule_id).expect(200); + + expect(readRule.actions).to.eql([ + { + ...webHookActionMock, + id: hookAction.id, + action_type_id: '.webhook', + }, + ]); + }); + }); + }); + + describe('throttle', () => { + const casesForEmptyActions = [ + { + payloadThrottle: NOTIFICATION_THROTTLE_NO_ACTIONS, + }, + { + payloadThrottle: NOTIFICATION_THROTTLE_RULE, + }, + { + payloadThrottle: '1d', + }, + ]; + casesForEmptyActions.forEach(({ payloadThrottle }) => { + it(`throttle is set correctly, if payload throttle="${payloadThrottle}" and actions empty`, async () => { + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.set_rule_actions, + value: { + throttle: payloadThrottle, + actions: [], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].throttle).to.eql( + NOTIFICATION_THROTTLE_NO_ACTIONS + ); + + // Check that the updates have been persisted + const { body: rule } = await fetchRule(ruleId).expect(200); + + expect(rule.throttle).to.eql(NOTIFICATION_THROTTLE_NO_ACTIONS); + }); + }); + + const casesForNonEmptyActions = [ + { + payloadThrottle: NOTIFICATION_THROTTLE_NO_ACTIONS, + expectedThrottle: NOTIFICATION_THROTTLE_NO_ACTIONS, + }, + { + payloadThrottle: NOTIFICATION_THROTTLE_RULE, + expectedThrottle: NOTIFICATION_THROTTLE_RULE, + }, + { + payloadThrottle: '1h', + expectedThrottle: '1h', + }, + ]; + casesForNonEmptyActions.forEach(({ payloadThrottle, expectedThrottle }) => { + it(`throttle is set correctly, if payload throttle="${payloadThrottle}" and actions non empty`, async () => { + // create a new action + const hookAction = await createWebHookAction(); + + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.set_rule_actions, + value: { + throttle: payloadThrottle, + actions: [ + { + id: hookAction.id, + group: 'default', + params: { body: '{}' }, + }, + ], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].throttle).to.eql(expectedThrottle); + + // Check that the updates have been persisted + const { body: rule } = await fetchRule(ruleId).expect(200); + + expect(rule.throttle).to.eql(expectedThrottle); + }); + }); + }); + + describe('notifyWhen', () => { + const cases = [ + { + payload: { throttle: NOTIFICATION_THROTTLE_NO_ACTIONS }, + // keeps existing default value which is onActiveAlert + expected: { notifyWhen: 'onActiveAlert' }, + }, + { + payload: { throttle: '1d' }, + expected: { notifyWhen: 'onThrottleInterval' }, + }, + { + payload: { throttle: NOTIFICATION_THROTTLE_RULE }, + expected: { notifyWhen: 'onActiveAlert' }, + }, + ]; + cases.forEach(({ payload, expected }) => { + it(`should set notifyWhen correctly, if payload throttle="${payload.throttle}"`, async () => { + const createdRule = await createRule(supertest, log, getSimpleRule('ruleId')); + + await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.set_rule_actions, + value: { + throttle: payload.throttle, + actions: [], + }, + }, + ], + }) + .expect(200); + + // Check whether notifyWhen set correctly + const { body: rule } = await fetchRuleByAlertApi(createdRule.id).expect(200); + + expect(rule.notify_when).to.eql(expected.notifyWhen); + }); + }); + }); + }); }); describe('overwrite_data_views', () => { @@ -1040,404 +1577,6 @@ export default ({ getService }: FtrProviderContext): void => { }); }); - describe('rule actions', () => { - const webHookActionMock = { - group: 'default', - params: { - body: '{}', - }, - }; - - describe('add_rule_actions', () => { - it('should set action correctly', async () => { - const ruleId = 'ruleId'; - const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); - - // create a new action - const hookAction = await createWebHookAction(); - - const { body } = await postBulkAction() - .send({ - ids: [createdRule.id], - action: BulkAction.edit, - [BulkAction.edit]: [ - { - type: BulkActionEditType.set_rule_actions, - value: { - throttle: '1h', - actions: [ - { - ...webHookActionMock, - id: hookAction.id, - }, - ], - }, - }, - ], - }) - .expect(200); - - // Check that the updated rule is returned with the response - expect(body.attributes.results.updated[0].actions).to.eql([ - { - ...webHookActionMock, - id: hookAction.id, - action_type_id: '.webhook', - }, - ]); - - // Check that the updates have been persisted - const { body: readRule } = await fetchRule(ruleId).expect(200); - - expect(readRule.actions).to.eql([ - { - ...webHookActionMock, - id: hookAction.id, - action_type_id: '.webhook', - }, - ]); - }); - - it('should set actions to empty if list of action is empty in payload', async () => { - // create a new action - const hookAction = await createWebHookAction(); - - const defaultRuleAction = { - id: hookAction.id, - action_type_id: '.webhook', - group: 'default', - params: { - body: '{"test":"a default action"}', - }, - }; - - const ruleId = 'ruleId'; - const createdRule = await createRule(supertest, log, { - ...getSimpleRule(ruleId), - actions: [defaultRuleAction], - throttle: '1d', - }); - - const { body } = await postBulkAction() - .send({ - ids: [createdRule.id], - action: BulkAction.edit, - [BulkAction.edit]: [ - { - type: BulkActionEditType.set_rule_actions, - value: { - throttle: '1h', - actions: [], - }, - }, - ], - }) - .expect(200); - - // Check that the updated rule is returned with the response - expect(body.attributes.results.updated[0].actions).to.eql([]); - - // Check that the updates have been persisted - const { body: readRule } = await fetchRule(ruleId).expect(200); - - expect(readRule.actions).to.eql([]); - }); - }); - - describe('add_rule_actions', () => { - it('should add action correctly to empty actions list', async () => { - const ruleId = 'ruleId'; - const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); - - // create a new action - const hookAction = await createWebHookAction(); - - const { body } = await postBulkAction() - .send({ - ids: [createdRule.id], - action: BulkAction.edit, - [BulkAction.edit]: [ - { - type: BulkActionEditType.add_rule_actions, - value: { - throttle: '1h', - actions: [ - { - ...webHookActionMock, - id: hookAction.id, - }, - ], - }, - }, - ], - }) - .expect(200); - - // Check that the updated rule is returned with the response - expect(body.attributes.results.updated[0].actions).to.eql([ - { - ...webHookActionMock, - id: hookAction.id, - action_type_id: '.webhook', - }, - ]); - - // Check that the updates have been persisted - const { body: readRule } = await fetchRule(ruleId).expect(200); - - expect(readRule.actions).to.eql([ - { - ...webHookActionMock, - id: hookAction.id, - action_type_id: '.webhook', - }, - ]); - }); - - it('should add action correctly to non empty actions list', async () => { - // create a new action - const hookAction = await createWebHookAction(); - - const defaultRuleAction = { - id: hookAction.id, - action_type_id: '.webhook', - group: 'default', - params: { - body: '{"test":"a default action"}', - }, - }; - - const ruleId = 'ruleId'; - const createdRule = await createRule(supertest, log, { - ...getSimpleRule(ruleId), - actions: [defaultRuleAction], - throttle: '1d', - }); - - const { body } = await postBulkAction() - .send({ - ids: [createdRule.id], - action: BulkAction.edit, - [BulkAction.edit]: [ - { - type: BulkActionEditType.add_rule_actions, - value: { - throttle: '1h', - actions: [ - { - ...webHookActionMock, - id: hookAction.id, - }, - ], - }, - }, - ], - }) - .expect(200); - - // Check that the updated rule is returned with the response - expect(body.attributes.results.updated[0].actions).to.eql([ - defaultRuleAction, - { - ...webHookActionMock, - id: hookAction.id, - action_type_id: '.webhook', - }, - ]); - - // Check that the updates have been persisted - const { body: readRule } = await fetchRule(ruleId).expect(200); - - expect(readRule.actions).to.eql([ - defaultRuleAction, - { - ...webHookActionMock, - id: hookAction.id, - action_type_id: '.webhook', - }, - ]); - }); - - it('should not change actions of rule if empty list of actions added', async () => { - // create a new action - const hookAction = await createWebHookAction(); - - const defaultRuleAction = { - id: hookAction.id, - action_type_id: '.webhook', - group: 'default', - params: { - body: '{"test":"a default action"}', - }, - }; - - const ruleId = 'ruleId'; - const createdRule = await createRule(supertest, log, { - ...getSimpleRule(ruleId), - actions: [defaultRuleAction], - throttle: '1d', - }); - - const { body } = await postBulkAction() - .send({ - ids: [createdRule.id], - action: BulkAction.edit, - [BulkAction.edit]: [ - { - type: BulkActionEditType.add_rule_actions, - value: { - throttle: '1h', - actions: [], - }, - }, - ], - }) - .expect(200); - - // Check that the updated rule is returned with the response - expect(body.attributes.results.updated[0].actions).to.eql([defaultRuleAction]); - - // Check that the updates have been persisted - const { body: readRule } = await fetchRule(ruleId).expect(200); - - expect(readRule.actions).to.eql([defaultRuleAction]); - }); - }); - - describe('throttle', () => { - const casesForEmptyActions = [ - { - payload: { throttle: NOTIFICATION_THROTTLE_NO_ACTIONS }, - }, - { - payload: { throttle: NOTIFICATION_THROTTLE_RULE }, - }, - { - payload: { throttle: '1h' }, - }, - ]; - casesForEmptyActions.forEach(({ payload }) => { - it(`is set correctly, if payload throttle="${payload.throttle}" and actions empty`, async () => { - const ruleId = 'ruleId'; - const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); - - const { body } = await postBulkAction() - .send({ - ids: [createdRule.id], - action: BulkAction.edit, - [BulkAction.edit]: [ - { - type: BulkActionEditType.set_rule_actions, - value: { - throttle: payload.throttle, - actions: [], - }, - }, - ], - }) - .expect(200); - - // Check that the updated rule is returned with the response - expect(body.attributes.results.updated[0].throttle).to.eql( - NOTIFICATION_THROTTLE_NO_ACTIONS - ); - - // Check that the updates have been persisted - const { body: rule } = await fetchRule(ruleId).expect(200); - - expect(rule.throttle).to.eql(NOTIFICATION_THROTTLE_NO_ACTIONS); - }); - }); - - // const casesForNonEmptyActions = [ - // { - // payload: { throttle: NOTIFICATION_THROTTLE_NO_ACTIONS }, - // }, - // { - // payload: { throttle: NOTIFICATION_THROTTLE_RULE }, - // }, - // { - // payload: { throttle: '1h' }, - // }, - // ]; - // casesForNonEmptyActions.forEach(({ payload, expected }) => { - // it.only(`is set correctly, if payload throttle="${payload.throttle}" and actions empty`, async () => { - // const ruleId = 'ruleId'; - // const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); - - // const { body } = await postBulkAction() - // .send({ - // ids: [createdRule.id], - // action: BulkAction.edit, - // [BulkAction.edit]: [ - // { - // type: BulkActionEditType.set_rule_actions, - // value: { - // throttle: payload.throttle, - // actions: [], - // }, - // }, - // ], - // }) - // .expect(200); - - // // Check that the updated rule is returned with the response - // expect(body.attributes.results.updated[0].throttle).to.eql(expected.throttle); - - // // Check that the updates have been persisted - // const { body: rule } = await fetchRule(ruleId).expect(200); - - // console.log('>>>>>', JSON.stringify(rule, null, 2)); - // expect(rule.throttle).to.eql(expected.throttle); - // }); - // }); - }); - - describe('notifyWhen', () => { - const cases = [ - { - payload: { throttle: NOTIFICATION_THROTTLE_NO_ACTIONS }, - // keeps existing default value which is onActiveAlert - expected: { notifyWhen: 'onActiveAlert' }, - }, - { - payload: { throttle: '1d' }, - expected: { notifyWhen: 'onThrottleInterval' }, - }, - { - payload: { throttle: NOTIFICATION_THROTTLE_RULE }, - expected: { notifyWhen: 'onActiveAlert' }, - }, - ]; - cases.forEach(({ payload, expected }) => { - it(`is set correctly, if payload throttle="${payload.throttle}"`, async () => { - const createdRule = await createRule(supertest, log, getSimpleRule('ruleId')); - - await postBulkAction() - .send({ - ids: [createdRule.id], - action: BulkAction.edit, - [BulkAction.edit]: [ - { - type: BulkActionEditType.set_rule_actions, - value: { - throttle: payload.throttle, - actions: [], - }, - }, - ], - }) - .expect(200); - - // Check whether notifyWhen set correctly - const { body: rule } = await fetchRuleByAlertApi(createdRule.id).expect(200); - - expect(rule.notify_when).to.eql(expected.notifyWhen); - }); - }); - }); - }); - it('should limit concurrent requests to 5', async () => { const ruleId = 'ruleId'; const timelineId = '91832785-286d-4ebe-b884-1a208d111a70'; From f9e805a54eeaac8a627eab800c081c6d19333e3d Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Thu, 18 Aug 2022 09:24:15 +0100 Subject: [PATCH 13/41] types --- .../detection_engine/schemas/common/schemas.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts index 3d92520190b14..cd1887dd02b54 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts @@ -16,6 +16,13 @@ import { UUID, LimitedSizeArray, } from '@kbn/securitysolution-io-ts-types'; +import { + throttle, + action_group as actionGroup, + action_params as actionParams, + action_id as actionId, +} from '@kbn/securitysolution-io-ts-alerting-types'; + import * as t from 'io-ts'; export const author = t.array(t.string); @@ -426,13 +433,13 @@ const bulkActionEditPayloadRuleActions = t.type({ t.literal(BulkActionEditType.set_rule_actions), ]), value: t.type({ - throttle: t.string, + throttle, actions: t.array( t.exact( t.type({ - group: t.string, - id: t.string, - params: t.UnknownRecord, + group: actionGroup, + id: actionId, + params: actionParams, }) ) ), From f7517a866e75545b6bcf16899e381aa45fb634fe Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Thu, 18 Aug 2022 10:19:41 +0100 Subject: [PATCH 14/41] increase bundle limit --- packages/kbn-optimizer/limits.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 2a116d9ab60ed..ed24e376c999a 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -93,7 +93,7 @@ pageLoadAssetSize: expressionShape: 34008 interactiveSetup: 80000 expressionTagcloud: 27505 - securitySolution: 273763 + securitySolution: 301655 customIntegrations: 28810 expressionMetricVis: 23121 expressionLegacyMetricVis: 23121 From 1cce11fcd7f43e533125743015c76ec9466e032c Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Thu, 18 Aug 2022 10:38:36 +0100 Subject: [PATCH 15/41] remove services.application.capabilities.actions.show; --- .../rules/all/bulk_actions/use_bulk_actions.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx index 58812ff98431c..6bfc119ad1b0c 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx @@ -40,7 +40,6 @@ import { } from '../../../../../containers/detection_engine/rules/use_find_rules_query'; import { BULK_RULE_ACTIONS } from '../../../../../../common/lib/apm/user_actions'; import { useStartTransaction } from '../../../../../../common/lib/apm/use_start_transaction'; -import { useKibana } from '../../../../../../common/lib/kibana'; import { useInvalidatePrePackagedRulesStatus } from '../../../../../containers/detection_engine/rules/use_pre_packaged_rules_status'; import type { DryRunResult, BulkActionForConfirmation } from './types'; @@ -77,9 +76,6 @@ export const useBulkActions = ({ const getIsMounted = useIsMounted(); const filterQuery = convertRulesFilterToKQL(filterOptions); const { startTransaction } = useStartTransaction(); - const { services } = useKibana(); - - const hasUserAccessToActions = services.application.capabilities.actions.show; // refetch tags if edit action is related to tags: add_tags/delete_tags/set_tags const resolveTagsRefetch = useCallback( @@ -368,7 +364,7 @@ export const useBulkActions = ({ key: i18n.BULK_ACTION_ADD_RULE_ACTIONS, name: i18n.BULK_ACTION_ADD_RULE_ACTIONS, 'data-test-subj': 'addRuleActionsBulk', - disabled: !hasUserAccessToActions || isEditDisabled, + disabled: isEditDisabled, onClick: handleBulkEdit(BulkActionEditType.add_rule_actions), toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, toolTipPosition: 'right', @@ -495,7 +491,6 @@ export const useBulkActions = ({ completeBulkEditForm, getIsMounted, resolveTagsRefetch, - hasUserAccessToActions, ] ); From 7f4f9664ffd9d45c9314e3ed7a127dccf487de04 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Thu, 18 Aug 2022 11:16:51 +0100 Subject: [PATCH 16/41] refactoring --- .../rules/step_rule_actions/get_schema.ts | 45 +++++++++++++++++++ .../rules/step_rule_actions/index.tsx | 2 +- .../rules/step_rule_actions/translations.tsx | 12 ----- .../validate_rule_actions_field/index.tsx | 8 ++++ .../translations.ts | 20 +++++++++ .../utils.test.ts | 0 .../validate_rule_actions_field}/utils.ts | 0 .../validate_rule_actions_field.test.tsx} | 6 +-- .../validate_rule_actions_field.ts} | 41 +---------------- .../bulk_actions/forms/rule_actions_form.tsx | 2 +- 10 files changed, 79 insertions(+), 57 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/get_schema.ts create mode 100644 x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/index.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/translations.ts rename x-pack/plugins/security_solution/public/detections/{components/rules/step_rule_actions => containers/detection_engine/rules/validate_rule_actions_field}/utils.test.ts (100%) rename x-pack/plugins/security_solution/public/detections/{components/rules/step_rule_actions => containers/detection_engine/rules/validate_rule_actions_field}/utils.ts (100%) rename x-pack/plugins/security_solution/public/detections/{components/rules/step_rule_actions/schema.test.tsx => containers/detection_engine/rules/validate_rule_actions_field/validate_rule_actions_field.test.tsx} (96%) rename x-pack/plugins/security_solution/public/detections/{components/rules/step_rule_actions/schema.tsx => containers/detection_engine/rules/validate_rule_actions_field/validate_rule_actions_field.ts} (62%) diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/get_schema.ts b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/get_schema.ts new file mode 100644 index 0000000000000..57a7dd50a370e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/get_schema.ts @@ -0,0 +1,45 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +import type { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public'; +import { validateRuleActionsField } from '../../../containers/detection_engine/rules/validate_rule_actions_field'; + +import type { FormSchema } from '../../../../shared_imports'; +import type { ActionsStepRule } from '../../../pages/detection_engine/rules/types'; + +export const getSchema = ({ + actionTypeRegistry, +}: { + actionTypeRegistry: ActionTypeRegistryContract; +}): FormSchema => ({ + actions: { + validations: [ + { + validator: validateRuleActionsField(actionTypeRegistry), + }, + ], + }, + enabled: {}, + kibanaSiemAppUrl: {}, + throttle: { + label: i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepRuleActions.fieldThrottleLabel', + { + defaultMessage: 'Actions frequency', + } + ), + helpText: i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepRuleActions.fieldThrottleHelpText', + { + defaultMessage: + 'Select when automated actions should be performed if a rule evaluates as true.', + } + ), + }, +}); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.tsx index d8264794f1df8..b967304d57349 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.tsx @@ -31,7 +31,7 @@ import { } from '../throttle_select_field'; import { RuleActionsField } from '../rule_actions_field'; import { useKibana } from '../../../../common/lib/kibana'; -import { getSchema } from './schema'; +import { getSchema } from './get_schema'; import * as I18n from './translations'; import { APP_UI_ID } from '../../../../../common/constants'; import { useManageCaseAction } from './use_manage_case_action'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/translations.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/translations.tsx index f0d3d7b7d351e..d467c3af05f8f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/translations.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/translations.tsx @@ -6,7 +6,6 @@ */ import { i18n } from '@kbn/i18n'; -import { startCase } from 'lodash/fp'; export const COMPLETE_WITHOUT_ENABLING = i18n.translate( 'xpack.securitySolution.detectionEngine.createRule.stepScheduleRule.completeWithoutEnablingTitle', @@ -29,14 +28,3 @@ export const NO_ACTIONS_READ_PERMISSIONS = i18n.translate( 'Cannot create rule actions. You do not have "Read" permissions for the "Actions" plugin.', } ); - -export const INVALID_MUSTACHE_TEMPLATE = (paramKey: string) => - i18n.translate( - 'xpack.securitySolution.detectionEngine.createRule.stepRuleActions.invalidMustacheTemplateErrorMessage', - { - defaultMessage: '{key} is not valid mustache template', - values: { - key: startCase(paramKey), - }, - } - ); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/index.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/index.tsx new file mode 100644 index 0000000000000..22d05080a408b --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/index.tsx @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { validateRuleActionsField } from './validate_rule_actions_field'; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/translations.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/translations.ts new file mode 100644 index 0000000000000..6540f7071ccd6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/translations.ts @@ -0,0 +1,20 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { startCase } from 'lodash/fp'; + +export const INVALID_MUSTACHE_TEMPLATE = (paramKey: string) => + i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepRuleActions.invalidMustacheTemplateErrorMessage', + { + defaultMessage: '{key} is not valid mustache template', + values: { + key: startCase(paramKey), + }, + } + ); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/utils.test.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/utils.test.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/utils.test.ts rename to x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/utils.test.ts diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/utils.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/utils.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/utils.ts rename to x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/utils.ts diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/schema.test.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/validate_rule_actions_field.test.tsx similarity index 96% rename from x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/schema.test.tsx rename to x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/validate_rule_actions_field.test.tsx index 58acba634311a..335d6faf631f5 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/schema.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/validate_rule_actions_field.test.tsx @@ -5,13 +5,13 @@ * 2.0. */ -import { validateSingleAction, validateRuleActionsField } from './schema'; +import { validateSingleAction, validateRuleActionsField } from './validate_rule_actions_field'; import { getActionTypeName, validateMustache, validateActionParams } from './utils'; import { actionTypeRegistryMock } from '@kbn/triggers-actions-ui-plugin/public/application/action_type_registry.mock'; -import type { FormHook } from '../../../../shared_imports'; +import type { FormHook } from '../../../../../shared_imports'; jest.mock('./utils'); -describe('stepRuleActions schema', () => { +describe('validate_rule_actions_field', () => { const actionTypeRegistry = actionTypeRegistryMock.create(); describe('validateSingleAction', () => { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/schema.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/validate_rule_actions_field.ts similarity index 62% rename from x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/schema.tsx rename to x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/validate_rule_actions_field.ts index efc34c7b4d13d..18aa758d0a499 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/schema.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/validate_rule_actions_field.ts @@ -7,19 +7,11 @@ /* istanbul ignore file */ -import { i18n } from '@kbn/i18n'; - import type { RuleAction, ActionTypeRegistryContract, } from '@kbn/triggers-actions-ui-plugin/public'; -import type { - FormSchema, - ValidationFunc, - ERROR_CODE, - ValidationError, -} from '../../../../shared_imports'; -import type { ActionsStepRule } from '../../../pages/detection_engine/rules/types'; +import type { ValidationFunc, ERROR_CODE, ValidationError } from '../../../../../shared_imports'; import { getActionTypeName, validateMustache, validateActionParams } from './utils'; export const validateSingleAction = async ( @@ -59,34 +51,3 @@ export const validateRuleActionsField = }; } }; - -export const getSchema = ({ - actionTypeRegistry, -}: { - actionTypeRegistry: ActionTypeRegistryContract; -}): FormSchema => ({ - actions: { - validations: [ - { - validator: validateRuleActionsField(actionTypeRegistry), - }, - ], - }, - enabled: {}, - kibanaSiemAppUrl: {}, - throttle: { - label: i18n.translate( - 'xpack.securitySolution.detectionEngine.createRule.stepRuleActions.fieldThrottleLabel', - { - defaultMessage: 'Actions frequency', - } - ), - helpText: i18n.translate( - 'xpack.securitySolution.detectionEngine.createRule.stepRuleActions.fieldThrottleHelpText', - { - defaultMessage: - 'Select when automated actions should be performed if a rule evaluates as true.', - } - ), - }, -}); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index 84ae12f08bd1f..0fc9a905414d6 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -36,7 +36,7 @@ import { import { allActionMessageParams } from '../../../helpers'; import { RuleActionsField } from '../../../../../../components/rules/rule_actions_field'; -import { validateRuleActionsField } from '../../../../../../components/rules/step_rule_actions/schema'; +import { validateRuleActionsField } from '../../../../../../containers/detection_engine/rules/validate_rule_actions_field'; const CommonUseField = getUseField({ component: Field }); From 075369a18890b523cb0ce4d46d3fddae856752e1 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Thu, 18 Aug 2022 12:44:39 +0100 Subject: [PATCH 17/41] fixes --- .../rules/all/bulk_actions/forms/rule_actions_form.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index 0fc9a905414d6..62aa3d22ad6e2 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -100,15 +100,16 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction return; } - const editAction = data.overwrite + const { actions = [], throttle: throttleToSubmit, overwrite: overwriteValue } = data; + const editAction = overwriteValue ? BulkActionEditType.set_rule_actions : BulkActionEditType.add_rule_actions; onConfirm({ type: editAction, value: { - actions: data.actions.map(({ actionTypeId, ...action }) => action), - throttle: data.throttle, + actions: actions.map(({ actionTypeId, ...action }) => action), + throttle: throttleToSubmit, }, }); }, [form, onConfirm]); @@ -116,7 +117,6 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction const throttleFieldComponentProps = useMemo( () => ({ idAria: 'bulkEditRulesRuleActionThrottle', - isLoading: true, dataTestSubj: 'bulkEditRulesRuleActionThrottle', hasNoInitialSelection: false, euiFieldProps: { @@ -126,7 +126,7 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction [] ); - const showActionsSelect = throttle !== defaultFormData.throttle; + const showActionsSelect = throttle !== NOTIFICATION_THROTTLE_NO_ACTIONS; return ( Date: Thu, 18 Aug 2022 18:35:33 +0100 Subject: [PATCH 18/41] refactor --- .../detection_engine/rules/bulk_edit_rules.ts | 55 +++++++++++++------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts index f435e59f60fb3..e3b935e4b4208 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts @@ -6,19 +6,21 @@ */ import pMap from 'p-map'; -import type { RulesClient } from '@kbn/alerting-plugin/server'; +import type { RulesClient, BulkEditError } from '@kbn/alerting-plugin/server'; import type { BulkActionEditPayload, bulkActionEditPayloadRuleActions, } from '../../../../common/detection_engine/schemas/common'; import { enrichFilterWithRuleTypeMapping } from './enrich_filter_with_rule_type_mappings'; import type { MlAuthz } from '../../machine_learning/authz'; - import { ruleParamsModifier } from './bulk_actions/rule_params_modifier'; import { splitBulkEditActions } from './bulk_actions/split_bulk_edit_actions'; import { validateBulkEditRule } from './bulk_actions/validations'; import { bulkEditActionToRulesClientOperation } from './bulk_actions/action_to_rules_client_operation'; -import { NOTIFICATION_THROTTLE_NO_ACTIONS } from '../../../../common/constants'; +import { + NOTIFICATION_THROTTLE_NO_ACTIONS, + MAX_RULES_TO_UPDATE_IN_PARALLEL, +} from '../../../../common/constants'; import { BulkActionEditType } from '../../../../common/detection_engine/schemas/common/schemas'; import { readRules } from './read_rules'; @@ -63,7 +65,8 @@ export const bulkEditRules = async ({ }); // rulesClient bulkEdit currently doesn't support bulk mute/unmute. - // this is a workaround to mitigate this + // this is a workaround to mitigate this, + // until https://github.com/elastic/kibana/pull/138900 is resolved // if rule actions has been applied: // - we go through each rule // - mute/unmute if needed, refetch rule @@ -73,27 +76,45 @@ export const bulkEditRules = async ({ const rulesAction = attributesActions.find(({ type }) => [BulkActionEditType.set_rule_actions, BulkActionEditType.add_rule_actions].includes(type) ) as bulkActionEditPayloadRuleActions; + if (rulesAction) { + const errors: BulkEditError[] = []; const rules = await pMap( result.rules, async (rule) => { - if (rule.muteAll && rulesAction.value.throttle !== NOTIFICATION_THROTTLE_NO_ACTIONS) { - await rulesClient.unmuteAll({ id: rule.id }); - return (await readRules({ rulesClient, id: rule.id, ruleId: undefined })) ?? rule; - } else if ( - !rule.muteAll && - rulesAction.value.throttle === NOTIFICATION_THROTTLE_NO_ACTIONS - ) { - await rulesClient.muteAll({ id: rule.id }); - return (await readRules({ rulesClient, id: rule.id, ruleId: undefined })) ?? rule; - } + try { + if (rule.muteAll && rulesAction.value.throttle !== NOTIFICATION_THROTTLE_NO_ACTIONS) { + await rulesClient.unmuteAll({ id: rule.id }); + return (await readRules({ rulesClient, id: rule.id, ruleId: undefined })) ?? rule; + } else if ( + !rule.muteAll && + rulesAction.value.throttle === NOTIFICATION_THROTTLE_NO_ACTIONS + ) { + await rulesClient.muteAll({ id: rule.id }); + return (await readRules({ rulesClient, id: rule.id, ruleId: undefined })) ?? rule; + } - return rule; + return rule; + } catch (err) { + errors.push({ + message: err.message, + rule: { + id: rule.id, + name: rule.name, + }, + }); + + return null; + } }, - { concurrency: 50 } + { concurrency: MAX_RULES_TO_UPDATE_IN_PARALLEL } ); - return { ...result, rules }; + return { + ...result, + rules: rules.filter((rule): rule is RuleAlertType => rule != null), + errors: [...result.errors, ...errors], + }; } return result; From d6ccf0b16bfd2bfe7da3dbfaa67e3cf4014236d0 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Mon, 22 Aug 2022 12:15:20 +0100 Subject: [PATCH 19/41] wording --- .../bulk_actions/forms/rule_actions_form.tsx | 56 +++++++++++++++---- .../rules/all/bulk_actions/translations.tsx | 17 +----- .../detection_engine/rules/bulk_edit_rules.ts | 9 +-- 3 files changed, 51 insertions(+), 31 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index 62aa3d22ad6e2..390e4995b47f9 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -6,6 +6,7 @@ */ import React, { useCallback, useMemo } from 'react'; import { EuiCallOut, EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; import type { RuleAction, @@ -136,17 +137,37 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction onSubmit={handleSubmit} flyoutSize="l" > - {overwrite && ( - <> - - {i18n.warningCalloutMessage(rulesCount)} - - - - )} - - - {i18n.infoCalloutMessage(rulesCount)} + + } + > +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
@@ -177,6 +198,19 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction 'data-test-subj': 'bulkEditRulesOverwriteRuleActions', }} /> + + {overwrite && ( + <> + + + + + + )}
); }; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx index 27cb27a15f4e2..7bd8127f674c6 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx @@ -77,6 +77,7 @@ export const bulkAddRuleActions = { defaultMessage: 'Actions frequency', } ), + THROTTLE_HELP_TEXT: i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.edit.addRuleActions.throttleHelpText', { @@ -84,20 +85,4 @@ export const bulkAddRuleActions = { 'Select when automated actions should be performed if a rule evaluates as true.', } ), - - warningCalloutMessage: (rulesCount: number): JSX.Element => ( - - ), - - infoCalloutMessage: (rulesCount: number): JSX.Element => ( - - ), }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts index e3b935e4b4208..c6bb6c95d64cb 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts @@ -72,10 +72,11 @@ export const bulkEditRules = async ({ // - mute/unmute if needed, refetch rule // calling mute for rule needed only when rule was unmuted before and throttle value is NOTIFICATION_THROTTLE_NO_ACTIONS // calling unmute needed only if rule was muted and throttle value is not NOTIFICATION_THROTTLE_NO_ACTIONS - // TODO: error handlers (?) - const rulesAction = attributesActions.find(({ type }) => - [BulkActionEditType.set_rule_actions, BulkActionEditType.add_rule_actions].includes(type) - ) as bulkActionEditPayloadRuleActions; + const rulesAction = attributesActions + .reverse() + .find(({ type }) => + [BulkActionEditType.set_rule_actions, BulkActionEditType.add_rule_actions].includes(type) + ) as bulkActionEditPayloadRuleActions; if (rulesAction) { const errors: BulkEditError[] = []; From 070319e86de34050d09771e7703d397a65c0856b Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Mon, 22 Aug 2022 15:49:36 +0100 Subject: [PATCH 20/41] update tests --- .../group1/perform_bulk_action.ts | 81 +++++++++++-------- 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts index 9d4e8dd94fec7..0f053d232baca 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts @@ -669,36 +669,6 @@ export default ({ getService }: FtrProviderContext): void => { expect(rule.timeline_title).to.be(undefined); }); - it('should return error when trying to bulk edit prebuilt rule', async () => { - await installPrePackagedRules(supertest, log); - const prebuiltRule = await fetchPrebuiltRule(); - - const { body } = await postBulkAction() - .send({ - ids: [prebuiltRule.id], - action: BulkAction.edit, - [BulkAction.edit]: [ - { - type: BulkActionEditType.add_tags, - value: ['new-tag'], - }, - ], - }) - .expect(500); - - expect(body.attributes.summary).to.eql({ failed: 1, succeeded: 0, total: 1 }); - expect(body.attributes.errors[0]).to.eql({ - message: "Elastic rule can't be edited", - status_code: 500, - rules: [ - { - id: prebuiltRule.id, - name: prebuiltRule.name, - }, - ], - }); - }); - it('should return error if index patterns action is applied to machine learning rule', async () => { const mlRule = await createRule(supertest, log, getSimpleMlRule()); @@ -907,7 +877,7 @@ export default ({ getService }: FtrProviderContext): void => { ]); }); - it('should set actions to empty if list of action is empty in payload', async () => { + it('should set actions to empty list, actions payload is empty list', async () => { // create a new action const hookAction = await createWebHookAction(); @@ -1111,6 +1081,51 @@ export default ({ getService }: FtrProviderContext): void => { expect(readRule.actions).to.eql([defaultRuleAction]); }); + + it('should change throttle if actions list in payload is empty', async () => { + // create a new action + const hookAction = await createWebHookAction(); + + const defaultRuleAction = { + id: hookAction.id, + action_type_id: '.webhook', + group: 'default', + params: { + body: '{"test":"a default action"}', + }, + }; + + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, { + ...getSimpleRule(ruleId), + actions: [defaultRuleAction], + throttle: '8h', + }); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.add_rule_actions, + value: { + throttle: '1h', + actions: [], + }, + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].throttle).to.be('1h'); + + // Check that the updates have been persisted + const { body: readRule } = await fetchRule(ruleId).expect(200); + + expect(readRule.throttle).to.eql('1h'); + }) }); describe('prebuilt rules', () => { @@ -1185,9 +1200,9 @@ export default ({ getService }: FtrProviderContext): void => { }, ]; casesForEmptyActions.forEach(({ payloadThrottle }) => { - it(`throttle is set correctly, if payload throttle="${payloadThrottle}" and actions empty`, async () => { + it(`throttle is set to NOTIFICATION_THROTTLE_NO_ACTIONS, if payload throttle="${payloadThrottle}" and actions list is empty`, async () => { const ruleId = 'ruleId'; - const createdRule = await createRule(supertest, log, getSimpleRule(ruleId)); + const createdRule = await createRule(supertest, log, { ...getSimpleRule(ruleId), throttle: '8h' }); const { body } = await postBulkAction() .send({ From f11fa66598025d0c51ff9dffffc9a2c9c96ecdd5 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 22 Aug 2022 14:56:14 +0000 Subject: [PATCH 21/41] [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' --- .../group1/perform_bulk_action.ts | 87 ++++++++++--------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts index 0f053d232baca..1d4a2060f3fad 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts @@ -1083,49 +1083,49 @@ export default ({ getService }: FtrProviderContext): void => { }); it('should change throttle if actions list in payload is empty', async () => { - // create a new action - const hookAction = await createWebHookAction(); + // create a new action + const hookAction = await createWebHookAction(); - const defaultRuleAction = { - id: hookAction.id, - action_type_id: '.webhook', - group: 'default', - params: { - body: '{"test":"a default action"}', - }, - }; - - const ruleId = 'ruleId'; - const createdRule = await createRule(supertest, log, { - ...getSimpleRule(ruleId), - actions: [defaultRuleAction], - throttle: '8h', - }); - - const { body } = await postBulkAction() - .send({ - ids: [createdRule.id], - action: BulkAction.edit, - [BulkAction.edit]: [ - { - type: BulkActionEditType.add_rule_actions, - value: { - throttle: '1h', - actions: [], - }, + const defaultRuleAction = { + id: hookAction.id, + action_type_id: '.webhook', + group: 'default', + params: { + body: '{"test":"a default action"}', + }, + }; + + const ruleId = 'ruleId'; + const createdRule = await createRule(supertest, log, { + ...getSimpleRule(ruleId), + actions: [defaultRuleAction], + throttle: '8h', + }); + + const { body } = await postBulkAction() + .send({ + ids: [createdRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.add_rule_actions, + value: { + throttle: '1h', + actions: [], }, - ], - }) - .expect(200); - - // Check that the updated rule is returned with the response - expect(body.attributes.results.updated[0].throttle).to.be('1h'); - - // Check that the updates have been persisted - const { body: readRule } = await fetchRule(ruleId).expect(200); - - expect(readRule.throttle).to.eql('1h'); - }) + }, + ], + }) + .expect(200); + + // Check that the updated rule is returned with the response + expect(body.attributes.results.updated[0].throttle).to.be('1h'); + + // Check that the updates have been persisted + const { body: readRule } = await fetchRule(ruleId).expect(200); + + expect(readRule.throttle).to.eql('1h'); + }); }); describe('prebuilt rules', () => { @@ -1202,7 +1202,10 @@ export default ({ getService }: FtrProviderContext): void => { casesForEmptyActions.forEach(({ payloadThrottle }) => { it(`throttle is set to NOTIFICATION_THROTTLE_NO_ACTIONS, if payload throttle="${payloadThrottle}" and actions list is empty`, async () => { const ruleId = 'ruleId'; - const createdRule = await createRule(supertest, log, { ...getSimpleRule(ruleId), throttle: '8h' }); + const createdRule = await createRule(supertest, log, { + ...getSimpleRule(ruleId), + throttle: '8h', + }); const { body } = await postBulkAction() .send({ From 3b37cb9e9de6f0dc594e13cca98b3dcfcd9b4c7e Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Thu, 25 Aug 2022 17:21:30 +0100 Subject: [PATCH 22/41] update message --- .../rules/all/bulk_actions/forms/rule_actions_form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index 390e4995b47f9..28e3234471426 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -164,7 +164,7 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction
  • From 4eb402a926c5fe1352b62ec8f465afaab88359c9 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Thu, 25 Aug 2022 18:15:04 +0100 Subject: [PATCH 23/41] fix i18n --- .../rules/all/bulk_actions/forms/rule_actions_form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index 28e3234471426..5e7bb8b63db47 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -164,7 +164,7 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction
  • From 0470b0cef30485e06647374a8426d3a363ababc4 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Thu, 25 Aug 2022 18:31:22 +0100 Subject: [PATCH 24/41] updates --- .../rules/all/bulk_actions/forms/rule_actions_form.tsx | 7 +------ .../rules/all/bulk_actions/translations.tsx | 8 ++++++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index 5e7bb8b63db47..d487628818248 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -161,12 +161,7 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction defaultMessage='If you’d like to delete actions for all selected rules, select "Perform no actions" in the dropdown and check Overwrite all selected rule actions.' /> -
  • - -
  • +
  • {i18n.RULE_VARIABLES_DETAIL}
  • diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx index 7bd8127f674c6..612364a963116 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx @@ -85,4 +85,12 @@ export const bulkAddRuleActions = { 'Select when automated actions should be performed if a rule evaluates as true.', } ), + + RULE_VARIABLES_DETAIL: i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.edit.addRuleActions.ruleVariablesDetail', + { + defaultMessage: + 'Rule variables may only affect some of the rules that you selected based on the rule types(for example \\u007b\\u007bcontext.rule.threshold\\u007d\\u007d will only work for threshold rule type).', + } + ), }; From 2cbc92662e7a9164c384f6ca0251b6f462d5b8d6 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Fri, 26 Aug 2022 16:21:55 +0100 Subject: [PATCH 25/41] attempt to reduce bundle size --- packages/kbn-optimizer/limits.yml | 2 +- .../schemas/common/schemas.ts | 88 ----------------- .../request/perform_bulk_action_schema.ts | 99 ++++++++++++++++++- .../detection_engine/rules/types.ts | 7 +- .../detection_engine/rules/all/actions.ts | 2 +- .../all/bulk_actions/bulk_edit_flyout.tsx | 2 +- .../forms/index_patterns_form.tsx | 2 +- .../bulk_actions/forms/rule_actions_form.tsx | 2 +- .../all/bulk_actions/forms/tags_form.tsx | 2 +- .../forms/timeline_template_form.tsx | 2 +- .../all/bulk_actions/use_bulk_actions.tsx | 2 +- .../bulk_actions/use_bulk_edit_form_flyout.ts | 6 +- .../utils/compute_dry_run_payload.ts | 2 +- .../action_to_rules_client_operation.ts | 2 +- .../bulk_actions/rule_params_modifier.ts | 2 +- .../split_bulk_edit_actions.test.ts | 2 +- .../bulk_actions/split_bulk_edit_actions.ts | 2 +- .../rules/bulk_actions/validations.ts | 2 +- .../detection_engine/rules/bulk_edit_rules.ts | 6 +- 19 files changed, 119 insertions(+), 115 deletions(-) diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 5758bbe93a1da..d41a5356af082 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -93,7 +93,7 @@ pageLoadAssetSize: expressionShape: 34008 interactiveSetup: 80000 expressionTagcloud: 27505 - securitySolution: 301655 + securitySolution: 273763 customIntegrations: 28810 expressionMetricVis: 23121 expressionLegacyMetricVis: 23121 diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts index cd1887dd02b54..0f1c18954bc4a 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts @@ -16,13 +16,6 @@ import { UUID, LimitedSizeArray, } from '@kbn/securitysolution-io-ts-types'; -import { - throttle, - action_group as actionGroup, - action_params as actionParams, - action_id as actionId, -} from '@kbn/securitysolution-io-ts-alerting-types'; - import * as t from 'io-ts'; export const author = t.array(t.string); @@ -389,84 +382,3 @@ export enum BulkActionEditType { 'add_rule_actions' = 'add_rule_actions', 'set_rule_actions' = 'set_rule_actions', } - -const bulkActionEditPayloadTags = t.type({ - type: t.union([ - t.literal(BulkActionEditType.add_tags), - t.literal(BulkActionEditType.delete_tags), - t.literal(BulkActionEditType.set_tags), - ]), - value: tags, -}); - -export type BulkActionEditPayloadTags = t.TypeOf; - -const bulkActionEditPayloadIndexPatterns = t.intersection([ - t.type({ - type: t.union([ - t.literal(BulkActionEditType.add_index_patterns), - t.literal(BulkActionEditType.delete_index_patterns), - t.literal(BulkActionEditType.set_index_patterns), - ]), - value: index, - }), - t.exact(t.partial({ overwrite_data_views: t.boolean })), -]); - -export type BulkActionEditPayloadIndexPatterns = t.TypeOf< - typeof bulkActionEditPayloadIndexPatterns ->; - -const bulkActionEditPayloadTimeline = t.type({ - type: t.literal(BulkActionEditType.set_timeline), - value: t.type({ - timeline_id, - timeline_title, - }), -}); - -export type BulkActionEditPayloadTimeline = t.TypeOf; - -const bulkActionEditPayloadRuleActions = t.type({ - type: t.union([ - t.literal(BulkActionEditType.add_rule_actions), - t.literal(BulkActionEditType.set_rule_actions), - ]), - value: t.type({ - throttle, - actions: t.array( - t.exact( - t.type({ - group: actionGroup, - id: actionId, - params: actionParams, - }) - ) - ), - }), -}); - -export type bulkActionEditPayloadRuleActions = t.TypeOf; - -export const bulkActionEditPayload = t.union([ - bulkActionEditPayloadTags, - bulkActionEditPayloadIndexPatterns, - bulkActionEditPayloadTimeline, - bulkActionEditPayloadRuleActions, -]); - -export type BulkActionEditPayload = t.TypeOf; - -/** - * actions that modifies rules attributes - */ -export type BulkActionEditForRuleAttributes = - | BulkActionEditPayloadTags - | bulkActionEditPayloadRuleActions; - -/** - * actions that modifies rules params - */ -export type BulkActionEditForRuleParams = - | BulkActionEditPayloadIndexPatterns - | BulkActionEditPayloadTimeline; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts index fa33e75e236fd..cf2e9774b89ba 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts @@ -7,7 +7,104 @@ import * as t from 'io-ts'; import { NonEmptyArray } from '@kbn/securitysolution-io-ts-types'; -import { BulkAction, queryOrUndefined, bulkActionEditPayload } from '../common/schemas'; + +import { + throttle, + action_group as actionGroup, + action_params as actionParams, + action_id as actionId, +} from '@kbn/securitysolution-io-ts-alerting-types'; + +import { + BulkAction, + queryOrUndefined, + BulkActionEditType, + tags, + index, + timeline_id, + timeline_title, +} from '../common/schemas'; + +const bulkActionEditPayloadTags = t.type({ + type: t.union([ + t.literal(BulkActionEditType.add_tags), + t.literal(BulkActionEditType.delete_tags), + t.literal(BulkActionEditType.set_tags), + ]), + value: tags, +}); + +export type BulkActionEditPayloadTags = t.TypeOf; + +const bulkActionEditPayloadIndexPatterns = t.intersection([ + t.type({ + type: t.union([ + t.literal(BulkActionEditType.add_index_patterns), + t.literal(BulkActionEditType.delete_index_patterns), + t.literal(BulkActionEditType.set_index_patterns), + ]), + value: index, + }), + t.exact(t.partial({ overwrite_data_views: t.boolean })), +]); + +export type BulkActionEditPayloadIndexPatterns = t.TypeOf< + typeof bulkActionEditPayloadIndexPatterns +>; + +const bulkActionEditPayloadTimeline = t.type({ + type: t.literal(BulkActionEditType.set_timeline), + value: t.type({ + timeline_id, + timeline_title, + }), +}); + +export type BulkActionEditPayloadTimeline = t.TypeOf; + +const bulkActionEditPayloadRuleActions = t.type({ + type: t.union([ + t.literal(BulkActionEditType.add_rule_actions), + t.literal(BulkActionEditType.set_rule_actions), + ]), + value: t.type({ + throttle, + actions: t.array( + t.exact( + t.type({ + group: actionGroup, + id: actionId, + params: actionParams, + }) + ) + ), + }), +}); + +export type BulkActionEditPayloadRuleActions = t.TypeOf; + +export const bulkActionEditPayload = t.union([ + bulkActionEditPayloadTags, + bulkActionEditPayloadIndexPatterns, + bulkActionEditPayloadTimeline, + bulkActionEditPayloadRuleActions, +]); + +export type BulkActionEditPayload = t.TypeOf; + +/** + * actions that modifies rules attributes + */ +export type BulkActionEditForRuleAttributes = + | BulkActionEditPayloadTags + | BulkActionEditPayloadRuleActions; + +/** + * actions that modifies rules params + */ +export type BulkActionEditForRuleParams = + | BulkActionEditPayloadIndexPatterns + | BulkActionEditPayloadTimeline; export const performBulkActionSchema = t.intersection([ t.exact( diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts index eaf9b3288dc2d..5b3633addcf70 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts @@ -25,11 +25,8 @@ import { import { RuleExecutionSummary } from '../../../../../common/detection_engine/rule_monitoring'; -import type { - SortOrder, - BulkAction, - BulkActionEditPayload, -} from '../../../../../common/detection_engine/schemas/common'; +import type { SortOrder, BulkAction } from '../../../../../common/detection_engine/schemas/common'; +import type { BulkActionEditPayload } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { alias_purpose as savedObjectResolveAliasPurpose, outcome as savedObjectResolveOutcome, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/actions.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/actions.ts index 28d3f4856579f..df688c8059647 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/actions.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/actions.ts @@ -7,7 +7,7 @@ import type { NavigateToAppOptions } from '@kbn/core/public'; import { APP_UI_ID } from '../../../../../../common/constants'; -import type { BulkActionEditPayload } from '../../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditPayload } from '../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkAction } from '../../../../../../common/detection_engine/schemas/common/schemas'; import type { HTTPError } from '../../../../../../common/detection_engine/types'; import { SecurityPageName } from '../../../../../app/types'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx index 0d6ff3c5a8655..d52d7df480b07 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkActionEditType } from '../../../../../../../common/detection_engine/schemas/common/schemas'; import { IndexPatternsForm } from './forms/index_patterns_form'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/index_patterns_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/index_patterns_form.tsx index 2ce632be3ef3c..922443da00c0f 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/index_patterns_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/index_patterns_form.tsx @@ -14,7 +14,7 @@ import * as i18n from '../../../translations'; import { DEFAULT_INDEX_KEY } from '../../../../../../../../common/constants'; import { useKibana } from '../../../../../../../common/lib/kibana'; -import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; import type { FormSchema } from '../../../../../../../shared_imports'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index d487628818248..7642d09c67677 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -21,7 +21,7 @@ import { getUseField, Field, } from '../../../../../../../shared_imports'; -import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; import { NOTIFICATION_THROTTLE_NO_ACTIONS } from '../../../../../../../../common/constants'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/tags_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/tags_form.tsx index 366115623d041..10287a3287e54 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/tags_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/tags_form.tsx @@ -11,7 +11,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import * as i18n from '../../../translations'; import { caseInsensitiveSort } from '../../helpers'; -import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; import type { FormSchema } from '../../../../../../../shared_imports'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/timeline_template_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/timeline_template_form.tsx index 3c5852926a5d7..b6295522ab727 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/timeline_template_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/timeline_template_form.tsx @@ -11,7 +11,7 @@ import { EuiCallOut } from '@elastic/eui'; import type { FormSchema } from '../../../../../../../shared_imports'; import { useForm, UseField } from '../../../../../../../shared_imports'; import { PickTimeline } from '../../../../../../components/rules/pick_timeline'; -import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; import { BulkEditFormWrapper } from './bulk_edit_form_wrapper'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx index 6bfc119ad1b0c..fa51d3cd9d852 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx @@ -14,7 +14,7 @@ import { useIsMounted } from '@kbn/securitysolution-hook-utils'; import type { Toast } from '@kbn/core/public'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; -import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkAction, BulkActionEditType, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_edit_form_flyout.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_edit_form_flyout.ts index babdd1bfa536e..8942f785b1855 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_edit_form_flyout.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_edit_form_flyout.ts @@ -7,10 +7,8 @@ import { useState, useCallback, useRef } from 'react'; import { useAsyncConfirmation } from '../rules_table/use_async_confirmation'; -import type { - BulkActionEditType, - BulkActionEditPayload, -} from '../../../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditType } from '../../../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { useBoolState } from '../../../../../../common/hooks/use_bool_state'; export const useBulkEditFormFlyout = () => { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts index 86b429ca4b552..16453a5b6fd60 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkAction, BulkActionEditType, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts index 74cce4f995a74..22dd18c4cf758 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts @@ -7,7 +7,7 @@ import type { BulkEditOperation } from '@kbn/alerting-plugin/server'; -import type { BulkActionEditForRuleAttributes } from '../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditForRuleAttributes } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; import { assertUnreachable } from '../../../../../common/utility_types'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts index 2b3fb5de9ef79..49ebcde27528d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts @@ -7,7 +7,7 @@ import type { RuleAlertType } from '../types'; -import type { BulkActionEditForRuleParams } from '../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditForRuleParams } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; import { invariant } from '../../../../../common/utils/invariant'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.test.ts index 0b7f540b4dcc3..e67f9a02e391c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { BulkActionEditPayload } from '../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditPayload } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; import { splitBulkEditActions } from './split_bulk_edit_actions'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts index ee42304aec0eb..dbbdf2ca8caaa 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts @@ -9,7 +9,7 @@ import type { BulkActionEditPayload, BulkActionEditForRuleAttributes, BulkActionEditForRuleParams, -} from '../../../../../common/detection_engine/schemas/common/schemas'; +} from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; /** diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts index 5c2b5c0fb478a..2865c8053bc05 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts @@ -9,7 +9,7 @@ import type { Type as RuleType } from '@kbn/securitysolution-io-ts-alerting-type import { invariant } from '../../../../../common/utils/invariant'; import { isMlRule } from '../../../../../common/machine_learning/helpers'; import { BulkActionsDryRunErrCode } from '../../../../../common/constants'; -import type { BulkActionEditPayload } from '../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkActionEditPayload } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; import type { RuleAlertType } from '../types'; import { isIndexPatternsBulkEditAction } from './utils'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts index c6bb6c95d64cb..5cffd8c9a24ec 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts @@ -9,8 +9,8 @@ import pMap from 'p-map'; import type { RulesClient, BulkEditError } from '@kbn/alerting-plugin/server'; import type { BulkActionEditPayload, - bulkActionEditPayloadRuleActions, -} from '../../../../common/detection_engine/schemas/common'; + BulkActionEditPayloadRuleActions, +} from '../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { enrichFilterWithRuleTypeMapping } from './enrich_filter_with_rule_type_mappings'; import type { MlAuthz } from '../../machine_learning/authz'; import { ruleParamsModifier } from './bulk_actions/rule_params_modifier'; @@ -76,7 +76,7 @@ export const bulkEditRules = async ({ .reverse() .find(({ type }) => [BulkActionEditType.set_rule_actions, BulkActionEditType.add_rule_actions].includes(type) - ) as bulkActionEditPayloadRuleActions; + ) as BulkActionEditPayloadRuleActions; if (rulesAction) { const errors: BulkEditError[] = []; From 34510ca14a2c5d70dab60e162da116278db0828b Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Fri, 26 Aug 2022 18:50:24 +0100 Subject: [PATCH 26/41] fix versino increment issue for prebuilt rules --- .../bulk_actions/rule_params_modifier.test.ts | 18 +++++- .../bulk_actions/rule_params_modifier.ts | 5 +- .../group1/perform_bulk_action.ts | 58 ++++++++++++++++++- 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.test.ts index c3b4fe0f20134..047b7241ca09d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.test.ts @@ -38,9 +38,13 @@ describe('deleteItemsFromArray', () => { }); describe('ruleParamsModifier', () => { - const ruleParamsMock = { index: ['initial-index-*'], version: 1 } as RuleAlertType['params']; + const ruleParamsMock = { + index: ['initial-index-*'], + version: 1, + immutable: false, + } as RuleAlertType['params']; - test('should increment version', () => { + test('should increment version if rule is custom (immutable === false)', () => { const editedRuleParams = ruleParamsModifier(ruleParamsMock, [ { type: BulkActionEditType.add_index_patterns, @@ -50,6 +54,16 @@ describe('ruleParamsModifier', () => { expect(editedRuleParams).toHaveProperty('version', ruleParamsMock.version + 1); }); + test('should not increment version if rule is prebuilt (immutable === true)', () => { + const editedRuleParams = ruleParamsModifier({ ...ruleParamsMock, immutable: true }, [ + { + type: BulkActionEditType.add_index_patterns, + value: ['my-index-*'], + }, + ]); + expect(editedRuleParams).toHaveProperty('version', ruleParamsMock.version); + }); + describe('index_patterns', () => { test('should add new index pattern to rule', () => { const editedRuleParams = ruleParamsModifier(ruleParamsMock, [ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts index 49ebcde27528d..47636198c361c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts @@ -111,7 +111,10 @@ export const ruleParamsModifier = ( ); // increment version even if actions are empty, as attributes can be modified as well outside of ruleParamsModifier - modifiedParams.version += 1; + // version must not be modified for immutable rule. Otherwise prebuilt rules upgrade flow will be broken + if (existingRuleParams.immutable === false) { + modifiedParams.version += 1; + } return modifiedParams; }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts index 1d4a2060f3fad..5d01b473d569e 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts @@ -1164,14 +1164,17 @@ export default ({ getService }: FtrProviderContext): void => { }) .expect(200); + const editedRule = body.attributes.results.updated[0]; // Check that the updated rule is returned with the response - expect(body.attributes.results.updated[0].actions).to.eql([ + expect(editedRule.actions).to.eql([ { ...webHookActionMock, id: hookAction.id, action_type_id: '.webhook', }, ]); + // version of prebuilt rule should not change + expect(editedRule.version).to.be(prebuiltRule.version); // Check that the updates have been persisted const { body: readRule } = await fetchRule(prebuiltRule.rule_id).expect(200); @@ -1183,8 +1186,61 @@ export default ({ getService }: FtrProviderContext): void => { action_type_id: '.webhook', }, ]); + expect(prebuiltRule.version).to.be(readRule.version); }); }); + + // if rule action is applied together with another edit action, that can't be applied to prebuilt rule (for example: tags action) + // bulk edit request should return error + it(`should return error if one of edit action is not eligible for prebuilt rule`, async () => { + await installPrePackagedRules(supertest, log); + const prebuiltRule = await fetchPrebuiltRule(); + const hookAction = await createWebHookAction(); + + const { body } = await postBulkAction() + .send({ + ids: [prebuiltRule.id], + action: BulkAction.edit, + [BulkAction.edit]: [ + { + type: BulkActionEditType.set_rule_actions, + value: { + throttle: '1h', + actions: [ + { + ...webHookActionMock, + id: hookAction.id, + }, + ], + }, + }, + { + type: BulkActionEditType.set_tags, + value: ['tag-1'], + }, + ], + }) + .expect(500); + + expect(body.attributes.summary).to.eql({ failed: 1, succeeded: 0, total: 1 }); + expect(body.attributes.errors[0]).to.eql({ + message: "Elastic rule can't be edited", + status_code: 500, + rules: [ + { + id: prebuiltRule.id, + name: prebuiltRule.name, + }, + ], + }); + + // Check that the updates were not made + const { body: readRule } = await fetchRule(prebuiltRule.rule_id).expect(200); + + expect(readRule.actions).to.eql(prebuiltRule.actions); + expect(readRule.tags).to.eql(prebuiltRule.tags); + expect(readRule.version).to.be(prebuiltRule.version); + }); }); describe('throttle', () => { From 0cd3934dc6c5e81df4f553d0a9d6c5fe9cc5e6e4 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Wed, 31 Aug 2022 10:20:42 +0100 Subject: [PATCH 27/41] fix issue with duplicated rule variables --- .../bulk_actions/forms/rule_actions_form.tsx | 6 +++-- .../pages/detection_engine/rules/helpers.tsx | 23 +++++++++++++------ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index 7642d09c67677..a82fdfd998a81 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -34,7 +34,7 @@ import { ThrottleSelectField, THROTTLE_OPTIONS, } from '../../../../../../components/rules/throttle_select_field'; -import { allActionMessageParams } from '../../../helpers'; +import { getAllActionMessageParams } from '../../../helpers'; import { RuleActionsField } from '../../../../../../components/rules/rule_actions_field'; import { validateRuleActionsField } from '../../../../../../containers/detection_engine/rules/validate_rule_actions_field'; @@ -127,6 +127,8 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction [] ); + const messageVariables = useMemo(() => getAllActionMessageParams(), []); + const showActionsSelect = throttle !== NOTIFICATION_THROTTLE_NO_ACTIONS; return ( @@ -179,7 +181,7 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction path="actions" component={RuleActionsField} componentProps={{ - messageVariables: allActionMessageParams, + messageVariables, }} /> diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx index 648d257ae3eb9..278ed497d12e8 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx @@ -381,12 +381,17 @@ const commonRuleParamsKeys = [ const queryRuleParams = ['index', 'filters', 'language', 'query', 'saved_id']; const machineLearningRuleParams = ['anomaly_threshold', 'machine_learning_job_id']; const thresholdRuleParams = ['threshold', ...queryRuleParams]; -const allRuleParamsKeys = [ - ...commonRuleParamsKeys, - ...queryRuleParams, - ...machineLearningRuleParams, - ...thresholdRuleParams, -].sort(); + +const getAllRuleParamsKeys = (): string[] => { + const allRuleParamsKeys = [ + ...commonRuleParamsKeys, + ...queryRuleParams, + ...machineLearningRuleParams, + ...thresholdRuleParams, + ].sort(); + + return Array.from(new Set(allRuleParamsKeys)); +}; const getRuleSpecificRuleParamKeys = (ruleType: Type) => { switch (ruleType) { @@ -441,7 +446,11 @@ export const getActionMessageParams = memoizeOne((ruleType: Type | undefined): A return transformRuleKeysToActionVariables(actionMessageRuleParams); }); -export const allActionMessageParams = transformRuleKeysToActionVariables(allRuleParamsKeys); +/** + * returns action variables available for all rule types + */ +export const getAllActionMessageParams = () => + transformRuleKeysToActionVariables(getAllRuleParamsKeys()); // typed as null not undefined as the initial state for this value is null. export const userHasPermissions = (canUserCRUD: boolean | null): boolean => From aa36d99b70384e535116e7928b8b9413b84aab61 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Wed, 31 Aug 2022 16:48:13 +0100 Subject: [PATCH 28/41] Update bulk_edit_rules.ts --- .../server/lib/detection_engine/rules/bulk_edit_rules.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts index 5cffd8c9a24ec..b451095d5f2ba 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts @@ -66,7 +66,7 @@ export const bulkEditRules = async ({ // rulesClient bulkEdit currently doesn't support bulk mute/unmute. // this is a workaround to mitigate this, - // until https://github.com/elastic/kibana/pull/138900 is resolved + // until https://github.com/elastic/kibana/issues/139084 is resolved // if rule actions has been applied: // - we go through each rule // - mute/unmute if needed, refetch rule From 905f358786f80674227ccac7c914ee7e46caeab5 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Mon, 5 Sep 2022 13:06:30 +0100 Subject: [PATCH 29/41] move bulk actions enums to request schema --- .../schemas/common/schemas.ts | 24 ------------- .../perform_bulk_action_schema.mock.ts | 2 +- .../perform_bulk_action_schema.test.ts | 7 ++-- .../request/perform_bulk_action_schema.ts | 35 +++++++++++++------ .../rules/rule_actions_overflow/index.tsx | 2 +- .../components/rules/rule_switch/index.tsx | 2 +- .../containers/detection_engine/rules/api.ts | 2 +- .../detection_engine/rules/types.ts | 7 ++-- .../detection_engine/rules/all/actions.ts | 2 +- .../bulk_action_dry_run_confirmation.tsx | 2 +- .../bulk_action_rule_errors_list.test.tsx | 2 +- .../bulk_action_rule_errors_list.tsx | 2 +- .../all/bulk_actions/bulk_edit_flyout.tsx | 2 +- .../forms/index_patterns_form.tsx | 2 +- .../bulk_actions/forms/rule_actions_form.tsx | 2 +- .../all/bulk_actions/forms/tags_form.tsx | 2 +- .../forms/timeline_template_form.tsx | 2 +- .../rules/all/bulk_actions/types.ts | 2 +- .../all/bulk_actions/use_bulk_actions.tsx | 2 +- .../bulk_actions/use_bulk_actions_dry_run.ts | 2 +- .../bulk_actions/use_bulk_edit_form_flyout.ts | 6 ++-- .../utils/compute_dry_run_payload.test.ts | 2 +- .../utils/compute_dry_run_payload.ts | 2 +- .../rules/all/rules_table_actions.tsx | 2 +- .../routes/rules/perform_bulk_action_route.ts | 2 +- .../action_to_rules_client_operation.test.ts | 2 +- .../action_to_rules_client_operation.ts | 2 +- .../bulk_actions/rule_params_modifier.test.ts | 2 +- .../bulk_actions/rule_params_modifier.ts | 2 +- .../split_bulk_edit_actions.test.ts | 2 +- .../bulk_actions/split_bulk_edit_actions.ts | 2 +- .../rules/bulk_actions/utils.ts | 2 +- .../rules/bulk_actions/validations.ts | 2 +- .../detection_engine/rules/bulk_edit_rules.ts | 2 +- 34 files changed, 68 insertions(+), 69 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts index 0f1c18954bc4a..aa07dfcbba8b2 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts @@ -8,7 +8,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { - enumeration, IsoDateString, NonEmptyString, PositiveInteger, @@ -359,26 +358,3 @@ export const privilege = t.type({ }); export type Privilege = t.TypeOf; - -export enum BulkAction { - 'enable' = 'enable', - 'disable' = 'disable', - 'export' = 'export', - 'delete' = 'delete', - 'duplicate' = 'duplicate', - 'edit' = 'edit', -} - -export const bulkAction = enumeration('BulkAction', BulkAction); - -export enum BulkActionEditType { - 'add_tags' = 'add_tags', - 'delete_tags' = 'delete_tags', - 'set_tags' = 'set_tags', - 'add_index_patterns' = 'add_index_patterns', - 'delete_index_patterns' = 'delete_index_patterns', - 'set_index_patterns' = 'set_index_patterns', - 'set_timeline' = 'set_timeline', - 'add_rule_actions' = 'add_rule_actions', - 'set_rule_actions' = 'set_rule_actions', -} diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.mock.ts index b3988568a4765..1768acc8dfbfa 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.mock.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { BulkAction, BulkActionEditType } from '../common/schemas'; +import { BulkAction, BulkActionEditType } from './perform_bulk_action_schema'; import type { PerformBulkActionSchema } from './perform_bulk_action_schema'; export const getPerformBulkActionSchemaMock = (): PerformBulkActionSchema => ({ diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts index f9bb01e4bf5fa..f6de8a29cc90d 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.test.ts @@ -6,10 +6,13 @@ */ import type { PerformBulkActionSchema } from './perform_bulk_action_schema'; -import { performBulkActionSchema } from './perform_bulk_action_schema'; +import { + performBulkActionSchema, + BulkAction, + BulkActionEditType, +} from './perform_bulk_action_schema'; import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; import { left } from 'fp-ts/lib/Either'; -import { BulkAction, BulkActionEditType } from '../common/schemas'; const retrieveValidationMessage = (payload: unknown) => { const decoded = performBulkActionSchema.decode(payload); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts index cf2e9774b89ba..af2f74ac13d4b 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts @@ -6,7 +6,7 @@ */ import * as t from 'io-ts'; -import { NonEmptyArray } from '@kbn/securitysolution-io-ts-types'; +import { NonEmptyArray, enumeration } from '@kbn/securitysolution-io-ts-types'; import { throttle, @@ -15,15 +15,30 @@ import { action_id as actionId, } from '@kbn/securitysolution-io-ts-alerting-types'; -import { - BulkAction, - queryOrUndefined, - BulkActionEditType, - tags, - index, - timeline_id, - timeline_title, -} from '../common/schemas'; +import { queryOrUndefined, tags, index, timeline_id, timeline_title } from '../common/schemas'; + +export enum BulkAction { + 'enable' = 'enable', + 'disable' = 'disable', + 'export' = 'export', + 'delete' = 'delete', + 'duplicate' = 'duplicate', + 'edit' = 'edit', +} + +export const bulkAction = enumeration('BulkAction', BulkAction); + +export enum BulkActionEditType { + 'add_tags' = 'add_tags', + 'delete_tags' = 'delete_tags', + 'set_tags' = 'set_tags', + 'add_index_patterns' = 'add_index_patterns', + 'delete_index_patterns' = 'delete_index_patterns', + 'set_index_patterns' = 'set_index_patterns', + 'set_timeline' = 'set_timeline', + 'add_rule_actions' = 'add_rule_actions', + 'set_rule_actions' = 'set_rule_actions', +} const bulkActionEditPayloadTags = t.type({ type: t.union([ diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx index b8e423827edce..beb8e8365d74e 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx @@ -16,7 +16,7 @@ import { noop } from 'lodash'; import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { APP_UI_ID, SecurityPageName } from '../../../../../common/constants'; -import { BulkAction } from '../../../../../common/detection_engine/schemas/common'; +import { BulkAction } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { getRulesUrl } from '../../../../common/components/link_to/redirect_to_detection_engine'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { useBoolState } from '../../../../common/hooks/use_bool_state'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx index 574f4ec166193..6c924a68da4a1 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx @@ -10,7 +10,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiSwitch } from '@elasti import { noop } from 'lodash'; import React, { useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; -import { BulkAction } from '../../../../../common/detection_engine/schemas/common'; +import { BulkAction } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { SINGLE_RULE_ACTIONS } from '../../../../common/lib/apm/user_actions'; import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts index 0e2f238aa527e..876a3a0a469a8 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts @@ -18,7 +18,7 @@ import { DETECTION_ENGINE_INSTALLED_INTEGRATIONS_URL, DETECTION_ENGINE_RULES_URL_FIND, } from '../../../../../common/constants'; -import type { BulkAction } from '../../../../../common/detection_engine/schemas/common'; +import type { BulkAction } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import type { FullResponseSchema, PreviewResponse, diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts index 5b3633addcf70..45c89c307de4e 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts @@ -25,8 +25,11 @@ import { import { RuleExecutionSummary } from '../../../../../common/detection_engine/rule_monitoring'; -import type { SortOrder, BulkAction } from '../../../../../common/detection_engine/schemas/common'; -import type { BulkActionEditPayload } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import type { SortOrder } from '../../../../../common/detection_engine/schemas/common'; +import type { + BulkActionEditPayload, + BulkAction, +} from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { alias_purpose as savedObjectResolveAliasPurpose, outcome as savedObjectResolveOutcome, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/actions.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/actions.ts index df688c8059647..d80835209010f 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/actions.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/actions.ts @@ -8,7 +8,7 @@ import type { NavigateToAppOptions } from '@kbn/core/public'; import { APP_UI_ID } from '../../../../../../common/constants'; import type { BulkActionEditPayload } from '../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkAction } from '../../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkAction } from '../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import type { HTTPError } from '../../../../../../common/detection_engine/types'; import { SecurityPageName } from '../../../../../app/types'; import { getEditRuleUrl } from '../../../../../common/components/link_to/redirect_to_detection_engine'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_dry_run_confirmation.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_dry_run_confirmation.tsx index 33d325b837d33..9207e0813ab70 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_dry_run_confirmation.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_dry_run_confirmation.tsx @@ -10,7 +10,7 @@ import { EuiConfirmModal } from '@elastic/eui'; import * as i18n from '../../translations'; import { BulkActionRuleErrorsList } from './bulk_action_rule_errors_list'; -import { BulkAction } from '../../../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkAction } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { assertUnreachable } from '../../../../../../../common/utility_types'; import type { BulkActionForConfirmation, DryRunResult } from './types'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.test.tsx index 82b78c319c056..987b244dd9fc6 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.test.tsx @@ -13,7 +13,7 @@ import { render, screen } from '@testing-library/react'; import { BulkActionRuleErrorsList } from './bulk_action_rule_errors_list'; import { BulkActionsDryRunErrCode } from '../../../../../../../common/constants'; import type { DryRunResult } from './types'; -import { BulkAction } from '../../../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkAction } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; const Wrapper: FC = ({ children }) => { return ( diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.tsx index 7f5b3ea3f74ee..8f0275000a4ef 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.tsx @@ -10,7 +10,7 @@ import { EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { BulkActionsDryRunErrCode } from '../../../../../../../common/constants'; -import { BulkAction } from '../../../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkAction } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import type { DryRunResult, BulkActionForConfirmation } from './types'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx index d52d7df480b07..db96a63f6245e 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_edit_flyout.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { IndexPatternsForm } from './forms/index_patterns_form'; import { TagsForm } from './forms/tags_form'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/index_patterns_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/index_patterns_form.tsx index 922443da00c0f..adb19e397027b 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/index_patterns_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/index_patterns_form.tsx @@ -14,8 +14,8 @@ import * as i18n from '../../../translations'; import { DEFAULT_INDEX_KEY } from '../../../../../../../../common/constants'; import { useKibana } from '../../../../../../../common/lib/kibana'; +import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; import type { FormSchema } from '../../../../../../../shared_imports'; import { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index a82fdfd998a81..5a8306dab5002 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -22,7 +22,7 @@ import { Field, } from '../../../../../../../shared_imports'; import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { NOTIFICATION_THROTTLE_NO_ACTIONS } from '../../../../../../../../common/constants'; import { BulkEditFormWrapper } from './bulk_edit_form_wrapper'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/tags_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/tags_form.tsx index 10287a3287e54..e53469e27a09a 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/tags_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/tags_form.tsx @@ -12,7 +12,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import * as i18n from '../../../translations'; import { caseInsensitiveSort } from '../../helpers'; import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import type { FormSchema } from '../../../../../../../shared_imports'; import { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/timeline_template_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/timeline_template_form.tsx index b6295522ab727..6aa5a3100c100 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/timeline_template_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/timeline_template_form.tsx @@ -12,7 +12,7 @@ import type { FormSchema } from '../../../../../../../shared_imports'; import { useForm, UseField } from '../../../../../../../shared_imports'; import { PickTimeline } from '../../../../../../components/rules/pick_timeline'; import type { BulkActionEditPayload } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { BulkEditFormWrapper } from './bulk_edit_form_wrapper'; import { bulkApplyTimelineTemplate as i18n } from '../translations'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/types.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/types.ts index 9041e83167469..d81c7c995a2fe 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/types.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/types.ts @@ -6,7 +6,7 @@ */ import type { BulkActionsDryRunErrCode } from '../../../../../../../common/constants'; -import type { BulkAction } from '../../../../../../../common/detection_engine/schemas/common/schemas'; +import type { BulkAction } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; /** * Only 2 bulk actions are supported for for confirmation dry run modal: diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx index fa51d3cd9d852..84da6c6cc6882 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx @@ -18,7 +18,7 @@ import type { BulkActionEditPayload } from '../../../../../../../common/detectio import { BulkAction, BulkActionEditType, -} from '../../../../../../../common/detection_engine/schemas/common/schemas'; +} from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { isMlRule } from '../../../../../../../common/machine_learning/helpers'; import { canEditRuleWithActions } from '../../../../../../common/utils/privileges'; import { useRulesTableContext } from '../rules_table/rules_table_context'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions_dry_run.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions_dry_run.ts index 28c4e4be608dc..5e14c0a57bf51 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions_dry_run.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions_dry_run.ts @@ -11,7 +11,7 @@ import { useMutation } from '@tanstack/react-query'; import type { BulkAction, BulkActionEditType, -} from '../../../../../../../common/detection_engine/schemas/common/schemas'; +} from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import type { BulkActionResponse } from '../../../../../containers/detection_engine/rules'; import { performBulkAction } from '../../../../../containers/detection_engine/rules'; import { computeDryRunPayload } from './utils/compute_dry_run_payload'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_edit_form_flyout.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_edit_form_flyout.ts index 8942f785b1855..6d629ae1869b4 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_edit_form_flyout.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_edit_form_flyout.ts @@ -7,8 +7,10 @@ import { useState, useCallback, useRef } from 'react'; import { useAsyncConfirmation } from '../rules_table/use_async_confirmation'; -import type { BulkActionEditType } from '../../../../../../../common/detection_engine/schemas/common/schemas'; -import type { BulkActionEditPayload } from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; +import type { + BulkActionEditPayload, + BulkActionEditType, +} from '../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { useBoolState } from '../../../../../../common/hooks/use_bool_state'; export const useBulkEditFormFlyout = () => { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.test.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.test.ts index cbdb34654a99b..361f7edc4823f 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.test.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.test.ts @@ -8,7 +8,7 @@ import { BulkAction, BulkActionEditType, -} from '../../../../../../../../common/detection_engine/schemas/common/schemas'; +} from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { computeDryRunPayload } from './compute_dry_run_payload'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts index 16453a5b6fd60..c6128100985b0 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/utils/compute_dry_run_payload.ts @@ -9,7 +9,7 @@ import type { BulkActionEditPayload } from '../../../../../../../../common/detec import { BulkAction, BulkActionEditType, -} from '../../../../../../../../common/detection_engine/schemas/common/schemas'; +} from '../../../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { assertUnreachable } from '../../../../../../../../common/utility_types'; /** diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.tsx index 8e32583a54c9b..cfd83c3ab408f 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.tsx @@ -9,7 +9,7 @@ import type { DefaultItemAction } from '@elastic/eui'; import { EuiToolTip } from '@elastic/eui'; import React from 'react'; import type { NavigateToAppOptions } from '@kbn/core/public'; -import { BulkAction } from '../../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkAction } from '../../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import type { UseAppToasts } from '../../../../../common/hooks/use_app_toasts'; import { canEditRuleWithActions } from '../../../../../common/utils/privileges'; import type { Rule } from '../../../../containers/detection_engine/rules'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts index 3c288184e0736..56d93a1ed0336 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts @@ -21,10 +21,10 @@ import { MAX_RULES_TO_UPDATE_IN_PARALLEL, RULES_TABLE_MAX_PAGE_SIZE, } from '../../../../../common/constants'; -import { BulkAction } from '../../../../../common/detection_engine/schemas/common/schemas'; import { performBulkActionSchema, performBulkActionQuerySchema, + BulkAction, } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import type { SetupPlugins } from '../../../../plugin'; import type { SecuritySolutionPluginRouter } from '../../../../types'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.test.ts index 90336cc195edb..54da8ec923245 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { bulkEditActionToRulesClientOperation } from './action_to_rules_client_operation'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts index 22dd18c4cf758..b462206aa8ff6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/action_to_rules_client_operation.ts @@ -8,7 +8,7 @@ import type { BulkEditOperation } from '@kbn/alerting-plugin/server'; import type { BulkActionEditForRuleAttributes } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { assertUnreachable } from '../../../../../common/utility_types'; import { transformToAlertThrottle, transformToNotifyWhen } from '../utils'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.test.ts index bb82a9a0724cf..8ea80e0fad430 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.test.ts @@ -6,7 +6,7 @@ */ import { addItemsToArray, deleteItemsFromArray, ruleParamsModifier } from './rule_params_modifier'; -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import type { RuleAlertType } from '../types'; describe('addItemsToArray', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts index 47636198c361c..14d49b14421b3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/rule_params_modifier.ts @@ -8,7 +8,7 @@ import type { RuleAlertType } from '../types'; import type { BulkActionEditForRuleParams } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { invariant } from '../../../../../common/utils/invariant'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.test.ts index e67f9a02e391c..46205c060be78 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.test.ts @@ -6,7 +6,7 @@ */ import type { BulkActionEditPayload } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { splitBulkEditActions } from './split_bulk_edit_actions'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts index dbbdf2ca8caaa..f9f16a7684294 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/split_bulk_edit_actions.ts @@ -5,12 +5,12 @@ * 2.0. */ +import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import type { BulkActionEditPayload, BulkActionEditForRuleAttributes, BulkActionEditForRuleParams, } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; /** * Split bulk edit actions in 2 chunks: actions applied to params and diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/utils.ts index 65a4af2308e0e..91cfe9544d550 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/utils.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; /** * helper utility that defines whether bulk edit action is related to index patterns, i.e. one of: diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts index 2865c8053bc05..5252fd1982ff3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_actions/validations.ts @@ -10,7 +10,7 @@ import { invariant } from '../../../../../common/utils/invariant'; import { isMlRule } from '../../../../../common/machine_learning/helpers'; import { BulkActionsDryRunErrCode } from '../../../../../common/constants'; import type { BulkActionEditPayload } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; -import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import type { RuleAlertType } from '../types'; import { isIndexPatternsBulkEditAction } from './utils'; import { throwDryRunError } from './dry_run'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts index b451095d5f2ba..339342691e63b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts @@ -21,7 +21,7 @@ import { NOTIFICATION_THROTTLE_NO_ACTIONS, MAX_RULES_TO_UPDATE_IN_PARALLEL, } from '../../../../common/constants'; -import { BulkActionEditType } from '../../../../common/detection_engine/schemas/common/schemas'; +import { BulkActionEditType } from '../../../../common/detection_engine/schemas/request/perform_bulk_action_schema'; import { readRules } from './read_rules'; import type { RuleAlertType } from './types'; From 76aa2d6dfc053ba96f7d34056bc6b49916bd94ad Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Mon, 5 Sep 2022 13:07:30 +0100 Subject: [PATCH 30/41] CR: spelling --- .../schemas/request/perform_bulk_action_schema.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts index af2f74ac13d4b..5334a79699ff2 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts @@ -108,14 +108,14 @@ export const bulkActionEditPayload = t.union([ export type BulkActionEditPayload = t.TypeOf; /** - * actions that modifies rules attributes + * actions that modify rules attributes */ export type BulkActionEditForRuleAttributes = | BulkActionEditPayloadTags | BulkActionEditPayloadRuleActions; /** - * actions that modifies rules params + * actions that modify rules params */ export type BulkActionEditForRuleParams = | BulkActionEditPayloadIndexPatterns From c1bfbac047b2658bb74c62cf77b4decb7e6efc96 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Mon, 5 Sep 2022 13:21:08 +0100 Subject: [PATCH 31/41] CR: typings --- .../request/perform_bulk_action_schema.ts | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts index 5334a79699ff2..58675bf3c0d99 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/perform_bulk_action_schema.ts @@ -77,6 +77,18 @@ const bulkActionEditPayloadTimeline = t.type({ export type BulkActionEditPayloadTimeline = t.TypeOf; +/** + * per rulesClient.bulkEdit rules actions operation contract (x-pack/plugins/alerting/server/rules_client/rules_client.ts) + * normalized rule action object is expected (NormalizedAlertAction) as value for the edit operation + */ +const normalizedRuleAction = t.exact( + t.type({ + group: actionGroup, + id: actionId, + params: actionParams, + }) +); + const bulkActionEditPayloadRuleActions = t.type({ type: t.union([ t.literal(BulkActionEditType.add_rule_actions), @@ -84,15 +96,7 @@ const bulkActionEditPayloadRuleActions = t.type({ ]), value: t.type({ throttle, - actions: t.array( - t.exact( - t.type({ - group: actionGroup, - id: actionId, - params: actionParams, - }) - ) - ), + actions: t.array(normalizedRuleAction), }), }); From 6f82e910daf8d4cc65b8cffa24634d2d3725195f Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Mon, 5 Sep 2022 13:41:58 +0100 Subject: [PATCH 32/41] CR: workaround feedback --- .../detection_engine/rules/bulk_edit_rules.ts | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts index 339342691e63b..b17b35fd010a8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/bulk_edit_rules.ts @@ -72,15 +72,17 @@ export const bulkEditRules = async ({ // - mute/unmute if needed, refetch rule // calling mute for rule needed only when rule was unmuted before and throttle value is NOTIFICATION_THROTTLE_NO_ACTIONS // calling unmute needed only if rule was muted and throttle value is not NOTIFICATION_THROTTLE_NO_ACTIONS - const rulesAction = attributesActions - .reverse() - .find(({ type }) => - [BulkActionEditType.set_rule_actions, BulkActionEditType.add_rule_actions].includes(type) - ) as BulkActionEditPayloadRuleActions; + const ruleActions = attributesActions.filter((rule): rule is BulkActionEditPayloadRuleActions => + [BulkActionEditType.set_rule_actions, BulkActionEditType.add_rule_actions].includes(rule.type) + ); + + // bulk edit actions are applying in a historical order. + // So, we need to find a rule action that will be applied the last, to be able to check if rule should be muted/unmuted + const rulesAction = ruleActions.pop(); if (rulesAction) { - const errors: BulkEditError[] = []; - const rules = await pMap( + const muteOrUnmuteErrors: BulkEditError[] = []; + const rulesToMuteOrUnmute = await pMap( result.rules, async (rule) => { try { @@ -97,7 +99,7 @@ export const bulkEditRules = async ({ return rule; } catch (err) { - errors.push({ + muteOrUnmuteErrors.push({ message: err.message, rule: { id: rule.id, @@ -113,8 +115,8 @@ export const bulkEditRules = async ({ return { ...result, - rules: rules.filter((rule): rule is RuleAlertType => rule != null), - errors: [...result.errors, ...errors], + rules: rulesToMuteOrUnmute.filter((rule): rule is RuleAlertType => rule != null), + errors: [...result.errors, ...muteOrUnmuteErrors], }; } From ea9ca29822ff0d7a3e265be74261e90336e4be88 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Mon, 5 Sep 2022 13:55:23 +0100 Subject: [PATCH 33/41] fix types for tests --- .../security_and_spaces/group1/perform_bulk_action.ts | 2 +- .../security_and_spaces/group1/perform_bulk_action_dry_run.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts index 2ee1d08c1bdd9..4d4bda5e6b4e0 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action.ts @@ -17,7 +17,7 @@ import { import { BulkAction, BulkActionEditType, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/common/schemas'; +} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request/perform_bulk_action_schema'; import { RulesSchema } from '@kbn/security-solution-plugin/common/detection_engine/schemas/response'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action_dry_run.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action_dry_run.ts index 429b34f3f0a54..e9c3b3b68487d 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action_dry_run.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/perform_bulk_action_dry_run.ts @@ -13,7 +13,7 @@ import { import { BulkAction, BulkActionEditType, -} from '@kbn/security-solution-plugin/common/detection_engine/schemas/common/schemas'; +} from '@kbn/security-solution-plugin/common/detection_engine/schemas/request/perform_bulk_action_schema'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createRule, From 5d48c027568b65d7175bad48d1d3474a157a2845 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Tue, 6 Sep 2022 16:15:01 +0100 Subject: [PATCH 34/41] Update x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx Co-authored-by: Joe Peeples --- .../rules/all/bulk_actions/forms/rule_actions_form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index 5a8306dab5002..661da946b80b1 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -145,7 +145,7 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction title={ } From d50a8b3a172df56f01d5051ea6c2c453358a61f3 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Tue, 6 Sep 2022 16:15:22 +0100 Subject: [PATCH 35/41] Update x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx Co-authored-by: Joe Peeples --- .../rules/all/bulk_actions/forms/rule_actions_form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index 661da946b80b1..16ff0ecc87f69 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -154,7 +154,7 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction
  • From f5f216def6b6dc1984068eb3e2be8285a761e9e2 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Tue, 6 Sep 2022 16:15:31 +0100 Subject: [PATCH 36/41] Update x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx Co-authored-by: Joe Peeples --- .../rules/all/bulk_actions/forms/rule_actions_form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index 16ff0ecc87f69..b96f5947d3713 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -160,7 +160,7 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction
  • {i18n.RULE_VARIABLES_DETAIL}
  • From fc5d28805a637ac0009f625c0b000701a9a0170d Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Tue, 6 Sep 2022 16:15:53 +0100 Subject: [PATCH 37/41] Update x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx Co-authored-by: Joe Peeples --- .../rules/all/bulk_actions/forms/rule_actions_form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index b96f5947d3713..0a0fe8ca4e0f2 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -202,7 +202,7 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction From cc32c070d9088c9b528ff89a0832173b03435605 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Tue, 6 Sep 2022 16:16:40 +0100 Subject: [PATCH 38/41] Update x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx Co-authored-by: Joe Peeples --- .../detection_engine/rules/all/bulk_actions/translations.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx index 612364a963116..dff019eaae3db 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx @@ -90,7 +90,7 @@ export const bulkAddRuleActions = { 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.edit.addRuleActions.ruleVariablesDetail', { defaultMessage: - 'Rule variables may only affect some of the rules that you selected based on the rule types(for example \\u007b\\u007bcontext.rule.threshold\\u007d\\u007d will only work for threshold rule type).', + 'Rule variables may affect only some of the rules you select, based on the rule types (for example, \\u007b\\u007bcontext.rule.threshold\\u007d\\u007d will only work for threshold rules).', } ), }; From 291b8bcc55c25828879b614eaed1e0a91a59d29a Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Tue, 6 Sep 2022 16:59:56 +0100 Subject: [PATCH 39/41] woridng --- .../bulk_actions/forms/rule_actions_form.tsx | 58 +++++++++++++------ 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index 0a0fe8ca4e0f2..2e29712bdd3cf 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -150,21 +150,35 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction /> } > -
      -
    • - -
    • -
    • - -
    • -
    • {i18n.RULE_VARIABLES_DETAIL}
    • -
    + + + + + + ), + overwriteActionsCheckbox: ( + + + + ), + }} + /> + + {i18n.RULE_VARIABLES_DETAIL} @@ -202,8 +216,18 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction + + + ), + }} /> From 6f530b26d54b73d98a8f3ab42300fb2695d4399f Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Tue, 6 Sep 2022 17:03:11 +0100 Subject: [PATCH 40/41] text updates --- .../detection_engine/rules/all/bulk_actions/translations.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx index dff019eaae3db..3c7fdd9cb7a8c 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/translations.tsx @@ -90,7 +90,7 @@ export const bulkAddRuleActions = { 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.edit.addRuleActions.ruleVariablesDetail', { defaultMessage: - 'Rule variables may affect only some of the rules you select, based on the rule types (for example, \\u007b\\u007bcontext.rule.threshold\\u007d\\u007d will only work for threshold rules).', + 'Rule variables may affect only some of the rules you select, based on the rule types (for example, \\u007b\\u007bcontext.rule.threshold\\u007d\\u007d will only display values for threshold rules).', } ), }; From 9c6dc77102592d63124917bb2780c6fbfecc18b3 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko Date: Tue, 6 Sep 2022 17:45:32 +0100 Subject: [PATCH 41/41] back to ul --- .../bulk_actions/forms/rule_actions_form.tsx | 62 ++++++++++--------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx index 2e29712bdd3cf..8a9e52c9d5528 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/forms/rule_actions_form.tsx @@ -150,35 +150,39 @@ const RuleActionsFormComponent = ({ rulesCount, onClose, onConfirm }: RuleAction /> } > - - - - - - ), - overwriteActionsCheckbox: ( - - - - ), - }} - /> - - {i18n.RULE_VARIABLES_DETAIL} +
      +
    • + +
    • +
    • + + + + ), + overwriteActionsCheckbox: ( + + + + ), + }} + /> +
    • +
    • {i18n.RULE_VARIABLES_DETAIL}
    • +