From f8892c7e2464037eda872c1d72f760b135c6ad25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Mon, 9 Mar 2020 13:16:30 +0100 Subject: [PATCH 01/19] WIP --- .../routes/__mocks__/request_responses.ts | 3 ++ .../routes/rules/create_rules_bulk_route.ts | 4 +++ .../routes/rules/create_rules_route.ts | 4 +++ .../routes/rules/import_rules_route.ts | 6 ++++ .../routes/rules/patch_rules_bulk_route.ts | 4 +++ .../routes/rules/patch_rules_route.ts | 4 +++ .../routes/rules/update_rules_bulk_route.ts | 4 +++ .../routes/rules/update_rules_route.ts | 4 +++ .../routes/rules/utils.test.ts | 14 +++++++++ .../detection_engine/routes/rules/utils.ts | 2 ++ .../routes/rules/validate.test.ts | 1 + .../routes/schemas/create_rules_schema.ts | 4 +++ .../routes/schemas/import_rules_schema.ts | 4 +++ .../routes/schemas/patch_rules_schema.ts | 4 +++ .../routes/schemas/response/rules_schema.ts | 4 +++ .../routes/schemas/response/schemas.ts | 2 ++ .../routes/schemas/schemas.ts | 2 ++ .../routes/schemas/update_rules_schema.ts | 4 +++ .../detection_engine/rules/create_rules.ts | 6 ++-- .../create_rules_stream_from_ndjson.test.ts | 20 +++++++++++++ .../rules/get_export_all.test.ts | 2 +- .../rules/get_export_by_object_ids.test.ts | 3 +- .../rules/install_prepacked_rules.ts | 4 +++ .../lib/detection_engine/rules/patch_rules.ts | 8 +++-- .../rules/update_prepacked_rules.ts | 6 ++-- .../detection_engine/rules/update_rules.ts | 11 ++++--- .../signals/__mocks__/es_results.ts | 2 ++ .../signals/build_bulk_body.test.ts | 4 +++ .../signals/build_rule.test.ts | 3 ++ .../detection_engine/signals/build_rule.ts | 2 ++ .../detection_engine/signals/build_signal.ts | 2 +- .../signals/signal_rule_alert_type.ts | 30 +++++++++++++++---- .../siem/server/lib/detection_engine/types.ts | 9 ++++-- 33 files changed, 165 insertions(+), 21 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 3c1a01fd58c60..b3271e025faab 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -50,6 +50,7 @@ export const mockPrepackagedRule = (): PrepackagedRules => ({ technique: [{ id: 'techniqueId', name: 'techniqueName', reference: 'techniqueRef' }], }, ], + throttle: null, enabled: true, filters: [], immutable: false, @@ -348,6 +349,7 @@ export const getResult = (): RuleAlertType => ({ alertTypeId: 'siem.signals', consumer: 'siem', params: { + actions: [], description: 'Detecting root and admin users', ruleId: 'rule-1', index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], @@ -391,6 +393,7 @@ export const getResult = (): RuleAlertType => ({ ], }, ], + throttle: null, references: ['http://www.example.com', 'https://ww.example.com'], version: 1, }, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts index ee8539faacf3e..4f428926fe71d 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts @@ -56,6 +56,7 @@ export const createRulesBulkRoute = (router: IRouter) => { .filter(rule => rule.rule_id == null || !dupes.includes(rule.rule_id)) .map(async payloadRule => { const { + actions, description, enabled, false_positives: falsePositives, @@ -75,6 +76,7 @@ export const createRulesBulkRoute = (router: IRouter) => { severity, tags, threat, + throttle, to, type, references, @@ -106,6 +108,7 @@ export const createRulesBulkRoute = (router: IRouter) => { const createdRule = await createRules({ alertsClient, actionsClient, + actions, description, enabled, falsePositives, @@ -127,6 +130,7 @@ export const createRulesBulkRoute = (router: IRouter) => { name, severity, tags, + throttle, to, type, threat, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts index cef7ded2b50b4..f904f0b37c135 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts @@ -31,6 +31,7 @@ export const createRulesRoute = (router: IRouter): void => { }, async (context, request, response) => { const { + actions, description, enabled, false_positives: falsePositives, @@ -52,6 +53,7 @@ export const createRulesRoute = (router: IRouter): void => { severity, tags, threat, + throttle, to, type, references, @@ -92,6 +94,7 @@ export const createRulesRoute = (router: IRouter): void => { const createdRule = await createRules({ alertsClient, actionsClient, + actions, description, enabled, falsePositives, @@ -113,6 +116,7 @@ export const createRulesRoute = (router: IRouter): void => { name, severity, tags, + throttle, to, type, threat, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts index d9fc9b4e3c04f..ebc8b9978ac5e 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts @@ -111,6 +111,7 @@ export const importRulesRoute = (router: IRouter, config: LegacyServices['config return null; } const { + actions, description, enabled, false_positives: falsePositives, @@ -131,6 +132,7 @@ export const importRulesRoute = (router: IRouter, config: LegacyServices['config severity, tags, threat, + throttle, to, type, references, @@ -158,6 +160,7 @@ export const importRulesRoute = (router: IRouter, config: LegacyServices['config await createRules({ alertsClient, actionsClient, + actions, description, enabled, falsePositives, @@ -182,6 +185,7 @@ export const importRulesRoute = (router: IRouter, config: LegacyServices['config to, type, threat, + throttle, references, version, }); @@ -190,6 +194,7 @@ export const importRulesRoute = (router: IRouter, config: LegacyServices['config await patchRules({ alertsClient, actionsClient, + actions, savedObjectsClient, description, enabled, @@ -216,6 +221,7 @@ export const importRulesRoute = (router: IRouter, config: LegacyServices['config to, type, threat, + throttle, references, version, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts index 7ca16a75fb562..73b7bcacefe65 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts @@ -46,6 +46,7 @@ export const patchRulesBulkRoute = (router: IRouter) => { const rules = await Promise.all( request.body.map(async payloadRule => { const { + actions, description, enabled, false_positives: falsePositives, @@ -70,6 +71,7 @@ export const patchRulesBulkRoute = (router: IRouter) => { to, type, threat, + throttle, references, version, } = payloadRule; @@ -78,6 +80,7 @@ export const patchRulesBulkRoute = (router: IRouter) => { const rule = await patchRules({ alertsClient, actionsClient, + actions, description, enabled, falsePositives, @@ -103,6 +106,7 @@ export const patchRulesBulkRoute = (router: IRouter) => { to, type, threat, + throttle, references, version, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.ts index dce5f4037db1c..3511e1e05d3e8 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.ts @@ -30,6 +30,7 @@ export const patchRulesRoute = (router: IRouter) => { }, async (context, request, response) => { const { + actions, description, enabled, false_positives: falsePositives, @@ -54,6 +55,7 @@ export const patchRulesRoute = (router: IRouter) => { to, type, threat, + throttle, references, version, } = request.body; @@ -75,6 +77,7 @@ export const patchRulesRoute = (router: IRouter) => { const rule = await patchRules({ actionsClient, alertsClient, + actions, description, enabled, falsePositives, @@ -100,6 +103,7 @@ export const patchRulesRoute = (router: IRouter) => { to, type, threat, + throttle, references, version, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts index 953fb16d26ac6..ede220b6a3b3e 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts @@ -47,6 +47,7 @@ export const updateRulesBulkRoute = (router: IRouter) => { const rules = await Promise.all( request.body.map(async payloadRule => { const { + actions, description, enabled, false_positives: falsePositives, @@ -71,6 +72,7 @@ export const updateRulesBulkRoute = (router: IRouter) => { to, type, threat, + throttle, references, version, } = payloadRule; @@ -80,6 +82,7 @@ export const updateRulesBulkRoute = (router: IRouter) => { const rule = await updateRules({ alertsClient, actionsClient, + actions, description, enabled, immutable: false, @@ -106,6 +109,7 @@ export const updateRulesBulkRoute = (router: IRouter) => { to, type, threat, + throttle, references, version, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts index fbb930d780f01..2d50fd450e665 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts @@ -30,6 +30,7 @@ export const updateRulesRoute = (router: IRouter) => { }, async (context, request, response) => { const { + actions, description, enabled, false_positives: falsePositives, @@ -54,6 +55,7 @@ export const updateRulesRoute = (router: IRouter) => { to, type, threat, + throttle, references, version, } = request.body; @@ -76,6 +78,7 @@ export const updateRulesRoute = (router: IRouter) => { const rule = await updateRules({ alertsClient, actionsClient, + actions, description, enabled, falsePositives, @@ -102,6 +105,7 @@ export const updateRulesRoute = (router: IRouter) => { to, type, threat, + throttle, references, version, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts index 25f0151923e2e..91fe70e67f594 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts @@ -37,6 +37,7 @@ describe('utils', () => { const fullRule = getResult(); const rule = transformAlertToRule(fullRule); const expected: OutputRuleAlertRest = { + actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -101,6 +102,7 @@ describe('utils', () => { const fullRule = getResult(); const { from, language, ...omitData } = transformAlertToRule(fullRule); const expected: Partial = { + actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -164,6 +166,7 @@ describe('utils', () => { fullRule.params.query = null; const rule = transformAlertToRule(fullRule); const expected: Partial = { + actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -228,6 +231,7 @@ describe('utils', () => { fullRule.params.query = undefined; const rule = transformAlertToRule(fullRule); const expected: Partial = { + actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -293,6 +297,7 @@ describe('utils', () => { fullRule.params.language = null; const { from, enabled, ...omitData } = transformAlertToRule(fullRule); const expected: Partial = { + actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -354,6 +359,7 @@ describe('utils', () => { fullRule.enabled = false; const ruleWithEnabledFalse = transformAlertToRule(fullRule); const expected: OutputRuleAlertRest = { + actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -419,6 +425,7 @@ describe('utils', () => { fullRule.params.immutable = false; const ruleWithEnabledFalse = transformAlertToRule(fullRule); const expected: OutputRuleAlertRest = { + actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -484,6 +491,7 @@ describe('utils', () => { fullRule.tags = ['tag 1', 'tag 2', `${INTERNAL_IDENTIFIER}_some_other_value`]; const rule = transformAlertToRule(fullRule); const expected: OutputRuleAlertRest = { + actions: [], created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', created_by: 'elastic', @@ -633,6 +641,7 @@ describe('utils', () => { data: [getResult()], }); const expected: OutputRuleAlertRest = { + actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -714,6 +723,7 @@ describe('utils', () => { test('outputs 200 if the data is of type siem alert', () => { const output = transform(getResult()); const expected: OutputRuleAlertRest = { + actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -886,6 +896,7 @@ describe('utils', () => { test('outputs 200 if the data is of type siem alert', () => { const output = transformOrBulkError('rule-1', getResult()); const expected: OutputRuleAlertRest = { + actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -1008,6 +1019,7 @@ describe('utils', () => { const transformed = transformAlertsToRules([result1]); expect(transformed).toEqual([ { + actions: [], created_at: '2019-12-13T16:40:33.400Z', created_by: 'elastic', description: 'Detecting root and admin users', @@ -1067,6 +1079,7 @@ describe('utils', () => { const transformed = transformAlertsToRules([result1, result2]); expect(transformed).toEqual([ { + actions: [], created_at: '2019-12-13T16:40:33.400Z', created_by: 'elastic', description: 'Detecting root and admin users', @@ -1115,6 +1128,7 @@ describe('utils', () => { version: 1, }, { + actions: [], created_at: '2019-12-13T16:40:33.400Z', created_by: 'elastic', description: 'Detecting root and admin users', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts index 064bd8315969e..5b04276317e8b 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts @@ -101,6 +101,7 @@ export const transformAlertToRule = ( ruleStatus?: SavedObject ): Partial => { return pickBy((value: unknown) => value != null, { + actions: alert.actions, created_at: alert.createdAt.toISOString(), updated_at: alert.updatedAt.toISOString(), created_by: alert.createdBy, @@ -131,6 +132,7 @@ export const transformAlertToRule = ( to: alert.params.to, type: alert.params.type, threat: alert.params.threat, + throttle: alert.params.throttle, version: alert.params.version, status: ruleStatus?.attributes.status, status_date: ruleStatus?.attributes.statusDate, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts index 812552aef0ed8..5349173d38646 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts @@ -18,6 +18,7 @@ import { RulesSchema } from '../schemas/response/rules_schema'; import { BulkError } from '../utils'; export const ruleOutput: RulesSchema = { + actions: [], created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', created_by: 'elastic', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts index eb79e06c8efa6..fda79744fcd16 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts @@ -8,6 +8,7 @@ import Joi from 'joi'; /* eslint-disable @typescript-eslint/camelcase */ import { + actions, enabled, description, false_positives, @@ -31,6 +32,7 @@ import { to, type, threat, + throttle, references, version, } from './schemas'; @@ -39,6 +41,7 @@ import { import { DEFAULT_MAX_SIGNALS } from '../../../../../common/constants'; export const createRulesSchema = Joi.object({ + actions: actions.default([]), description: description.required(), enabled: enabled.default(true), false_positives: false_positives.default([]), @@ -66,6 +69,7 @@ export const createRulesSchema = Joi.object({ to: to.default('now'), type: type.required(), threat: threat.default([]), + throttle: throttle.default(null), references: references.default([]), version: version.default(1), }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts index 1254694645b9c..3d6cc2424b6f6 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts @@ -9,6 +9,7 @@ import Joi from 'joi'; /* eslint-disable @typescript-eslint/camelcase */ import { id, + actions, created_at, updated_at, created_by, @@ -37,6 +38,7 @@ import { to, type, threat, + throttle, references, version, } from './schemas'; @@ -55,6 +57,7 @@ import { DEFAULT_MAX_SIGNALS } from '../../../../../common/constants'; */ export const importRulesSchema = Joi.object({ id, + actions: actions.default([]), description: description.required(), enabled: enabled.default(true), false_positives: false_positives.default([]), @@ -83,6 +86,7 @@ export const importRulesSchema = Joi.object({ to: to.default('now'), type: type.required(), threat: threat.default([]), + throttle: throttle.default(null), references: references.default([]), version: version.default(1), created_at, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.ts index d0ed1af01833b..b7518b3057b2e 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.ts @@ -8,6 +8,7 @@ import Joi from 'joi'; /* eslint-disable @typescript-eslint/camelcase */ import { + actions, enabled, description, false_positives, @@ -31,6 +32,7 @@ import { to, type, threat, + throttle, references, id, version, @@ -38,6 +40,7 @@ import { /* eslint-enable @typescript-eslint/camelcase */ export const patchRulesSchema = Joi.object({ + actions, description, enabled, false_positives, @@ -62,6 +65,7 @@ export const patchRulesSchema = Joi.object({ to, type, threat, + throttle, references, version, }).xor('id', 'rule_id'); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_schema.ts index ae2d6269279e1..62cc793ff6467 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_schema.ts @@ -11,6 +11,7 @@ import { Either } from 'fp-ts/lib/Either'; import { checkTypeDependents } from './check_type_dependents'; import { + actions, description, enabled, false_positives, @@ -39,6 +40,7 @@ import { timeline_title, type, threat, + throttle, job_status, status_date, last_success_at, @@ -104,6 +106,8 @@ export const dependentRulesSchema = t.partial({ * Instead use dependentRulesSchema and check_type_dependents for how to do those. */ export const partialRulesSchema = t.partial({ + actions, + throttle, status: job_status, status_date, last_success_at, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts index 14de14a8464fb..d6beb584b97f1 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts @@ -24,6 +24,7 @@ export const file_name = t.string; * become the actual ESFilter as a type. */ export const filters = t.array(t.unknown); // Filters are not easily type-able yet +export const actions = t.array(t.unknown); // TODO: Create a regular expression type or custom date math part type here export const from = t.string; @@ -45,6 +46,7 @@ export const output_index = t.string; export const saved_id = t.string; export const timeline_id = t.string; export const timeline_title = t.string; +export const throttle = t.string; /** * Note that this is a plain unknown object because we allow the UI diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts index 9b311b1b58ea7..7599fb2ca36fa 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts @@ -105,3 +105,5 @@ export const updated_by = Joi.string(); export const version = Joi.number() .integer() .min(1); +export const actions = Joi.array(); +export const throttle = Joi.string().allow(null); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts index 3e5a608d6b657..9d4903fc0e8ab 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts @@ -8,6 +8,7 @@ import Joi from 'joi'; /* eslint-disable @typescript-eslint/camelcase */ import { + actions, enabled, description, false_positives, @@ -31,6 +32,7 @@ import { to, type, threat, + throttle, references, id, version, @@ -47,6 +49,7 @@ import { DEFAULT_MAX_SIGNALS } from '../../../../../common/constants'; * - id is on here because you can pass in an id to update using it instead of rule_id. */ export const updateRulesSchema = Joi.object({ + actions: actions.default([]), description: description.required(), enabled: enabled.default(true), id, @@ -75,6 +78,7 @@ export const updateRulesSchema = Joi.object({ to: to.default('now'), type: type.required(), threat: threat.default([]), + throttle: throttle.default(null), references: references.default([]), version, }).xor('id', 'rule_id'); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts index c8205859407c0..5ef868017e88f 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts @@ -12,6 +12,7 @@ import { addTags } from './add_tags'; export const createRules = ({ alertsClient, actionsClient, // TODO: Use this actionsClient once we have actions such as email, etc... + actions, description, enabled, falsePositives, @@ -34,6 +35,7 @@ export const createRules = ({ severity, tags, threat, + throttle, to, type, references, @@ -71,8 +73,8 @@ export const createRules = ({ }, schedule: { interval }, enabled, - actions: [], // TODO: Create and add actions here once we have email, etc... - throttle: null, + actions, + throttle, }, }); }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts index b1dc62f6fc90f..6bae6bc9eda97 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts @@ -48,6 +48,7 @@ describe('create_rules_stream_from_ndjson', () => { ]); expect(result).toEqual([ { + actions: [], rule_id: 'rule-1', output_index: '.siem-signals', risk_score: 50, @@ -67,10 +68,12 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], + throttle: null, references: [], version: 1, }, { + actions: [], rule_id: 'rule-2', output_index: '.siem-signals', risk_score: 50, @@ -90,6 +93,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], + throttle: null, references: [], version: 1, }, @@ -132,6 +136,7 @@ describe('create_rules_stream_from_ndjson', () => { ]); expect(result).toEqual([ { + actions: [], rule_id: 'rule-1', output_index: '.siem-signals', risk_score: 50, @@ -151,10 +156,12 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], + throttle: null, references: [], version: 1, }, { + actions: [], rule_id: 'rule-2', output_index: '.siem-signals', risk_score: 50, @@ -174,6 +181,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], + throttle: null, references: [], version: 1, }, @@ -199,6 +207,7 @@ describe('create_rules_stream_from_ndjson', () => { ]); expect(result).toEqual([ { + actions: [], rule_id: 'rule-1', output_index: '.siem-signals', risk_score: 50, @@ -218,10 +227,12 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], + throttle: null, references: [], version: 1, }, { + actions: [], rule_id: 'rule-2', output_index: '.siem-signals', risk_score: 50, @@ -241,6 +252,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], + throttle: null, references: [], version: 1, }, @@ -266,6 +278,7 @@ describe('create_rules_stream_from_ndjson', () => { ]); const resultOrError = result as Error[]; expect(resultOrError[0]).toEqual({ + actions: [], rule_id: 'rule-1', output_index: '.siem-signals', risk_score: 50, @@ -285,11 +298,13 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], + throttle: null, references: [], version: 1, }); expect(resultOrError[1].message).toEqual('Unexpected token , in JSON at position 1'); expect(resultOrError[2]).toEqual({ + actions: [], rule_id: 'rule-2', output_index: '.siem-signals', risk_score: 50, @@ -309,6 +324,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], + throttle: null, references: [], version: 1, }); @@ -333,6 +349,7 @@ describe('create_rules_stream_from_ndjson', () => { ]); const resultOrError = result as TypeError[]; expect(resultOrError[0]).toEqual({ + actions: [], rule_id: 'rule-1', output_index: '.siem-signals', risk_score: 50, @@ -352,6 +369,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], + throttle: null, references: [], version: 1, }); @@ -359,6 +377,7 @@ describe('create_rules_stream_from_ndjson', () => { 'child "description" fails because ["description" is required]' ); expect(resultOrError[2]).toEqual({ + actions: [], rule_id: 'rule-2', output_index: '.siem-signals', risk_score: 50, @@ -378,6 +397,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], + throttle: null, references: [], version: 1, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts index 33f60bf0ba543..c50702665e304 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts @@ -21,7 +21,7 @@ describe('getExportAll', () => { const exports = await getExportAll(alertsClient); expect(exports).toEqual({ rulesNdjson: - '{"created_at":"2019-12-13T16:40:33.400Z","updated_at":"2019-12-13T16:40:33.400Z","created_by":"elastic","description":"Detecting root and admin users","enabled":true,"false_positives":[],"filters":[{"query":{"match_phrase":{"host.name":"some-host"}}}],"from":"now-6m","id":"04128c15-0d1b-4716-a4c5-46997ac7f3bd","immutable":false,"index":["auditbeat-*","filebeat-*","packetbeat-*","winlogbeat-*"],"interval":"5m","rule_id":"rule-1","language":"kuery","output_index":".siem-signals","max_signals":100,"risk_score":50,"name":"Detect Root/Admin Users","query":"user.name: root or user.name: admin","references":["http://www.example.com","https://ww.example.com"],"timeline_id":"some-timeline-id","timeline_title":"some-timeline-title","meta":{"someMeta":"someField"},"severity":"high","updated_by":"elastic","tags":[],"to":"now","type":"query","threat":[{"framework":"MITRE ATT&CK","tactic":{"id":"TA0040","name":"impact","reference":"https://attack.mitre.org/tactics/TA0040/"},"technique":[{"id":"T1499","name":"endpoint denial of service","reference":"https://attack.mitre.org/techniques/T1499/"}]}],"version":1}\n', + '{"actions":[],"created_at":"2019-12-13T16:40:33.400Z","updated_at":"2019-12-13T16:40:33.400Z","created_by":"elastic","description":"Detecting root and admin users","enabled":true,"false_positives":[],"filters":[{"query":{"match_phrase":{"host.name":"some-host"}}}],"from":"now-6m","id":"04128c15-0d1b-4716-a4c5-46997ac7f3bd","immutable":false,"index":["auditbeat-*","filebeat-*","packetbeat-*","winlogbeat-*"],"interval":"5m","rule_id":"rule-1","language":"kuery","output_index":".siem-signals","max_signals":100,"risk_score":50,"name":"Detect Root/Admin Users","query":"user.name: root or user.name: admin","references":["http://www.example.com","https://ww.example.com"],"timeline_id":"some-timeline-id","timeline_title":"some-timeline-title","meta":{"someMeta":"someField"},"severity":"high","updated_by":"elastic","tags":[],"to":"now","type":"query","threat":[{"framework":"MITRE ATT&CK","tactic":{"id":"TA0040","name":"impact","reference":"https://attack.mitre.org/tactics/TA0040/"},"technique":[{"id":"T1499","name":"endpoint denial of service","reference":"https://attack.mitre.org/techniques/T1499/"}]}],"version":1}\n', exportDetails: '{"exported_count":1,"missing_rules":[],"missing_rules_count":0}\n', }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts index 83b487163bdfb..92890296b881c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts @@ -29,7 +29,7 @@ describe('get_export_by_object_ids', () => { const exports = await getExportByObjectIds(alertsClient, objects); expect(exports).toEqual({ rulesNdjson: - '{"created_at":"2019-12-13T16:40:33.400Z","updated_at":"2019-12-13T16:40:33.400Z","created_by":"elastic","description":"Detecting root and admin users","enabled":true,"false_positives":[],"filters":[{"query":{"match_phrase":{"host.name":"some-host"}}}],"from":"now-6m","id":"04128c15-0d1b-4716-a4c5-46997ac7f3bd","immutable":false,"index":["auditbeat-*","filebeat-*","packetbeat-*","winlogbeat-*"],"interval":"5m","rule_id":"rule-1","language":"kuery","output_index":".siem-signals","max_signals":100,"risk_score":50,"name":"Detect Root/Admin Users","query":"user.name: root or user.name: admin","references":["http://www.example.com","https://ww.example.com"],"timeline_id":"some-timeline-id","timeline_title":"some-timeline-title","meta":{"someMeta":"someField"},"severity":"high","updated_by":"elastic","tags":[],"to":"now","type":"query","threat":[{"framework":"MITRE ATT&CK","tactic":{"id":"TA0040","name":"impact","reference":"https://attack.mitre.org/tactics/TA0040/"},"technique":[{"id":"T1499","name":"endpoint denial of service","reference":"https://attack.mitre.org/techniques/T1499/"}]}],"version":1}\n', + '{"actions":[],"created_at":"2019-12-13T16:40:33.400Z","updated_at":"2019-12-13T16:40:33.400Z","created_by":"elastic","description":"Detecting root and admin users","enabled":true,"false_positives":[],"filters":[{"query":{"match_phrase":{"host.name":"some-host"}}}],"from":"now-6m","id":"04128c15-0d1b-4716-a4c5-46997ac7f3bd","immutable":false,"index":["auditbeat-*","filebeat-*","packetbeat-*","winlogbeat-*"],"interval":"5m","rule_id":"rule-1","language":"kuery","output_index":".siem-signals","max_signals":100,"risk_score":50,"name":"Detect Root/Admin Users","query":"user.name: root or user.name: admin","references":["http://www.example.com","https://ww.example.com"],"timeline_id":"some-timeline-id","timeline_title":"some-timeline-title","meta":{"someMeta":"someField"},"severity":"high","updated_by":"elastic","tags":[],"to":"now","type":"query","threat":[{"framework":"MITRE ATT&CK","tactic":{"id":"TA0040","name":"impact","reference":"https://attack.mitre.org/tactics/TA0040/"},"technique":[{"id":"T1499","name":"endpoint denial of service","reference":"https://attack.mitre.org/techniques/T1499/"}]}],"version":1}\n', exportDetails: '{"exported_count":1,"missing_rules":[],"missing_rules_count":0}\n', }); }); @@ -72,6 +72,7 @@ describe('get_export_by_object_ids', () => { missingRules: [], rules: [ { + actions: [], created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', created_by: 'elastic', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts index 3d9ec128963f6..03a1e1ff3c1c0 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts @@ -18,6 +18,7 @@ export const installPrepackagedRules = ( ): Array> => rules.reduce>>((acc, rule) => { const { + actions, description, enabled, false_positives: falsePositives, @@ -41,6 +42,7 @@ export const installPrepackagedRules = ( to, type, threat, + throttle, references, version, } = rule; @@ -49,6 +51,7 @@ export const installPrepackagedRules = ( createRules({ alertsClient, actionsClient, + actions, description, enabled, falsePositives, @@ -73,6 +76,7 @@ export const installPrepackagedRules = ( to, type, threat, + throttle, references, version, }), diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts index 5fdef59a72f04..9ef0acc60d751 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts @@ -15,6 +15,7 @@ import { calculateVersion, calculateName, calculateInterval } from './utils'; export const patchRules = async ({ alertsClient, actionsClient, // TODO: Use this whenever we add feature support for different action types + actions, savedObjectsClient, description, falsePositives, @@ -39,11 +40,11 @@ export const patchRules = async ({ severity, tags, threat, + throttle, to, type, references, version, - throttle, }: PatchRuleParams): Promise => { const rule = await readRules({ alertsClient, ruleId, id }); if (rule == null) { @@ -51,6 +52,7 @@ export const patchRules = async ({ } const calculatedVersion = calculateVersion(rule.params.immutable, rule.params.version, { + actions, description, falsePositives, query, @@ -70,11 +72,11 @@ export const patchRules = async ({ severity, tags, threat, + throttle, to, type, references, version, - throttle, }); const nextParams = defaults( @@ -115,7 +117,7 @@ export const patchRules = async ({ schedule: { interval: calculateInterval(interval, rule.schedule.interval), }, - actions: rule.actions, + actions: actions ?? rule.actions ?? [], params: nextParams, }, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_prepacked_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_prepacked_rules.ts index 7889267a7267b..1949be663ca29 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_prepacked_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_prepacked_rules.ts @@ -19,6 +19,7 @@ export const updatePrepackagedRules = async ( ): Promise => { await rules.forEach(async rule => { const { + actions, description, false_positives: falsePositives, from, @@ -39,9 +40,9 @@ export const updatePrepackagedRules = async ( to, type, threat, + throttle, references, version, - throttle, } = rule; // Note: we do not pass down enabled as we do not want to suddenly disable @@ -49,6 +50,7 @@ export const updatePrepackagedRules = async ( return patchRules({ alertsClient, actionsClient, + actions, description, falsePositives, from, @@ -72,9 +74,9 @@ export const updatePrepackagedRules = async ( to, type, threat, + throttle, references, version, - throttle, }); }); }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts index 3a10841b70d7e..fbfd6d3b88a38 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts @@ -14,6 +14,7 @@ import { calculateVersion } from './utils'; export const updateRules = async ({ alertsClient, actionsClient, // TODO: Use this whenever we add feature support for different action types + actions, savedObjectsClient, description, falsePositives, @@ -38,11 +39,11 @@ export const updateRules = async ({ severity, tags, threat, + throttle, to, type, references, version, - throttle, }: UpdateRuleParams): Promise => { const rule = await readRules({ alertsClient, ruleId, id }); if (rule == null) { @@ -50,6 +51,7 @@ export const updateRules = async ({ } const calculatedVersion = calculateVersion(rule.params.immutable, rule.params.version, { + actions, description, falsePositives, query, @@ -69,11 +71,11 @@ export const updateRules = async ({ severity, tags, threat, + throttle, to, type, references, version, - throttle, }); const update = await alertsClient.update({ @@ -82,8 +84,8 @@ export const updateRules = async ({ tags: addTags(tags, rule.params.ruleId, immutable), name, schedule: { interval }, - actions: rule.actions, - throttle: throttle ?? rule.throttle ?? null, + actions, + throttle: ['no_actions', 'rule'].includes(throttle as string) ? null : throttle, params: { description, ruleId: rule.params.ruleId, @@ -103,6 +105,7 @@ export const updateRules = async ({ riskScore, severity, threat, + throttle, to, type, references, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts index fded0696ff8bf..42e10da33c66e 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts @@ -13,6 +13,7 @@ export const sampleRuleAlertParams = ( maxSignals?: number | undefined, riskScore?: number | undefined ): RuleTypeParams => ({ + actions: [], ruleId: 'rule-1', description: 'Detecting root and admin users', falsePositives: [], @@ -34,6 +35,7 @@ export const sampleRuleAlertParams = ( timelineTitle: undefined, meta: undefined, threat: undefined, + throttle: null, version: 1, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts index b71a7080f4147..23b55f8a811c5 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts @@ -60,6 +60,7 @@ describe('buildBulkBody', () => { original_time: 'someTimeStamp', status: 'open', rule: { + actions: [], id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', rule_id: 'rule-1', false_positives: [], @@ -149,6 +150,7 @@ describe('buildBulkBody', () => { original_time: 'someTimeStamp', status: 'open', rule: { + actions: [], id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', rule_id: 'rule-1', false_positives: [], @@ -236,6 +238,7 @@ describe('buildBulkBody', () => { original_time: 'someTimeStamp', status: 'open', rule: { + actions: [], id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', rule_id: 'rule-1', false_positives: [], @@ -316,6 +319,7 @@ describe('buildBulkBody', () => { original_time: 'someTimeStamp', status: 'open', rule: { + actions: [], id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', rule_id: 'rule-1', false_positives: [], diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts index af0883f4ce6b5..010dd673a4b74 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts @@ -39,6 +39,7 @@ describe('buildRule', () => { tags: ['some fake tag 1', 'some fake tag 2'], }); const expected: Partial = { + actions: [], created_by: 'elastic', description: 'Detecting root and admin users', enabled: false, @@ -95,6 +96,7 @@ describe('buildRule', () => { tags: ['some fake tag 1', 'some fake tag 2'], }); const expected: Partial = { + actions: [], created_by: 'elastic', description: 'Detecting root and admin users', enabled: true, @@ -140,6 +142,7 @@ describe('buildRule', () => { tags: ['some fake tag 1', 'some fake tag 2'], }); const expected: Partial = { + actions: [], created_by: 'elastic', description: 'Detecting root and admin users', enabled: true, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts index 70465bf1d9201..ea81e319c16b9 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts @@ -35,6 +35,7 @@ export const buildRule = ({ return pickBy((value: unknown) => value != null, { id, rule_id: ruleParams.ruleId, + actions: ruleParams.actions, false_positives: ruleParams.falsePositives, saved_id: ruleParams.savedId, timeline_id: ruleParams.timelineId, @@ -61,6 +62,7 @@ export const buildRule = ({ created_by: createdBy, updated_by: updatedBy, threat: ruleParams.threat, + throttle: ruleParams.throttle, version: ruleParams.version, created_at: createdAt, updated_at: updatedAt, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_signal.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_signal.ts index 684cad99f09f0..3fe2d1981a5d7 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_signal.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_signal.ts @@ -70,7 +70,7 @@ export const removeInternalTagsFromRule = ( } else { const ruleWithoutInternalTags: Partial = { ...rule, - tags: rule.tags.filter(tag => !tag.startsWith(INTERNAL_IDENTIFIER)), + tags: rule.tags.filter((tag: string) => !tag.startsWith(INTERNAL_IDENTIFIER)), }; return ruleWithoutInternalTags; } diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index f7fabfb980195..c7464bffa1261 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +/* eslint-disable complexity */ + import { schema } from '@kbn/config-schema'; import { Logger } from 'src/core/server'; import moment from 'moment'; @@ -72,6 +74,7 @@ export const signalRulesAlertType = ({ riskScore: schema.number(), severity: schema.string(), threat: schema.nullable(schema.arrayOf(schema.object({}, { allowUnknowns: true }))), + throttle: schema.nullable(schema.string()), to: schema.string(), type: schema.string(), references: schema.arrayOf(schema.string(), { defaultValue: [] }), @@ -91,6 +94,7 @@ export const signalRulesAlertType = ({ query, to, type, + throttle, } = params; // TODO: Remove this hard extraction of name once this is fixed: https://github.com/elastic/kibana/issues/50522 const savedObject = await services.savedObjectsClient.get('alert', alertId); @@ -209,13 +213,29 @@ export const signalRulesAlertType = ({ `[+] Initial search call of signal rule name: "${name}", id: "${alertId}", rule_id: "${ruleId}"` ); const noReIndexResult = await services.callCluster('search', noReIndex); + if (noReIndexResult.hits.total.value !== 0) { + const inputIndexes = inputIndex.join(', '); + + if (throttle && throttle !== 'no_actions') { + const alertInstance = services.alertInstanceFactory(ruleId!); + const newSignalsCount = noReIndexResult.hits.total.value; + + alertInstance + .replaceState({ + signalsCount: newSignalsCount, + }) + .scheduleActions('default', { + inputIndexes, + outputIndex, + name, + alertId, + ruleId, + }); + } + logger.info( - `Found ${ - noReIndexResult.hits.total.value - } signals from the indexes of "[${inputIndex.join( - ', ' - )}]" using signal rule name: "${name}", id: "${alertId}", rule_id: "${ruleId}", pushing signals to index "${outputIndex}"` + `Found ${noReIndexResult.hits.total.value} signals from the indexes of "[${inputIndexes}]" using signal rule name: "${name}", id: "${alertId}", rule_id: "${ruleId}", pushing signals to index "${outputIndex}"` ); } diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts index 5e5ff157c92c6..a4d914bd5efc4 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts @@ -4,6 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { AlertAction } from '../../../../../../plugins/triggers_actions_ui/public/types'; + import { CallAPIOptions } from '../../../../../../../src/core/server'; import { Filter } from '../../../../../../../src/plugins/data/server'; import { IRuleStatusAttributes } from './rules/types'; @@ -23,6 +26,7 @@ export interface ThreatParams { } export interface RuleAlertParams { + actions: AlertAction[]; description: string; enabled: boolean; falsePositives: string[]; @@ -49,7 +53,7 @@ export interface RuleAlertParams { threat: ThreatParams[] | undefined | null; type: 'query' | 'saved_query'; version: number; - throttle?: string; + throttle?: string | null; } export type RuleTypeParams = Omit; @@ -94,11 +98,12 @@ export type RuleAlertParamsRest = Omit< last_success_message?: IRuleStatusAttributes['lastSuccessMessage'] | undefined; }; -export type OutputRuleAlertRest = RuleAlertParamsRest & { +export type OutputRuleAlertRest = Omit & { id: string; created_by: string | undefined | null; updated_by: string | undefined | null; immutable: boolean; + throttle?: RuleAlertParams['throttle']; }; export type ImportRuleAlertRest = Omit & { From e9a87aa22b00b06b94f905d83f7e7a2c3d9b4a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Mon, 9 Mar 2020 14:15:35 +0100 Subject: [PATCH 02/19] cleanup --- .../routes/__mocks__/request_responses.ts | 2 +- .../routes/rules/utils.test.ts | 13 ++++ .../routes/rules/validate.test.ts | 1 + .../add_prepackaged_rules_schema.test.ts | 57 +++++++++++++++++ .../schemas/add_prepackaged_rules_schema.ts | 4 ++ .../schemas/create_rules_bulk_schema.test.ts | 63 +++++++++++++++++++ .../schemas/create_rules_schema.test.ts | 57 +++++++++++++++++ .../routes/schemas/create_rules_schema.ts | 4 +- .../schemas/import_rules_schema.test.ts | 57 +++++++++++++++++ .../routes/schemas/import_rules_schema.ts | 4 +- .../routes/schemas/patch_rules_schema.test.ts | 57 +++++++++++++++++ .../routes/schemas/response/schemas.ts | 8 ++- .../routes/schemas/schemas.ts | 6 +- .../schemas/update_rules_schema.test.ts | 57 +++++++++++++++++ .../routes/schemas/update_rules_schema.ts | 4 +- .../detection_engine/rules/create_rules.ts | 4 +- .../create_rules_stream_from_ndjson.test.ts | 20 +++--- .../rules/get_export_all.test.ts | 2 +- .../rules/get_export_by_object_ids.test.ts | 3 +- .../detection_engine/rules/update_rules.ts | 4 +- .../lib/detection_engine/rules/utils.test.ts | 19 +++++- .../lib/detection_engine/rules/utils.ts | 11 ++++ .../signals/__mocks__/es_results.ts | 2 +- .../signals/build_bulk_body.test.ts | 4 ++ .../signals/build_rule.test.ts | 49 +++++++++++++++ .../signals/signal_rule_alert_type.ts | 10 ++- .../siem/server/lib/detection_engine/types.ts | 9 +-- 27 files changed, 492 insertions(+), 39 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index b3271e025faab..070c5ab91de48 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -393,7 +393,7 @@ export const getResult = (): RuleAlertType => ({ ], }, ], - throttle: null, + throttle: 'no_actions', references: ['http://www.example.com', 'https://ww.example.com'], version: 1, }, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts index 91fe70e67f594..c9956eead61e6 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts @@ -77,6 +77,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', filters: [ { query: { @@ -140,6 +141,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', filters: [ { query: { @@ -205,6 +207,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', filters: [ { query: { @@ -270,6 +273,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', filters: [ { query: { @@ -333,6 +337,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', filters: [ { query: { @@ -399,6 +404,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', filters: [ { query: { @@ -465,6 +471,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', filters: [ { query: { @@ -531,6 +538,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', filters: [ { query: { @@ -683,6 +691,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', filters: [ { query: { @@ -765,6 +774,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', filters: [ { query: { @@ -938,6 +948,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', filters: [ { query: { @@ -1059,6 +1070,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', timeline_id: 'some-timeline-id', timeline_title: 'some-timeline-title', to: 'now', @@ -1168,6 +1180,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', timeline_id: 'some-timeline-id', timeline_title: 'some-timeline-title', to: 'now', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts index 5349173d38646..6d04bfbbbf0d8 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts @@ -59,6 +59,7 @@ export const ruleOutput: RulesSchema = { ], }, ], + throttle: 'no_actions', version: 1, filters: [ { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts index b536cfac05df3..42e15140dc419 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts @@ -1274,4 +1274,61 @@ describe('add prepackaged rules schema', () => { 'child "severity" fails because ["severity" must be one of [low, medium, high, critical]]' ); }); + + test('You cannot set the throttle to a value other than no_actions, rule, 1h, 1d, or 7d', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + throttle: '1w', + }).error.message + ).toEqual( + 'child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]' + ); + }); + + test('The default for "actions" will be an empty array', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).value.actions + ).toEqual([]); + }); + + test('The default for "throttle" will be no_actions', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).value.throttle + ).toEqual('no_actions'); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts index b62c480492c84..ef72771b396a0 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts @@ -8,6 +8,7 @@ import Joi from 'joi'; /* eslint-disable @typescript-eslint/camelcase */ import { + actions, enabled, description, false_positives, @@ -31,6 +32,7 @@ import { to, type, threat, + throttle, references, version, } from './schemas'; @@ -48,6 +50,7 @@ import { DEFAULT_MAX_SIGNALS } from '../../../../../common/constants'; * - index is a required field that must exist */ export const addPrepackagedRulesSchema = Joi.object({ + actions, description: description.required(), enabled: enabled.default(false), false_positives: false_positives.default([]), @@ -78,6 +81,7 @@ export const addPrepackagedRulesSchema = Joi.object({ to: to.default('now'), type: type.required(), threat: threat.default([]), + throttle, references: references.default([]), version: version.required(), }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_bulk_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_bulk_schema.test.ts index 2a64478962ced..91bb28ad6bc92 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_bulk_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_bulk_schema.test.ts @@ -141,4 +141,67 @@ describe('create_rules_bulk_schema', () => { '"value" at position 0 fails because [child "severity" fails because ["severity" must be one of [low, medium, high, critical]]]' ); }); + + test('You cannot set the throttle to a value other than no_actions, rule, 1h, 1d, or 7d', () => { + expect( + createRulesBulkSchema.validate>([ + { + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + throttle: '1w', + }, + ]).error.message + ).toEqual( + '"value" at position 0 fails because [child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]]' + ); + }); + + test('The default for "actions" will be an empty array', () => { + expect( + createRulesBulkSchema.validate>([ + { + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }, + ]).value[0].actions + ).toEqual([]); + }); + + test('The default for "throttle" will be no_actions', () => { + expect( + createRulesBulkSchema.validate>([ + { + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }, + ]).value[0].throttle + ).toEqual('no_actions'); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts index 052a149f3d4dc..f3cfd6b0dde44 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts @@ -1224,4 +1224,61 @@ describe('create rules schema', () => { 'child "severity" fails because ["severity" must be one of [low, medium, high, critical]]' ); }); + + test('You cannot set the throttle to a value other than no_actions, rule, 1h, 1d, or 7d', () => { + expect( + createRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + throttle: '1w', + }).error.message + ).toEqual( + 'child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]' + ); + }); + + test('The default for "actions" will be an empty array', () => { + expect( + createRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).value.actions + ).toEqual([]); + }); + + test('The default for "throttle" will be no_actions', () => { + expect( + createRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).value.throttle + ).toEqual('no_actions'); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts index fda79744fcd16..1af4a1709d271 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts @@ -41,7 +41,7 @@ import { import { DEFAULT_MAX_SIGNALS } from '../../../../../common/constants'; export const createRulesSchema = Joi.object({ - actions: actions.default([]), + actions, description: description.required(), enabled: enabled.default(true), false_positives: false_positives.default([]), @@ -69,7 +69,7 @@ export const createRulesSchema = Joi.object({ to: to.default('now'), type: type.required(), threat: threat.default([]), - throttle: throttle.default(null), + throttle, references: references.default([]), version: version.default(1), }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts index da441681de50b..ece4f679cf0c0 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts @@ -1423,4 +1423,61 @@ describe('import rules schema', () => { 'child "severity" fails because ["severity" must be one of [low, medium, high, critical]]' ); }); + + test('You cannot set the throttle to a value other than no_actions, rule, 1h, 1d, or 7d', () => { + expect( + importRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + throttle: '1w', + }).error.message + ).toEqual( + 'child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]' + ); + }); + + test('The default for "actions" will be an empty array', () => { + expect( + importRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).value.actions + ).toEqual([]); + }); + + test('The default for "throttle" will be no_actions', () => { + expect( + importRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).value.throttle + ).toEqual('no_actions'); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts index 3d6cc2424b6f6..8ab669982939b 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts @@ -57,7 +57,7 @@ import { DEFAULT_MAX_SIGNALS } from '../../../../../common/constants'; */ export const importRulesSchema = Joi.object({ id, - actions: actions.default([]), + actions, description: description.required(), enabled: enabled.default(true), false_positives: false_positives.default([]), @@ -86,7 +86,7 @@ export const importRulesSchema = Joi.object({ to: to.default('now'), type: type.required(), threat: threat.default([]), - throttle: throttle.default(null), + throttle, references: references.default([]), version: version.default(1), created_at, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts index 11bed22e1c047..c2d24803349f4 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts @@ -1012,4 +1012,61 @@ describe('patch rules schema', () => { 'child "severity" fails because ["severity" must be one of [low, medium, high, critical]]' ); }); + + test('You cannot set the throttle to a value other than no_actions, rule, 1h, 1d, or 7d', () => { + expect( + patchRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + throttle: '1w', + }).error.message + ).toEqual( + 'child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]' + ); + }); + + test('The default for "actions" will be an empty array', () => { + expect( + patchRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).value.actions + ).toEqual([]); + }); + + test('The default for "throttle" will be no_actions', () => { + expect( + patchRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).value.throttle + ).toEqual('no_actions'); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts index d6beb584b97f1..4465795af90a3 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts @@ -46,7 +46,13 @@ export const output_index = t.string; export const saved_id = t.string; export const timeline_id = t.string; export const timeline_title = t.string; -export const throttle = t.string; +export const throttle = t.keyof({ + no_actions: null, + rule: null, + '1h': null, + '1d': null, + '7d': null, +}); /** * Note that this is a plain unknown object because we allow the UI diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts index 7599fb2ca36fa..b3583071c652a 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts @@ -105,5 +105,7 @@ export const updated_by = Joi.string(); export const version = Joi.number() .integer() .min(1); -export const actions = Joi.array(); -export const throttle = Joi.string().allow(null); +export const actions = Joi.array().default([]); +export const throttle = Joi.string() + .valid('no_actions', 'rule', '1h', '1d', '7d') + .default('no_actions'); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts index c7899f3afa7b8..9cb9fa28acb4b 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts @@ -1243,4 +1243,61 @@ describe('create rules schema', () => { 'child "severity" fails because ["severity" must be one of [low, medium, high, critical]]' ); }); + + test('You cannot set the throttle to a value other than no_actions, rule, 1h, 1d, or 7d', () => { + expect( + updateRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + throttle: '1w', + }).error.message + ).toEqual( + 'child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]' + ); + }); + + test('The default for "actions" will be an empty array', () => { + expect( + updateRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).value.actions + ).toEqual([]); + }); + + test('The default for "throttle" will be no_actions', () => { + expect( + updateRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'low', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).value.throttle + ).toEqual('no_actions'); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts index 9d4903fc0e8ab..ef90a98ca4da8 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts @@ -49,7 +49,7 @@ import { DEFAULT_MAX_SIGNALS } from '../../../../../common/constants'; * - id is on here because you can pass in an id to update using it instead of rule_id. */ export const updateRulesSchema = Joi.object({ - actions: actions.default([]), + actions, description: description.required(), enabled: enabled.default(true), id, @@ -78,7 +78,7 @@ export const updateRulesSchema = Joi.object({ to: to.default('now'), type: type.required(), threat: threat.default([]), - throttle: throttle.default(null), + throttle, references: references.default([]), version, }).xor('id', 'rule_id'); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts index 5ef868017e88f..770ec0375c41b 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts @@ -8,6 +8,7 @@ import { Alert } from '../../../../../../../plugins/alerting/common'; import { APP_ID, SIGNALS_ID } from '../../../../common/constants'; import { CreateRuleParams } from './types'; import { addTags } from './add_tags'; +import { getAlertThrottle } from './utils'; export const createRules = ({ alertsClient, @@ -66,6 +67,7 @@ export const createRules = ({ riskScore, severity, threat, + throttle, to, type, references, @@ -74,7 +76,7 @@ export const createRules = ({ schedule: { interval }, enabled, actions, - throttle, + throttle: getAlertThrottle(throttle), }, }); }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts index 6bae6bc9eda97..99d78b7044904 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts @@ -68,7 +68,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: null, + throttle: 'no_actions', references: [], version: 1, }, @@ -93,7 +93,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: null, + throttle: 'no_actions', references: [], version: 1, }, @@ -156,7 +156,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: null, + throttle: 'no_actions', references: [], version: 1, }, @@ -181,7 +181,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: null, + throttle: 'no_actions', references: [], version: 1, }, @@ -227,7 +227,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: null, + throttle: 'no_actions', references: [], version: 1, }, @@ -252,7 +252,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: null, + throttle: 'no_actions', references: [], version: 1, }, @@ -298,7 +298,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: null, + throttle: 'no_actions', references: [], version: 1, }); @@ -324,7 +324,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: null, + throttle: 'no_actions', references: [], version: 1, }); @@ -369,7 +369,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: null, + throttle: 'no_actions', references: [], version: 1, }); @@ -397,7 +397,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: null, + throttle: 'no_actions', references: [], version: 1, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts index c50702665e304..7762f907967f5 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts @@ -21,7 +21,7 @@ describe('getExportAll', () => { const exports = await getExportAll(alertsClient); expect(exports).toEqual({ rulesNdjson: - '{"actions":[],"created_at":"2019-12-13T16:40:33.400Z","updated_at":"2019-12-13T16:40:33.400Z","created_by":"elastic","description":"Detecting root and admin users","enabled":true,"false_positives":[],"filters":[{"query":{"match_phrase":{"host.name":"some-host"}}}],"from":"now-6m","id":"04128c15-0d1b-4716-a4c5-46997ac7f3bd","immutable":false,"index":["auditbeat-*","filebeat-*","packetbeat-*","winlogbeat-*"],"interval":"5m","rule_id":"rule-1","language":"kuery","output_index":".siem-signals","max_signals":100,"risk_score":50,"name":"Detect Root/Admin Users","query":"user.name: root or user.name: admin","references":["http://www.example.com","https://ww.example.com"],"timeline_id":"some-timeline-id","timeline_title":"some-timeline-title","meta":{"someMeta":"someField"},"severity":"high","updated_by":"elastic","tags":[],"to":"now","type":"query","threat":[{"framework":"MITRE ATT&CK","tactic":{"id":"TA0040","name":"impact","reference":"https://attack.mitre.org/tactics/TA0040/"},"technique":[{"id":"T1499","name":"endpoint denial of service","reference":"https://attack.mitre.org/techniques/T1499/"}]}],"version":1}\n', + '{"actions":[],"created_at":"2019-12-13T16:40:33.400Z","updated_at":"2019-12-13T16:40:33.400Z","created_by":"elastic","description":"Detecting root and admin users","enabled":true,"false_positives":[],"filters":[{"query":{"match_phrase":{"host.name":"some-host"}}}],"from":"now-6m","id":"04128c15-0d1b-4716-a4c5-46997ac7f3bd","immutable":false,"index":["auditbeat-*","filebeat-*","packetbeat-*","winlogbeat-*"],"interval":"5m","rule_id":"rule-1","language":"kuery","output_index":".siem-signals","max_signals":100,"risk_score":50,"name":"Detect Root/Admin Users","query":"user.name: root or user.name: admin","references":["http://www.example.com","https://ww.example.com"],"timeline_id":"some-timeline-id","timeline_title":"some-timeline-title","meta":{"someMeta":"someField"},"severity":"high","updated_by":"elastic","tags":[],"to":"now","type":"query","threat":[{"framework":"MITRE ATT&CK","tactic":{"id":"TA0040","name":"impact","reference":"https://attack.mitre.org/tactics/TA0040/"},"technique":[{"id":"T1499","name":"endpoint denial of service","reference":"https://attack.mitre.org/techniques/T1499/"}]}],"throttle":"no_actions","version":1}\n', exportDetails: '{"exported_count":1,"missing_rules":[],"missing_rules_count":0}\n', }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts index 92890296b881c..2404ae6dc16cb 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts @@ -29,7 +29,7 @@ describe('get_export_by_object_ids', () => { const exports = await getExportByObjectIds(alertsClient, objects); expect(exports).toEqual({ rulesNdjson: - '{"actions":[],"created_at":"2019-12-13T16:40:33.400Z","updated_at":"2019-12-13T16:40:33.400Z","created_by":"elastic","description":"Detecting root and admin users","enabled":true,"false_positives":[],"filters":[{"query":{"match_phrase":{"host.name":"some-host"}}}],"from":"now-6m","id":"04128c15-0d1b-4716-a4c5-46997ac7f3bd","immutable":false,"index":["auditbeat-*","filebeat-*","packetbeat-*","winlogbeat-*"],"interval":"5m","rule_id":"rule-1","language":"kuery","output_index":".siem-signals","max_signals":100,"risk_score":50,"name":"Detect Root/Admin Users","query":"user.name: root or user.name: admin","references":["http://www.example.com","https://ww.example.com"],"timeline_id":"some-timeline-id","timeline_title":"some-timeline-title","meta":{"someMeta":"someField"},"severity":"high","updated_by":"elastic","tags":[],"to":"now","type":"query","threat":[{"framework":"MITRE ATT&CK","tactic":{"id":"TA0040","name":"impact","reference":"https://attack.mitre.org/tactics/TA0040/"},"technique":[{"id":"T1499","name":"endpoint denial of service","reference":"https://attack.mitre.org/techniques/T1499/"}]}],"version":1}\n', + '{"actions":[],"created_at":"2019-12-13T16:40:33.400Z","updated_at":"2019-12-13T16:40:33.400Z","created_by":"elastic","description":"Detecting root and admin users","enabled":true,"false_positives":[],"filters":[{"query":{"match_phrase":{"host.name":"some-host"}}}],"from":"now-6m","id":"04128c15-0d1b-4716-a4c5-46997ac7f3bd","immutable":false,"index":["auditbeat-*","filebeat-*","packetbeat-*","winlogbeat-*"],"interval":"5m","rule_id":"rule-1","language":"kuery","output_index":".siem-signals","max_signals":100,"risk_score":50,"name":"Detect Root/Admin Users","query":"user.name: root or user.name: admin","references":["http://www.example.com","https://ww.example.com"],"timeline_id":"some-timeline-id","timeline_title":"some-timeline-title","meta":{"someMeta":"someField"},"severity":"high","updated_by":"elastic","tags":[],"to":"now","type":"query","threat":[{"framework":"MITRE ATT&CK","tactic":{"id":"TA0040","name":"impact","reference":"https://attack.mitre.org/tactics/TA0040/"},"technique":[{"id":"T1499","name":"endpoint denial of service","reference":"https://attack.mitre.org/techniques/T1499/"}]}],"throttle":"no_actions","version":1}\n', exportDetails: '{"exported_count":1,"missing_rules":[],"missing_rules_count":0}\n', }); }); @@ -118,6 +118,7 @@ describe('get_export_by_object_ids', () => { ], }, ], + throttle: 'no_actions', version: 1, }, ], diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts index fbfd6d3b88a38..deb2a85a008a4 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts @@ -9,7 +9,7 @@ import { readRules } from './read_rules'; import { IRuleSavedAttributesSavedObjectAttributes, UpdateRuleParams } from './types'; import { addTags } from './add_tags'; import { ruleStatusSavedObjectType } from './saved_object_mappings'; -import { calculateVersion } from './utils'; +import { calculateVersion, getAlertThrottle } from './utils'; export const updateRules = async ({ alertsClient, @@ -85,7 +85,7 @@ export const updateRules = async ({ name, schedule: { interval }, actions, - throttle: ['no_actions', 'rule'].includes(throttle as string) ? null : throttle, + throttle: getAlertThrottle(throttle), params: { description, ruleId: rule.params.ruleId, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.test.ts index b7c36b20f44be..09d70ad88bcfb 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { calculateInterval, calculateVersion, calculateName } from './utils'; +import { calculateInterval, calculateVersion, calculateName, getAlertThrottle } from './utils'; import { PatchRuleParams } from './types'; describe('utils', () => { @@ -70,4 +70,21 @@ describe('utils', () => { expect(name).toEqual('untitled'); }); }); + + describe('#getAlertThrottle', () => { + test('should return null if throttle is undefined', () => { + const throttle = getAlertThrottle(undefined); + expect(throttle).toEqual(null); + }); + + test('should return null if throttle is null', () => { + const throttle = getAlertThrottle(null); + expect(throttle).toEqual(null); + }); + + test('should return string if throttle is string', () => { + const throttle = getAlertThrottle('1d'); + expect(throttle).toEqual('1d'); + }); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.ts index 7d6091f6b97fa..456130fee3a32 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.ts @@ -73,3 +73,14 @@ export const calculateName = ({ return 'untitled'; } }; + +/* + Alert throttle has to be null in case there are no actions or actions are exectured per rule exectution +*/ +export const getAlertThrottle = (throttle: string | null | undefined): null | string => { + if (!throttle || ['no_actions', 'rule'].includes(throttle)) { + return null; + } + + return throttle; +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts index 42e10da33c66e..3a8347af1c6a7 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts @@ -35,7 +35,7 @@ export const sampleRuleAlertParams = ( timelineTitle: undefined, meta: undefined, threat: undefined, - throttle: null, + throttle: 'no_actions', version: 1, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts index 23b55f8a811c5..8c3dea2d5b0bd 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts @@ -78,6 +78,7 @@ describe('buildBulkBody', () => { references: ['http://google.com'], severity: 'high', tags: ['some fake tag 1', 'some fake tag 2'], + throttle: 'no_actions', type: 'query', to: 'now', enabled: true, @@ -168,6 +169,7 @@ describe('buildBulkBody', () => { references: ['http://google.com'], severity: 'high', tags: ['some fake tag 1', 'some fake tag 2'], + throttle: 'no_actions', type: 'query', to: 'now', enabled: true, @@ -256,6 +258,7 @@ describe('buildBulkBody', () => { references: ['http://google.com'], severity: 'high', tags: ['some fake tag 1', 'some fake tag 2'], + throttle: 'no_actions', type: 'query', to: 'now', enabled: true, @@ -337,6 +340,7 @@ describe('buildBulkBody', () => { references: ['http://google.com'], severity: 'high', tags: ['some fake tag 1', 'some fake tag 2'], + throttle: 'no_actions', type: 'query', to: 'now', enabled: true, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts index 010dd673a4b74..412f44321434a 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts @@ -59,6 +59,7 @@ describe('buildRule', () => { rule_id: 'rule-1', severity: 'high', tags: ['some fake tag 1', 'some fake tag 2'], + throttle: 'no_actions', to: 'now', type: 'query', updated_by: 'elastic', @@ -116,6 +117,7 @@ describe('buildRule', () => { rule_id: 'rule-1', severity: 'high', tags: ['some fake tag 1', 'some fake tag 2'], + throttle: 'no_actions', to: 'now', type: 'query', updated_by: 'elastic', @@ -141,6 +143,53 @@ describe('buildRule', () => { interval: 'some interval', tags: ['some fake tag 1', 'some fake tag 2'], }); + const expected: Partial = { + actions: [], + created_by: 'elastic', + description: 'Detecting root and admin users', + enabled: true, + false_positives: [], + from: 'now-6m', + id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + immutable: false, + index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + interval: 'some interval', + language: 'kuery', + max_signals: 10000, + name: 'some-name', + output_index: '.siem-signals', + query: 'user.name: root or user.name: admin', + references: ['http://google.com'], + risk_score: 50, + rule_id: 'rule-1', + severity: 'high', + tags: ['some fake tag 1', 'some fake tag 2'], + throttle: 'no_actions', + to: 'now', + type: 'query', + updated_by: 'elastic', + version: 1, + updated_at: rule.updated_at, + created_at: rule.created_at, + }; + expect(rule).toEqual(expected); + }); + + test('it omits a null value such as if throttle is undefined if is present', () => { + const ruleParams = sampleRuleAlertParams(); + ruleParams.throttle = undefined; + const rule = buildRule({ + ruleParams, + name: 'some-name', + id: sampleRuleGuid, + enabled: true, + createdAt: '2020-01-28T15:58:34.810Z', + updatedAt: '2020-01-28T15:59:14.004Z', + createdBy: 'elastic', + updatedBy: 'elastic', + interval: 'some interval', + tags: ['some fake tag 1', 'some fake tag 2'], + }); const expected: Partial = { actions: [], created_by: 'elastic', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index c7464bffa1261..c5ae562d15bf2 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -/* eslint-disable complexity */ - import { schema } from '@kbn/config-schema'; import { Logger } from 'src/core/server'; import moment from 'moment'; @@ -74,7 +72,7 @@ export const signalRulesAlertType = ({ riskScore: schema.number(), severity: schema.string(), threat: schema.nullable(schema.arrayOf(schema.object({}, { allowUnknowns: true }))), - throttle: schema.nullable(schema.string()), + throttle: schema.string(), to: schema.string(), type: schema.string(), references: schema.arrayOf(schema.string(), { defaultValue: [] }), @@ -213,13 +211,13 @@ export const signalRulesAlertType = ({ `[+] Initial search call of signal rule name: "${name}", id: "${alertId}", rule_id: "${ruleId}"` ); const noReIndexResult = await services.callCluster('search', noReIndex); + const newSignalsCount = noReIndexResult.hits.total.value; - if (noReIndexResult.hits.total.value !== 0) { + if (newSignalsCount !== 0) { const inputIndexes = inputIndex.join(', '); if (throttle && throttle !== 'no_actions') { const alertInstance = services.alertInstanceFactory(ruleId!); - const newSignalsCount = noReIndexResult.hits.total.value; alertInstance .replaceState({ @@ -235,7 +233,7 @@ export const signalRulesAlertType = ({ } logger.info( - `Found ${noReIndexResult.hits.total.value} signals from the indexes of "[${inputIndexes}]" using signal rule name: "${name}", id: "${alertId}", rule_id: "${ruleId}", pushing signals to index "${outputIndex}"` + `Found ${newSignalsCount} signals from the indexes of "[${inputIndexes}]" using signal rule name: "${name}", id: "${alertId}", rule_id: "${ruleId}", pushing signals to index "${outputIndex}"` ); } diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts index a4d914bd5efc4..80bf69072f1a3 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts @@ -4,9 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { AlertAction } from '../../../../../../plugins/triggers_actions_ui/public/types'; - +import { AlertAction } from '../../../../../../plugins/alerting/common/alert'; import { CallAPIOptions } from '../../../../../../../src/core/server'; import { Filter } from '../../../../../../../src/plugins/data/server'; import { IRuleStatusAttributes } from './rules/types'; @@ -53,7 +51,7 @@ export interface RuleAlertParams { threat: ThreatParams[] | undefined | null; type: 'query' | 'saved_query'; version: number; - throttle?: string | null; + throttle: string | undefined | null; } export type RuleTypeParams = Omit; @@ -98,12 +96,11 @@ export type RuleAlertParamsRest = Omit< last_success_message?: IRuleStatusAttributes['lastSuccessMessage'] | undefined; }; -export type OutputRuleAlertRest = Omit & { +export type OutputRuleAlertRest = RuleAlertParamsRest & { id: string; created_by: string | undefined | null; updated_by: string | undefined | null; immutable: boolean; - throttle?: RuleAlertParams['throttle']; }; export type ImportRuleAlertRest = Omit & { From a628adef5ab732bea6a852ccd574c26e09dec152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Mon, 9 Mar 2020 16:00:16 +0100 Subject: [PATCH 03/19] fix tests --- .../server/lib/detection_engine/routes/rules/utils.test.ts | 1 + .../routes/schemas/add_prepackaged_rules_schema.test.ts | 3 +++ 2 files changed, 4 insertions(+) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts index c9956eead61e6..e05143f88d6c7 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts @@ -1131,6 +1131,7 @@ describe('utils', () => { ], }, ], + throttle: 'no_actions', timeline_id: 'some-timeline-id', timeline_title: 'some-timeline-title', to: 'now', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts index 42e15140dc419..90f0dca16b822 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts @@ -1281,6 +1281,7 @@ describe('add prepackaged rules schema', () => { rule_id: 'rule-1', risk_score: 50, description: 'some description', + index: ['auditbeat-*'], name: 'some-name', severity: 'low', type: 'query', @@ -1302,6 +1303,7 @@ describe('add prepackaged rules schema', () => { rule_id: 'rule-1', risk_score: 50, description: 'some description', + index: ['auditbeat-*'], name: 'some-name', severity: 'low', type: 'query', @@ -1320,6 +1322,7 @@ describe('add prepackaged rules schema', () => { rule_id: 'rule-1', risk_score: 50, description: 'some description', + index: ['auditbeat-*'], name: 'some-name', severity: 'low', type: 'query', From 027ea3a0f7e8366c259646b8f469fcc68e7bdf3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopycin=CC=81ski?= Date: Mon, 9 Mar 2020 18:13:53 +0100 Subject: [PATCH 04/19] PR comments --- .../detection_engine/routes/schemas/response/schemas.ts | 7 ++++++- .../security_and_spaces/tests/utils.ts | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts index 4465795af90a3..35f75b4ca87a1 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts @@ -24,7 +24,12 @@ export const file_name = t.string; * become the actual ESFilter as a type. */ export const filters = t.array(t.unknown); // Filters are not easily type-able yet -export const actions = t.array(t.unknown); + +/** + * TODO: Right now the actions is an "unknown", when it could more than likely + * become the actual AlertAction as a type. + */ +export const actions = t.array(t.unknown); // Actions are not easily type-able yet // TODO: Create a regular expression type or custom date math part type here export const from = t.string; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts index bef700d0409a5..b01e908e34d37 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts @@ -112,6 +112,7 @@ export const binaryToString = (res: any, callback: any): void => { * This is the typical output of a simple rule that Kibana will output with all the defaults. */ export const getSimpleRuleOutput = (ruleId = 'rule-1'): Partial => ({ + actions: [], created_by: 'elastic', description: 'Simple Rule Query', enabled: true, @@ -133,6 +134,7 @@ export const getSimpleRuleOutput = (ruleId = 'rule-1'): Partial Date: Tue, 10 Mar 2020 15:53:23 +0100 Subject: [PATCH 05/19] PR comments --- .../signals/signal_rule_alert_type.ts | 29 ++++--------------- .../siem/server/lib/detection_engine/types.ts | 2 +- .../security_and_spaces/tests/utils.ts | 4 +++ 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index c5ae562d15bf2..5377ad261e3fb 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -92,7 +92,6 @@ export const signalRulesAlertType = ({ query, to, type, - throttle, } = params; // TODO: Remove this hard extraction of name once this is fixed: https://github.com/elastic/kibana/issues/50522 const savedObject = await services.savedObjectsClient.get('alert', alertId); @@ -211,29 +210,13 @@ export const signalRulesAlertType = ({ `[+] Initial search call of signal rule name: "${name}", id: "${alertId}", rule_id: "${ruleId}"` ); const noReIndexResult = await services.callCluster('search', noReIndex); - const newSignalsCount = noReIndexResult.hits.total.value; - - if (newSignalsCount !== 0) { - const inputIndexes = inputIndex.join(', '); - - if (throttle && throttle !== 'no_actions') { - const alertInstance = services.alertInstanceFactory(ruleId!); - - alertInstance - .replaceState({ - signalsCount: newSignalsCount, - }) - .scheduleActions('default', { - inputIndexes, - outputIndex, - name, - alertId, - ruleId, - }); - } - + if (noReIndexResult.hits.total.value !== 0) { logger.info( - `Found ${newSignalsCount} signals from the indexes of "[${inputIndexes}]" using signal rule name: "${name}", id: "${alertId}", rule_id: "${ruleId}", pushing signals to index "${outputIndex}"` + `Found ${ + noReIndexResult.hits.total.value + } signals from the indexes of "[${inputIndex.join( + ', ' + )}]" using signal rule name: "${name}", id: "${alertId}", rule_id: "${ruleId}", pushing signals to index "${outputIndex}"` ); } diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts index 80bf69072f1a3..824228d92cf8f 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts @@ -51,7 +51,7 @@ export interface RuleAlertParams { threat: ThreatParams[] | undefined | null; type: 'query' | 'saved_query'; version: number; - throttle: string | undefined | null; + throttle: 'no_actions' | 'rule' | '1h' | '1d' | '7d' | undefined | null; } export type RuleTypeParams = Omit; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts index b01e908e34d37..b626476f98f8c 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts @@ -214,6 +214,7 @@ export const ruleToNdjson = (rule: Partial): Buffer => { * @param ruleId The ruleId to set which is optional and defaults to rule-1 */ export const getComplexRule = (ruleId = 'rule-1'): Partial => ({ + actions: [], name: 'Complex Rule Query', description: 'Complex Rule Query', false_positives: [ @@ -281,6 +282,7 @@ export const getComplexRule = (ruleId = 'rule-1'): Partial ], }, ], + throttle: 'no_actions', references: [ 'http://www.example.com/some-article-about-attack', 'Some plain text string here explaining why this is a valid thing to look out for', @@ -296,6 +298,7 @@ export const getComplexRule = (ruleId = 'rule-1'): Partial * @param ruleId The ruleId to set which is optional and defaults to rule-1 */ export const getComplexRuleOutput = (ruleId = 'rule-1'): Partial => ({ + actions: [], created_by: 'elastic', name: 'Complex Rule Query', description: 'Complex Rule Query', @@ -365,6 +368,7 @@ export const getComplexRuleOutput = (ruleId = 'rule-1'): Partial Date: Tue, 10 Mar 2020 16:50:22 +0100 Subject: [PATCH 06/19] fix types --- .../routes/schemas/create_rules_schema.test.ts | 2 +- .../routes/schemas/patch_rules_schema.test.ts | 2 +- .../routes/schemas/update_rules_schema.test.ts | 2 +- .../plugins/siem/server/lib/detection_engine/rules/types.ts | 2 ++ .../plugins/siem/server/lib/detection_engine/rules/utils.ts | 4 ++-- .../siem/server/lib/detection_engine/signals/build_signal.ts | 2 +- .../legacy/plugins/siem/server/lib/detection_engine/types.ts | 4 ++-- 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts index f3cfd6b0dde44..0f22ebc13fe5e 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts @@ -1239,7 +1239,7 @@ describe('create rules schema', () => { language: 'kuery', max_signals: 1, version: 1, - throttle: '1w', + throttle: '7d', }).error.message ).toEqual( 'child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]' diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts index c2d24803349f4..58d3166b6f0ae 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts @@ -1027,7 +1027,7 @@ describe('patch rules schema', () => { language: 'kuery', max_signals: 1, version: 1, - throttle: '1w', + throttle: '7d', }).error.message ).toEqual( 'child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]' diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts index 9cb9fa28acb4b..a29df1bc6b812 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts @@ -1258,7 +1258,7 @@ describe('create rules schema', () => { language: 'kuery', max_signals: 1, version: 1, - throttle: '1w', + throttle: '7d', }).error.message ).toEqual( 'child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]' diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts index 1efa46c6b8b57..109803997c618 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts @@ -195,3 +195,5 @@ export const isRuleStatusFindTypes = ( ): obj is Array> => { return obj ? obj.every(ruleStatus => isRuleStatusFindType(ruleStatus)) : false; }; + +export type Throttle = 'no_actions' | 'rule' | '1h' | '1d' | '7d' | null; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.ts index 456130fee3a32..2a6453b51ea33 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.ts @@ -5,7 +5,7 @@ */ import { pickBy, isEmpty } from 'lodash/fp'; -import { PatchRuleParams } from './types'; +import { PatchRuleParams, Throttle } from './types'; export const calculateInterval = ( interval: string | undefined, @@ -77,7 +77,7 @@ export const calculateName = ({ /* Alert throttle has to be null in case there are no actions or actions are exectured per rule exectution */ -export const getAlertThrottle = (throttle: string | null | undefined): null | string => { +export const getAlertThrottle = (throttle: Throttle | undefined): Throttle => { if (!throttle || ['no_actions', 'rule'].includes(throttle)) { return null; } diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_signal.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_signal.ts index 3fe2d1981a5d7..684cad99f09f0 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_signal.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_signal.ts @@ -70,7 +70,7 @@ export const removeInternalTagsFromRule = ( } else { const ruleWithoutInternalTags: Partial = { ...rule, - tags: rule.tags.filter((tag: string) => !tag.startsWith(INTERNAL_IDENTIFIER)), + tags: rule.tags.filter(tag => !tag.startsWith(INTERNAL_IDENTIFIER)), }; return ruleWithoutInternalTags; } diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts index 824228d92cf8f..ca2e490cb51ea 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts @@ -7,7 +7,7 @@ import { AlertAction } from '../../../../../../plugins/alerting/common/alert'; import { CallAPIOptions } from '../../../../../../../src/core/server'; import { Filter } from '../../../../../../../src/plugins/data/server'; -import { IRuleStatusAttributes } from './rules/types'; +import { IRuleStatusAttributes, Throttle } from './rules/types'; export type PartialFilter = Partial; @@ -51,7 +51,7 @@ export interface RuleAlertParams { threat: ThreatParams[] | undefined | null; type: 'query' | 'saved_query'; version: number; - throttle: 'no_actions' | 'rule' | '1h' | '1d' | '7d' | undefined | null; + throttle: Throttle | undefined; } export type RuleTypeParams = Omit; From 782d109d9154298058da6bb5d190b52a71c70ef2 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Wed, 11 Mar 2020 19:12:26 +0100 Subject: [PATCH 07/19] PR comments --- .../routes/__mocks__/request_responses.ts | 2 -- .../routes/rules/utils.test.ts | 14 ---------- .../detection_engine/routes/rules/utils.ts | 2 +- .../routes/rules/validate.test.ts | 1 - .../add_prepackaged_rules_schema.test.ts | 26 ++---------------- .../schemas/create_rules_bulk_schema.test.ts | 27 ++----------------- .../schemas/create_rules_schema.test.ts | 25 ++--------------- .../schemas/import_rules_schema.test.ts | 25 ++--------------- .../routes/schemas/patch_rules_schema.test.ts | 25 ++--------------- .../routes/schemas/response/schemas.ts | 8 +----- .../routes/schemas/schemas.ts | 4 +-- .../schemas/update_rules_schema.test.ts | 25 ++--------------- .../detection_engine/rules/create_rules.ts | 4 +-- .../create_rules_stream_from_ndjson.test.ts | 20 +++++++------- .../rules/get_export_all.test.ts | 2 +- .../rules/get_export_by_object_ids.test.ts | 3 +-- .../lib/detection_engine/rules/types.ts | 2 -- .../detection_engine/rules/update_rules.ts | 5 ++-- .../lib/detection_engine/rules/utils.test.ts | 19 +------------ .../lib/detection_engine/rules/utils.ts | 13 +-------- .../signals/__mocks__/es_results.ts | 2 -- .../signals/build_bulk_body.test.ts | 12 ++++++--- .../signals/build_bulk_body.ts | 7 +++++ .../signals/build_rule.test.ts | 12 ++++++--- .../detection_engine/signals/build_rule.ts | 9 +++++-- .../signals/search_after_bulk_create.test.ts | 16 +++++++++++ .../signals/search_after_bulk_create.ts | 9 +++++++ .../signals/signal_rule_alert_type.ts | 8 +++++- .../signals/single_bulk_create.test.ts | 10 +++++++ .../signals/single_bulk_create.ts | 7 +++++ .../siem/server/lib/detection_engine/types.ts | 15 +++++++---- .../security_and_spaces/tests/utils.ts | 3 --- 32 files changed, 121 insertions(+), 241 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 070c5ab91de48..69217d7eaef3f 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -349,7 +349,6 @@ export const getResult = (): RuleAlertType => ({ alertTypeId: 'siem.signals', consumer: 'siem', params: { - actions: [], description: 'Detecting root and admin users', ruleId: 'rule-1', index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], @@ -393,7 +392,6 @@ export const getResult = (): RuleAlertType => ({ ], }, ], - throttle: 'no_actions', references: ['http://www.example.com', 'https://ww.example.com'], version: 1, }, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts index e05143f88d6c7..91fe70e67f594 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts @@ -77,7 +77,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', filters: [ { query: { @@ -141,7 +140,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', filters: [ { query: { @@ -207,7 +205,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', filters: [ { query: { @@ -273,7 +270,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', filters: [ { query: { @@ -337,7 +333,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', filters: [ { query: { @@ -404,7 +399,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', filters: [ { query: { @@ -471,7 +465,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', filters: [ { query: { @@ -538,7 +531,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', filters: [ { query: { @@ -691,7 +683,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', filters: [ { query: { @@ -774,7 +765,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', filters: [ { query: { @@ -948,7 +938,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', filters: [ { query: { @@ -1070,7 +1059,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', timeline_id: 'some-timeline-id', timeline_title: 'some-timeline-title', to: 'now', @@ -1131,7 +1119,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', timeline_id: 'some-timeline-id', timeline_title: 'some-timeline-title', to: 'now', @@ -1181,7 +1168,6 @@ describe('utils', () => { ], }, ], - throttle: 'no_actions', timeline_id: 'some-timeline-id', timeline_title: 'some-timeline-title', to: 'now', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts index 5b04276317e8b..255536c5dd101 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts @@ -132,7 +132,7 @@ export const transformAlertToRule = ( to: alert.params.to, type: alert.params.type, threat: alert.params.threat, - throttle: alert.params.throttle, + throttle: alert.throttle, version: alert.params.version, status: ruleStatus?.attributes.status, status_date: ruleStatus?.attributes.statusDate, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts index 6d04bfbbbf0d8..5349173d38646 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts @@ -59,7 +59,6 @@ export const ruleOutput: RulesSchema = { ], }, ], - throttle: 'no_actions', version: 1, filters: [ { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts index 90f0dca16b822..7f0f93d365dae 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts @@ -1275,28 +1275,6 @@ describe('add prepackaged rules schema', () => { ); }); - test('You cannot set the throttle to a value other than no_actions, rule, 1h, 1d, or 7d', () => { - expect( - addPrepackagedRulesSchema.validate>({ - rule_id: 'rule-1', - risk_score: 50, - description: 'some description', - index: ['auditbeat-*'], - name: 'some-name', - severity: 'low', - type: 'query', - references: ['index-1'], - query: 'some query', - language: 'kuery', - max_signals: 1, - version: 1, - throttle: '1w', - }).error.message - ).toEqual( - 'child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]' - ); - }); - test('The default for "actions" will be an empty array', () => { expect( addPrepackagedRulesSchema.validate>({ @@ -1316,7 +1294,7 @@ describe('add prepackaged rules schema', () => { ).toEqual([]); }); - test('The default for "throttle" will be no_actions', () => { + test('The default for "throttle" will be null', () => { expect( addPrepackagedRulesSchema.validate>({ rule_id: 'rule-1', @@ -1332,6 +1310,6 @@ describe('add prepackaged rules schema', () => { max_signals: 1, version: 1, }).value.throttle - ).toEqual('no_actions'); + ).toEqual(null); }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_bulk_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_bulk_schema.test.ts index 91bb28ad6bc92..b29e718d7d47b 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_bulk_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_bulk_schema.test.ts @@ -142,29 +142,6 @@ describe('create_rules_bulk_schema', () => { ); }); - test('You cannot set the throttle to a value other than no_actions, rule, 1h, 1d, or 7d', () => { - expect( - createRulesBulkSchema.validate>([ - { - rule_id: 'rule-1', - risk_score: 50, - description: 'some description', - name: 'some-name', - severity: 'low', - type: 'query', - references: ['index-1'], - query: 'some query', - language: 'kuery', - max_signals: 1, - version: 1, - throttle: '1w', - }, - ]).error.message - ).toEqual( - '"value" at position 0 fails because [child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]]' - ); - }); - test('The default for "actions" will be an empty array', () => { expect( createRulesBulkSchema.validate>([ @@ -185,7 +162,7 @@ describe('create_rules_bulk_schema', () => { ).toEqual([]); }); - test('The default for "throttle" will be no_actions', () => { + test('The default for "throttle" will be null', () => { expect( createRulesBulkSchema.validate>([ { @@ -202,6 +179,6 @@ describe('create_rules_bulk_schema', () => { version: 1, }, ]).value[0].throttle - ).toEqual('no_actions'); + ).toEqual(null); }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts index 0f22ebc13fe5e..5aaafdc982c81 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts @@ -1225,27 +1225,6 @@ describe('create rules schema', () => { ); }); - test('You cannot set the throttle to a value other than no_actions, rule, 1h, 1d, or 7d', () => { - expect( - createRulesSchema.validate>({ - rule_id: 'rule-1', - risk_score: 50, - description: 'some description', - name: 'some-name', - severity: 'low', - type: 'query', - references: ['index-1'], - query: 'some query', - language: 'kuery', - max_signals: 1, - version: 1, - throttle: '7d', - }).error.message - ).toEqual( - 'child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]' - ); - }); - test('The default for "actions" will be an empty array', () => { expect( createRulesSchema.validate>({ @@ -1264,7 +1243,7 @@ describe('create rules schema', () => { ).toEqual([]); }); - test('The default for "throttle" will be no_actions', () => { + test('The default for "throttle" will be null', () => { expect( createRulesSchema.validate>({ rule_id: 'rule-1', @@ -1279,6 +1258,6 @@ describe('create rules schema', () => { max_signals: 1, version: 1, }).value.throttle - ).toEqual('no_actions'); + ).toEqual(null); }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts index ece4f679cf0c0..bdc4405cd15e7 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts @@ -1424,27 +1424,6 @@ describe('import rules schema', () => { ); }); - test('You cannot set the throttle to a value other than no_actions, rule, 1h, 1d, or 7d', () => { - expect( - importRulesSchema.validate>({ - rule_id: 'rule-1', - risk_score: 50, - description: 'some description', - name: 'some-name', - severity: 'low', - type: 'query', - references: ['index-1'], - query: 'some query', - language: 'kuery', - max_signals: 1, - version: 1, - throttle: '1w', - }).error.message - ).toEqual( - 'child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]' - ); - }); - test('The default for "actions" will be an empty array', () => { expect( importRulesSchema.validate>({ @@ -1463,7 +1442,7 @@ describe('import rules schema', () => { ).toEqual([]); }); - test('The default for "throttle" will be no_actions', () => { + test('The default for "throttle" will be null', () => { expect( importRulesSchema.validate>({ rule_id: 'rule-1', @@ -1478,6 +1457,6 @@ describe('import rules schema', () => { max_signals: 1, version: 1, }).value.throttle - ).toEqual('no_actions'); + ).toEqual(null); }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts index 58d3166b6f0ae..e66c1c28406c2 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts @@ -1013,27 +1013,6 @@ describe('patch rules schema', () => { ); }); - test('You cannot set the throttle to a value other than no_actions, rule, 1h, 1d, or 7d', () => { - expect( - patchRulesSchema.validate>({ - rule_id: 'rule-1', - risk_score: 50, - description: 'some description', - name: 'some-name', - severity: 'low', - type: 'query', - references: ['index-1'], - query: 'some query', - language: 'kuery', - max_signals: 1, - version: 1, - throttle: '7d', - }).error.message - ).toEqual( - 'child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]' - ); - }); - test('The default for "actions" will be an empty array', () => { expect( patchRulesSchema.validate>({ @@ -1052,7 +1031,7 @@ describe('patch rules schema', () => { ).toEqual([]); }); - test('The default for "throttle" will be no_actions', () => { + test('The default for "throttle" will be null', () => { expect( patchRulesSchema.validate>({ rule_id: 'rule-1', @@ -1067,6 +1046,6 @@ describe('patch rules schema', () => { max_signals: 1, version: 1, }).value.throttle - ).toEqual('no_actions'); + ).toEqual(null); }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts index 35f75b4ca87a1..b9202e47874cc 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts @@ -51,13 +51,7 @@ export const output_index = t.string; export const saved_id = t.string; export const timeline_id = t.string; export const timeline_title = t.string; -export const throttle = t.keyof({ - no_actions: null, - rule: null, - '1h': null, - '1d': null, - '7d': null, -}); +export const throttle = t.string; /** * Note that this is a plain unknown object because we allow the UI diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts index b3583071c652a..887bb4778b5e9 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts @@ -106,6 +106,4 @@ export const version = Joi.number() .integer() .min(1); export const actions = Joi.array().default([]); -export const throttle = Joi.string() - .valid('no_actions', 'rule', '1h', '1d', '7d') - .default('no_actions'); +export const throttle = Joi.string().default(null); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts index a29df1bc6b812..4e0f690f2e5d0 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts @@ -1244,27 +1244,6 @@ describe('create rules schema', () => { ); }); - test('You cannot set the throttle to a value other than no_actions, rule, 1h, 1d, or 7d', () => { - expect( - updateRulesSchema.validate>({ - rule_id: 'rule-1', - risk_score: 50, - description: 'some description', - name: 'some-name', - severity: 'low', - type: 'query', - references: ['index-1'], - query: 'some query', - language: 'kuery', - max_signals: 1, - version: 1, - throttle: '7d', - }).error.message - ).toEqual( - 'child "throttle" fails because ["throttle" must be one of [no_actions, rule, 1h, 1d, 7d]]' - ); - }); - test('The default for "actions" will be an empty array', () => { expect( updateRulesSchema.validate>({ @@ -1283,7 +1262,7 @@ describe('create rules schema', () => { ).toEqual([]); }); - test('The default for "throttle" will be no_actions', () => { + test('The default for "throttle" will be null', () => { expect( updateRulesSchema.validate>({ rule_id: 'rule-1', @@ -1298,6 +1277,6 @@ describe('create rules schema', () => { max_signals: 1, version: 1, }).value.throttle - ).toEqual('no_actions'); + ).toEqual(null); }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts index 770ec0375c41b..5ef868017e88f 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts @@ -8,7 +8,6 @@ import { Alert } from '../../../../../../../plugins/alerting/common'; import { APP_ID, SIGNALS_ID } from '../../../../common/constants'; import { CreateRuleParams } from './types'; import { addTags } from './add_tags'; -import { getAlertThrottle } from './utils'; export const createRules = ({ alertsClient, @@ -67,7 +66,6 @@ export const createRules = ({ riskScore, severity, threat, - throttle, to, type, references, @@ -76,7 +74,7 @@ export const createRules = ({ schedule: { interval }, enabled, actions, - throttle: getAlertThrottle(throttle), + throttle, }, }); }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts index 598fca0255607..da78680e9ca17 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts @@ -69,7 +69,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: 'no_actions', + throttle: null, references: [], version: 1, }, @@ -94,7 +94,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: 'no_actions', + throttle: null, references: [], version: 1, }, @@ -157,7 +157,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: 'no_actions', + throttle: null, references: [], version: 1, }, @@ -182,7 +182,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: 'no_actions', + throttle: null, references: [], version: 1, }, @@ -228,7 +228,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: 'no_actions', + throttle: null, references: [], version: 1, }, @@ -253,7 +253,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: 'no_actions', + throttle: null, references: [], version: 1, }, @@ -299,7 +299,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: 'no_actions', + throttle: null, references: [], version: 1, }); @@ -325,7 +325,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: 'no_actions', + throttle: null, references: [], version: 1, }); @@ -370,7 +370,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: 'no_actions', + throttle: null, references: [], version: 1, }); @@ -398,7 +398,7 @@ describe('create_rules_stream_from_ndjson', () => { max_signals: 100, tags: [], threat: [], - throttle: 'no_actions', + throttle: null, references: [], version: 1, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts index 7762f907967f5..c50702665e304 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts @@ -21,7 +21,7 @@ describe('getExportAll', () => { const exports = await getExportAll(alertsClient); expect(exports).toEqual({ rulesNdjson: - '{"actions":[],"created_at":"2019-12-13T16:40:33.400Z","updated_at":"2019-12-13T16:40:33.400Z","created_by":"elastic","description":"Detecting root and admin users","enabled":true,"false_positives":[],"filters":[{"query":{"match_phrase":{"host.name":"some-host"}}}],"from":"now-6m","id":"04128c15-0d1b-4716-a4c5-46997ac7f3bd","immutable":false,"index":["auditbeat-*","filebeat-*","packetbeat-*","winlogbeat-*"],"interval":"5m","rule_id":"rule-1","language":"kuery","output_index":".siem-signals","max_signals":100,"risk_score":50,"name":"Detect Root/Admin Users","query":"user.name: root or user.name: admin","references":["http://www.example.com","https://ww.example.com"],"timeline_id":"some-timeline-id","timeline_title":"some-timeline-title","meta":{"someMeta":"someField"},"severity":"high","updated_by":"elastic","tags":[],"to":"now","type":"query","threat":[{"framework":"MITRE ATT&CK","tactic":{"id":"TA0040","name":"impact","reference":"https://attack.mitre.org/tactics/TA0040/"},"technique":[{"id":"T1499","name":"endpoint denial of service","reference":"https://attack.mitre.org/techniques/T1499/"}]}],"throttle":"no_actions","version":1}\n', + '{"actions":[],"created_at":"2019-12-13T16:40:33.400Z","updated_at":"2019-12-13T16:40:33.400Z","created_by":"elastic","description":"Detecting root and admin users","enabled":true,"false_positives":[],"filters":[{"query":{"match_phrase":{"host.name":"some-host"}}}],"from":"now-6m","id":"04128c15-0d1b-4716-a4c5-46997ac7f3bd","immutable":false,"index":["auditbeat-*","filebeat-*","packetbeat-*","winlogbeat-*"],"interval":"5m","rule_id":"rule-1","language":"kuery","output_index":".siem-signals","max_signals":100,"risk_score":50,"name":"Detect Root/Admin Users","query":"user.name: root or user.name: admin","references":["http://www.example.com","https://ww.example.com"],"timeline_id":"some-timeline-id","timeline_title":"some-timeline-title","meta":{"someMeta":"someField"},"severity":"high","updated_by":"elastic","tags":[],"to":"now","type":"query","threat":[{"framework":"MITRE ATT&CK","tactic":{"id":"TA0040","name":"impact","reference":"https://attack.mitre.org/tactics/TA0040/"},"technique":[{"id":"T1499","name":"endpoint denial of service","reference":"https://attack.mitre.org/techniques/T1499/"}]}],"version":1}\n', exportDetails: '{"exported_count":1,"missing_rules":[],"missing_rules_count":0}\n', }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts index 2404ae6dc16cb..92890296b881c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts @@ -29,7 +29,7 @@ describe('get_export_by_object_ids', () => { const exports = await getExportByObjectIds(alertsClient, objects); expect(exports).toEqual({ rulesNdjson: - '{"actions":[],"created_at":"2019-12-13T16:40:33.400Z","updated_at":"2019-12-13T16:40:33.400Z","created_by":"elastic","description":"Detecting root and admin users","enabled":true,"false_positives":[],"filters":[{"query":{"match_phrase":{"host.name":"some-host"}}}],"from":"now-6m","id":"04128c15-0d1b-4716-a4c5-46997ac7f3bd","immutable":false,"index":["auditbeat-*","filebeat-*","packetbeat-*","winlogbeat-*"],"interval":"5m","rule_id":"rule-1","language":"kuery","output_index":".siem-signals","max_signals":100,"risk_score":50,"name":"Detect Root/Admin Users","query":"user.name: root or user.name: admin","references":["http://www.example.com","https://ww.example.com"],"timeline_id":"some-timeline-id","timeline_title":"some-timeline-title","meta":{"someMeta":"someField"},"severity":"high","updated_by":"elastic","tags":[],"to":"now","type":"query","threat":[{"framework":"MITRE ATT&CK","tactic":{"id":"TA0040","name":"impact","reference":"https://attack.mitre.org/tactics/TA0040/"},"technique":[{"id":"T1499","name":"endpoint denial of service","reference":"https://attack.mitre.org/techniques/T1499/"}]}],"throttle":"no_actions","version":1}\n', + '{"actions":[],"created_at":"2019-12-13T16:40:33.400Z","updated_at":"2019-12-13T16:40:33.400Z","created_by":"elastic","description":"Detecting root and admin users","enabled":true,"false_positives":[],"filters":[{"query":{"match_phrase":{"host.name":"some-host"}}}],"from":"now-6m","id":"04128c15-0d1b-4716-a4c5-46997ac7f3bd","immutable":false,"index":["auditbeat-*","filebeat-*","packetbeat-*","winlogbeat-*"],"interval":"5m","rule_id":"rule-1","language":"kuery","output_index":".siem-signals","max_signals":100,"risk_score":50,"name":"Detect Root/Admin Users","query":"user.name: root or user.name: admin","references":["http://www.example.com","https://ww.example.com"],"timeline_id":"some-timeline-id","timeline_title":"some-timeline-title","meta":{"someMeta":"someField"},"severity":"high","updated_by":"elastic","tags":[],"to":"now","type":"query","threat":[{"framework":"MITRE ATT&CK","tactic":{"id":"TA0040","name":"impact","reference":"https://attack.mitre.org/tactics/TA0040/"},"technique":[{"id":"T1499","name":"endpoint denial of service","reference":"https://attack.mitre.org/techniques/T1499/"}]}],"version":1}\n', exportDetails: '{"exported_count":1,"missing_rules":[],"missing_rules_count":0}\n', }); }); @@ -118,7 +118,6 @@ describe('get_export_by_object_ids', () => { ], }, ], - throttle: 'no_actions', version: 1, }, ], diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts index 109803997c618..1efa46c6b8b57 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts @@ -195,5 +195,3 @@ export const isRuleStatusFindTypes = ( ): obj is Array> => { return obj ? obj.every(ruleStatus => isRuleStatusFindType(ruleStatus)) : false; }; - -export type Throttle = 'no_actions' | 'rule' | '1h' | '1d' | '7d' | null; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts index deb2a85a008a4..8518ccc3d8c06 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts @@ -9,7 +9,7 @@ import { readRules } from './read_rules'; import { IRuleSavedAttributesSavedObjectAttributes, UpdateRuleParams } from './types'; import { addTags } from './add_tags'; import { ruleStatusSavedObjectType } from './saved_object_mappings'; -import { calculateVersion, getAlertThrottle } from './utils'; +import { calculateVersion } from './utils'; export const updateRules = async ({ alertsClient, @@ -85,7 +85,7 @@ export const updateRules = async ({ name, schedule: { interval }, actions, - throttle: getAlertThrottle(throttle), + throttle, params: { description, ruleId: rule.params.ruleId, @@ -105,7 +105,6 @@ export const updateRules = async ({ riskScore, severity, threat, - throttle, to, type, references, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.test.ts index 09d70ad88bcfb..b7c36b20f44be 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { calculateInterval, calculateVersion, calculateName, getAlertThrottle } from './utils'; +import { calculateInterval, calculateVersion, calculateName } from './utils'; import { PatchRuleParams } from './types'; describe('utils', () => { @@ -70,21 +70,4 @@ describe('utils', () => { expect(name).toEqual('untitled'); }); }); - - describe('#getAlertThrottle', () => { - test('should return null if throttle is undefined', () => { - const throttle = getAlertThrottle(undefined); - expect(throttle).toEqual(null); - }); - - test('should return null if throttle is null', () => { - const throttle = getAlertThrottle(null); - expect(throttle).toEqual(null); - }); - - test('should return string if throttle is string', () => { - const throttle = getAlertThrottle('1d'); - expect(throttle).toEqual('1d'); - }); - }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.ts index 2a6453b51ea33..7d6091f6b97fa 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/utils.ts @@ -5,7 +5,7 @@ */ import { pickBy, isEmpty } from 'lodash/fp'; -import { PatchRuleParams, Throttle } from './types'; +import { PatchRuleParams } from './types'; export const calculateInterval = ( interval: string | undefined, @@ -73,14 +73,3 @@ export const calculateName = ({ return 'untitled'; } }; - -/* - Alert throttle has to be null in case there are no actions or actions are exectured per rule exectution -*/ -export const getAlertThrottle = (throttle: Throttle | undefined): Throttle => { - if (!throttle || ['no_actions', 'rule'].includes(throttle)) { - return null; - } - - return throttle; -}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts index 3a8347af1c6a7..fded0696ff8bf 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts @@ -13,7 +13,6 @@ export const sampleRuleAlertParams = ( maxSignals?: number | undefined, riskScore?: number | undefined ): RuleTypeParams => ({ - actions: [], ruleId: 'rule-1', description: 'Detecting root and admin users', falsePositives: [], @@ -35,7 +34,6 @@ export const sampleRuleAlertParams = ( timelineTitle: undefined, meta: undefined, threat: undefined, - throttle: 'no_actions', version: 1, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts index 8c3dea2d5b0bd..bb83ee594d5e8 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts @@ -25,6 +25,7 @@ describe('buildBulkBody', () => { ruleParams: sampleParams, id: sampleRuleGuid, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -32,6 +33,7 @@ describe('buildBulkBody', () => { interval: '5m', enabled: true, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); // Timestamp will potentially always be different so remove it for the test delete fakeSignalSourceHit['@timestamp']; @@ -78,7 +80,6 @@ describe('buildBulkBody', () => { references: ['http://google.com'], severity: 'high', tags: ['some fake tag 1', 'some fake tag 2'], - throttle: 'no_actions', type: 'query', to: 'now', enabled: true, @@ -107,6 +108,7 @@ describe('buildBulkBody', () => { ruleParams: sampleParams, id: sampleRuleGuid, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -114,6 +116,7 @@ describe('buildBulkBody', () => { interval: '5m', enabled: true, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); // Timestamp will potentially always be different so remove it for the test delete fakeSignalSourceHit['@timestamp']; @@ -169,7 +172,6 @@ describe('buildBulkBody', () => { references: ['http://google.com'], severity: 'high', tags: ['some fake tag 1', 'some fake tag 2'], - throttle: 'no_actions', type: 'query', to: 'now', enabled: true, @@ -197,6 +199,7 @@ describe('buildBulkBody', () => { ruleParams: sampleParams, id: sampleRuleGuid, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -204,6 +207,7 @@ describe('buildBulkBody', () => { interval: '5m', enabled: true, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); // Timestamp will potentially always be different so remove it for the test delete fakeSignalSourceHit['@timestamp']; @@ -258,7 +262,6 @@ describe('buildBulkBody', () => { references: ['http://google.com'], severity: 'high', tags: ['some fake tag 1', 'some fake tag 2'], - throttle: 'no_actions', type: 'query', to: 'now', enabled: true, @@ -284,6 +287,7 @@ describe('buildBulkBody', () => { ruleParams: sampleParams, id: sampleRuleGuid, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -291,6 +295,7 @@ describe('buildBulkBody', () => { interval: '5m', enabled: true, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); // Timestamp will potentially always be different so remove it for the test delete fakeSignalSourceHit['@timestamp']; @@ -340,7 +345,6 @@ describe('buildBulkBody', () => { references: ['http://google.com'], severity: 'high', tags: ['some fake tag 1', 'some fake tag 2'], - throttle: 'no_actions', type: 'query', to: 'now', enabled: true, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.ts index e77755073b374..f75eab668a9a6 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.ts @@ -9,11 +9,13 @@ import { buildRule } from './build_rule'; import { buildSignal } from './build_signal'; import { buildEventTypeSignal } from './build_event_type_signal'; import { RuleTypeParams } from '../types'; +import { AlertAction } from '../../../../../../../plugins/alerting/common'; interface BuildBulkBodyParams { doc: SignalSourceHit; ruleParams: RuleTypeParams; id: string; + actions: AlertAction[]; name: string; createdAt: string; createdBy: string; @@ -22,6 +24,7 @@ interface BuildBulkBodyParams { interval: string; enabled: boolean; tags: string[]; + throttle: string | null; } // format search_after result for signals index. @@ -30,6 +33,7 @@ export const buildBulkBody = ({ ruleParams, id, name, + actions, createdAt, createdBy, updatedAt, @@ -37,8 +41,10 @@ export const buildBulkBody = ({ interval, enabled, tags, + throttle, }: BuildBulkBodyParams): SignalHit => { const rule = buildRule({ + actions, ruleParams, id, name, @@ -49,6 +55,7 @@ export const buildBulkBody = ({ updatedBy, interval, tags, + throttle, }); const signal = buildSignal(doc, rule); const event = buildEventTypeSignal(doc); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts index 412f44321434a..a53c33b271a8b 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts @@ -27,6 +27,7 @@ describe('buildRule', () => { }, ]; const rule = buildRule({ + actions: [], ruleParams, name: 'some-name', id: sampleRuleGuid, @@ -37,6 +38,7 @@ describe('buildRule', () => { updatedBy: 'elastic', interval: 'some interval', tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); const expected: Partial = { actions: [], @@ -59,7 +61,6 @@ describe('buildRule', () => { rule_id: 'rule-1', severity: 'high', tags: ['some fake tag 1', 'some fake tag 2'], - throttle: 'no_actions', to: 'now', type: 'query', updated_by: 'elastic', @@ -85,6 +86,7 @@ describe('buildRule', () => { const ruleParams = sampleRuleAlertParams(); ruleParams.filters = undefined; const rule = buildRule({ + actions: [], ruleParams, name: 'some-name', id: sampleRuleGuid, @@ -95,6 +97,7 @@ describe('buildRule', () => { updatedBy: 'elastic', interval: 'some interval', tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); const expected: Partial = { actions: [], @@ -117,7 +120,6 @@ describe('buildRule', () => { rule_id: 'rule-1', severity: 'high', tags: ['some fake tag 1', 'some fake tag 2'], - throttle: 'no_actions', to: 'now', type: 'query', updated_by: 'elastic', @@ -132,6 +134,7 @@ describe('buildRule', () => { const ruleParams = sampleRuleAlertParams(); ruleParams.filters = undefined; const rule = buildRule({ + actions: [], ruleParams, name: 'some-name', id: sampleRuleGuid, @@ -142,6 +145,7 @@ describe('buildRule', () => { updatedBy: 'elastic', interval: 'some interval', tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); const expected: Partial = { actions: [], @@ -164,7 +168,6 @@ describe('buildRule', () => { rule_id: 'rule-1', severity: 'high', tags: ['some fake tag 1', 'some fake tag 2'], - throttle: 'no_actions', to: 'now', type: 'query', updated_by: 'elastic', @@ -177,8 +180,8 @@ describe('buildRule', () => { test('it omits a null value such as if throttle is undefined if is present', () => { const ruleParams = sampleRuleAlertParams(); - ruleParams.throttle = undefined; const rule = buildRule({ + actions: [], ruleParams, name: 'some-name', id: sampleRuleGuid, @@ -189,6 +192,7 @@ describe('buildRule', () => { updatedBy: 'elastic', interval: 'some interval', tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); const expected: Partial = { actions: [], diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts index ea81e319c16b9..8b30a3faeb5a4 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts @@ -6,11 +6,13 @@ import { pickBy } from 'lodash/fp'; import { RuleTypeParams, OutputRuleAlertRest } from '../types'; +import { AlertAction } from '../../../../../../../plugins/alerting/common'; interface BuildRuleParams { ruleParams: RuleTypeParams; name: string; id: string; + actions: AlertAction[]; enabled: boolean; createdAt: string; createdBy: string; @@ -18,12 +20,14 @@ interface BuildRuleParams { updatedBy: string; interval: string; tags: string[]; + throttle: string | null; } export const buildRule = ({ ruleParams, name, id, + actions, enabled, createdAt, createdBy, @@ -31,11 +35,12 @@ export const buildRule = ({ updatedBy, interval, tags, + throttle, }: BuildRuleParams): Partial => { return pickBy((value: unknown) => value != null, { id, rule_id: ruleParams.ruleId, - actions: ruleParams.actions, + actions, false_positives: ruleParams.falsePositives, saved_id: ruleParams.savedId, timeline_id: ruleParams.timelineId, @@ -62,7 +67,7 @@ export const buildRule = ({ created_by: createdBy, updated_by: updatedBy, threat: ruleParams.threat, - throttle: ruleParams.throttle, + throttle, version: ruleParams.version, created_at: createdAt, updated_at: updatedAt, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.test.ts index bf7a97a29aef3..fae86b84da45f 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.test.ts @@ -40,6 +40,7 @@ describe('searchAfterAndBulkCreate', () => { id: sampleRuleGuid, signalsIndex: DEFAULT_SIGNALS_INDEX, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -49,6 +50,7 @@ describe('searchAfterAndBulkCreate', () => { pageSize: 1, filter: undefined, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); expect(mockService.callCluster).toHaveBeenCalledTimes(0); expect(result).toEqual(true); @@ -95,6 +97,7 @@ describe('searchAfterAndBulkCreate', () => { id: sampleRuleGuid, signalsIndex: DEFAULT_SIGNALS_INDEX, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -104,6 +107,7 @@ describe('searchAfterAndBulkCreate', () => { pageSize: 1, filter: undefined, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); expect(mockService.callCluster).toHaveBeenCalledTimes(5); expect(result).toEqual(true); @@ -121,6 +125,7 @@ describe('searchAfterAndBulkCreate', () => { id: sampleRuleGuid, signalsIndex: DEFAULT_SIGNALS_INDEX, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -130,6 +135,7 @@ describe('searchAfterAndBulkCreate', () => { pageSize: 1, filter: undefined, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); expect(mockLogger.error).toHaveBeenCalled(); expect(result).toEqual(false); @@ -154,6 +160,7 @@ describe('searchAfterAndBulkCreate', () => { id: sampleRuleGuid, signalsIndex: DEFAULT_SIGNALS_INDEX, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -163,6 +170,7 @@ describe('searchAfterAndBulkCreate', () => { pageSize: 1, filter: undefined, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); expect(mockLogger.error).toHaveBeenCalled(); expect(result).toEqual(false); @@ -187,6 +195,7 @@ describe('searchAfterAndBulkCreate', () => { id: sampleRuleGuid, signalsIndex: DEFAULT_SIGNALS_INDEX, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -196,6 +205,7 @@ describe('searchAfterAndBulkCreate', () => { pageSize: 1, filter: undefined, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); expect(result).toEqual(true); }); @@ -222,6 +232,7 @@ describe('searchAfterAndBulkCreate', () => { id: sampleRuleGuid, signalsIndex: DEFAULT_SIGNALS_INDEX, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -231,6 +242,7 @@ describe('searchAfterAndBulkCreate', () => { pageSize: 1, filter: undefined, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); expect(result).toEqual(true); }); @@ -257,6 +269,7 @@ describe('searchAfterAndBulkCreate', () => { id: sampleRuleGuid, signalsIndex: DEFAULT_SIGNALS_INDEX, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -266,6 +279,7 @@ describe('searchAfterAndBulkCreate', () => { pageSize: 1, filter: undefined, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); expect(result).toEqual(true); }); @@ -294,6 +308,7 @@ describe('searchAfterAndBulkCreate', () => { id: sampleRuleGuid, signalsIndex: DEFAULT_SIGNALS_INDEX, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -303,6 +318,7 @@ describe('searchAfterAndBulkCreate', () => { pageSize: 1, filter: undefined, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); expect(result).toEqual(false); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts index 1cfd2f812a195..dc15c98a65ed5 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts @@ -5,6 +5,7 @@ */ import { AlertServices } from '../../../../../../../plugins/alerting/server'; +import { AlertAction } from '../../../../../../../plugins/alerting/common'; import { RuleTypeParams } from '../types'; import { Logger } from '../../../../../../../../src/core/server'; import { singleSearchAfter } from './single_search_after'; @@ -19,6 +20,7 @@ interface SearchAfterAndBulkCreateParams { id: string; signalsIndex: string; name: string; + actions: AlertAction[]; createdAt: string; createdBy: string; updatedBy: string; @@ -28,6 +30,7 @@ interface SearchAfterAndBulkCreateParams { pageSize: number; filter: unknown; tags: string[]; + throttle: string | null; } // search_after through documents and re-index using bulk endpoint. @@ -39,6 +42,7 @@ export const searchAfterAndBulkCreate = async ({ id, signalsIndex, filter, + actions, name, createdAt, createdBy, @@ -48,6 +52,7 @@ export const searchAfterAndBulkCreate = async ({ enabled, pageSize, tags, + throttle, }: SearchAfterAndBulkCreateParams): Promise => { if (someResult.hits.hits.length === 0) { return true; @@ -61,6 +66,7 @@ export const searchAfterAndBulkCreate = async ({ logger, id, signalsIndex, + actions, name, createdAt, createdBy, @@ -69,6 +75,7 @@ export const searchAfterAndBulkCreate = async ({ interval, enabled, tags, + throttle, }); const totalHits = typeof someResult.hits.total === 'number' ? someResult.hits.total : someResult.hits.total.value; @@ -123,6 +130,7 @@ export const searchAfterAndBulkCreate = async ({ logger, id, signalsIndex, + actions, name, createdAt, createdBy, @@ -131,6 +139,7 @@ export const searchAfterAndBulkCreate = async ({ interval, enabled, tags, + throttle, }); logger.debug('finished next bulk index'); } catch (exc) { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index 5377ad261e3fb..4bcd0c15b47be 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -13,6 +13,7 @@ import { DEFAULT_MAX_SIGNALS, DEFAULT_SEARCH_AFTER_PAGE_SIZE, } from '../../../../common/constants'; +import { AlertAction } from '../../../../../../../plugins/alerting/common'; import { buildEventsSearchQuery } from './build_events_query'; import { getInputIndex } from './get_input_output_index'; @@ -26,12 +27,14 @@ interface AlertAttributes { enabled: boolean; name: string; tags: string[]; + actions: AlertAction[]; createdBy: string; createdAt: string; updatedBy: string; schedule: { interval: string; }; + throttle: string | null; } export const signalRulesAlertType = ({ logger, @@ -72,7 +75,6 @@ export const signalRulesAlertType = ({ riskScore: schema.number(), severity: schema.string(), threat: schema.nullable(schema.arrayOf(schema.object({}, { allowUnknowns: true }))), - throttle: schema.string(), to: schema.string(), type: schema.string(), references: schema.arrayOf(schema.string(), { defaultValue: [] }), @@ -144,6 +146,8 @@ export const signalRulesAlertType = ({ const updatedAt = savedObject.updated_at ?? ''; const interval = savedObject.attributes.schedule.interval; const enabled = savedObject.attributes.enabled; + const actions = savedObject.attributes.actions; + const throttle = savedObject.attributes.throttle; const gap = getGapBetweenRuns({ previousStartedAt: previousStartedAt != null ? moment(previousStartedAt) : null, // TODO: Remove this once previousStartedAt is no longer a string interval, @@ -228,6 +232,7 @@ export const signalRulesAlertType = ({ id: alertId, signalsIndex: outputIndex, filter: esFilter, + actions, name, createdBy, createdAt, @@ -237,6 +242,7 @@ export const signalRulesAlertType = ({ enabled, pageSize: searchAfterSize, tags, + throttle, }); if (bulkIndexResult) { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.test.ts index 09e2c6b4fd586..afabd4c44de7d 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.test.ts @@ -151,6 +151,7 @@ describe('singleBulkCreate', () => { logger: mockLogger, id: sampleRuleGuid, signalsIndex: DEFAULT_SIGNALS_INDEX, + actions: [], name: 'rule-name', createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', @@ -159,6 +160,7 @@ describe('singleBulkCreate', () => { interval: '5m', enabled: true, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); expect(successfulsingleBulkCreate).toEqual(true); }); @@ -182,6 +184,7 @@ describe('singleBulkCreate', () => { id: sampleRuleGuid, signalsIndex: DEFAULT_SIGNALS_INDEX, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -189,6 +192,7 @@ describe('singleBulkCreate', () => { interval: '5m', enabled: true, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); expect(successfulsingleBulkCreate).toEqual(true); }); @@ -204,6 +208,7 @@ describe('singleBulkCreate', () => { id: sampleRuleGuid, signalsIndex: DEFAULT_SIGNALS_INDEX, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -211,6 +216,7 @@ describe('singleBulkCreate', () => { interval: '5m', enabled: true, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); expect(successfulsingleBulkCreate).toEqual(true); }); @@ -227,6 +233,7 @@ describe('singleBulkCreate', () => { id: sampleRuleGuid, signalsIndex: DEFAULT_SIGNALS_INDEX, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -234,6 +241,7 @@ describe('singleBulkCreate', () => { interval: '5m', enabled: true, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); expect(mockLogger.error).not.toHaveBeenCalled(); @@ -252,6 +260,7 @@ describe('singleBulkCreate', () => { id: sampleRuleGuid, signalsIndex: DEFAULT_SIGNALS_INDEX, name: 'rule-name', + actions: [], createdAt: '2020-01-28T15:58:34.810Z', updatedAt: '2020-01-28T15:59:14.004Z', createdBy: 'elastic', @@ -259,6 +268,7 @@ describe('singleBulkCreate', () => { interval: '5m', enabled: true, tags: ['some fake tag 1', 'some fake tag 2'], + throttle: null, }); expect(mockLogger.error).toHaveBeenCalled(); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts index 7d6d6d99fa422..95218a94fbfe9 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts @@ -12,6 +12,7 @@ import { RuleTypeParams } from '../types'; import { generateId } from './utils'; import { buildBulkBody } from './build_bulk_body'; import { Logger } from '../../../../../../../../src/core/server'; +import { AlertAction } from '../../../../../../../plugins/alerting/common'; interface SingleBulkCreateParams { someResult: SignalSearchResponse; @@ -20,6 +21,7 @@ interface SingleBulkCreateParams { logger: Logger; id: string; signalsIndex: string; + actions: AlertAction[]; name: string; createdAt: string; createdBy: string; @@ -28,6 +30,7 @@ interface SingleBulkCreateParams { interval: string; enabled: boolean; tags: string[]; + throttle: string | null; } /** @@ -60,6 +63,7 @@ export const singleBulkCreate = async ({ logger, id, signalsIndex, + actions, name, createdAt, createdBy, @@ -68,6 +72,7 @@ export const singleBulkCreate = async ({ interval, enabled, tags, + throttle, }: SingleBulkCreateParams): Promise => { someResult.hits.hits = filterDuplicateRules(id, someResult); @@ -99,6 +104,7 @@ export const singleBulkCreate = async ({ doc, ruleParams, id, + actions, name, createdAt, createdBy, @@ -107,6 +113,7 @@ export const singleBulkCreate = async ({ interval, enabled, tags, + throttle, }), ]); const start = performance.now(); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts index ca2e490cb51ea..abb6983f82dc3 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AlertAction } from '../../../../../../plugins/alerting/common/alert'; +import { AlertAction } from '../../../../../../plugins/alerting/common'; import { CallAPIOptions } from '../../../../../../../src/core/server'; import { Filter } from '../../../../../../../src/plugins/data/server'; -import { IRuleStatusAttributes, Throttle } from './rules/types'; +import { IRuleStatusAttributes } from './rules/types'; export type PartialFilter = Partial; @@ -51,10 +51,13 @@ export interface RuleAlertParams { threat: ThreatParams[] | undefined | null; type: 'query' | 'saved_query'; version: number; - throttle: Throttle | undefined; + throttle: string | null; } -export type RuleTypeParams = Omit; +export type RuleTypeParams = Omit< + RuleAlertParams, + 'name' | 'enabled' | 'interval' | 'tags' | 'actions' | 'throttle' +>; export type RuleAlertParamsRest = Omit< RuleAlertParams, @@ -96,11 +99,13 @@ export type RuleAlertParamsRest = Omit< last_success_message?: IRuleStatusAttributes['lastSuccessMessage'] | undefined; }; -export type OutputRuleAlertRest = RuleAlertParamsRest & { +export type OutputRuleAlertRest = Omit & { id: string; created_by: string | undefined | null; updated_by: string | undefined | null; immutable: boolean; + tags: string[]; + throttle?: string | null; }; export type ImportRuleAlertRest = Omit & { diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts index b626476f98f8c..51983ab037b3f 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts @@ -134,7 +134,6 @@ export const getSimpleRuleOutput = (ruleId = 'rule-1'): Partial ], }, ], - throttle: 'no_actions', references: [ 'http://www.example.com/some-article-about-attack', 'Some plain text string here explaining why this is a valid thing to look out for', @@ -368,7 +366,6 @@ export const getComplexRuleOutput = (ruleId = 'rule-1'): Partial Date: Thu, 12 Mar 2020 09:56:48 +0100 Subject: [PATCH 08/19] types --- .../legacy/plugins/siem/server/lib/detection_engine/types.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts index 66a042c51a19f..00b7161373cab 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts @@ -100,13 +100,11 @@ export type RuleAlertParamsRest = Omit< last_success_message?: IRuleStatusAttributes['lastSuccessMessage'] | undefined; }; -export type OutputRuleAlertRest = Omit & { +export type OutputRuleAlertRest = RuleAlertParamsRest & { id: string; created_by: string | undefined | null; updated_by: string | undefined | null; immutable: boolean; - tags: string[]; - throttle?: string | null; }; export type ImportRuleAlertRest = Omit & { From 782d5004c1edcaa10e5462495399ce3ffe2a53d3 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Thu, 12 Mar 2020 13:01:17 +0100 Subject: [PATCH 09/19] try to fix types --- .../detection_engine/routes/rules/utils.test.ts | 14 +++++++------- .../lib/detection_engine/rules/patch_rules.ts | 4 +--- .../lib/detection_engine/rules/update_rules.ts | 4 ++-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts index 6e10c776281af..503324b5a8f30 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts @@ -36,7 +36,7 @@ describe('utils', () => { test('should work with a full data set', () => { const fullRule = getResult(); const rule = transformAlertToRule(fullRule); - const expected: OutputRuleAlertRest = { + const expected: Omit = { actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', @@ -363,7 +363,7 @@ describe('utils', () => { const fullRule = getResult(); fullRule.enabled = false; const ruleWithEnabledFalse = transformAlertToRule(fullRule); - const expected: OutputRuleAlertRest = { + const expected: Omit = { actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', @@ -430,7 +430,7 @@ describe('utils', () => { const fullRule = getResult(); fullRule.params.immutable = false; const ruleWithEnabledFalse = transformAlertToRule(fullRule); - const expected: OutputRuleAlertRest = { + const expected: Omit = { actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', @@ -497,7 +497,7 @@ describe('utils', () => { const fullRule = getResult(); fullRule.tags = ['tag 1', 'tag 2', `${INTERNAL_IDENTIFIER}_some_other_value`]; const rule = transformAlertToRule(fullRule); - const expected: OutputRuleAlertRest = { + const expected: Omit = { actions: [], created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -648,7 +648,7 @@ describe('utils', () => { total: 0, data: [getResult()], }); - const expected: OutputRuleAlertRest = { + const expected: Omit = { actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', @@ -731,7 +731,7 @@ describe('utils', () => { describe('transform', () => { test('outputs 200 if the data is of type siem alert', () => { const output = transform(getResult()); - const expected: OutputRuleAlertRest = { + const expected: Omit = { actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', @@ -905,7 +905,7 @@ describe('utils', () => { describe('transformOrBulkError', () => { test('outputs 200 if the data is of type siem alert', () => { const output = transformOrBulkError('rule-1', getResult()); - const expected: OutputRuleAlertRest = { + const expected: Omit = { actions: [], created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts index f1406deeb04a9..776a367158abf 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts @@ -53,7 +53,6 @@ export const patchRules = async ({ } const calculatedVersion = calculateVersion(rule.params.immutable, rule.params.version, { - actions, description, falsePositives, query, @@ -73,7 +72,6 @@ export const patchRules = async ({ severity, tags, threat, - throttle, to, type, references, @@ -120,7 +118,7 @@ export const patchRules = async ({ schedule: { interval: calculateInterval(interval, rule.schedule.interval), }, - actions: actions ?? rule.actions ?? [], + actions: rule.actions, params: nextParams, }, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts index 8e3dd49933296..02f08cda79bed 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts @@ -86,8 +86,8 @@ export const updateRules = async ({ tags: addTags(tags, rule.params.ruleId, immutable), name, schedule: { interval }, - actions, - throttle, + actions: rule.actions, + throttle: throttle ?? rule.throttle ?? null, params: { description, ruleId: rule.params.ruleId, From 2b0afb4517f531af5aa54410245e1ab206a54eb6 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Sun, 15 Mar 2020 12:06:18 +0100 Subject: [PATCH 10/19] PR comments --- .../routes/schemas/response/schemas.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts index 98d909ab5eab3..013660d0eee73 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts @@ -26,10 +26,19 @@ export const file_name = t.string; export const filters = t.array(t.unknown); // Filters are not easily type-able yet /** - * TODO: Right now the actions is an "unknown", when it could more than likely - * become the actual AlertAction as a type. + * Params is an "object", since it is a type of AlertActionParams which is action templates. + * @see x-pack/plugins/alerting/common/alert.ts */ -export const actions = t.array(t.unknown); // Actions are not easily type-able yet +export const action = t.exact( + t.type({ + group: t.string, + id: t.string, + actionTypeId: t.string, + params: t.object, + }) +); + +export const actions = t.array(action); // TODO: Create a regular expression type or custom date math part type here export const from = t.string; From 4da10a4a96f976acff246478fa5765781de5587a Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Tue, 17 Mar 2020 12:54:56 +0100 Subject: [PATCH 11/19] fix merge conflicts --- .../lib/detection_engine/rules/patch_rules.ts | 4 ++-- .../lib/detection_engine/rules/update_rules.ts | 4 ++-- .../signals/signal_rule_alert_type.ts | 13 ++----------- .../server/lib/detection_engine/signals/types.ts | 3 +++ 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts index 776a367158abf..fa8fe3c443681 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts @@ -113,12 +113,12 @@ export const patchRules = async ({ id: rule.id, data: { tags: addTags(tags ?? rule.tags, rule.params.ruleId, immutable ?? rule.params.immutable), - throttle: throttle ?? rule.throttle ?? null, + throttle: throttle ?? throttle === null ? null : rule.throttle, name: calculateName({ updatedName: name, originalName: rule.name }), schedule: { interval: calculateInterval(interval, rule.schedule.interval), }, - actions: rule.actions, + actions: actions ?? rule.actions, params: nextParams, }, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts index 02f08cda79bed..6570c25eec388 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts @@ -86,8 +86,8 @@ export const updateRules = async ({ tags: addTags(tags, rule.params.ruleId, immutable), name, schedule: { interval }, - actions: rule.actions, - throttle: throttle ?? rule.throttle ?? null, + actions: actions ?? rule.actions, + throttle: throttle ?? throttle === null ? null : rule.throttle, params: { description, ruleId: rule.params.ruleId, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index 7e87797efe0d9..d870ce0b23fb6 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -5,18 +5,7 @@ */ import { Logger } from 'src/core/server'; -<<<<<<< HEAD -import moment from 'moment'; -import { i18n } from '@kbn/i18n'; -import { - SIGNALS_ID, - DEFAULT_MAX_SIGNALS, - DEFAULT_SEARCH_AFTER_PAGE_SIZE, -} from '../../../../common/constants'; -import { AlertAction } from '../../../../../../../plugins/alerting/common'; -======= import { SIGNALS_ID, DEFAULT_SEARCH_AFTER_PAGE_SIZE } from '../../../../common/constants'; ->>>>>>> a755e55907ef0b084c850814809e77df650d07bc import { buildEventsSearchQuery } from './build_events_query'; import { getInputIndex } from './get_input_output_index'; @@ -74,6 +63,7 @@ export const signalRulesAlertType = ({ }); const { + actions, name, tags, createdAt, @@ -81,6 +71,7 @@ export const signalRulesAlertType = ({ updatedBy, enabled, schedule: { interval }, + throttle, } = savedObject.attributes; const updatedAt = savedObject.updated_at ?? ''; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts index eaed3f2ead3a5..a04b39cacaa2f 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts @@ -11,6 +11,7 @@ import { State, AlertExecutorOptions, } from '../../../../../../../plugins/alerting/server'; +import { AlertAction } from '../../../../../../../plugins/alerting/common'; export interface SignalsParams { signalIds: string[] | undefined | null; @@ -147,6 +148,7 @@ export interface SignalHit { } export interface AlertAttributes { + actions: AlertAction[]; enabled: boolean; name: string; tags: string[]; @@ -156,4 +158,5 @@ export interface AlertAttributes { schedule: { interval: string; }; + throttle: string | null; } From aabbc327b822031a67a1882fa397804c797adec9 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Tue, 17 Mar 2020 13:03:00 +0100 Subject: [PATCH 12/19] cleanup --- .../routes/schemas/add_prepackaged_rules_schema.ts | 4 ++-- .../detection_engine/routes/schemas/create_rules_schema.ts | 4 ++-- .../detection_engine/routes/schemas/import_rules_schema.ts | 4 ++-- .../server/lib/detection_engine/routes/schemas/schemas.ts | 4 ++-- .../detection_engine/routes/schemas/update_rules_schema.ts | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts index 6b357dca67263..ade7ebab379f6 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts @@ -51,7 +51,7 @@ import { DEFAULT_MAX_SIGNALS } from '../../../../../common/constants'; * - index is a required field that must exist */ export const addPrepackagedRulesSchema = Joi.object({ - actions, + actions: actions.default([]), description: description.required(), enabled: enabled.default(false), false_positives: false_positives.default([]), @@ -82,7 +82,7 @@ export const addPrepackagedRulesSchema = Joi.object({ to: to.default('now'), type: type.required(), threat: threat.default([]), - throttle, + throttle: throttle.default(null), references: references.default([]), note: note.allow(''), version: version.required(), diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts index a7e0a4305e60b..b418017e318da 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts @@ -42,7 +42,7 @@ import { import { DEFAULT_MAX_SIGNALS } from '../../../../../common/constants'; export const createRulesSchema = Joi.object({ - actions, + actions: actions.default([]), description: description.required(), enabled: enabled.default(true), false_positives: false_positives.default([]), @@ -70,7 +70,7 @@ export const createRulesSchema = Joi.object({ to: to.default('now'), type: type.required(), threat: threat.default([]), - throttle, + throttle: throttle.default(null), references: references.default([]), note: note.allow(''), version: version.default(1), diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts index 44575caf7ff34..0af660e8eb981 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts @@ -58,7 +58,7 @@ import { DEFAULT_MAX_SIGNALS } from '../../../../../common/constants'; */ export const importRulesSchema = Joi.object({ id, - actions, + actions: actions.default([]), description: description.required(), enabled: enabled.default(true), false_positives: false_positives.default([]), @@ -87,7 +87,7 @@ export const importRulesSchema = Joi.object({ to: to.default('now'), type: type.required(), threat: threat.default([]), - throttle, + throttle: throttle.default(null), references: references.default([]), note: note.allow(''), version: version.default(1), diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts index afa59dd834ee5..521b1785c4554 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts @@ -105,6 +105,6 @@ export const updated_by = Joi.string(); export const version = Joi.number() .integer() .min(1); -export const actions = Joi.array().default([]); -export const throttle = Joi.string().default(null); +export const actions = Joi.array(); +export const throttle = Joi.string().allow(null); export const note = Joi.string(); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts index 5221f988bf62b..0cc70cc39de91 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts @@ -50,7 +50,7 @@ import { DEFAULT_MAX_SIGNALS } from '../../../../../common/constants'; * - id is on here because you can pass in an id to update using it instead of rule_id. */ export const updateRulesSchema = Joi.object({ - actions, + actions: actions.default([]), description: description.required(), enabled: enabled.default(true), id, @@ -79,7 +79,7 @@ export const updateRulesSchema = Joi.object({ to: to.default('now'), type: type.required(), threat: threat.default([]), - throttle, + throttle: throttle.default(null), references: references.default([]), note: note.allow(''), version, From 50abbc2e088eeb3d36ef18214e804031a8988188 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Tue, 17 Mar 2020 18:19:50 +0100 Subject: [PATCH 13/19] cleanup --- .../routes/schemas/patch_rules_schema.test.ts | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts index 6c5cbd24e2053..ecdba7ccc0091 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts @@ -1013,42 +1013,6 @@ describe('patch rules schema', () => { ); }); - test('The default for "actions" will be an empty array', () => { - expect( - patchRulesSchema.validate>({ - rule_id: 'rule-1', - risk_score: 50, - description: 'some description', - name: 'some-name', - severity: 'low', - type: 'query', - references: ['index-1'], - query: 'some query', - language: 'kuery', - max_signals: 1, - version: 1, - }).value.actions - ).toEqual([]); - }); - - test('The default for "throttle" will be null', () => { - expect( - patchRulesSchema.validate>({ - rule_id: 'rule-1', - risk_score: 50, - description: 'some description', - name: 'some-name', - severity: 'low', - type: 'query', - references: ['index-1'], - query: 'some query', - language: 'kuery', - max_signals: 1, - version: 1, - }).value.throttle - ).toEqual(null); - }); - describe('note', () => { test('[rule_id, description, from, to, index, name, severity, interval, type, note] does validate', () => { expect( From 1e969a937d68b49bc544041ab879fda88bbd3907 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Tue, 17 Mar 2020 20:23:51 +0100 Subject: [PATCH 14/19] add unit tests --- .../add_prepackaged_rules_schema.test.ts | 158 +++++++++++++++++- .../schemas/create_rules_schema.test.ts | 144 +++++++++++++++- .../schemas/import_rules_schema.test.ts | 144 +++++++++++++++- .../routes/schemas/patch_rules_schema.test.ts | 144 +++++++++++++++- .../routes/schemas/schemas.ts | 12 +- .../schemas/update_rules_schema.test.ts | 144 +++++++++++++++- .../detection_engine/rules/create_rules.ts | 2 +- .../siem/server/lib/detection_engine/types.ts | 3 +- 8 files changed, 743 insertions(+), 8 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts index 3774330392204..cb16edd2047ad 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ThreatParams, PrepackagedRules } from '../../types'; +import { ThreatParams, PrepackagedRules, AlertAction } from '../../types'; import { addPrepackagedRulesSchema } from './add_prepackaged_rules_schema'; describe('add prepackaged rules schema', () => { @@ -1294,6 +1294,162 @@ describe('add prepackaged rules schema', () => { ).toEqual([]); }); + test('You cannot send in an array of actions that are missing "group"', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial> & { + actions: Array>; + } + >({ + actions: [ + { + id: 'id', + actionTypeId: 'actionTypeId', + params: {}, + }, + ], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "group" fails because ["group" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "id"', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial> & { + actions: Array>; + } + >({ + actions: [ + { + group: 'group', + actionTypeId: 'actionTypeId', + params: {}, + }, + ], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "id" fails because ["id" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "actionTypeId"', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial> & { + actions: Array>; + } + >({ + actions: [ + { + group: 'group', + id: 'id', + params: {}, + }, + ], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "params"', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial> & { + actions: Array>; + } + >({ + actions: [ + { + group: 'group', + id: 'id', + actionTypeId: 'actionTypeId', + }, + ], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "params" fails because ["params" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are including "action_type_id', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial> & { + actions: Array & { action_type_id: string }>; + } + >({ + actions: [ + { + group: 'group', + id: 'id', + action_type_id: 'action_type_id', + params: {}, + }, + ], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + ); + }); + test('The default for "throttle" will be null', () => { expect( addPrepackagedRulesSchema.validate>({ diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts index b076db7b53af3..c0e66c1a1706f 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts @@ -6,7 +6,7 @@ import { createRulesSchema } from './create_rules_schema'; import { PatchRuleAlertParamsRest } from '../../rules/types'; -import { ThreatParams, RuleAlertParamsRest } from '../../types'; +import { ThreatParams, RuleAlertParamsRest, AlertAction } from '../../types'; describe('create rules schema', () => { test('empty objects do not validate', () => { @@ -1243,6 +1243,148 @@ describe('create rules schema', () => { ).toEqual([]); }); + test('You cannot send in an array of actions that are missing "group"', () => { + expect( + createRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ id: 'id', actionTypeId: 'actionTypeId', params: {} }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "group" fails because ["group" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "id"', () => { + expect( + createRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ group: 'group', actionTypeId: 'actionTypeId', params: {} }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "id" fails because ["id" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "actionTypeId"', () => { + expect( + createRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ group: 'group', id: 'id', params: {} }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "params"', () => { + expect( + createRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ group: 'group', id: 'id', actionTypeId: 'actionTypeId' }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "params" fails because ["params" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are including "action_type_id', () => { + expect( + createRulesSchema.validate< + Partial< + Omit & { + actions: Array & { action_type_id: string }>; + } + > + >({ + actions: [ + { + group: 'group', + id: 'id', + action_type_id: 'action_type_id', + params: {}, + }, + ], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + ); + }); + test('The default for "throttle" will be null', () => { expect( createRulesSchema.validate>({ diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts index 98b6ec3be1fed..1667c13a9da68 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts @@ -9,7 +9,7 @@ import { importRulesQuerySchema, importRulesPayloadSchema, } from './import_rules_schema'; -import { ThreatParams, ImportRuleAlertRest } from '../../types'; +import { ThreatParams, ImportRuleAlertRest, AlertAction } from '../../types'; import { ImportRulesRequestParams } from '../../rules/types'; describe('import rules schema', () => { @@ -1442,6 +1442,148 @@ describe('import rules schema', () => { ).toEqual([]); }); + test('You cannot send in an array of actions that are missing "group"', () => { + expect( + importRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ id: 'id', actionTypeId: 'actionTypeId', params: {} }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "group" fails because ["group" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "id"', () => { + expect( + importRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ group: 'group', actionTypeId: 'actionTypeId', params: {} }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "id" fails because ["id" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "actionTypeId"', () => { + expect( + importRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ group: 'group', id: 'id', params: {} }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "params"', () => { + expect( + importRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ group: 'group', id: 'id', actionTypeId: 'actionTypeId' }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "params" fails because ["params" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are including "action_type_id', () => { + expect( + importRulesSchema.validate< + Partial< + Omit & { + actions: Array & { action_type_id: string }>; + } + > + >({ + actions: [ + { + group: 'group', + id: 'id', + action_type_id: 'action_type_id', + params: {}, + }, + ], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + ); + }); + test('The default for "throttle" will be null', () => { expect( importRulesSchema.validate>({ diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts index ecdba7ccc0091..64c9de216d373 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts @@ -6,7 +6,7 @@ import { patchRulesSchema } from './patch_rules_schema'; import { PatchRuleAlertParamsRest } from '../../rules/types'; -import { ThreatParams } from '../../types'; +import { ThreatParams, AlertAction } from '../../types'; describe('patch rules schema', () => { test('empty objects do not validate as they require at least id or rule_id', () => { @@ -1053,4 +1053,146 @@ describe('patch rules schema', () => { ).toEqual('child "note" fails because ["note" must be a string]'); }); }); + + test('You cannot send in an array of actions that are missing "group"', () => { + expect( + patchRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ id: 'id', actionTypeId: 'actionTypeId', params: {} }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "group" fails because ["group" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "id"', () => { + expect( + patchRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ group: 'group', actionTypeId: 'actionTypeId', params: {} }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "id" fails because ["id" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "actionTypeId"', () => { + expect( + patchRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ group: 'group', id: 'id', params: {} }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "params"', () => { + expect( + patchRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ group: 'group', id: 'id', actionTypeId: 'actionTypeId' }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "params" fails because ["params" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are including "action_type_id', () => { + expect( + patchRulesSchema.validate< + Partial< + Omit & { + actions: Array & { action_type_id: string }>; + } + > + >({ + actions: [ + { + group: 'group', + id: 'id', + action_type_id: 'action_type_id', + params: {}, + }, + ], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + ); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts index 521b1785c4554..297e1fd9f0f5a 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts @@ -105,6 +105,16 @@ export const updated_by = Joi.string(); export const version = Joi.number() .integer() .min(1); -export const actions = Joi.array(); +export const action_group = Joi.string(); +export const action_id = Joi.string(); +export const action_actionTypeId = Joi.string(); +export const action_params = Joi.object(); +export const action = Joi.object({ + group: action_group.required(), + id: action_id.required(), + actionTypeId: action_actionTypeId.required(), + params: action_params.required(), +}); +export const actions = Joi.array().items(action); export const throttle = Joi.string().allow(null); export const note = Joi.string(); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts index c4c44f3bac991..c3e04d82193ff 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts @@ -6,7 +6,7 @@ import { updateRulesSchema } from './update_rules_schema'; import { PatchRuleAlertParamsRest } from '../../rules/types'; -import { ThreatParams, RuleAlertParamsRest } from '../../types'; +import { ThreatParams, RuleAlertParamsRest, AlertAction } from '../../types'; describe('create rules schema', () => { test('empty objects do not validate as they require at least id or rule_id', () => { @@ -1262,6 +1262,148 @@ describe('create rules schema', () => { ).toEqual([]); }); + test('You cannot send in an array of actions that are missing "group"', () => { + expect( + updateRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ id: 'id', actionTypeId: 'actionTypeId', params: {} }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "group" fails because ["group" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "id"', () => { + expect( + updateRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ group: 'group', actionTypeId: 'actionTypeId', params: {} }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "id" fails because ["id" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "actionTypeId"', () => { + expect( + updateRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ group: 'group', id: 'id', params: {} }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are missing "params"', () => { + expect( + updateRulesSchema.validate< + Partial< + Omit & { + actions: Array>; + } + > + >({ + actions: [{ group: 'group', id: 'id', actionTypeId: 'actionTypeId' }], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "params" fails because ["params" is required]]]' + ); + }); + + test('You cannot send in an array of actions that are including "action_type_id', () => { + expect( + updateRulesSchema.validate< + Partial< + Omit & { + actions: Array & { action_type_id: string }>; + } + > + >({ + actions: [ + { + group: 'group', + id: 'id', + action_type_id: 'action_type_id', + params: {}, + }, + ], + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + name: 'some-name', + severity: 'junk', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error.message + ).toEqual( + 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + ); + }); + test('The default for "throttle" will be null', () => { expect( updateRulesSchema.validate>({ diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts index 29d7d630bd2aa..c9d1189a005b2 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts @@ -75,7 +75,7 @@ export const createRules = ({ }, schedule: { interval }, enabled, - actions, + actions: actions ?? [], throttle, }, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts index 00b7161373cab..a3796e1c2882c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts @@ -5,6 +5,7 @@ */ import { AlertAction } from '../../../../../../plugins/alerting/common'; +export { AlertAction } from '../../../../../../plugins/alerting/common'; import { CallAPIOptions } from '../../../../../../../src/core/server'; import { Filter } from '../../../../../../../src/plugins/data/server'; import { IRuleStatusAttributes } from './rules/types'; @@ -24,7 +25,7 @@ export interface ThreatParams { } export interface RuleAlertParams { - actions: AlertAction[]; + actions: AlertAction[] | undefined; description: string; note: string | undefined | null; enabled: boolean; From abd64717316f67a83a7c207a0dda4ba32935e81a Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Thu, 19 Mar 2020 09:35:06 +0100 Subject: [PATCH 15/19] fix types --- .../lib/detection_engine/signals/bulk_create_ml_signals.ts | 3 +++ .../lib/detection_engine/signals/signal_rule_alert_type.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts index 1ab34f26d4b70..3a15820036a1a 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts @@ -9,11 +9,13 @@ import { SearchResponse } from 'elasticsearch'; import { Logger } from '../../../../../../../../src/core/server'; import { AlertServices } from '../../../../../../../plugins/alerting/server'; +import { AlertAction } from '../../../../../../../plugins/alerting/common'; import { RuleTypeParams } from '../types'; import { singleBulkCreate } from './single_bulk_create'; import { AnomalyResults, Anomaly } from '../../machine_learning'; interface BulkCreateMlSignalsParams { + actions: AlertAction[]; someResult: AnomalyResults; ruleParams: RuleTypeParams; services: AlertServices; @@ -28,6 +30,7 @@ interface BulkCreateMlSignalsParams { interval: string; enabled: boolean; tags: string[]; + throttle: string | null; } interface EcsAnomaly extends Anomaly { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index 813f4b4fc1e65..89dcd3274ebed 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -120,6 +120,8 @@ export const signalRulesAlertType = ({ } creationSucceeded = await bulkCreateMlSignals({ + actions, + throttle, someResult: anomalyResults, ruleParams: params, services, From aaf4df52569e805376ce20fe7d3696a030d26228 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Thu, 19 Mar 2020 21:59:55 +0100 Subject: [PATCH 16/19] PR comments --- .../schemas/add_prepackaged_rules_schema.test.ts | 10 +++++----- .../routes/schemas/create_rules_schema.test.ts | 10 +++++----- .../routes/schemas/import_rules_schema.test.ts | 8 ++++---- .../routes/schemas/patch_rules_schema.test.ts | 10 +++++----- .../routes/schemas/update_rules_schema.test.ts | 10 +++++----- .../server/lib/detection_engine/rules/create_rules.ts | 2 +- .../server/lib/detection_engine/rules/patch_rules.ts | 4 +++- .../server/lib/detection_engine/rules/update_rules.ts | 2 +- .../lib/detection_engine/signals/build_rule.test.ts | 6 +++--- .../plugins/siem/server/lib/detection_engine/types.ts | 2 +- 10 files changed, 33 insertions(+), 31 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts index a18b5e399fce8..93d9730dcb510 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts @@ -1321,7 +1321,7 @@ describe('add prepackaged rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1352,7 +1352,7 @@ describe('add prepackaged rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1383,7 +1383,7 @@ describe('add prepackaged rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1414,7 +1414,7 @@ describe('add prepackaged rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1446,7 +1446,7 @@ describe('add prepackaged rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts index f0d3c9c85316e..a1c89e073f3e1 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts @@ -1266,7 +1266,7 @@ describe('create rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1293,7 +1293,7 @@ describe('create rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1320,7 +1320,7 @@ describe('create rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1347,7 +1347,7 @@ describe('create rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1381,7 +1381,7 @@ describe('create rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts index 2703621b6190b..a90fee50c8546 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts @@ -1492,7 +1492,7 @@ describe('import rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1519,7 +1519,7 @@ describe('import rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1546,7 +1546,7 @@ describe('import rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1580,7 +1580,7 @@ describe('import rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts index 96ce712c9bea9..6450f3bb75fe0 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts @@ -1077,7 +1077,7 @@ describe('patch rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1104,7 +1104,7 @@ describe('patch rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1131,7 +1131,7 @@ describe('patch rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1158,7 +1158,7 @@ describe('patch rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1192,7 +1192,7 @@ describe('patch rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts index 21228fbef614d..37042d331b87f 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts @@ -1285,7 +1285,7 @@ describe('create rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1312,7 +1312,7 @@ describe('create rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1339,7 +1339,7 @@ describe('create rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1366,7 +1366,7 @@ describe('create rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', @@ -1400,7 +1400,7 @@ describe('create rules schema', () => { risk_score: 50, description: 'some description', name: 'some-name', - severity: 'junk', + severity: 'low', type: 'query', references: ['index-1'], query: 'some query', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts index b4758e2ab6bb1..138e8f3bb1170 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts @@ -84,7 +84,7 @@ export const createRules = ({ }, schedule: { interval }, enabled, - actions: actions ?? [], + actions, throttle, }, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts index 6edc830ecb78c..c8791d14aa3d7 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts @@ -54,6 +54,7 @@ export const patchRules = async ({ } const calculatedVersion = calculateVersion(rule.params.immutable, rule.params.version, { + actions, description, falsePositives, query, @@ -73,6 +74,7 @@ export const patchRules = async ({ severity, tags, threat, + throttle, to, type, references, @@ -116,7 +118,7 @@ export const patchRules = async ({ id: rule.id, data: { tags: addTags(tags ?? rule.tags, rule.params.ruleId, immutable ?? rule.params.immutable), - throttle: throttle ?? throttle === null ? null : rule.throttle, + throttle: throttle !== undefined ? throttle : rule.throttle, name: calculateName({ updatedName: name, originalName: rule.name }), schedule: { interval: calculateInterval(interval, rule.schedule.interval), diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts index 43e1c3ed9fb99..2fe78bd9ca142 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts @@ -92,7 +92,7 @@ export const updateRules = async ({ name, schedule: { interval }, actions: actions ?? rule.actions, - throttle: throttle ?? throttle === null ? null : rule.throttle, + throttle: throttle !== undefined ? throttle : rule.throttle, params: { description, ruleId: rule.params.ruleId, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts index b7278c615b2f0..37d7ed8a51082 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts @@ -109,7 +109,7 @@ describe('buildRule', () => { expect(rule).toEqual(expected); }); - test('it omits a null value such as if enabled is null if is present', () => { + test('it omits a null value such as if "enabled" is null if is present', () => { const ruleParams = sampleRuleAlertParams(); ruleParams.filters = undefined; const rule = buildRule({ @@ -184,7 +184,7 @@ describe('buildRule', () => { expect(rule).toEqual(expected); }); - test('it omits a null value such as if filters is undefined if is present', () => { + test('it omits a null value such as if "filters" is undefined if is present', () => { const ruleParams = sampleRuleAlertParams(); ruleParams.filters = undefined; const rule = buildRule({ @@ -259,7 +259,7 @@ describe('buildRule', () => { expect(rule).toEqual(expected); }); - test('it omits a null value such as if throttle is undefined if is present', () => { + test('it omits a null value such as if "throttle" is undefined if is present', () => { const ruleParams = sampleRuleAlertParams(); const rule = buildRule({ actions: [], diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts index 2495b24124b20..d8941b08aa70e 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts @@ -32,7 +32,7 @@ export interface ThreatParams { export type RuleType = 'query' | 'saved_query' | 'machine_learning'; export interface RuleAlertParams { - actions: AlertAction[] | undefined; + actions: AlertAction[]; anomalyThreshold: number | undefined; description: string; note: string | undefined | null; From 1b03386f383ce089f414873d33bf9399b2ca2ac8 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Thu, 19 Mar 2020 22:09:52 +0100 Subject: [PATCH 17/19] update response schema --- .../routes/schemas/response/schemas.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts index f7f2653a58b08..77c4601c647da 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts @@ -29,12 +29,16 @@ export const filters = t.array(t.unknown); // Filters are not easily type-able y * Params is an "object", since it is a type of AlertActionParams which is action templates. * @see x-pack/plugins/alerting/common/alert.ts */ +export const action_group = t.string; +export const action_id = t.string; +export const action_action_type_id = t.string; +export const action_params = t.object; export const action = t.exact( t.type({ - group: t.string, - id: t.string, - actionTypeId: t.string, - params: t.object, + group: action_group, + id: action_id, + actionTypeId: action_action_type_id, + params: action_params, }) ); From 07aa54f941cc7c582beaad35f7d16d159753045c Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Fri, 20 Mar 2020 00:12:42 +0100 Subject: [PATCH 18/19] actionTypeId => action_type_id --- .../detection_engine/routes/rules/utils.ts | 3 +- .../add_prepackaged_rules_schema.test.ts | 29 ++++++------- .../schemas/create_rules_schema.test.ts | 29 ++++++------- .../schemas/import_rules_schema.test.ts | 29 ++++++------- .../routes/schemas/patch_rules_schema.test.ts | 29 ++++++------- .../routes/schemas/response/schemas.ts | 2 +- .../routes/schemas/schemas.ts | 4 +- .../schemas/update_rules_schema.test.ts | 29 ++++++------- .../detection_engine/rules/create_rules.ts | 3 +- .../lib/detection_engine/rules/patch_rules.ts | 3 +- .../rules/transform_actions.test.ts | 41 +++++++++++++++++++ .../rules/transform_actions.ts | 32 +++++++++++++++ .../detection_engine/rules/update_rules.ts | 3 +- .../signals/build_bulk_body.ts | 5 +-- .../detection_engine/signals/build_rule.ts | 5 +-- .../signals/bulk_create_ml_signals.ts | 5 +-- .../signals/search_after_bulk_create.ts | 5 +-- .../signals/single_bulk_create.ts | 5 +-- .../lib/detection_engine/signals/types.ts | 5 +-- .../siem/server/lib/detection_engine/types.ts | 7 +++- 20 files changed, 176 insertions(+), 97 deletions(-) create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/transform_actions.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/transform_actions.ts diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts index 80930331fca50..3d831026256fc 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts @@ -29,6 +29,7 @@ import { OutputError, } from '../utils'; import { hasListsFeature } from '../../feature_flags'; +import { transformAlertToRuleAction } from '../../rules/transform_actions'; type PromiseFromStreams = ImportRuleAlertRest | Error; @@ -102,7 +103,7 @@ export const transformAlertToRule = ( ruleStatus?: SavedObject ): Partial => { return pickBy((value: unknown) => value != null, { - actions: alert.actions, + actions: alert.actions.map(transformAlertToRuleAction), created_at: alert.createdAt.toISOString(), updated_at: alert.updatedAt.toISOString(), created_by: alert.createdBy, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts index 93d9730dcb510..2b18e1b9bf52c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ThreatParams, PrepackagedRules, AlertAction } from '../../types'; +import { AlertAction } from '../../../../../../../../plugins/alerting/common'; +import { ThreatParams, PrepackagedRules, RuleAlertAction } from '../../types'; import { addPrepackagedRulesSchema } from './add_prepackaged_rules_schema'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags'; @@ -1307,13 +1308,13 @@ describe('add prepackaged rules schema', () => { expect( addPrepackagedRulesSchema.validate< Partial> & { - actions: Array>; + actions: Array>; } >({ actions: [ { id: 'id', - actionTypeId: 'actionTypeId', + action_type_id: 'actionTypeId', params: {}, }, ], @@ -1338,13 +1339,13 @@ describe('add prepackaged rules schema', () => { expect( addPrepackagedRulesSchema.validate< Partial> & { - actions: Array>; + actions: Array>; } >({ actions: [ { group: 'group', - actionTypeId: 'actionTypeId', + action_type_id: 'action_type_id', params: {}, }, ], @@ -1365,11 +1366,11 @@ describe('add prepackaged rules schema', () => { ); }); - test('You cannot send in an array of actions that are missing "actionTypeId"', () => { + test('You cannot send in an array of actions that are missing "action_type_id"', () => { expect( addPrepackagedRulesSchema.validate< Partial> & { - actions: Array>; + actions: Array>; } >({ actions: [ @@ -1392,7 +1393,7 @@ describe('add prepackaged rules schema', () => { version: 1, }).error.message ).toEqual( - 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + 'child "actions" fails because ["actions" at position 0 fails because [child "action_type_id" fails because ["action_type_id" is required]]]' ); }); @@ -1400,14 +1401,14 @@ describe('add prepackaged rules schema', () => { expect( addPrepackagedRulesSchema.validate< Partial> & { - actions: Array>; + actions: Array>; } >({ actions: [ { group: 'group', id: 'id', - actionTypeId: 'actionTypeId', + action_type_id: 'action_type_id', }, ], rule_id: 'rule-1', @@ -1427,18 +1428,18 @@ describe('add prepackaged rules schema', () => { ); }); - test('You cannot send in an array of actions that are including "action_type_id', () => { + test('You cannot send in an array of actions that are including "actionTypeId', () => { expect( addPrepackagedRulesSchema.validate< Partial> & { - actions: Array & { action_type_id: string }>; + actions: AlertAction[]; } >({ actions: [ { group: 'group', id: 'id', - action_type_id: 'action_type_id', + actionTypeId: 'actionTypeId', params: {}, }, ], @@ -1455,7 +1456,7 @@ describe('add prepackaged rules schema', () => { version: 1, }).error.message ).toEqual( - 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + 'child "actions" fails because ["actions" at position 0 fails because [child "action_type_id" fails because ["action_type_id" is required]]]' ); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts index a1c89e073f3e1..d9c3055512815 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts @@ -4,9 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ +import { AlertAction } from '../../../../../../../../plugins/alerting/common'; import { createRulesSchema } from './create_rules_schema'; import { PatchRuleAlertParamsRest } from '../../rules/types'; -import { ThreatParams, RuleAlertParamsRest, AlertAction } from '../../types'; +import { ThreatParams, RuleAlertParamsRest, RuleAlertAction } from '../../types'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags'; describe('create rules schema', () => { @@ -1257,11 +1258,11 @@ describe('create rules schema', () => { createRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ - actions: [{ id: 'id', actionTypeId: 'actionTypeId', params: {} }], + actions: [{ id: 'id', action_type_id: 'action_type_id', params: {} }], rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1284,11 +1285,11 @@ describe('create rules schema', () => { createRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ - actions: [{ group: 'group', actionTypeId: 'actionTypeId', params: {} }], + actions: [{ group: 'group', action_type_id: 'action_type_id', params: {} }], rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1306,12 +1307,12 @@ describe('create rules schema', () => { ); }); - test('You cannot send in an array of actions that are missing "actionTypeId"', () => { + test('You cannot send in an array of actions that are missing "action_type_id"', () => { expect( createRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ @@ -1329,7 +1330,7 @@ describe('create rules schema', () => { version: 1, }).error.message ).toEqual( - 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + 'child "actions" fails because ["actions" at position 0 fails because [child "action_type_id" fails because ["action_type_id" is required]]]' ); }); @@ -1338,11 +1339,11 @@ describe('create rules schema', () => { createRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ - actions: [{ group: 'group', id: 'id', actionTypeId: 'actionTypeId' }], + actions: [{ group: 'group', id: 'id', action_type_id: 'action_type_id' }], rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1360,12 +1361,12 @@ describe('create rules schema', () => { ); }); - test('You cannot send in an array of actions that are including "action_type_id', () => { + test('You cannot send in an array of actions that are including "actionTypeId"', () => { expect( createRulesSchema.validate< Partial< Omit & { - actions: Array & { action_type_id: string }>; + actions: AlertAction[]; } > >({ @@ -1373,7 +1374,7 @@ describe('create rules schema', () => { { group: 'group', id: 'id', - action_type_id: 'action_type_id', + actionTypeId: 'actionTypeId', params: {}, }, ], @@ -1390,7 +1391,7 @@ describe('create rules schema', () => { version: 1, }).error.message ).toEqual( - 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + 'child "actions" fails because ["actions" at position 0 fails because [child "action_type_id" fails because ["action_type_id" is required]]]' ); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts index a90fee50c8546..ffb49896ef7c7 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts @@ -4,12 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ +import { AlertAction } from '../../../../../../../../plugins/alerting/common'; import { importRulesSchema, importRulesQuerySchema, importRulesPayloadSchema, } from './import_rules_schema'; -import { ThreatParams, ImportRuleAlertRest, AlertAction } from '../../types'; +import { ThreatParams, ImportRuleAlertRest, RuleAlertAction } from '../../types'; import { ImportRulesRequestParams } from '../../rules/types'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags'; @@ -1456,11 +1457,11 @@ describe('import rules schema', () => { importRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ - actions: [{ id: 'id', actionTypeId: 'actionTypeId', params: {} }], + actions: [{ id: 'id', action_type_id: 'action_type_id', params: {} }], rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1483,11 +1484,11 @@ describe('import rules schema', () => { importRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ - actions: [{ group: 'group', actionTypeId: 'actionTypeId', params: {} }], + actions: [{ group: 'group', action_type_id: 'action_type_id', params: {} }], rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1505,12 +1506,12 @@ describe('import rules schema', () => { ); }); - test('You cannot send in an array of actions that are missing "actionTypeId"', () => { + test('You cannot send in an array of actions that are missing "action_type_id"', () => { expect( importRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ @@ -1528,7 +1529,7 @@ describe('import rules schema', () => { version: 1, }).error.message ).toEqual( - 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + 'child "actions" fails because ["actions" at position 0 fails because [child "action_type_id" fails because ["action_type_id" is required]]]' ); }); @@ -1537,11 +1538,11 @@ describe('import rules schema', () => { importRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ - actions: [{ group: 'group', id: 'id', actionTypeId: 'actionTypeId' }], + actions: [{ group: 'group', id: 'id', action_type_id: 'action_type_id' }], rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1559,12 +1560,12 @@ describe('import rules schema', () => { ); }); - test('You cannot send in an array of actions that are including "action_type_id', () => { + test('You cannot send in an array of actions that are including "actionTypeId', () => { expect( importRulesSchema.validate< Partial< Omit & { - actions: Array & { action_type_id: string }>; + actions: AlertAction[]; } > >({ @@ -1572,7 +1573,7 @@ describe('import rules schema', () => { { group: 'group', id: 'id', - action_type_id: 'action_type_id', + actionTypeId: 'actionTypeId', params: {}, }, ], @@ -1589,7 +1590,7 @@ describe('import rules schema', () => { version: 1, }).error.message ).toEqual( - 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + 'child "actions" fails because ["actions" at position 0 fails because [child "action_type_id" fails because ["action_type_id" is required]]]' ); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts index 6450f3bb75fe0..42945e0970cba 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts @@ -4,9 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ +import { AlertAction } from '../../../../../../../../plugins/alerting/common'; import { patchRulesSchema } from './patch_rules_schema'; import { PatchRuleAlertParamsRest } from '../../rules/types'; -import { ThreatParams, AlertAction } from '../../types'; +import { ThreatParams, RuleAlertAction } from '../../types'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags'; describe('patch rules schema', () => { @@ -1068,11 +1069,11 @@ describe('patch rules schema', () => { patchRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ - actions: [{ id: 'id', actionTypeId: 'actionTypeId', params: {} }], + actions: [{ id: 'id', action_type_id: 'action_type_id', params: {} }], rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1095,11 +1096,11 @@ describe('patch rules schema', () => { patchRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ - actions: [{ group: 'group', actionTypeId: 'actionTypeId', params: {} }], + actions: [{ group: 'group', action_type_id: 'action_type_id', params: {} }], rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1117,12 +1118,12 @@ describe('patch rules schema', () => { ); }); - test('You cannot send in an array of actions that are missing "actionTypeId"', () => { + test('You cannot send in an array of actions that are missing "action_type_id"', () => { expect( patchRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ @@ -1140,7 +1141,7 @@ describe('patch rules schema', () => { version: 1, }).error.message ).toEqual( - 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + 'child "actions" fails because ["actions" at position 0 fails because [child "action_type_id" fails because ["action_type_id" is required]]]' ); }); @@ -1149,11 +1150,11 @@ describe('patch rules schema', () => { patchRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ - actions: [{ group: 'group', id: 'id', actionTypeId: 'actionTypeId' }], + actions: [{ group: 'group', id: 'id', action_type_id: 'action_type_id' }], rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1171,12 +1172,12 @@ describe('patch rules schema', () => { ); }); - test('You cannot send in an array of actions that are including "action_type_id', () => { + test('You cannot send in an array of actions that are including "actionTypeId', () => { expect( patchRulesSchema.validate< Partial< Omit & { - actions: Array & { action_type_id: string }>; + actions: AlertAction[]; } > >({ @@ -1184,7 +1185,7 @@ describe('patch rules schema', () => { { group: 'group', id: 'id', - action_type_id: 'action_type_id', + actionTypeId: 'actionTypeId', params: {}, }, ], @@ -1201,7 +1202,7 @@ describe('patch rules schema', () => { version: 1, }).error.message ).toEqual( - 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + 'child "actions" fails because ["actions" at position 0 fails because [child "action_type_id" fails because ["action_type_id" is required]]]' ); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts index 77c4601c647da..538c8f754fd6e 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/response/schemas.ts @@ -37,7 +37,7 @@ export const action = t.exact( t.type({ group: action_group, id: action_id, - actionTypeId: action_action_type_id, + action_type_id: action_action_type_id, params: action_params, }) ); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts index 56c646abcc65c..16e419f389f09 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts @@ -112,12 +112,12 @@ export const version = Joi.number() .min(1); export const action_group = Joi.string(); export const action_id = Joi.string(); -export const action_actionTypeId = Joi.string(); +export const action_action_type_id = Joi.string(); export const action_params = Joi.object(); export const action = Joi.object({ group: action_group.required(), id: action_id.required(), - actionTypeId: action_actionTypeId.required(), + action_type_id: action_action_type_id.required(), params: action_params.required(), }); export const actions = Joi.array().items(action); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts index 37042d331b87f..db3709cd6b126 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts @@ -4,9 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ +import { AlertAction } from '../../../../../../../../plugins/alerting/common'; import { updateRulesSchema } from './update_rules_schema'; import { PatchRuleAlertParamsRest } from '../../rules/types'; -import { ThreatParams, RuleAlertParamsRest, AlertAction } from '../../types'; +import { ThreatParams, RuleAlertParamsRest, RuleAlertAction } from '../../types'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags'; describe('create rules schema', () => { @@ -1276,11 +1277,11 @@ describe('create rules schema', () => { updateRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ - actions: [{ id: 'id', actionTypeId: 'actionTypeId', params: {} }], + actions: [{ id: 'id', action_type_id: 'action_type_id', params: {} }], rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1303,11 +1304,11 @@ describe('create rules schema', () => { updateRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ - actions: [{ group: 'group', actionTypeId: 'actionTypeId', params: {} }], + actions: [{ group: 'group', action_type_id: 'action_type_id', params: {} }], rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1325,12 +1326,12 @@ describe('create rules schema', () => { ); }); - test('You cannot send in an array of actions that are missing "actionTypeId"', () => { + test('You cannot send in an array of actions that are missing "action_type_id"', () => { expect( updateRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ @@ -1348,7 +1349,7 @@ describe('create rules schema', () => { version: 1, }).error.message ).toEqual( - 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + 'child "actions" fails because ["actions" at position 0 fails because [child "action_type_id" fails because ["action_type_id" is required]]]' ); }); @@ -1357,11 +1358,11 @@ describe('create rules schema', () => { updateRulesSchema.validate< Partial< Omit & { - actions: Array>; + actions: Array>; } > >({ - actions: [{ group: 'group', id: 'id', actionTypeId: 'actionTypeId' }], + actions: [{ group: 'group', id: 'id', action_type_id: 'action_type_id' }], rule_id: 'rule-1', risk_score: 50, description: 'some description', @@ -1379,12 +1380,12 @@ describe('create rules schema', () => { ); }); - test('You cannot send in an array of actions that are including "action_type_id', () => { + test('You cannot send in an array of actions that are including "actionTypeId"', () => { expect( updateRulesSchema.validate< Partial< Omit & { - actions: Array & { action_type_id: string }>; + actions: AlertAction[]; } > >({ @@ -1392,7 +1393,7 @@ describe('create rules schema', () => { { group: 'group', id: 'id', - action_type_id: 'action_type_id', + actionTypeId: 'actionTypeId', params: {}, }, ], @@ -1409,7 +1410,7 @@ describe('create rules schema', () => { version: 1, }).error.message ).toEqual( - 'child "actions" fails because ["actions" at position 0 fails because [child "actionTypeId" fails because ["actionTypeId" is required]]]' + 'child "actions" fails because ["actions" at position 0 fails because [child "action_type_id" fails because ["action_type_id" is required]]]' ); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts index 138e8f3bb1170..db70b90d5a17c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts @@ -9,6 +9,7 @@ import { APP_ID, SIGNALS_ID } from '../../../../common/constants'; import { CreateRuleParams } from './types'; import { addTags } from './add_tags'; import { hasListsFeature } from '../feature_flags'; +import { transformRuleToAlertAction } from './transform_actions'; export const createRules = ({ alertsClient, @@ -84,7 +85,7 @@ export const createRules = ({ }, schedule: { interval }, enabled, - actions, + actions: actions?.map(transformRuleToAlertAction), throttle, }, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts index c8791d14aa3d7..be466ffeed27c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts @@ -11,6 +11,7 @@ import { PatchRuleParams, IRuleSavedAttributesSavedObjectAttributes } from './ty import { addTags } from './add_tags'; import { ruleStatusSavedObjectType } from './saved_object_mappings'; import { calculateVersion, calculateName, calculateInterval } from './utils'; +import { transformRuleToAlertAction } from './transform_actions'; export const patchRules = async ({ alertsClient, @@ -123,7 +124,7 @@ export const patchRules = async ({ schedule: { interval: calculateInterval(interval, rule.schedule.interval), }, - actions: actions ?? rule.actions, + actions: actions?.map(transformRuleToAlertAction) ?? rule.actions, params: nextParams, }, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/transform_actions.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/transform_actions.test.ts new file mode 100644 index 0000000000000..93b5f238be9ed --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/transform_actions.test.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { transformRuleToAlertAction, transformAlertToRuleAction } from './transform_actions'; + +describe('transform_actions', () => { + test('it should transform RuleAlertAction[] to AlertAction[]', () => { + const ruleAction = { + id: 'id', + group: 'group', + action_type_id: 'action_type_id', + params: {}, + }; + const alertAction = transformRuleToAlertAction(ruleAction); + expect(alertAction).toEqual({ + id: ruleAction.id, + group: ruleAction.group, + actionTypeId: ruleAction.action_type_id, + params: ruleAction.params, + }); + }); + + test('it should transform AlertAction[] to RuleAlertAction[]', () => { + const alertAction = { + id: 'id', + group: 'group', + actionTypeId: 'actionTypeId', + params: {}, + }; + const ruleAction = transformAlertToRuleAction(alertAction); + expect(ruleAction).toEqual({ + id: alertAction.id, + group: alertAction.group, + action_type_id: alertAction.actionTypeId, + params: alertAction.params, + }); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/transform_actions.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/transform_actions.ts new file mode 100644 index 0000000000000..c1c17d2c70836 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/transform_actions.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { AlertAction } from '../../../../../../../plugins/alerting/common'; +import { RuleAlertAction } from '../types'; + +export const transformRuleToAlertAction = ({ + group, + id, + action_type_id, + params, +}: RuleAlertAction): AlertAction => ({ + group, + id, + params, + actionTypeId: action_type_id, +}); + +export const transformAlertToRuleAction = ({ + group, + id, + actionTypeId, + params, +}: AlertAction): RuleAlertAction => ({ + group, + id, + params, + action_type_id: actionTypeId, +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts index 2fe78bd9ca142..a7e4d35b2f38c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts @@ -11,6 +11,7 @@ import { addTags } from './add_tags'; import { ruleStatusSavedObjectType } from './saved_object_mappings'; import { calculateVersion } from './utils'; import { hasListsFeature } from '../feature_flags'; +import { transformRuleToAlertAction } from './transform_actions'; export const updateRules = async ({ alertsClient, @@ -91,7 +92,7 @@ export const updateRules = async ({ tags: addTags(tags, rule.params.ruleId, immutable), name, schedule: { interval }, - actions: actions ?? rule.actions, + actions: actions.map(transformRuleToAlertAction) ?? rule.actions, throttle: throttle !== undefined ? throttle : rule.throttle, params: { description, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.ts index f75eab668a9a6..adbd5f81d372a 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.ts @@ -8,14 +8,13 @@ import { SignalSourceHit, SignalHit } from './types'; import { buildRule } from './build_rule'; import { buildSignal } from './build_signal'; import { buildEventTypeSignal } from './build_event_type_signal'; -import { RuleTypeParams } from '../types'; -import { AlertAction } from '../../../../../../../plugins/alerting/common'; +import { RuleTypeParams, RuleAlertAction } from '../types'; interface BuildBulkBodyParams { doc: SignalSourceHit; ruleParams: RuleTypeParams; id: string; - actions: AlertAction[]; + actions: RuleAlertAction[]; name: string; createdAt: string; createdBy: string; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts index 7ba26c87da747..e94ca18b186e4 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts @@ -5,14 +5,13 @@ */ import { pickBy } from 'lodash/fp'; -import { RuleTypeParams, OutputRuleAlertRest } from '../types'; -import { AlertAction } from '../../../../../../../plugins/alerting/common'; +import { RuleTypeParams, OutputRuleAlertRest, RuleAlertAction } from '../types'; interface BuildRuleParams { ruleParams: RuleTypeParams; name: string; id: string; - actions: AlertAction[]; + actions: RuleAlertAction[]; enabled: boolean; createdAt: string; createdBy: string; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts index 3a15820036a1a..95adb90172404 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts @@ -9,13 +9,12 @@ import { SearchResponse } from 'elasticsearch'; import { Logger } from '../../../../../../../../src/core/server'; import { AlertServices } from '../../../../../../../plugins/alerting/server'; -import { AlertAction } from '../../../../../../../plugins/alerting/common'; -import { RuleTypeParams } from '../types'; +import { RuleTypeParams, RuleAlertAction } from '../types'; import { singleBulkCreate } from './single_bulk_create'; import { AnomalyResults, Anomaly } from '../../machine_learning'; interface BulkCreateMlSignalsParams { - actions: AlertAction[]; + actions: RuleAlertAction[]; someResult: AnomalyResults; ruleParams: RuleTypeParams; services: AlertServices; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts index 8b5623c507812..a12778d5b8f16 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts @@ -5,8 +5,7 @@ */ import { AlertServices } from '../../../../../../../plugins/alerting/server'; -import { AlertAction } from '../../../../../../../plugins/alerting/common'; -import { RuleTypeParams } from '../types'; +import { RuleTypeParams, RuleAlertAction } from '../types'; import { Logger } from '../../../../../../../../src/core/server'; import { singleSearchAfter } from './single_search_after'; import { singleBulkCreate } from './single_bulk_create'; @@ -21,7 +20,7 @@ interface SearchAfterAndBulkCreateParams { inputIndexPattern: string[]; signalsIndex: string; name: string; - actions: AlertAction[]; + actions: RuleAlertAction[]; createdAt: string; createdBy: string; updatedBy: string; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts index 95218a94fbfe9..333a938e09d45 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts @@ -8,11 +8,10 @@ import { countBy, isEmpty } from 'lodash'; import { performance } from 'perf_hooks'; import { AlertServices } from '../../../../../../../plugins/alerting/server'; import { SignalSearchResponse, BulkResponse } from './types'; -import { RuleTypeParams } from '../types'; +import { RuleTypeParams, RuleAlertAction } from '../types'; import { generateId } from './utils'; import { buildBulkBody } from './build_bulk_body'; import { Logger } from '../../../../../../../../src/core/server'; -import { AlertAction } from '../../../../../../../plugins/alerting/common'; interface SingleBulkCreateParams { someResult: SignalSearchResponse; @@ -21,7 +20,7 @@ interface SingleBulkCreateParams { logger: Logger; id: string; signalsIndex: string; - actions: AlertAction[]; + actions: RuleAlertAction[]; name: string; createdAt: string; createdBy: string; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts index a3c22c11c00dd..06acff825f68e 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts @@ -4,14 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { RuleAlertParams, OutputRuleAlertRest } from '../types'; +import { RuleAlertParams, OutputRuleAlertRest, RuleAlertAction } from '../types'; import { SearchResponse } from '../../types'; import { AlertType, State, AlertExecutorOptions, } from '../../../../../../../plugins/alerting/server'; -import { AlertAction } from '../../../../../../../plugins/alerting/common'; export interface SignalsParams { signalIds: string[] | undefined | null; @@ -148,7 +147,7 @@ export interface SignalHit { } export interface AlertAttributes { - actions: AlertAction[]; + actions: RuleAlertAction[]; enabled: boolean; name: string; tags: string[]; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts index d8941b08aa70e..2cbdc7db3ba64 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts @@ -5,7 +5,6 @@ */ import { AlertAction } from '../../../../../../plugins/alerting/common'; -export { AlertAction } from '../../../../../../plugins/alerting/common'; import { CallAPIOptions } from '../../../../../../../src/core/server'; import { Filter } from '../../../../../../../src/plugins/data/server'; import { IRuleStatusAttributes } from './rules/types'; @@ -25,6 +24,10 @@ export interface ThreatParams { technique: IMitreAttack[]; } +export type RuleAlertAction = Omit & { + action_type_id: string; +}; + // Notice below we are using lists: ListsDefaultArraySchema[]; which is coming directly from the response output section. // TODO: Eventually this whole RuleAlertParams will be replaced with io-ts. For now we can slowly strangle it out and reduce duplicate types // We don't have the input types defined through io-ts just yet but as we being introducing types from there we will more and more remove @@ -32,7 +35,7 @@ export interface ThreatParams { export type RuleType = 'query' | 'saved_query' | 'machine_learning'; export interface RuleAlertParams { - actions: AlertAction[]; + actions: RuleAlertAction[]; anomalyThreshold: number | undefined; description: string; note: string | undefined | null; From 585884e48c0e382d0cc39d875f35c4d6a9957fdf Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Fri, 20 Mar 2020 00:17:18 +0100 Subject: [PATCH 19/19] Add extra check --- .../siem/server/lib/detection_engine/rules/update_rules.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts index a7e4d35b2f38c..ead065d7f198d 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts @@ -92,7 +92,7 @@ export const updateRules = async ({ tags: addTags(tags, rule.params.ruleId, immutable), name, schedule: { interval }, - actions: actions.map(transformRuleToAlertAction) ?? rule.actions, + actions: actions?.map(transformRuleToAlertAction) ?? rule.actions, throttle: throttle !== undefined ? throttle : rule.throttle, params: { description,