diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/select_rule_type/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/select_rule_type/index.tsx index b3b35699914f6..229ccde54ecab 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/select_rule_type/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/select_rule_type/index.tsx @@ -14,9 +14,10 @@ import { isMlRule } from '../../helpers'; interface SelectRuleTypeProps { field: FieldHook; + isReadOnly: boolean; } -export const SelectRuleType: React.FC = ({ field }) => { +export const SelectRuleType: React.FC = ({ field, isReadOnly = false }) => { const ruleType = field.value as RuleType; const setType = useCallback( (type: RuleType) => { @@ -37,6 +38,7 @@ export const SelectRuleType: React.FC = ({ field }) => { description={i18n.QUERY_TYPE_DESCRIPTION} icon={} selectable={{ + isDisabled: isReadOnly, onClick: setQuery, isSelected: !isMlRule(ruleType), }} @@ -49,6 +51,7 @@ export const SelectRuleType: React.FC = ({ field }) => { isDisabled={!license} icon={} selectable={{ + isDisabled: isReadOnly, onClick: setMl, isSelected: isMlRule(ruleType), }} diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_define_rule/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_define_rule/index.tsx index 6b1a9a828d950..d3ef185f3786b 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_define_rule/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_define_rule/index.tsx @@ -178,7 +178,13 @@ const StepDefineRuleComponent: FC = ({ <>
- + <> ({ scheduledTaskId: '2dabe330-0702-11ea-8b50-773b89126888', }); +export const getMlResult = (): RuleAlertType => { + const result = getResult(); + + return { + ...result, + params: { + ...result.params, + query: undefined, + language: undefined, + filters: undefined, + index: undefined, + type: 'machine_learning', + anomalyThreshold: 44, + machineLearningJobId: 'some_job_id', + }, + }; +}; + export const updateActionResult = (): ActionResult => ({ id: 'result-1', actionTypeId: 'action-id-1', 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 920cf97d32a7a..d95ef595e5c40 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 @@ -228,6 +228,8 @@ export const importRulesRoute = (router: IRouter, config: LegacyServices['config references, note, version, + anomalyThreshold, + machineLearningJobId, }); resolve({ rule_id: ruleId, status_code: 200 }); } else if (rule != null) { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.test.ts new file mode 100644 index 0000000000000..4c8d0f51f251b --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.test.ts @@ -0,0 +1,50 @@ +/* + * 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 { alertsClientMock } from '../../../../../../../plugins/alerting/server/mocks'; +import { actionsClientMock } from '../../../../../../../plugins/actions/server/mocks'; +import { getMlResult } from '../routes/__mocks__/request_responses'; +import { createRules } from './create_rules'; + +describe('createRules', () => { + let actionsClient: ReturnType; + let alertsClient: ReturnType; + + beforeEach(() => { + actionsClient = actionsClientMock.create(); + alertsClient = alertsClientMock.create(); + }); + + it('calls the alertsClient with ML params', async () => { + const params = { + ...getMlResult().params, + anomalyThreshold: 55, + machineLearningJobId: 'new_job_id', + }; + + await createRules({ + alertsClient, + actionsClient, + ...params, + ruleId: 'new-rule-id', + enabled: true, + interval: '', + name: '', + tags: [], + }); + + expect(alertsClient.create).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + params: expect.objectContaining({ + anomalyThreshold: 55, + machineLearningJobId: 'new_job_id', + }), + }), + }) + ); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.test.ts new file mode 100644 index 0000000000000..b424d2912ebc8 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/patch_rules.test.ts @@ -0,0 +1,51 @@ +/* + * 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 { savedObjectsClientMock } from '../../../../../../../../src/core/server/mocks'; +import { alertsClientMock } from '../../../../../../../plugins/alerting/server/mocks'; +import { actionsClientMock } from '../../../../../../../plugins/actions/server/mocks'; +import { getMlResult } from '../routes/__mocks__/request_responses'; +import { patchRules } from './patch_rules'; + +describe('patchRules', () => { + let actionsClient: ReturnType; + let alertsClient: ReturnType; + let savedObjectsClient: ReturnType; + + beforeEach(() => { + actionsClient = actionsClientMock.create(); + alertsClient = alertsClientMock.create(); + savedObjectsClient = savedObjectsClientMock.create(); + }); + + it('calls the alertsClient with ML params', async () => { + alertsClient.get.mockResolvedValue(getMlResult()); + const params = { + ...getMlResult().params, + anomalyThreshold: 55, + machineLearningJobId: 'new_job_id', + }; + + await patchRules({ + alertsClient, + actionsClient, + savedObjectsClient, + id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + ...params, + }); + + expect(alertsClient.update).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + params: expect.objectContaining({ + anomalyThreshold: 55, + machineLearningJobId: 'new_job_id', + }), + }), + }) + ); + }); +}); 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 4fb73235854c0..a8da01f87a6fb 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 @@ -46,6 +46,8 @@ export const patchRules = async ({ version, throttle, lists, + anomalyThreshold, + machineLearningJobId, }: PatchRuleParams): Promise => { const rule = await readRules({ alertsClient, ruleId, id }); if (rule == null) { @@ -79,6 +81,8 @@ export const patchRules = async ({ throttle, note, lists, + anomalyThreshold, + machineLearningJobId, }); const nextParams = defaults( @@ -109,6 +113,8 @@ export const patchRules = async ({ note, version: calculatedVersion, lists, + anomalyThreshold, + machineLearningJobId, } ); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.test.ts new file mode 100644 index 0000000000000..5ee740a8b8845 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.test.ts @@ -0,0 +1,56 @@ +/* + * 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 { savedObjectsClientMock } from '../../../../../../../../src/core/server/mocks'; +import { alertsClientMock } from '../../../../../../../plugins/alerting/server/mocks'; +import { actionsClientMock } from '../../../../../../../plugins/actions/server/mocks'; +import { getMlResult } from '../routes/__mocks__/request_responses'; +import { updateRules } from './update_rules'; + +describe('updateRules', () => { + let actionsClient: ReturnType; + let alertsClient: ReturnType; + let savedObjectsClient: ReturnType; + + beforeEach(() => { + actionsClient = actionsClientMock.create(); + alertsClient = alertsClientMock.create(); + savedObjectsClient = savedObjectsClientMock.create(); + }); + + it('calls the alertsClient with ML params', async () => { + alertsClient.get.mockResolvedValue(getMlResult()); + + const params = { + ...getMlResult().params, + anomalyThreshold: 55, + machineLearningJobId: 'new_job_id', + }; + + await updateRules({ + alertsClient, + actionsClient, + savedObjectsClient, + id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + ...params, + enabled: true, + interval: '', + name: '', + tags: [], + }); + + expect(alertsClient.update).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + params: expect.objectContaining({ + anomalyThreshold: 55, + machineLearningJobId: 'new_job_id', + }), + }), + }) + ); + }); +}); 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 b2a1d2a6307d2..ae8ea9dd32cd2 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 @@ -46,6 +46,8 @@ export const updateRules = async ({ throttle, note, lists, + anomalyThreshold, + machineLearningJobId, }: UpdateRuleParams): Promise => { const rule = await readRules({ alertsClient, ruleId, id }); if (rule == null) { @@ -78,6 +80,8 @@ export const updateRules = async ({ version, throttle, note, + anomalyThreshold, + machineLearningJobId, }); // TODO: Remove this and use regular lists once the feature is stable for a release @@ -115,6 +119,8 @@ export const updateRules = async ({ references, note, version: calculatedVersion, + anomalyThreshold, + machineLearningJobId, ...listsParam, }, },