From a88290ba2a149eba4f98cb3c7306276f0bb6f20b Mon Sep 17 00:00:00 2001 From: Devin Hurley Date: Thu, 14 Oct 2021 15:59:39 -0400 Subject: [PATCH 1/9] WIP - undo me --- .../schemas/common/schemas.ts | 11 +++- .../legacy_inject_references.ts | 1 + .../notifications/legacy_types.ts | 7 +++ .../routes/rules/update_rules_route.ts | 51 +++++++++++++++++++ .../inject_references.ts | 5 ++ 5 files changed, 74 insertions(+), 1 deletion(-) 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 3933d7e39275e..750646e71aa58 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 @@ -222,7 +222,16 @@ export type QueryFilter = t.TypeOf; export const queryFilterOrUndefined = t.union([queryFilter, t.undefined]); export type QueryFilterOrUndefined = t.TypeOf; -export const references = t.array(t.string); +// export const references = t.array(t.string); +export const references = t.array( + t.exact( + t.type({ + name: t.string, + type: t.string, + id: t.string, + }) + ) +); export type References = t.TypeOf; export const referencesOrUndefined = t.union([references, t.undefined]); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_references.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_references.ts index 5a7118d64ba3a..9601e35bf92ac 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_references.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_references.ts @@ -48,6 +48,7 @@ export const legacyInjectReferences = ({ const ruleParamsWithSavedObjectReferences: LegacyRulesNotificationParams = { ...params, ruleAlertId, + // references: savedObjectReferences, }; return ruleParamsWithSavedObjectReferences; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts index 28fa62f28ed2e..3d765335e4ff3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts @@ -141,6 +141,13 @@ export type LegacyNotificationAlertTypeDefinition = Omit< */ export const legacyRulesNotificationParams = schema.object({ ruleAlertId: schema.string(), + references: schema.arrayOf( + schema.object({ + name: schema.string(), + type: schema.string(), + id: schema.string(), + }) + ), }); /** diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts index 7cfe83093a549..6c44f846ef075 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts @@ -19,6 +19,8 @@ import { getIdError } from './utils'; import { transformValidate } from './validate'; import { updateRules } from '../../rules/update_rules'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +// eslint-disable-next-line no-restricted-imports +import { legacyRuleActionsSavedObjectType } from '../../rule_actions/legacy_saved_object_mappings'; export const updateRulesRoute = ( router: SecuritySolutionPluginRouter, @@ -68,6 +70,55 @@ export const updateRulesRoute = ( spaceId: context.securitySolution.getSpaceId(), }); + /** + * , + { + term: { + 'alert.params.ruleAlertId': rule?.id, + }, + }, + */ + + // const thing = await savedObjectsClient.find({ + // type: 'action', + // }); + + /** + * On update / patch I'm going to take the actions as they are, better off taking rules client.find (siem.notification) result + * and putting that into the actions array of the rule, then set the rules onThrottle property, notifyWhen and throttle from null -> actualy value (1hr etc..) + * Then use the rules client to delete the siem.notification + * Then with the legacy Rule Actions saved object type, just delete it. + */ + + // find it using the references array, not params.ruleAlertId + if (rule != null) { + const siemNotification = await rulesClient.find({ + options: { + hasReference: { + type: 'alert', + id: rule.id, + }, + }, + }); + + const thing2 = await savedObjectsClient.find({ type: legacyRuleActionsSavedObjectType }); + + console.error( + 'DID WE FIND THE SIEM NOTIFICATION FOR THIS ALERT?', + JSON.stringify(siemNotification, null, 2) + ); + + console.error('RULE SIDE CAR', JSON.stringify(thing2, null, 2)); + + if (rule?.actions != null) { + rule.actions = siemNotification.data[0].actions; + rule.throttle = siemNotification.data[0].schedule.interval; + rule.notifyWhen = 'onThrottleInterval'; + } + } + + // use alert.references[] in find filter ^^^ + if (rule != null) { const ruleStatuses = await ruleStatusClient.find({ logsCount: 1, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.ts index dae5e3037b737..bf7a9c2113a01 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.ts @@ -42,9 +42,14 @@ export const injectReferences = ({ exceptionsList: params.exceptionsList, savedObjectReferences, }); + // const actionsReferences = injectActionsReferences({ + // logger, + // savedObjectReferences + // }); const ruleParamsWithSavedObjectReferences: RuleParams = { ...params, exceptionsList, + // references: savedObjectReferences, }; return ruleParamsWithSavedObjectReferences; }; From cea2025ad17e689c290e606288792cc3fe4360ad Mon Sep 17 00:00:00 2001 From: Devin Hurley Date: Thu, 14 Oct 2021 17:02:56 -0400 Subject: [PATCH 2/9] move migration code into update rules so it is called no matter HTTP PUT or PATCH --- .../routes/rules/update_rules_bulk_route.ts | 32 ++++++++++++ .../routes/rules/update_rules_route.ts | 35 +------------ .../lib/detection_engine/rules/types.ts | 9 +++- .../detection_engine/rules/update_rules.ts | 51 +++++++++++++++++-- 4 files changed, 89 insertions(+), 38 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts index 6138690070b62..ff11a41e5d6ed 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts @@ -19,6 +19,8 @@ import { getIdBulkError } from './utils'; import { transformValidateBulkError } from './validate'; import { transformBulkError, buildSiemResponse, createBulkErrorObject } from '../utils'; import { updateRules } from '../../rules/update_rules'; +// eslint-disable-next-line no-restricted-imports +import { legacyRuleActionsSavedObjectType } from '../../rule_actions/legacy_saved_object_mappings'; export const updateRulesBulkRoute = ( router: SecuritySolutionPluginRouter, @@ -77,6 +79,36 @@ export const updateRulesBulkRoute = ( ruleUpdate: payloadRule, isRuleRegistryEnabled, }); + + if (rule != null) { + const siemNotification = await rulesClient.find({ + options: { + hasReference: { + type: 'alert', + id: rule.id, + }, + }, + }); + + await rulesClient.delete({ id: siemNotification.data[0].id }); + + const thing2 = await savedObjectsClient.find({ + type: legacyRuleActionsSavedObjectType, + }); + + console.error( + 'DID WE FIND THE SIEM NOTIFICATION FOR THIS ALERT?', + JSON.stringify(siemNotification, null, 2) + ); + + console.error('RULE SIDE CAR', JSON.stringify(thing2, null, 2)); + + if (rule?.actions != null) { + rule.actions = siemNotification.data[0].actions; + rule.throttle = siemNotification.data[0].schedule.interval; + rule.notifyWhen = 'onThrottleInterval'; + } + } if (rule != null) { const ruleStatuses = await ruleStatusClient.find({ logsCount: 1, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts index 6c44f846ef075..7471010f95057 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts @@ -66,6 +66,7 @@ export const updateRulesRoute = ( isRuleRegistryEnabled, rulesClient, ruleStatusClient, + savedObjectsClient, ruleUpdate: request.body, spaceId: context.securitySolution.getSpaceId(), }); @@ -83,40 +84,6 @@ export const updateRulesRoute = ( // type: 'action', // }); - /** - * On update / patch I'm going to take the actions as they are, better off taking rules client.find (siem.notification) result - * and putting that into the actions array of the rule, then set the rules onThrottle property, notifyWhen and throttle from null -> actualy value (1hr etc..) - * Then use the rules client to delete the siem.notification - * Then with the legacy Rule Actions saved object type, just delete it. - */ - - // find it using the references array, not params.ruleAlertId - if (rule != null) { - const siemNotification = await rulesClient.find({ - options: { - hasReference: { - type: 'alert', - id: rule.id, - }, - }, - }); - - const thing2 = await savedObjectsClient.find({ type: legacyRuleActionsSavedObjectType }); - - console.error( - 'DID WE FIND THE SIEM NOTIFICATION FOR THIS ALERT?', - JSON.stringify(siemNotification, null, 2) - ); - - console.error('RULE SIDE CAR', JSON.stringify(thing2, null, 2)); - - if (rule?.actions != null) { - rule.actions = siemNotification.data[0].actions; - rule.throttle = siemNotification.data[0].schedule.interval; - rule.notifyWhen = 'onThrottleInterval'; - } - } - // use alert.references[] in find filter ^^^ if (rule != null) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts index 8adf19a53f92b..7e8c2f813b284 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts @@ -8,7 +8,13 @@ import { get } from 'lodash/fp'; import { Readable } from 'stream'; -import { SavedObject, SavedObjectAttributes, SavedObjectsFindResult } from 'kibana/server'; +import { + SavedObject, + SavedObjectAttributes, + SavedObjectsClient, + SavedObjectsClientContract, + SavedObjectsFindResult, +} from 'kibana/server'; import type { MachineLearningJobIdOrUndefined, From, @@ -273,6 +279,7 @@ export interface UpdateRulesOptions { rulesClient: RulesClient; defaultOutputIndex: string; ruleUpdate: UpdateRulesSchema; + savedObjectsClient: SavedObjectsClientContract; } export interface PatchRulesOptions { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts index f4060f7f831a9..c308b7a96b904 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts @@ -17,6 +17,8 @@ import { typeSpecificSnakeToCamel } from '../schemas/rule_converters'; import { RuleParams } from '../schemas/rule_schemas'; import { enableRule } from './enable_rule'; import { maybeMute, transformToAlertThrottle, transformToNotifyWhen } from './utils'; +// eslint-disable-next-line no-restricted-imports +import { legacyRuleActionsSavedObjectType } from '../rule_actions/legacy_saved_object_mappings'; export const updateRules = async ({ isRuleRegistryEnabled, @@ -25,6 +27,7 @@ export const updateRules = async ({ ruleStatusClient, defaultOutputIndex, ruleUpdate, + savedObjectsClient, }: UpdateRulesOptions): Promise | null> => { const existingRule = await readRules({ isRuleRegistryEnabled, @@ -36,6 +39,44 @@ export const updateRules = async ({ return null; } + /** + * On update / patch I'm going to take the actions as they are, better off taking rules client.find (siem.notification) result + * and putting that into the actions array of the rule, then set the rules onThrottle property, notifyWhen and throttle from null -> actualy value (1hr etc..) + * Then use the rules client to delete the siem.notification + * Then with the legacy Rule Actions saved object type, just delete it. + */ + + // find it using the references array, not params.ruleAlertId + let migratedRule = false; + if (existingRule != null) { + const siemNotification = await rulesClient.find({ + options: { + hasReference: { + type: 'alert', + id: existingRule.id, + }, + }, + }); + + await rulesClient.delete({ id: siemNotification.data[0].id }); + + const thing2 = await savedObjectsClient.find({ type: legacyRuleActionsSavedObjectType }); + + console.error( + 'DID WE FIND THE SIEM NOTIFICATION FOR THIS ALERT?', + JSON.stringify(siemNotification, null, 2) + ); + + console.error('RULE SIDE CAR', JSON.stringify(thing2, null, 2)); + + if (existingRule?.actions != null) { + existingRule.actions = siemNotification.data[0].actions; + existingRule.throttle = siemNotification.data[0].schedule.interval; + existingRule.notifyWhen = transformToNotifyWhen(siemNotification.data[0].throttle); + migratedRule = true; + } + } + const typeSpecificParams = typeSpecificSnakeToCamel(ruleUpdate); const enabled = ruleUpdate.enabled ?? true; const newInternalRule = { @@ -77,9 +118,13 @@ export const updateRules = async ({ ...typeSpecificParams, }, schedule: { interval: ruleUpdate.interval ?? '5m' }, - actions: ruleUpdate.actions != null ? ruleUpdate.actions.map(transformRuleToAlertAction) : [], - throttle: transformToAlertThrottle(ruleUpdate.throttle), - notifyWhen: transformToNotifyWhen(ruleUpdate.throttle), + actions: migratedRule + ? existingRule.actions + : ruleUpdate.actions != null + ? ruleUpdate.actions.map(transformRuleToAlertAction) + : [], + throttle: migratedRule ? existingRule.throttle : transformToAlertThrottle(ruleUpdate.throttle), + notifyWhen: migratedRule ? existingRule.notifyWhen : transformToNotifyWhen(ruleUpdate.throttle), }; const update = await rulesClient.update({ From 1ffd393b0cf26cd941dcc66f69718b86f0b56127 Mon Sep 17 00:00:00 2001 From: Devin Hurley Date: Fri, 15 Oct 2021 11:02:08 -0400 Subject: [PATCH 3/9] cleanup --- .../schemas/common/schemas.ts | 11 +--------- .../notifications/legacy_types.ts | 7 ------ .../routes/rules/update_rules_bulk_route.ts | 8 +------ .../routes/rules/update_rules_route.ts | 2 -- .../lib/detection_engine/rules/types.ts | 1 - .../rules/update_rules.mock.ts | 3 +++ .../detection_engine/rules/update_rules.ts | 22 +++++++++---------- 7 files changed, 16 insertions(+), 38 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 750646e71aa58..3933d7e39275e 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 @@ -222,16 +222,7 @@ export type QueryFilter = t.TypeOf; export const queryFilterOrUndefined = t.union([queryFilter, t.undefined]); export type QueryFilterOrUndefined = t.TypeOf; -// export const references = t.array(t.string); -export const references = t.array( - t.exact( - t.type({ - name: t.string, - type: t.string, - id: t.string, - }) - ) -); +export const references = t.array(t.string); export type References = t.TypeOf; export const referencesOrUndefined = t.union([references, t.undefined]); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts index 3d765335e4ff3..28fa62f28ed2e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts @@ -141,13 +141,6 @@ export type LegacyNotificationAlertTypeDefinition = Omit< */ export const legacyRulesNotificationParams = schema.object({ ruleAlertId: schema.string(), - references: schema.arrayOf( - schema.object({ - name: schema.string(), - type: schema.string(), - id: schema.string(), - }) - ), }); /** diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts index ff11a41e5d6ed..c17b01aa66c98 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts @@ -75,6 +75,7 @@ export const updateRulesBulkRoute = ( spaceId: context.securitySolution.getSpaceId(), rulesClient, ruleStatusClient, + savedObjectsClient, defaultOutputIndex: siemClient.getSignalsIndex(), ruleUpdate: payloadRule, isRuleRegistryEnabled, @@ -96,13 +97,6 @@ export const updateRulesBulkRoute = ( type: legacyRuleActionsSavedObjectType, }); - console.error( - 'DID WE FIND THE SIEM NOTIFICATION FOR THIS ALERT?', - JSON.stringify(siemNotification, null, 2) - ); - - console.error('RULE SIDE CAR', JSON.stringify(thing2, null, 2)); - if (rule?.actions != null) { rule.actions = siemNotification.data[0].actions; rule.throttle = siemNotification.data[0].schedule.interval; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts index 7471010f95057..eb762a2753f5e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts @@ -19,8 +19,6 @@ import { getIdError } from './utils'; import { transformValidate } from './validate'; import { updateRules } from '../../rules/update_rules'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -// eslint-disable-next-line no-restricted-imports -import { legacyRuleActionsSavedObjectType } from '../../rule_actions/legacy_saved_object_mappings'; export const updateRulesRoute = ( router: SecuritySolutionPluginRouter, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts index 7e8c2f813b284..948a9e656b260 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts @@ -11,7 +11,6 @@ import { Readable } from 'stream'; import { SavedObject, SavedObjectAttributes, - SavedObjectsClient, SavedObjectsClientContract, SavedObjectsFindResult, } from 'kibana/server'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts index 58d6cf1fd5e6b..9a7711fcc8987 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts @@ -6,6 +6,7 @@ */ import { rulesClientMock } from '../../../../../alerting/server/mocks'; +import { savedObjectsClientMock } from '../../../../../../../src/core/server/mocks'; import { getUpdateMachineLearningSchemaMock, getUpdateRulesSchemaMock, @@ -16,6 +17,7 @@ export const getUpdateRulesOptionsMock = (isRuleRegistryEnabled: boolean) => ({ spaceId: 'default', rulesClient: rulesClientMock.create(), ruleStatusClient: ruleExecutionLogClientMock.create(), + savedObjectsClient: savedObjectsClientMock.create(), defaultOutputIndex: '.siem-signals-default', ruleUpdate: getUpdateRulesSchemaMock(), isRuleRegistryEnabled, @@ -25,6 +27,7 @@ export const getUpdateMlRulesOptionsMock = (isRuleRegistryEnabled: boolean) => ( spaceId: 'default', rulesClient: rulesClientMock.create(), ruleStatusClient: ruleExecutionLogClientMock.create(), + savedObjectsClient: savedObjectsClientMock.create(), defaultOutputIndex: '.siem-signals-default', ruleUpdate: getUpdateMachineLearningSchemaMock(), isRuleRegistryEnabled, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts index c308b7a96b904..2a82cfd8ba6a9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts @@ -58,21 +58,21 @@ export const updateRules = async ({ }, }); - await rulesClient.delete({ id: siemNotification.data[0].id }); - - const thing2 = await savedObjectsClient.find({ type: legacyRuleActionsSavedObjectType }); - - console.error( - 'DID WE FIND THE SIEM NOTIFICATION FOR THIS ALERT?', - JSON.stringify(siemNotification, null, 2) - ); - - console.error('RULE SIDE CAR', JSON.stringify(thing2, null, 2)); + const legacyRuleActionsSO = await savedObjectsClient.find({ + type: legacyRuleActionsSavedObjectType, + }); - if (existingRule?.actions != null) { + if (siemNotification != null && siemNotification.data.length > 0) { existingRule.actions = siemNotification.data[0].actions; existingRule.throttle = siemNotification.data[0].schedule.interval; existingRule.notifyWhen = transformToNotifyWhen(siemNotification.data[0].throttle); + await rulesClient.delete({ id: siemNotification.data[0].id }); + if (legacyRuleActionsSO != null && legacyRuleActionsSO.saved_objects.length > 0) { + await savedObjectsClient.delete( + legacyRuleActionsSavedObjectType, + legacyRuleActionsSO.saved_objects[0].id + ); + } migratedRule = true; } } From d77f889d4d012e217287bea430a2fc2c21f6e717 Mon Sep 17 00:00:00 2001 From: Devin Hurley Date: Fri, 15 Oct 2021 11:42:17 -0400 Subject: [PATCH 4/9] remove duplicate code --- .../routes/rules/update_rules_bulk_route.ts | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts index c17b01aa66c98..667309d8455a0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts @@ -81,28 +81,6 @@ export const updateRulesBulkRoute = ( isRuleRegistryEnabled, }); - if (rule != null) { - const siemNotification = await rulesClient.find({ - options: { - hasReference: { - type: 'alert', - id: rule.id, - }, - }, - }); - - await rulesClient.delete({ id: siemNotification.data[0].id }); - - const thing2 = await savedObjectsClient.find({ - type: legacyRuleActionsSavedObjectType, - }); - - if (rule?.actions != null) { - rule.actions = siemNotification.data[0].actions; - rule.throttle = siemNotification.data[0].schedule.interval; - rule.notifyWhen = 'onThrottleInterval'; - } - } if (rule != null) { const ruleStatuses = await ruleStatusClient.find({ logsCount: 1, From d53612143413929d9daf700a333b4e4738f035c7 Mon Sep 17 00:00:00 2001 From: Devin Hurley Date: Fri, 15 Oct 2021 12:08:33 -0400 Subject: [PATCH 5/9] remove unused import --- .../detection_engine/routes/rules/update_rules_bulk_route.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts index 667309d8455a0..42cd8a011f6bd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts @@ -19,8 +19,6 @@ import { getIdBulkError } from './utils'; import { transformValidateBulkError } from './validate'; import { transformBulkError, buildSiemResponse, createBulkErrorObject } from '../utils'; import { updateRules } from '../../rules/update_rules'; -// eslint-disable-next-line no-restricted-imports -import { legacyRuleActionsSavedObjectType } from '../../rule_actions/legacy_saved_object_mappings'; export const updateRulesBulkRoute = ( router: SecuritySolutionPluginRouter, From d3cd83bf302227a075b19e418038b05864fcff09 Mon Sep 17 00:00:00 2001 From: Devin Hurley Date: Mon, 18 Oct 2021 09:04:32 -0400 Subject: [PATCH 6/9] delete commented-out code --- .../legacy_inject_references.ts | 1 - .../routes/rules/update_rules_bulk_route.ts | 1 - .../routes/rules/update_rules_route.ts | 15 --------------- .../saved_object_references/inject_references.ts | 5 ----- 4 files changed, 22 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_references.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_references.ts index 9601e35bf92ac..5a7118d64ba3a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_references.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_saved_object_references/legacy_inject_references.ts @@ -48,7 +48,6 @@ export const legacyInjectReferences = ({ const ruleParamsWithSavedObjectReferences: LegacyRulesNotificationParams = { ...params, ruleAlertId, - // references: savedObjectReferences, }; return ruleParamsWithSavedObjectReferences; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts index 42cd8a011f6bd..6e9f137bf20aa 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts @@ -78,7 +78,6 @@ export const updateRulesBulkRoute = ( ruleUpdate: payloadRule, isRuleRegistryEnabled, }); - if (rule != null) { const ruleStatuses = await ruleStatusClient.find({ logsCount: 1, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts index eb762a2753f5e..7101ffd76f9d6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts @@ -69,21 +69,6 @@ export const updateRulesRoute = ( spaceId: context.securitySolution.getSpaceId(), }); - /** - * , - { - term: { - 'alert.params.ruleAlertId': rule?.id, - }, - }, - */ - - // const thing = await savedObjectsClient.find({ - // type: 'action', - // }); - - // use alert.references[] in find filter ^^^ - if (rule != null) { const ruleStatuses = await ruleStatusClient.find({ logsCount: 1, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.ts index bf7a9c2113a01..dae5e3037b737 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/saved_object_references/inject_references.ts @@ -42,14 +42,9 @@ export const injectReferences = ({ exceptionsList: params.exceptionsList, savedObjectReferences, }); - // const actionsReferences = injectActionsReferences({ - // logger, - // savedObjectReferences - // }); const ruleParamsWithSavedObjectReferences: RuleParams = { ...params, exceptionsList, - // references: savedObjectReferences, }; return ruleParamsWithSavedObjectReferences; }; From 2f74c4e3e5cb4a820268369d2e0a023ff3aa3a99 Mon Sep 17 00:00:00 2001 From: Devin Hurley Date: Mon, 18 Oct 2021 11:44:04 -0400 Subject: [PATCH 7/9] update patchRules function with same logic as updateRules for migrating actions --- .../rules/add_prepackaged_rules_route.ts | 1 + .../routes/rules/import_rules_route.ts | 1 + .../routes/rules/patch_rules_bulk_route.ts | 1 + .../routes/rules/patch_rules_route.ts | 1 + .../rules/patch_rules.mock.ts | 3 ++ .../lib/detection_engine/rules/patch_rules.ts | 53 +++++++++++++++++-- .../lib/detection_engine/rules/types.ts | 1 + .../rules/update_prepacked_rules.test.ts | 4 ++ .../rules/update_prepacked_rules.ts | 5 ++ 9 files changed, 67 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts index fed34743e220a..ddf4e956beac4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts @@ -171,6 +171,7 @@ export const createPrepackagedRules = async ( ); await updatePrepackagedRules( rulesClient, + savedObjectsClient, context.securitySolution.getSpaceId(), ruleStatusClient, rulesToUpdate, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts index 8269fe8b36132..9a0623cb83820 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts @@ -273,6 +273,7 @@ export const importRulesRoute = ( } else if (rule != null && request.query.overwrite) { await patchRules({ rulesClient, + savedObjectsClient, author, buildingBlockType, spaceId: context.securitySolution.getSpaceId(), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts index 67d68221d846f..3fa576d89d16b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts @@ -136,6 +136,7 @@ export const patchRulesBulkRoute = ( const rule = await patchRules({ rule: existingRule, rulesClient, + savedObjectsClient, author, buildingBlockType, description, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts index cf140f22289de..bbec98e935406 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts @@ -136,6 +136,7 @@ export const patchRulesRoute = ( const rule = await patchRules({ rulesClient, + savedObjectsClient, author, buildingBlockType, description, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.mock.ts index 1d09e4ca5c508..3626bcd5f127e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.mock.ts @@ -7,6 +7,7 @@ import { PatchRulesOptions } from './types'; import { rulesClientMock } from '../../../../../alerting/server/mocks'; +import { savedObjectsClientMock } from '../../../../../../../src/core/server/mocks'; import { getAlertMock } from '../routes/__mocks__/request_responses'; import { getMlRuleParams, getQueryRuleParams } from '../schemas/rule_schemas.mock'; import { ruleExecutionLogClientMock } from '../rule_execution_log/__mocks__/rule_execution_log_client'; @@ -15,6 +16,7 @@ export const getPatchRulesOptionsMock = (isRuleRegistryEnabled: boolean): PatchR author: ['Elastic'], buildingBlockType: undefined, rulesClient: rulesClientMock.create(), + savedObjectsClient: savedObjectsClientMock.create(), spaceId: 'default', ruleStatusClient: ruleExecutionLogClientMock.create(), anomalyThreshold: undefined, @@ -68,6 +70,7 @@ export const getPatchMlRulesOptionsMock = (isRuleRegistryEnabled: boolean): Patc author: ['Elastic'], buildingBlockType: undefined, rulesClient: rulesClientMock.create(), + savedObjectsClient: savedObjectsClientMock.create(), spaceId: 'default', ruleStatusClient: ruleExecutionLogClientMock.create(), anomalyThreshold: 55, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts index c3b7e7288dc57..70b35ec019fee 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts @@ -13,6 +13,8 @@ import { normalizeMachineLearningJobIds, normalizeThresholdObject, } from '../../../../common/detection_engine/utils'; +// eslint-disable-next-line no-restricted-imports +import { legacyRuleActionsSavedObjectType } from '../rule_actions/legacy_saved_object_mappings'; import { internalRuleUpdate, RuleParams } from '../schemas/rule_schemas'; import { addTags } from './add_tags'; import { enableRule } from './enable_rule'; @@ -35,8 +37,10 @@ class PatchError extends Error { } } +// eslint-disable-next-line complexity export const patchRules = async ({ rulesClient, + savedObjectsClient, author, buildingBlockType, ruleStatusClient, @@ -92,6 +96,39 @@ export const patchRules = async ({ return null; } + /** + * On update / patch I'm going to take the actions as they are, better off taking rules client.find (siem.notification) result + * and putting that into the actions array of the rule, then set the rules onThrottle property, notifyWhen and throttle from null -> actualy value (1hr etc..) + * Then use the rules client to delete the siem.notification + * Then with the legacy Rule Actions saved object type, just delete it. + */ + + // find it using the references array, not params.ruleAlertId + let migratedRule = false; + const siemNotification = await rulesClient.find({ + options: { + hasReference: { + type: 'alert', + id: rule.id, + }, + }, + }); + + const legacyRuleActionsSO = await savedObjectsClient.find({ + type: legacyRuleActionsSavedObjectType, + }); + + if (siemNotification != null && siemNotification.data.length > 0) { + await rulesClient.delete({ id: siemNotification.data[0].id }); + if (legacyRuleActionsSO != null && legacyRuleActionsSO.saved_objects.length > 0) { + await savedObjectsClient.delete( + legacyRuleActionsSavedObjectType, + legacyRuleActionsSO.saved_objects[0].id + ); + } + migratedRule = true; + } + const calculatedVersion = calculateVersion(rule.params.immutable, rule.params.version, { author, buildingBlockType, @@ -191,14 +228,24 @@ export const patchRules = async ({ const newRule = { tags: addTags(tags ?? rule.tags, rule.params.ruleId, rule.params.immutable), - throttle: throttle !== undefined ? transformToAlertThrottle(throttle) : rule.throttle, - notifyWhen: throttle !== undefined ? transformToNotifyWhen(throttle) : rule.notifyWhen, name: calculateName({ updatedName: name, originalName: rule.name }), schedule: { interval: calculateInterval(interval, rule.schedule.interval), }, - actions: actions?.map(transformRuleToAlertAction) ?? rule.actions, params: removeUndefined(nextParams), + actions: migratedRule + ? siemNotification.data[0].actions + : actions?.map(transformRuleToAlertAction) ?? rule.actions, + throttle: migratedRule + ? siemNotification.data[0].schedule.interval + : throttle !== undefined + ? transformToAlertThrottle(throttle) + : rule.throttle, + notifyWhen: migratedRule + ? transformToNotifyWhen(siemNotification.data[0].throttle) + : throttle !== undefined + ? transformToNotifyWhen(throttle) + : rule.notifyWhen, }; const [validated, errors] = validate(newRule, internalRuleUpdate); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts index 0b43d678633e9..969188f823dc3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts @@ -283,6 +283,7 @@ export interface PatchRulesOptions { spaceId: string; ruleStatusClient: IRuleExecutionLogClient; rulesClient: RulesClient; + savedObjectsClient: SavedObjectsClientContract; anomalyThreshold: AnomalyThresholdOrUndefined; author: AuthorOrUndefined; buildingBlockType: BuildingBlockTypeOrUndefined; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.test.ts index 7c9f0c9ec67a3..9bd0fe3cef59a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.test.ts @@ -6,6 +6,7 @@ */ import { rulesClientMock } from '../../../../../alerting/server/mocks'; +import { savedObjectsClientMock } from '../../../../../../../src/core/server/mocks'; import { getFindResultWithSingleHit } from '../routes/__mocks__/request_responses'; import { updatePrepackagedRules } from './update_prepacked_rules'; import { patchRules } from './patch_rules'; @@ -19,10 +20,12 @@ describe.each([ ])('updatePrepackagedRules - %s', (_, isRuleRegistryEnabled) => { let rulesClient: ReturnType; let ruleStatusClient: ReturnType; + let savedObjectsClient: ReturnType; beforeEach(() => { rulesClient = rulesClientMock.create(); ruleStatusClient = ruleExecutionLogClientMock.create(); + savedObjectsClient = savedObjectsClientMock.create(); }); it('should omit actions and enabled when calling patchRules', async () => { @@ -40,6 +43,7 @@ describe.each([ await updatePrepackagedRules( rulesClient, + savedObjectsClient, 'default', ruleStatusClient, [{ ...prepackagedRule, actions }], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts index d9c2ecd1b5732..00f48b0bd1932 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts @@ -6,6 +6,7 @@ */ import { chunk } from 'lodash/fp'; +import { SavedObjectsClientContract } from 'kibana/server'; import { AddPrepackagedRulesSchemaDecoded } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema'; import { RulesClient, PartialAlert } from '../../../../../alerting/server'; import { patchRules } from './patch_rules'; @@ -51,6 +52,7 @@ export const UPDATE_CHUNK_SIZE = 50; */ export const updatePrepackagedRules = async ( rulesClient: RulesClient, + savedObjectsClient: SavedObjectsClientContract, spaceId: string, ruleStatusClient: IRuleExecutionLogClient, rules: AddPrepackagedRulesSchemaDecoded[], @@ -61,6 +63,7 @@ export const updatePrepackagedRules = async ( for (const ruleChunk of ruleChunks) { const rulePromises = createPromises( rulesClient, + savedObjectsClient, spaceId, ruleStatusClient, ruleChunk, @@ -82,6 +85,7 @@ export const updatePrepackagedRules = async ( */ export const createPromises = ( rulesClient: RulesClient, + savedObjectsClient: SavedObjectsClientContract, spaceId: string, ruleStatusClient: IRuleExecutionLogClient, rules: AddPrepackagedRulesSchemaDecoded[], @@ -150,6 +154,7 @@ export const createPromises = ( // or enable rules on the user when they were not expecting it if a rule updates return patchRules({ rulesClient, + savedObjectsClient, author, buildingBlockType, description, From 6498ff33caae762bae62cf4e55fd95cbe68633fc Mon Sep 17 00:00:00 2001 From: Devin Hurley Date: Mon, 18 Oct 2021 16:33:55 -0400 Subject: [PATCH 8/9] updates with feedback on PR --- .../lib/detection_engine/rules/patch_rules.ts | 61 ++++---------- .../lib/detection_engine/rules/types.ts | 6 ++ .../detection_engine/rules/update_rules.ts | 84 ++++++++----------- .../lib/detection_engine/rules/utils.ts | 56 +++++++++++++ .../legacy_notifications/one_action.json | 2 +- 5 files changed, 111 insertions(+), 98 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts index 70b35ec019fee..6e8285acc334d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts @@ -13,8 +13,6 @@ import { normalizeMachineLearningJobIds, normalizeThresholdObject, } from '../../../../common/detection_engine/utils'; -// eslint-disable-next-line no-restricted-imports -import { legacyRuleActionsSavedObjectType } from '../rule_actions/legacy_saved_object_mappings'; import { internalRuleUpdate, RuleParams } from '../schemas/rule_schemas'; import { addTags } from './add_tags'; import { enableRule } from './enable_rule'; @@ -23,6 +21,7 @@ import { calculateInterval, calculateName, calculateVersion, + legacyMigrate, maybeMute, removeUndefined, transformToAlertThrottle, @@ -37,7 +36,6 @@ class PatchError extends Error { } } -// eslint-disable-next-line complexity export const patchRules = async ({ rulesClient, savedObjectsClient, @@ -96,39 +94,12 @@ export const patchRules = async ({ return null; } - /** - * On update / patch I'm going to take the actions as they are, better off taking rules client.find (siem.notification) result - * and putting that into the actions array of the rule, then set the rules onThrottle property, notifyWhen and throttle from null -> actualy value (1hr etc..) - * Then use the rules client to delete the siem.notification - * Then with the legacy Rule Actions saved object type, just delete it. - */ - - // find it using the references array, not params.ruleAlertId - let migratedRule = false; - const siemNotification = await rulesClient.find({ - options: { - hasReference: { - type: 'alert', - id: rule.id, - }, - }, - }); - - const legacyRuleActionsSO = await savedObjectsClient.find({ - type: legacyRuleActionsSavedObjectType, + const { migratedActions, migratedThrottle, migratedNotifyWhen } = await legacyMigrate({ + rulesClient, + savedObjectsClient, + id: rule.id, }); - if (siemNotification != null && siemNotification.data.length > 0) { - await rulesClient.delete({ id: siemNotification.data[0].id }); - if (legacyRuleActionsSO != null && legacyRuleActionsSO.saved_objects.length > 0) { - await savedObjectsClient.delete( - legacyRuleActionsSavedObjectType, - legacyRuleActionsSO.saved_objects[0].id - ); - } - migratedRule = true; - } - const calculatedVersion = calculateVersion(rule.params.immutable, rule.params.version, { author, buildingBlockType, @@ -233,19 +204,15 @@ export const patchRules = async ({ interval: calculateInterval(interval, rule.schedule.interval), }, params: removeUndefined(nextParams), - actions: migratedRule - ? siemNotification.data[0].actions - : actions?.map(transformRuleToAlertAction) ?? rule.actions, - throttle: migratedRule - ? siemNotification.data[0].schedule.interval - : throttle !== undefined - ? transformToAlertThrottle(throttle) - : rule.throttle, - notifyWhen: migratedRule - ? transformToNotifyWhen(siemNotification.data[0].throttle) - : throttle !== undefined - ? transformToNotifyWhen(throttle) - : rule.notifyWhen, + actions: actions?.map(transformRuleToAlertAction) ?? migratedActions ?? rule.actions, + throttle: + throttle !== undefined + ? transformToAlertThrottle(throttle) + : migratedThrottle ?? rule.throttle, + notifyWhen: + throttle !== undefined + ? transformToNotifyWhen(throttle) + : migratedNotifyWhen ?? rule.notifyWhen, }; const [validated, errors] = validate(newRule, internalRuleUpdate); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts index 969188f823dc3..1b3796e2d7b78 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts @@ -358,3 +358,9 @@ export interface FindRuleOptions { fields: FieldsOrUndefined; sortOrder: SortOrderOrUndefined; } + +export interface LegacyMigrateParams { + rulesClient: RulesClient; + savedObjectsClient: SavedObjectsClientContract; + id: string; +} diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts index 2a82cfd8ba6a9..8a2bbf875ff10 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts @@ -6,7 +6,7 @@ */ /* eslint-disable complexity */ - +import { validate } from '@kbn/securitysolution-io-ts-utils'; import { DEFAULT_MAX_SIGNALS } from '../../../../common/constants'; import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions'; import { PartialAlert } from '../../../../../alerting/server'; @@ -14,11 +14,17 @@ import { readRules } from './read_rules'; import { UpdateRulesOptions } from './types'; import { addTags } from './add_tags'; import { typeSpecificSnakeToCamel } from '../schemas/rule_converters'; -import { RuleParams } from '../schemas/rule_schemas'; +import { internalRuleUpdate, RuleParams } from '../schemas/rule_schemas'; import { enableRule } from './enable_rule'; -import { maybeMute, transformToAlertThrottle, transformToNotifyWhen } from './utils'; -// eslint-disable-next-line no-restricted-imports -import { legacyRuleActionsSavedObjectType } from '../rule_actions/legacy_saved_object_mappings'; +import { legacyMigrate, maybeMute, transformToAlertThrottle, transformToNotifyWhen } from './utils'; + +class UpdateError extends Error { + public readonly statusCode: number; + constructor(message: string, statusCode: number) { + super(message); + this.statusCode = statusCode; + } +} export const updateRules = async ({ isRuleRegistryEnabled, @@ -39,43 +45,11 @@ export const updateRules = async ({ return null; } - /** - * On update / patch I'm going to take the actions as they are, better off taking rules client.find (siem.notification) result - * and putting that into the actions array of the rule, then set the rules onThrottle property, notifyWhen and throttle from null -> actualy value (1hr etc..) - * Then use the rules client to delete the siem.notification - * Then with the legacy Rule Actions saved object type, just delete it. - */ - - // find it using the references array, not params.ruleAlertId - let migratedRule = false; - if (existingRule != null) { - const siemNotification = await rulesClient.find({ - options: { - hasReference: { - type: 'alert', - id: existingRule.id, - }, - }, - }); - - const legacyRuleActionsSO = await savedObjectsClient.find({ - type: legacyRuleActionsSavedObjectType, - }); - - if (siemNotification != null && siemNotification.data.length > 0) { - existingRule.actions = siemNotification.data[0].actions; - existingRule.throttle = siemNotification.data[0].schedule.interval; - existingRule.notifyWhen = transformToNotifyWhen(siemNotification.data[0].throttle); - await rulesClient.delete({ id: siemNotification.data[0].id }); - if (legacyRuleActionsSO != null && legacyRuleActionsSO.saved_objects.length > 0) { - await savedObjectsClient.delete( - legacyRuleActionsSavedObjectType, - legacyRuleActionsSO.saved_objects[0].id - ); - } - migratedRule = true; - } - } + const { migratedActions, migratedThrottle, migratedNotifyWhen } = await legacyMigrate({ + rulesClient, + savedObjectsClient, + id: existingRule.id, + }); const typeSpecificParams = typeSpecificSnakeToCamel(ruleUpdate); const enabled = ruleUpdate.enabled ?? true; @@ -118,18 +92,28 @@ export const updateRules = async ({ ...typeSpecificParams, }, schedule: { interval: ruleUpdate.interval ?? '5m' }, - actions: migratedRule - ? existingRule.actions - : ruleUpdate.actions != null - ? ruleUpdate.actions.map(transformRuleToAlertAction) - : [], - throttle: migratedRule ? existingRule.throttle : transformToAlertThrottle(ruleUpdate.throttle), - notifyWhen: migratedRule ? existingRule.notifyWhen : transformToNotifyWhen(ruleUpdate.throttle), + actions: + ruleUpdate.actions != null + ? ruleUpdate.actions.map(transformRuleToAlertAction) + : migratedActions ?? [], + throttle: + ruleUpdate.throttle !== existingRule.throttle + ? transformToAlertThrottle(ruleUpdate.throttle) + : migratedThrottle ?? transformToAlertThrottle(ruleUpdate.throttle), + notifyWhen: + transformToNotifyWhen(ruleUpdate.throttle) !== transformToNotifyWhen(existingRule.throttle) + ? transformToNotifyWhen(ruleUpdate.throttle) + : migratedNotifyWhen ?? transformToNotifyWhen(ruleUpdate.throttle), }; + const [validated, errors] = validate(newInternalRule, internalRuleUpdate); + if (errors != null || validated === null) { + throw new UpdateError(`Applying update would create invalid rule: ${errors}`, 400); + } + const update = await rulesClient.update({ id: existingRule.id, - data: newInternalRule, + data: validated, }); await maybeMute({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts index 4647a4a9951df..b060da2109ef4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts @@ -19,6 +19,7 @@ import type { ThreatMappingOrUndefined, ThreatQueryOrUndefined, ThreatsOrUndefined, + ThrottleOrUndefinedOrNull, TypeOrUndefined, LanguageOrUndefined, SeverityOrUndefined, @@ -65,6 +66,9 @@ import { RulesClient } from '../../../../../alerting/server'; import { LegacyRuleActions } from '../rule_actions/legacy_types'; import { FullResponseSchema } from '../../../../common/detection_engine/schemas/request'; import { transformAlertToRuleAction } from '../../../../common/detection_engine/transform_actions'; +// eslint-disable-next-line no-restricted-imports +import { legacyRuleActionsSavedObjectType } from '../rule_actions/legacy_saved_object_mappings'; +import { LegacyMigrateParams } from './types'; export const calculateInterval = ( interval: string | undefined, @@ -296,3 +300,55 @@ export const maybeMute = async ({ // Do nothing, no-operation } }; + +/** + * Determines if rule needs to be migrated from legacy actions + * and returns necessary pieces for the updated rule + */ +export const legacyMigrate = async ({ + rulesClient, + savedObjectsClient, + id, +}: LegacyMigrateParams): Promise<{ + migratedActions?: AlertAction[]; + migratedThrottle?: ThrottleOrUndefinedOrNull; + migratedNotifyWhen?: AlertNotifyWhenType | null; +}> => { + /** + * On update / patch I'm going to take the actions as they are, better off taking rules client.find (siem.notification) result + * and putting that into the actions array of the rule, then set the rules onThrottle property, notifyWhen and throttle from null -> actualy value (1hr etc..) + * Then use the rules client to delete the siem.notification + * Then with the legacy Rule Actions saved object type, just delete it. + */ + + // find it using the references array, not params.ruleAlertId + const [siemNotification, legacyRuleActionsSO] = await Promise.all([ + rulesClient.find({ + options: { + hasReference: { + type: 'alert', + id, + }, + }, + }), + savedObjectsClient.find({ + type: legacyRuleActionsSavedObjectType, + }), + ]); + + if (siemNotification != null && siemNotification.data.length > 0) { + await Promise.all([ + rulesClient.delete({ id: siemNotification.data[0].id }), + savedObjectsClient.delete( + legacyRuleActionsSavedObjectType, + legacyRuleActionsSO.saved_objects[0].id + ), + ]); + return { + migratedActions: siemNotification.data[0].actions, + migratedThrottle: siemNotification.data[0].schedule.interval, + migratedNotifyWhen: transformToNotifyWhen(siemNotification.data[0].throttle), + }; + } + return {}; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/legacy_notifications/one_action.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/legacy_notifications/one_action.json index 1966dcf5ff53c..bb77458864ff0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/legacy_notifications/one_action.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/legacy_notifications/one_action.json @@ -3,7 +3,7 @@ "interval": "1m", "actions": [ { - "id": "42534430-2092-11ec-99a6-05d79563c01a", + "id": "b2713700-304a-11ec-86fe-afe030918fa7", "group": "default", "params": { "message": "Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts" From 5059c56c52b95e4ca268e7c6e69c019868710db4 Mon Sep 17 00:00:00 2001 From: Devin Hurley Date: Mon, 18 Oct 2021 22:56:21 -0400 Subject: [PATCH 9/9] execute migration before the patch / update calls --- .../routes/rules/import_rules_route.ts | 8 +++- .../routes/rules/patch_rules_bulk_route.ts | 9 ++++- .../routes/rules/patch_rules_route.ts | 9 ++++- .../rules/update_rules_bulk_route.test.ts | 2 + .../routes/rules/update_rules_bulk_route.ts | 15 +++++++ .../routes/rules/update_rules_route.test.ts | 2 +- .../routes/rules/update_rules_route.ts | 15 +++++++ .../lib/detection_engine/rules/patch_rules.ts | 19 ++------- .../lib/detection_engine/rules/types.ts | 4 +- .../rules/update_prepacked_rules.ts | 9 ++++- .../detection_engine/rules/update_rules.ts | 23 ++--------- .../lib/detection_engine/rules/utils.ts | 40 +++++++++++-------- 12 files changed, 96 insertions(+), 59 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts index 9a0623cb83820..b09ef1a215747 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts @@ -40,6 +40,7 @@ import { } from '../utils'; import { patchRules } from '../../rules/patch_rules'; +import { legacyMigrate } from '../../rules/utils'; import { getTupleDuplicateErrorsAndUniqueRules } from './utils'; import { createRulesStreamFromNdJson } from '../../rules/create_rules_stream_from_ndjson'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; @@ -271,6 +272,11 @@ export const importRulesRoute = ( status_code: 200, }); } else if (rule != null && request.query.overwrite) { + const migratedRule = await legacyMigrate({ + rulesClient, + savedObjectsClient, + rule, + }); await patchRules({ rulesClient, savedObjectsClient, @@ -292,7 +298,7 @@ export const importRulesRoute = ( timelineTitle, meta, filters, - rule, + rule: migratedRule, index, interval, maxSignals, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts index 3fa576d89d16b..2b514ba911091 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts @@ -24,6 +24,7 @@ import { transformValidateBulkError } from './validate'; import { patchRules } from '../../rules/patch_rules'; import { readRules } from '../../rules/read_rules'; import { PartialFilter } from '../../types'; +import { legacyMigrate } from '../../rules/utils'; export const patchRulesBulkRoute = ( router: SecuritySolutionPluginRouter, @@ -133,8 +134,14 @@ export const patchRulesBulkRoute = ( throwHttpError(await mlAuthz.validateRuleType(existingRule?.params.type)); } - const rule = await patchRules({ + const migratedRule = await legacyMigrate({ + rulesClient, + savedObjectsClient, rule: existingRule, + }); + + const rule = await patchRules({ + rule: migratedRule, rulesClient, savedObjectsClient, author, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts index bbec98e935406..0096cd2e38180 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts @@ -24,6 +24,7 @@ import { buildSiemResponse } from '../utils'; import { getIdError } from './utils'; import { transformValidate } from './validate'; import { readRules } from '../../rules/read_rules'; +import { legacyMigrate } from '../../rules/utils'; import { PartialFilter } from '../../types'; export const patchRulesRoute = ( @@ -134,6 +135,12 @@ export const patchRulesRoute = ( throwHttpError(await mlAuthz.validateRuleType(existingRule?.params.type)); } + const migratedRule = await legacyMigrate({ + rulesClient, + savedObjectsClient, + rule: existingRule, + }); + const rule = await patchRules({ rulesClient, savedObjectsClient, @@ -155,7 +162,7 @@ export const patchRulesRoute = ( timelineTitle, meta, filters, - rule: existingRule, + rule: migratedRule, index, interval, maxSignals, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.test.ts index f7bef76944a97..22e8f6543eb7c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.test.ts @@ -41,6 +41,8 @@ describe.each([ getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) ); + clients.appClient.getSignalsIndex.mockReturnValue('.siem-signals-test-index'); + updateRulesBulkRoute(server.router, ml, isRuleRegistryEnabled); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts index 6e9f137bf20aa..d8b7e8cb2b724 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts @@ -19,6 +19,8 @@ import { getIdBulkError } from './utils'; import { transformValidateBulkError } from './validate'; import { transformBulkError, buildSiemResponse, createBulkErrorObject } from '../utils'; import { updateRules } from '../../rules/update_rules'; +import { legacyMigrate } from '../../rules/utils'; +import { readRules } from '../../rules/read_rules'; export const updateRulesBulkRoute = ( router: SecuritySolutionPluginRouter, @@ -69,6 +71,19 @@ export const updateRulesBulkRoute = ( throwHttpError(await mlAuthz.validateRuleType(payloadRule.type)); + const existingRule = await readRules({ + isRuleRegistryEnabled, + rulesClient, + ruleId: payloadRule.rule_id, + id: payloadRule.id, + }); + + await legacyMigrate({ + rulesClient, + savedObjectsClient, + rule: existingRule, + }); + const rule = await updateRules({ spaceId: context.securitySolution.getSpaceId(), rulesClient, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.test.ts index 7d611f3cccbf2..37df792b421b0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.test.ts @@ -44,7 +44,7 @@ describe.each([ getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) ); // successful update clients.ruleExecutionLogClient.find.mockResolvedValue([]); // successful transform: ; - + clients.appClient.getSignalsIndex.mockReturnValue('.siem-signals-test-index'); updateRulesRoute(server.router, ml, isRuleRegistryEnabled); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts index 7101ffd76f9d6..cf443e3293510 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts @@ -19,6 +19,8 @@ import { getIdError } from './utils'; import { transformValidate } from './validate'; import { updateRules } from '../../rules/update_rules'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +import { legacyMigrate } from '../../rules/utils'; +import { readRules } from '../../rules/read_rules'; export const updateRulesRoute = ( router: SecuritySolutionPluginRouter, @@ -59,6 +61,19 @@ export const updateRulesRoute = ( throwHttpError(await mlAuthz.validateRuleType(request.body.type)); const ruleStatusClient = context.securitySolution.getExecutionLogClient(); + + const existingRule = await readRules({ + isRuleRegistryEnabled, + rulesClient, + ruleId: request.body.rule_id, + id: request.body.id, + }); + + await legacyMigrate({ + rulesClient, + savedObjectsClient, + rule: existingRule, + }); const rule = await updateRules({ defaultOutputIndex: siemClient.getSignalsIndex(), isRuleRegistryEnabled, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts index 6e8285acc334d..fd48cd4eebc2c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts @@ -21,7 +21,6 @@ import { calculateInterval, calculateName, calculateVersion, - legacyMigrate, maybeMute, removeUndefined, transformToAlertThrottle, @@ -94,12 +93,6 @@ export const patchRules = async ({ return null; } - const { migratedActions, migratedThrottle, migratedNotifyWhen } = await legacyMigrate({ - rulesClient, - savedObjectsClient, - id: rule.id, - }); - const calculatedVersion = calculateVersion(rule.params.immutable, rule.params.version, { author, buildingBlockType, @@ -204,15 +197,9 @@ export const patchRules = async ({ interval: calculateInterval(interval, rule.schedule.interval), }, params: removeUndefined(nextParams), - actions: actions?.map(transformRuleToAlertAction) ?? migratedActions ?? rule.actions, - throttle: - throttle !== undefined - ? transformToAlertThrottle(throttle) - : migratedThrottle ?? rule.throttle, - notifyWhen: - throttle !== undefined - ? transformToNotifyWhen(throttle) - : migratedNotifyWhen ?? rule.notifyWhen, + actions: actions?.map(transformRuleToAlertAction) ?? rule.actions, + throttle: throttle !== undefined ? transformToAlertThrottle(throttle) : rule.throttle, + notifyWhen: throttle !== undefined ? transformToNotifyWhen(throttle) : rule.notifyWhen, }; const [validated, errors] = validate(newRule, internalRuleUpdate); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts index 1b3796e2d7b78..a4ef081154010 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts @@ -330,7 +330,7 @@ export interface PatchRulesOptions { version: VersionOrUndefined; exceptionsList: ListArrayOrUndefined; actions: RuleAlertAction[] | undefined; - rule: SanitizedAlert | null; + rule: SanitizedAlert | null | undefined; namespace?: NamespaceOrUndefined; } @@ -362,5 +362,5 @@ export interface FindRuleOptions { export interface LegacyMigrateParams { rulesClient: RulesClient; savedObjectsClient: SavedObjectsClientContract; - id: string; + rule: SanitizedAlert | null | undefined; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts index 00f48b0bd1932..dcf43d41e8d78 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts @@ -14,6 +14,7 @@ import { readRules } from './read_rules'; import { PartialFilter } from '../types'; import { RuleParams } from '../schemas/rule_schemas'; import { IRuleExecutionLogClient } from '../rule_execution_log/types'; +import { legacyMigrate } from './utils'; /** * How many rules to update at a time is set to 50 from errors coming from @@ -150,6 +151,12 @@ export const createPromises = ( // TODO: Fix these either with an is conversion or by better typing them within io-ts const filters: PartialFilter[] | undefined = filtersObject as PartialFilter[]; + const migratedRule = await legacyMigrate({ + rulesClient, + savedObjectsClient, + rule: existingRule, + }); + // Note: we do not pass down enabled as we do not want to suddenly disable // or enable rules on the user when they were not expecting it if a rule updates return patchRules({ @@ -165,7 +172,7 @@ export const createPromises = ( language, license, outputIndex, - rule: existingRule, + rule: migratedRule, savedId, spaceId, ruleStatusClient, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts index 8a2bbf875ff10..4268ed9014066 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts @@ -16,7 +16,7 @@ import { addTags } from './add_tags'; import { typeSpecificSnakeToCamel } from '../schemas/rule_converters'; import { internalRuleUpdate, RuleParams } from '../schemas/rule_schemas'; import { enableRule } from './enable_rule'; -import { legacyMigrate, maybeMute, transformToAlertThrottle, transformToNotifyWhen } from './utils'; +import { maybeMute, transformToAlertThrottle, transformToNotifyWhen } from './utils'; class UpdateError extends Error { public readonly statusCode: number; @@ -45,12 +45,6 @@ export const updateRules = async ({ return null; } - const { migratedActions, migratedThrottle, migratedNotifyWhen } = await legacyMigrate({ - rulesClient, - savedObjectsClient, - id: existingRule.id, - }); - const typeSpecificParams = typeSpecificSnakeToCamel(ruleUpdate); const enabled = ruleUpdate.enabled ?? true; const newInternalRule = { @@ -92,18 +86,9 @@ export const updateRules = async ({ ...typeSpecificParams, }, schedule: { interval: ruleUpdate.interval ?? '5m' }, - actions: - ruleUpdate.actions != null - ? ruleUpdate.actions.map(transformRuleToAlertAction) - : migratedActions ?? [], - throttle: - ruleUpdate.throttle !== existingRule.throttle - ? transformToAlertThrottle(ruleUpdate.throttle) - : migratedThrottle ?? transformToAlertThrottle(ruleUpdate.throttle), - notifyWhen: - transformToNotifyWhen(ruleUpdate.throttle) !== transformToNotifyWhen(existingRule.throttle) - ? transformToNotifyWhen(ruleUpdate.throttle) - : migratedNotifyWhen ?? transformToNotifyWhen(ruleUpdate.throttle), + actions: ruleUpdate.actions != null ? ruleUpdate.actions.map(transformRuleToAlertAction) : [], + throttle: transformToAlertThrottle(ruleUpdate.throttle), + notifyWhen: transformToNotifyWhen(ruleUpdate.throttle), }; const [validated, errors] = validate(newInternalRule, internalRuleUpdate); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts index b060da2109ef4..a558024a73e34 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts @@ -19,7 +19,6 @@ import type { ThreatMappingOrUndefined, ThreatQueryOrUndefined, ThreatsOrUndefined, - ThrottleOrUndefinedOrNull, TypeOrUndefined, LanguageOrUndefined, SeverityOrUndefined, @@ -308,12 +307,11 @@ export const maybeMute = async ({ export const legacyMigrate = async ({ rulesClient, savedObjectsClient, - id, -}: LegacyMigrateParams): Promise<{ - migratedActions?: AlertAction[]; - migratedThrottle?: ThrottleOrUndefinedOrNull; - migratedNotifyWhen?: AlertNotifyWhenType | null; -}> => { + rule, +}: LegacyMigrateParams): Promise | null | undefined> => { + if (rule == null || rule.id == null) { + return rule; + } /** * On update / patch I'm going to take the actions as they are, better off taking rules client.find (siem.notification) result * and putting that into the actions array of the rule, then set the rules onThrottle property, notifyWhen and throttle from null -> actualy value (1hr etc..) @@ -327,7 +325,7 @@ export const legacyMigrate = async ({ options: { hasReference: { type: 'alert', - id, + id: rule.id, }, }, }), @@ -339,16 +337,24 @@ export const legacyMigrate = async ({ if (siemNotification != null && siemNotification.data.length > 0) { await Promise.all([ rulesClient.delete({ id: siemNotification.data[0].id }), - savedObjectsClient.delete( - legacyRuleActionsSavedObjectType, - legacyRuleActionsSO.saved_objects[0].id - ), + legacyRuleActionsSO != null && legacyRuleActionsSO.saved_objects.length > 0 + ? savedObjectsClient.delete( + legacyRuleActionsSavedObjectType, + legacyRuleActionsSO.saved_objects[0].id + ) + : null, ]); - return { - migratedActions: siemNotification.data[0].actions, - migratedThrottle: siemNotification.data[0].schedule.interval, - migratedNotifyWhen: transformToNotifyWhen(siemNotification.data[0].throttle), + const migratedRule = { + ...rule, + actions: siemNotification.data[0].actions, + throttle: siemNotification.data[0].schedule.interval, + notifyWhen: transformToNotifyWhen(siemNotification.data[0].throttle), }; + await rulesClient.update({ + id: rule.id, + data: migratedRule, + }); + return migratedRule; } - return {}; + return rule; };