From 5fb4a702089a51726dc6e7a724f3cb76bf62f02b Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Fri, 30 Aug 2024 20:09:03 +0200 Subject: [PATCH 01/34] response actions in eql and esql rules --- .../model/rule_schema/rule_schemas.gen.ts | 3 +- .../rule_schema/rule_schemas.schema.yaml | 30 ++++++++---------- .../components/step_rule_actions/index.tsx | 4 +-- .../e2e/automated_response_actions/form.cy.ts | 31 +++++++++++++++++-- .../cypress/tasks/response_actions.ts | 27 ++++++++++++++-- .../api/rules/create_rule/route.test.ts | 29 ++++++++++++++++- .../api/rules/update_rule/route.test.ts | 30 +++++++++++++++++- .../common_params_camel_to_snake.ts | 2 ++ .../convert_rule_response_to_alerting_rule.ts | 10 +++--- .../type_specific_camel_to_snake.ts | 3 -- .../mergers/apply_rule_defaults.ts | 4 +-- .../mergers/apply_rule_patch.ts | 3 +- .../rule_management/utils/validate.ts | 30 +++++++++++------- .../endpoint_response_action.ts | 3 ++ .../rule_response_actions/types.ts | 8 +++++ .../rule_types/eql/create_eql_alert_type.ts | 13 ++++++-- .../detection_engine/rule_types/eql/eql.ts | 13 +++++++- .../rule_types/esql/create_esql_alert_type.ts | 20 +++++++++--- .../detection_engine/rule_types/esql/esql.ts | 16 ++++++++-- .../lib/detection_engine/rule_types/types.ts | 2 ++ .../security_solution/server/plugin.ts | 10 ++++-- 21 files changed, 228 insertions(+), 63 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts index 972c0ce519044..a06151fd0cee5 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts @@ -117,6 +117,7 @@ export const BaseOptionalFields = z.object({ meta: RuleMetadata.optional(), investigation_fields: InvestigationFields.optional(), throttle: RuleActionThrottle.optional(), + response_actions: z.array(ResponseAction).optional(), }); export type BaseDefaultableFields = z.infer; @@ -261,7 +262,6 @@ export const QueryRuleOptionalFields = z.object({ data_view_id: DataViewId.optional(), filters: RuleFilterArray.optional(), saved_id: SavedQueryId.optional(), - response_actions: z.array(ResponseAction).optional(), alert_suppression: AlertSuppression.optional(), }); @@ -312,7 +312,6 @@ export const SavedQueryRuleOptionalFields = z.object({ index: IndexPatternArray.optional(), data_view_id: DataViewId.optional(), filters: RuleFilterArray.optional(), - response_actions: z.array(ResponseAction).optional(), alert_suppression: AlertSuppression.optional(), query: RuleQuery.optional(), }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml index 4ade72c15fbb9..240174878e020 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: title: Security Rule Schema version: 'not applicable' -paths: {} +paths: { } components: x-codegen-enabled: true schemas: @@ -70,6 +70,10 @@ components: investigation_fields: $ref: './common_attributes.schema.yaml#/components/schemas/InvestigationFields' + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' # Throttle throttle: $ref: './common_attributes.schema.yaml#/components/schemas/RuleActionThrottle' @@ -262,7 +266,7 @@ components: properties: type: type: string - enum: [eql] + enum: [ eql ] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -338,7 +342,7 @@ components: properties: type: type: string - enum: [query] + enum: [ query ] description: Rule type required: - type @@ -354,10 +358,6 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' saved_id: $ref: './common_attributes.schema.yaml#/components/schemas/SavedQueryId' - response_actions: - type: array - items: - $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' @@ -418,7 +418,7 @@ components: properties: type: type: string - enum: [saved_query] + enum: [ saved_query ] description: Rule type saved_id: $ref: './common_attributes.schema.yaml#/components/schemas/SavedQueryId' @@ -435,10 +435,6 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/DataViewId' filters: $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' - response_actions: - type: array - items: - $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' query: @@ -499,7 +495,7 @@ components: properties: type: type: string - enum: [threshold] + enum: [ threshold ] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -579,7 +575,7 @@ components: properties: type: type: string - enum: [threat_match] + enum: [ threat_match ] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -675,7 +671,7 @@ components: properties: type: type: string - enum: [machine_learning] + enum: [ machine_learning ] description: Rule type anomaly_threshold: $ref: './specific_attributes/ml_attributes.schema.yaml#/components/schemas/AnomalyThreshold' @@ -737,7 +733,7 @@ components: properties: type: type: string - enum: [new_terms] + enum: [ new_terms ] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -823,7 +819,7 @@ components: properties: type: type: string - enum: [esql] + enum: [ esql ] description: Rule type language: $ref: '#/components/schemas/EsqlQueryLanguage' diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx index b555054a75e0c..33c86e87d364e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx @@ -17,7 +17,7 @@ import type { import { UseArray } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import type { RuleObjectId } from '../../../../../common/api/detection_engine/model/rule_schema'; -import { isQueryRule } from '../../../../../common/detection_engine/utils'; +import { isQueryRule, isEsqlRule, isEqlRule } from '../../../../../common/detection_engine/utils'; import { ResponseActionsForm } from '../../../rule_response_actions/response_actions_form'; import type { RuleStepProps, @@ -101,7 +101,7 @@ const StepRuleActionsComponent: FC = ({ [actionMessageParams, summaryActionMessageParams] ); const displayResponseActionsOptions = useMemo(() => { - if (isQueryRule(ruleType)) { + if (isQueryRule(ruleType) || isEsqlRule(ruleType) || isEqlRule(ruleType)) { return ( {ResponseActionsForm} diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index bc909bb62a30e..a88f251a3b226 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -1,8 +1,9 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import { @@ -12,6 +13,7 @@ import { tryAddingDisabledResponseAction, validateAvailableCommands, visitRuleActions, + fillUpNewEsqlRule, } from '../../tasks/response_actions'; import { cleanupRule, generateRandomStringName, loadRule } from '../../tasks/api_fixtures'; import { ResponseActionTypesEnum } from '../../../../../common/api/detection_engine'; @@ -202,6 +204,31 @@ describe( }); }); + describe('User should be able to add response action to ESQL rule', () => { + let ruleId: string; + const [ruleName, ruleDescription] = generateRandomStringName(2); + + beforeEach(() => { + login(ROLE.soc_manager); + }); + afterEach(() => { + if (ruleId) { + cleanupRule(ruleId); + } + }); + + it('create and save endpoint response action inside of a rule', () => { + fillUpNewEsqlRule(ruleName, ruleDescription); + addEndpointResponseAction(); + focusAndOpenCommandDropdown(); + validateAvailableCommands(); + cy.getByTestSubj(`command-type-isolate`).click(); + + cy.getByTestSubj('create-enabled-false').click(); + cy.contains(`${ruleName} was created`); + }); + }); + describe('User should not see endpoint action when no rbac', () => { const [ruleName, ruleDescription] = generateRandomStringName(2); diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts index 0e46b99c40d72..3fd26db3298c4 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts @@ -1,8 +1,9 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import { inputConsoleCommand, submitCommand } from './response_console'; @@ -69,6 +70,28 @@ export const fillUpNewRule = (name = 'Test', description = 'Test') => { cy.getByTestSubj('about-continue').click(); cy.getByTestSubj('schedule-continue').click(); }; + +export const fillUpNewEsqlRule = (name = 'Test', description = 'Test') => { + loadPage('app/security/rules/management'); + cy.getByTestSubj('create-new-rule').click(); + cy.getByTestSubj('stepDefineRule').within(() => { + cy.getByTestSubj('esqlRuleType').click(); + cy.getByTestSubj('globalQueryBar').first().click(); + cy.getByTestSubj('kibanaCodeEditor').type( + 'FROM logs-* METADATA _index, _id {backspace}{enter}' + ); + }); + cy.getByTestSubj('define-continue').click(); + cy.getByTestSubj('detectionEngineStepAboutRuleName').within(() => { + cy.getByTestSubj('input').type(name); + }); + cy.getByTestSubj('detectionEngineStepAboutRuleDescription').within(() => { + cy.getByTestSubj('input').type(description); + }); + cy.getByTestSubj('about-continue').click(); + cy.getByTestSubj('schedule-continue').click(); +}; + export const visitRuleActions = (ruleId: string) => { loadPage(`app/security/rules/id/${ruleId}/edit`); cy.getByTestSubj('edit-rule-actions-tab').should('exist'); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts index 7441aec8c8fa5..f31903a065b1a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts @@ -182,7 +182,7 @@ describe('Create rule route', () => { }); const defaultAction = getResponseAction(); - test('is successful', async () => { + test('is successful in query rule', async () => { const request = requestMock.create({ method: 'post', path: DETECTION_ENGINE_RULES_URL, @@ -196,6 +196,33 @@ describe('Create rule route', () => { expect(response.status).toEqual(200); }); + test('is successful in esql rule', async () => { + const request = requestMock.create({ + method: 'post', + path: DETECTION_ENGINE_RULES_URL, + body: { + ...getCreateEsqlRulesSchemaMock('rule-2'), + response_actions: [defaultAction], + }, + }); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + expect(response.status).toEqual(200); + }); + test('is successful in eql rule', async () => { + const request = requestMock.create({ + method: 'post', + path: DETECTION_ENGINE_RULES_URL, + body: { + ...getCreateEqlRuleSchemaMock('rule-3'), + response_actions: [defaultAction], + }, + }); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + expect(response.status).toEqual(200); + }); + test('fails when isolate rbac is set to false', async () => { (context.securitySolution.getEndpointAuthz as jest.Mock).mockReturnValue(() => ({ canIsolateHost: jest.fn().mockReturnValue(false), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts index 87f42a014c1d2..b9efed17117db 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts @@ -189,7 +189,7 @@ describe('Update rule route', () => { }); const defaultAction = getResponseAction(); - test('is successful', async () => { + test('is successful for query rule', async () => { const request = requestMock.create({ method: 'post', path: DETECTION_ENGINE_RULES_URL, @@ -203,6 +203,34 @@ describe('Update rule route', () => { expect(response.status).toEqual(200); }); + test('is successful for esql rule', async () => { + const request = requestMock.create({ + method: 'post', + path: DETECTION_ENGINE_RULES_URL, + body: { + ...getCreateEsqlRulesSchemaMock('rule-2'), + response_actions: [defaultAction], + }, + }); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + expect(response.status).toEqual(200); + }); + + test('is successful for eql rule', async () => { + const request = requestMock.create({ + method: 'post', + path: DETECTION_ENGINE_RULES_URL, + body: { + ...getCreateEqlRuleSchemaMock('rule-3'), + response_actions: [defaultAction], + }, + }); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + expect(response.status).toEqual(200); + }); + test('fails when isolate rbac is set to false', async () => { (context.securitySolution.getEndpointAuthz as jest.Mock).mockReturnValue(() => ({ canIsolateHost: jest.fn().mockReturnValue(false), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts index 6f98230043e74..bd942385e984a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { transformAlertToRuleResponseAction } from '../../../../../../../common/detection_engine/transform_actions'; import { convertObjectKeysToSnakeCase } from '../../../../../../utils/object_case_converters'; import type { BaseRuleParams } from '../../../../rule_schema'; import { migrateLegacyInvestigationFields } from '../../../utils/utils'; @@ -43,5 +44,6 @@ export const commonParamsCamelToSnake = (params: BaseRuleParams) => { related_integrations: params.relatedIntegrations ?? [], required_fields: params.requiredFields ?? [], setup: params.setup ?? '', + response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts index 52a00f1d6f42d..384ba452bdb41 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts @@ -93,6 +93,9 @@ export const convertRuleResponseToAlertingRule = ( note: rule.note, version: rule.version, exceptionsList: rule.exceptions_list, + responseActions: params.response_actions?.map((rule) => + transformRuleToAlertResponseAction(rule) + ), ...typeSpecificParams, }, schedule: { interval: rule.interval }, @@ -157,9 +160,7 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific query: params.query ?? '', filters: params.filters, savedId: params.saved_id, - responseActions: params.response_actions?.map((rule) => - transformRuleToAlertResponseAction(rule) - ), + alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), }; } @@ -172,9 +173,6 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific filters: params.filters, savedId: params.saved_id, dataViewId: params.data_view_id, - responseActions: params.response_actions?.map((rule) => - transformRuleToAlertResponseAction(rule) - ), alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), }; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts index 0808d1921e9bf..5a2f7ba0d3548 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts @@ -7,7 +7,6 @@ import type { RequiredOptional } from '@kbn/zod-helpers'; import type { TypeSpecificResponse } from '../../../../../../../common/api/detection_engine/model/rule_schema'; -import { transformAlertToRuleResponseAction } from '../../../../../../../common/detection_engine/transform_actions'; import { assertUnreachable } from '../../../../../../../common/utility_types'; import { convertObjectKeysToSnakeCase } from '../../../../../../utils/object_case_converters'; import type { TypeSpecificRuleParams } from '../../../../rule_schema'; @@ -67,7 +66,6 @@ export const typeSpecificCamelToSnake = ( query: params.query, filters: params.filters, saved_id: params.savedId, - response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), }; } @@ -80,7 +78,6 @@ export const typeSpecificCamelToSnake = ( filters: params.filters, saved_id: params.savedId, data_view_id: params.dataViewId, - response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), }; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts index 837df0b3b2f1f..07e1b2593070e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts @@ -42,6 +42,7 @@ export const RULE_DEFAULTS = { author: [], output_index: '', version: 1, + response_actions: [], }; export function applyRuleDefaults(rule: RuleCreateProps & { immutable?: boolean }) { @@ -56,6 +57,7 @@ export function applyRuleDefaults(rule: RuleCreateProps & { immutable?: boolean immutable, rule_source: convertImmutableToRuleSource(immutable), required_fields: addEcsToRequiredFields(rule.required_fields), + response_actions: rule.response_actions, }; } @@ -125,7 +127,6 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { query: props.query ?? '', filters: props.filters, saved_id: props.saved_id, - response_actions: props.response_actions, alert_suppression: props.alert_suppression, }; } @@ -138,7 +139,6 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { filters: props.filters, saved_id: props.saved_id, data_view_id: props.data_view_id, - response_actions: props.response_actions, alert_suppression: props.alert_suppression, }; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts index 9d02cd8dbb9df..72264dc7efc44 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts @@ -111,6 +111,7 @@ export const applyRulePatch = async ({ interval: rulePatch.interval ?? existingRule.interval, throttle: rulePatch.throttle ?? existingRule.throttle, actions: rulePatch.actions ?? existingRule.actions, + response_actions: rulePatch.response_actions ?? existingRule.response_actions, ...typeSpecificParams, }; @@ -189,7 +190,6 @@ const patchQueryParams = ( query: rulePatch.query ?? existingRule.query, filters: rulePatch.filters ?? existingRule.filters, saved_id: rulePatch.saved_id ?? existingRule.saved_id, - response_actions: rulePatch.response_actions ?? existingRule.response_actions, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, }; }; @@ -206,7 +206,6 @@ const patchSavedQueryParams = ( query: rulePatch.query ?? existingRule.query, filters: rulePatch.filters ?? existingRule.filters, saved_id: rulePatch.saved_id ?? existingRule.saved_id, - response_actions: rulePatch.response_actions ?? existingRule.response_actions, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts index 500db54acd867..03ac448e7cfd5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts @@ -9,6 +9,7 @@ import type { PartialRule } from '@kbn/alerting-plugin/server'; import type { Rule } from '@kbn/alerting-plugin/common'; import { isEqual, xorWith } from 'lodash'; import { stringifyZodError } from '@kbn/zod-helpers'; +import type { BaseCreateProps, BasePatchProps } from '../../../../../common/api/detection_engine'; import { type QueryRule, type ResponseAction, @@ -21,15 +22,11 @@ import { RESPONSE_ACTION_API_COMMAND_TO_CONSOLE_COMMAND_MAP, RESPONSE_CONSOLE_ACTION_COMMANDS_TO_REQUIRED_AUTHZ, } from '../../../../../common/endpoint/service/response_actions/constants'; -import { isQueryRule } from '../../../../../common/detection_engine/utils'; +import { isEqlRule, isEsqlRule, isQueryRule } from '../../../../../common/detection_engine/utils'; import type { SecuritySolutionApiRequestHandlerContext } from '../../../..'; import { CustomHttpRequestError } from '../../../../utils/custom_http_request_error'; -import { - hasValidRuleType, - type RuleAlertType, - type RuleParams, - type UnifiedQueryRuleParams, -} from '../../rule_schema'; +import type { BaseRuleParams } from '../../rule_schema'; +import { hasValidRuleType, type RuleAlertType, type RuleParams } from '../../rule_schema'; import { type BulkError, createBulkErrorObject } from '../../routes/utils'; import { internalRuleToAPIResponse } from '../logic/detection_rules_client/converters/internal_rule_to_api_response'; @@ -64,11 +61,18 @@ export const validateResponseActionsPermissions = async ( ruleUpdate: RuleCreateProps | RuleUpdateProps, existingRule?: RuleAlertType | null ): Promise => { - if (!isQueryRule(ruleUpdate.type)) { + if ( + !isQueryRule(ruleUpdate.type) && + !isEsqlRule(ruleUpdate.type) && + !isEqlRule(ruleUpdate.type) + ) { return; } - if (!isQueryRulePayload(ruleUpdate) || (existingRule && !isQueryRuleObject(existingRule))) { + if ( + !rulePayloadContainsResponseActions(ruleUpdate) || + (existingRule && !ruleObjectContainsResponseActions(existingRule)) + ) { return; } @@ -108,10 +112,14 @@ export const validateResponseActionsPermissions = async ( }); }; -function isQueryRulePayload(rule: RuleCreateProps | RuleUpdateProps): rule is QueryRule { +// TODO TD: fix types +function rulePayloadContainsResponseActions( + rule: BaseCreateProps | BasePatchProps +): rule is QueryRule { return 'response_actions' in rule; } -function isQueryRuleObject(rule?: RuleAlertType): rule is Rule { +// @ts-expect-error TODO TC: fix types +function ruleObjectContainsResponseActions(rule?: RuleAlertType): rule is Rule { return rule != null && 'params' in rule && 'responseActions' in rule?.params; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/endpoint_response_action.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/endpoint_response_action.ts index a310cb33497e8..11d7ec28dc739 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/endpoint_response_action.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/endpoint_response_action.ts @@ -31,6 +31,9 @@ export const endpointResponseAction = async ( ); const ruleId = alerts[0][ALERT_RULE_UUID]; const ruleName = alerts[0][ALERT_RULE_NAME]; + // Query rules contain rule details with dotted syntax, while EQL/Esql rules contain rule details with nested syntax + const ruleId = alerts[0][ALERT_RULE_UUID] ?? alerts[0].kibana?.alert?.rule.rule_id; + const ruleName = alerts[0][ALERT_RULE_NAME] ?? alerts[0].kibana?.alert?.rule.name; const logMsgPrefix = `Rule [${ruleName}][${ruleId}]:`; const { comment, command } = responseAction.params; const errors: string[] = []; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/types.ts index e7317acfd7ca1..2f23ee6a6ac6c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/types.ts @@ -19,6 +19,14 @@ export type Alert = ParsedTechnicalFields & { process?: { pid: string; }; + kibana: { + alert?: { + rule: { + name: string; + rule_id: string; + }; + }; + }; }; export interface AlertAgent { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts index 81971feeecfc1..2497d7efea710 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts @@ -11,16 +11,22 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; import { EqlRuleParams } from '../../rule_schema'; import { eqlExecutor } from './eql'; -import type { CreateRuleOptions, SecurityAlertType, SignalSourceHit } from '../types'; +import type { + CreateRuleOptions, + SecurityAlertType, + SignalSourceHit, + CreateQueryRuleAdditionalOptions, +} from '../types'; import { validateIndexPatterns } from '../utils'; import type { BuildReasonMessage } from '../utils/reason_formatters'; import { wrapSuppressedAlerts } from '../utils/wrap_suppressed_alerts'; import { getIsAlertSuppressionActive } from '../utils/get_is_alert_suppression_active'; export const createEqlAlertType = ( - createOptions: CreateRuleOptions + createOptions: CreateRuleOptions & CreateQueryRuleAdditionalOptions ): SecurityAlertType => { - const { experimentalFeatures, version, licensing } = createOptions; + const { experimentalFeatures, version, licensing, scheduleNotificationResponseActionsService } = + createOptions; return { id: EQL_RULE_TYPE_ID, name: 'Event Correlation Rule', @@ -125,6 +131,7 @@ export const createEqlAlertType = ( alertWithSuppression, isAlertSuppressionActive: isNonSeqAlertSuppressionActive, experimentalFeatures, + scheduleNotificationResponseActionsService, }); return { ...result, state }; }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts index a3a1ba545c0ea..62d57b38b261c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts @@ -66,6 +66,7 @@ interface EqlExecutorParams { alertWithSuppression: SuppressedAlertService; isAlertSuppressionActive: boolean; experimentalFeatures: ExperimentalFeatures; + scheduleNotificationResponseActionsService?: CreateQueryRuleAdditionalOptions['scheduleNotificationResponseActionsService']; } export const eqlExecutor = async ({ @@ -88,6 +89,7 @@ export const eqlExecutor = async ({ alertWithSuppression, isAlertSuppressionActive, experimentalFeatures, + scheduleNotificationResponseActionsService, }: EqlExecutorParams): Promise => { const ruleParams = completeRule.ruleParams; @@ -187,7 +189,16 @@ export const eqlExecutor = async ({ result.warningMessages.push(maxSignalsWarning); } - + if ( + completeRule.ruleParams.responseActions?.length && + result.createdSignalsCount && + scheduleNotificationResponseActionsService + ) { + scheduleNotificationResponseActionsService({ + signals: result.createdSignals.map((signal) => expandDottedObject(signal as object)), + responseActions: completeRule.ruleParams.responseActions, + }); + } return result; } catch (error) { if ( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts index 10c82ad8fed7c..83b3c554cb20e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts @@ -11,12 +11,17 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; import { EsqlRuleParams } from '../../rule_schema'; import { esqlExecutor } from './esql'; -import type { CreateRuleOptions, SecurityAlertType } from '../types'; +import type { + CreateRuleOptions, + SecurityAlertType, + CreateQueryRuleAdditionalOptions, +} from '../types'; export const createEsqlAlertType = ( - createOptions: CreateRuleOptions + createOptions: CreateRuleOptions & CreateQueryRuleAdditionalOptions ): SecurityAlertType => { - const { version, experimentalFeatures, licensing } = createOptions; + const { version, experimentalFeatures, licensing, scheduleNotificationResponseActionsService } = + createOptions; return { id: ESQL_RULE_TYPE_ID, name: 'ES|QL Rule', @@ -44,6 +49,13 @@ export const createEsqlAlertType = ( isExportable: false, category: DEFAULT_APP_CATEGORIES.security.id, producer: SERVER_APP_ID, - executor: (params) => esqlExecutor({ ...params, experimentalFeatures, version, licensing }), + executor: (params) => + esqlExecutor({ + ...params, + experimentalFeatures, + version, + licensing, + scheduleNotificationResponseActionsService, + }), }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts index b129a7ef0c5bb..77602bf15c135 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts @@ -19,6 +19,7 @@ import { } from '@kbn/securitysolution-utils'; import type { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { buildEsqlSearchRequest } from './build_esql_search_request'; +import { expandDottedObject } from '../../../../../common/utils/expand_dotted'; import { performEsqlRequest } from './esql_request'; import { wrapEsqlAlerts } from './wrap_esql_alerts'; import { wrapSuppressedEsqlAlerts } from './wrap_suppressed_esql_alerts'; @@ -28,8 +29,7 @@ import { rowToDocument } from './utils'; import { fetchSourceDocuments } from './fetch_source_documents'; import { buildReasonMessageForEsqlAlert } from '../utils/reason_formatters'; -import type { RunOpts, SignalSource } from '../types'; - +import type { RunOpts, SignalSource, CreateQueryRuleAdditionalOptions } from '../types'; import { addToSearchAfterReturn, createSearchAfterReturnType, @@ -63,6 +63,7 @@ export const esqlExecutor = async ({ spaceId, experimentalFeatures, licensing, + scheduleNotificationResponseActionsService, }: { runOpts: RunOpts; services: RuleExecutorServices; @@ -71,6 +72,7 @@ export const esqlExecutor = async ({ version: string; experimentalFeatures: ExperimentalFeatures; licensing: LicensingPluginSetup; + scheduleNotificationResponseActionsService?: CreateQueryRuleAdditionalOptions['scheduleNotificationResponseActionsService']; }) => { const ruleParams = completeRule.ruleParams; /** @@ -225,6 +227,16 @@ export const esqlExecutor = async ({ break; } } + if ( + completeRule.ruleParams.responseActions?.length && + result.createdSignalsCount && + scheduleNotificationResponseActionsService + ) { + scheduleNotificationResponseActionsService({ + signals: result.createdSignals.map((signal) => expandDottedObject(signal as object)), + responseActions: completeRule.ruleParams.responseActions, + }); + } // no more results will be found if (response.values.length < size) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts index 4069b7782e0e8..d3d649722bb60 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts @@ -163,6 +163,8 @@ export interface ScheduleNotificationActions { signals: unknown[]; responseActions: RuleResponseAction[]; } + +// TODO TC: Rename - it's not about QueryRule anymore export interface CreateQueryRuleAdditionalOptions { scheduleNotificationResponseActionsService?: (params: ScheduleNotificationActions) => void; } diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index c24e70baa5db8..cc324c18e1597 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -320,9 +320,15 @@ export class Plugin implements ISecuritySolutionPlugin { const securityRuleTypeWrapper = createSecurityRuleTypeWrapper(securityRuleTypeOptions); - plugins.alerting.registerType(securityRuleTypeWrapper(createEqlAlertType(ruleOptions))); + plugins.alerting.registerType( + securityRuleTypeWrapper(createEqlAlertType({ ...ruleOptions, ...queryRuleAdditionalOptions })) + ); if (!experimentalFeatures.esqlRulesDisabled) { - plugins.alerting.registerType(securityRuleTypeWrapper(createEsqlAlertType(ruleOptions))); + plugins.alerting.registerType( + securityRuleTypeWrapper( + createEsqlAlertType({ ...ruleOptions, ...queryRuleAdditionalOptions }) + ) + ); } plugins.alerting.registerType( securityRuleTypeWrapper( From 2b342da9fd0326c95da2d146079978e1e1cf04bb Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Mon, 2 Sep 2024 11:02:41 +0200 Subject: [PATCH 02/34] limit to esql and eql --- .../rule_schema/rule_schemas.schema.yaml | 22 ++++++++++++++----- .../e2e/automated_response_actions/form.cy.ts | 2 +- .../cypress/tasks/response_actions.ts | 2 -- .../api/rules/create_rule/route.test.ts | 7 ++++-- .../api/rules/update_rule/route.test.ts | 3 ++- .../common_params_camel_to_snake.ts | 2 -- .../convert_rule_response_to_alerting_rule.ts | 16 ++++++++++---- .../type_specific_camel_to_snake.ts | 5 +++++ .../mergers/apply_rule_defaults.ts | 6 +++-- .../mergers/apply_rule_patch.ts | 5 ++++- .../rule_management/utils/validate.ts | 20 ++++++++++------- 11 files changed, 62 insertions(+), 28 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml index 240174878e020..3123f9c5e225f 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml @@ -70,10 +70,6 @@ components: investigation_fields: $ref: './common_attributes.schema.yaml#/components/schemas/InvestigationFields' - response_actions: - type: array - items: - $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' # Throttle throttle: $ref: './common_attributes.schema.yaml#/components/schemas/RuleActionThrottle' @@ -296,6 +292,10 @@ components: $ref: './specific_attributes/eql_attributes.schema.yaml#/components/schemas/TimestampField' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' EqlRuleCreateFields: allOf: @@ -358,6 +358,10 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' saved_id: $ref: './common_attributes.schema.yaml#/components/schemas/SavedQueryId' + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' @@ -435,6 +439,10 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/DataViewId' filters: $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' query: @@ -836,6 +844,10 @@ components: properties: alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' EsqlRulePatchFields: allOf: @@ -956,10 +968,10 @@ components: discriminator: propertyName: type anyOf: + - $ref: '#/components/schemas/ThresholdRule' - $ref: '#/components/schemas/EqlRule' - $ref: '#/components/schemas/QueryRule' - $ref: '#/components/schemas/SavedQueryRule' - - $ref: '#/components/schemas/ThresholdRule' - $ref: '#/components/schemas/ThreatMatchRule' - $ref: '#/components/schemas/MachineLearningRule' - $ref: '#/components/schemas/NewTermsRule' diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index a88f251a3b226..d33b5531a9350 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -8,12 +8,12 @@ import { addEndpointResponseAction, + fillUpNewEsqlRule, fillUpNewRule, focusAndOpenCommandDropdown, tryAddingDisabledResponseAction, validateAvailableCommands, visitRuleActions, - fillUpNewEsqlRule, } from '../../tasks/response_actions'; import { cleanupRule, generateRandomStringName, loadRule } from '../../tasks/api_fixtures'; import { ResponseActionTypesEnum } from '../../../../../common/api/detection_engine'; diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts index 3fd26db3298c4..f2c4800206659 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts @@ -70,7 +70,6 @@ export const fillUpNewRule = (name = 'Test', description = 'Test') => { cy.getByTestSubj('about-continue').click(); cy.getByTestSubj('schedule-continue').click(); }; - export const fillUpNewEsqlRule = (name = 'Test', description = 'Test') => { loadPage('app/security/rules/management'); cy.getByTestSubj('create-new-rule').click(); @@ -91,7 +90,6 @@ export const fillUpNewEsqlRule = (name = 'Test', description = 'Test') => { cy.getByTestSubj('about-continue').click(); cy.getByTestSubj('schedule-continue').click(); }; - export const visitRuleActions = (ruleId: string) => { loadPage(`app/security/rules/id/${ruleId}/edit`); cy.getByTestSubj('edit-rule-actions-tab').should('exist'); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts index f31903a065b1a..e76933f612885 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts @@ -16,7 +16,11 @@ import { } from '../../../../routes/__mocks__/request_responses'; import { requestContextMock, serverMock, requestMock } from '../../../../routes/__mocks__'; import { createRuleRoute } from './route'; -import { getCreateRulesSchemaMock } from '../../../../../../../common/api/detection_engine/model/rule_schema/mocks'; +import { + getCreateEqlRuleSchemaMock, + getCreateEsqlRulesSchemaMock, + getCreateRulesSchemaMock, +} from '../../../../../../../common/api/detection_engine/model/rule_schema/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { getQueryRuleParams } from '../../../../rule_schema/mocks'; import { HttpAuthzError } from '../../../../../machine_learning/validation'; @@ -195,7 +199,6 @@ describe('Create rule route', () => { const response = await server.inject(request, requestContextMock.convertContext(context)); expect(response.status).toEqual(200); }); - test('is successful in esql rule', async () => { const request = requestMock.create({ method: 'post', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts index b9efed17117db..8456ce573d3ba 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts @@ -17,6 +17,8 @@ import { getRulesSchemaMock } from '../../../../../../../common/api/detection_en import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import { updateRuleRoute } from './route'; import { + getCreateEqlRuleSchemaMock, + getCreateEsqlRulesSchemaMock, getCreateRulesSchemaMock, getUpdateRulesSchemaMock, } from '../../../../../../../common/api/detection_engine/model/rule_schema/mocks'; @@ -202,7 +204,6 @@ describe('Update rule route', () => { const response = await server.inject(request, requestContextMock.convertContext(context)); expect(response.status).toEqual(200); }); - test('is successful for esql rule', async () => { const request = requestMock.create({ method: 'post', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts index bd942385e984a..6f98230043e74 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { transformAlertToRuleResponseAction } from '../../../../../../../common/detection_engine/transform_actions'; import { convertObjectKeysToSnakeCase } from '../../../../../../utils/object_case_converters'; import type { BaseRuleParams } from '../../../../rule_schema'; import { migrateLegacyInvestigationFields } from '../../../utils/utils'; @@ -44,6 +43,5 @@ export const commonParamsCamelToSnake = (params: BaseRuleParams) => { related_integrations: params.relatedIntegrations ?? [], required_fields: params.requiredFields ?? [], setup: params.setup ?? '', - response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts index 384ba452bdb41..76ad36da0443c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts @@ -93,9 +93,6 @@ export const convertRuleResponseToAlertingRule = ( note: rule.note, version: rule.version, exceptionsList: rule.exceptions_list, - responseActions: params.response_actions?.map((rule) => - transformRuleToAlertResponseAction(rule) - ), ...typeSpecificParams, }, schedule: { interval: rule.interval }, @@ -120,6 +117,9 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific timestampField: params.timestamp_field, eventCategoryOverride: params.event_category_override, tiebreakerField: params.tiebreaker_field, + responseActions: params.response_actions?.map((rule) => + transformRuleToAlertResponseAction(rule) + ), alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), }; } @@ -128,6 +128,9 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific type: params.type, language: params.language, query: params.query, + responseActions: params.response_actions?.map((rule) => + transformRuleToAlertResponseAction(rule) + ), alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), }; } @@ -160,7 +163,9 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific query: params.query ?? '', filters: params.filters, savedId: params.saved_id, - + responseActions: params.response_actions?.map((rule) => + transformRuleToAlertResponseAction(rule) + ), alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), }; } @@ -173,6 +178,9 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific filters: params.filters, savedId: params.saved_id, dataViewId: params.data_view_id, + responseActions: params.response_actions?.map((rule) => + transformRuleToAlertResponseAction(rule) + ), alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), }; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts index 5a2f7ba0d3548..5e1faca1f7bc3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts @@ -7,6 +7,7 @@ import type { RequiredOptional } from '@kbn/zod-helpers'; import type { TypeSpecificResponse } from '../../../../../../../common/api/detection_engine/model/rule_schema'; +import { transformAlertToRuleResponseAction } from '../../../../../../../common/detection_engine/transform_actions'; import { assertUnreachable } from '../../../../../../../common/utility_types'; import { convertObjectKeysToSnakeCase } from '../../../../../../utils/object_case_converters'; import type { TypeSpecificRuleParams } from '../../../../rule_schema'; @@ -27,6 +28,7 @@ export const typeSpecificCamelToSnake = ( event_category_override: params.eventCategoryOverride, tiebreaker_field: params.tiebreakerField, alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), + response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; } case 'esql': { @@ -35,6 +37,7 @@ export const typeSpecificCamelToSnake = ( language: params.language, query: params.query, alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), + response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; } case 'threat_match': { @@ -66,6 +69,7 @@ export const typeSpecificCamelToSnake = ( query: params.query, filters: params.filters, saved_id: params.savedId, + response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), }; } @@ -78,6 +82,7 @@ export const typeSpecificCamelToSnake = ( filters: params.filters, saved_id: params.savedId, data_view_id: params.dataViewId, + response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), }; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts index 07e1b2593070e..a5dd806322bc7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts @@ -42,7 +42,6 @@ export const RULE_DEFAULTS = { author: [], output_index: '', version: 1, - response_actions: [], }; export function applyRuleDefaults(rule: RuleCreateProps & { immutable?: boolean }) { @@ -57,7 +56,6 @@ export function applyRuleDefaults(rule: RuleCreateProps & { immutable?: boolean immutable, rule_source: convertImmutableToRuleSource(immutable), required_fields: addEcsToRequiredFields(rule.required_fields), - response_actions: rule.response_actions, }; } @@ -88,6 +86,7 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { event_category_override: props.event_category_override, tiebreaker_field: props.tiebreaker_field, alert_suppression: props.alert_suppression, + response_actions: props.response_actions, }; } case 'esql': { @@ -96,6 +95,7 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { language: props.language, query: props.query, alert_suppression: props.alert_suppression, + response_actions: props.response_actions, }; } case 'threat_match': { @@ -127,6 +127,7 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { query: props.query ?? '', filters: props.filters, saved_id: props.saved_id, + response_actions: props.response_actions, alert_suppression: props.alert_suppression, }; } @@ -139,6 +140,7 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { filters: props.filters, saved_id: props.saved_id, data_view_id: props.data_view_id, + response_actions: props.response_actions, alert_suppression: props.alert_suppression, }; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts index 72264dc7efc44..3d85cd367f10e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts @@ -111,7 +111,6 @@ export const applyRulePatch = async ({ interval: rulePatch.interval ?? existingRule.interval, throttle: rulePatch.throttle ?? existingRule.throttle, actions: rulePatch.actions ?? existingRule.actions, - response_actions: rulePatch.response_actions ?? existingRule.response_actions, ...typeSpecificParams, }; @@ -139,6 +138,7 @@ const patchEqlParams = ( rulePatch.event_category_override ?? existingRule.event_category_override, tiebreaker_field: rulePatch.tiebreaker_field ?? existingRule.tiebreaker_field, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, + response_actions: rulePatch.response_actions ?? existingRule.response_actions, }; }; @@ -151,6 +151,7 @@ const patchEsqlParams = ( language: rulePatch.language ?? existingRule.language, query: rulePatch.query ?? existingRule.query, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, + response_actions: rulePatch.response_actions ?? existingRule.response_actions, }; }; @@ -190,6 +191,7 @@ const patchQueryParams = ( query: rulePatch.query ?? existingRule.query, filters: rulePatch.filters ?? existingRule.filters, saved_id: rulePatch.saved_id ?? existingRule.saved_id, + response_actions: rulePatch.response_actions ?? existingRule.response_actions, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, }; }; @@ -206,6 +208,7 @@ const patchSavedQueryParams = ( query: rulePatch.query ?? existingRule.query, filters: rulePatch.filters ?? existingRule.filters, saved_id: rulePatch.saved_id ?? existingRule.saved_id, + response_actions: rulePatch.response_actions ?? existingRule.response_actions, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts index 03ac448e7cfd5..22627547bf86e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts @@ -9,7 +9,6 @@ import type { PartialRule } from '@kbn/alerting-plugin/server'; import type { Rule } from '@kbn/alerting-plugin/common'; import { isEqual, xorWith } from 'lodash'; import { stringifyZodError } from '@kbn/zod-helpers'; -import type { BaseCreateProps, BasePatchProps } from '../../../../../common/api/detection_engine'; import { type QueryRule, type ResponseAction, @@ -22,11 +21,15 @@ import { RESPONSE_ACTION_API_COMMAND_TO_CONSOLE_COMMAND_MAP, RESPONSE_CONSOLE_ACTION_COMMANDS_TO_REQUIRED_AUTHZ, } from '../../../../../common/endpoint/service/response_actions/constants'; -import { isEqlRule, isEsqlRule, isQueryRule } from '../../../../../common/detection_engine/utils'; +import { isQueryRule, isEsqlRule, isEqlRule } from '../../../../../common/detection_engine/utils'; import type { SecuritySolutionApiRequestHandlerContext } from '../../../..'; import { CustomHttpRequestError } from '../../../../utils/custom_http_request_error'; -import type { BaseRuleParams } from '../../rule_schema'; -import { hasValidRuleType, type RuleAlertType, type RuleParams } from '../../rule_schema'; +import { + hasValidRuleType, + type RuleAlertType, + type RuleParams, + type UnifiedQueryRuleParams, +} from '../../rule_schema'; import { type BulkError, createBulkErrorObject } from '../../routes/utils'; import { internalRuleToAPIResponse } from '../logic/detection_rules_client/converters/internal_rule_to_api_response'; @@ -112,14 +115,15 @@ export const validateResponseActionsPermissions = async ( }); }; -// TODO TD: fix types +// TODO TC: figure out typings function rulePayloadContainsResponseActions( - rule: BaseCreateProps | BasePatchProps + rule: RuleCreateProps | RuleUpdateProps ): rule is QueryRule { return 'response_actions' in rule; } -// @ts-expect-error TODO TC: fix types -function ruleObjectContainsResponseActions(rule?: RuleAlertType): rule is Rule { +function ruleObjectContainsResponseActions( + rule?: RuleAlertType +): rule is Rule { return rule != null && 'params' in rule && 'responseActions' in rule?.params; } From 0db366dd80bef298388d5b6387b140e789110b3c Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Mon, 2 Sep 2024 11:07:54 +0200 Subject: [PATCH 03/34] add type --- .../rule_management/utils/validate.ts | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts index 22627547bf86e..b4df420246432 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts @@ -10,7 +10,6 @@ import type { Rule } from '@kbn/alerting-plugin/common'; import { isEqual, xorWith } from 'lodash'; import { stringifyZodError } from '@kbn/zod-helpers'; import { - type QueryRule, type ResponseAction, type RuleCreateProps, RuleResponse, @@ -24,12 +23,7 @@ import { import { isQueryRule, isEsqlRule, isEqlRule } from '../../../../../common/detection_engine/utils'; import type { SecuritySolutionApiRequestHandlerContext } from '../../../..'; import { CustomHttpRequestError } from '../../../../utils/custom_http_request_error'; -import { - hasValidRuleType, - type RuleAlertType, - type RuleParams, - type UnifiedQueryRuleParams, -} from '../../rule_schema'; +import { hasValidRuleType, type RuleAlertType, type RuleParams } from '../../rule_schema'; import { type BulkError, createBulkErrorObject } from '../../routes/utils'; import { internalRuleToAPIResponse } from '../logic/detection_rules_client/converters/internal_rule_to_api_response'; @@ -115,15 +109,14 @@ export const validateResponseActionsPermissions = async ( }); }; -// TODO TC: figure out typings function rulePayloadContainsResponseActions( rule: RuleCreateProps | RuleUpdateProps -): rule is QueryRule { +): rule is { response_actions: ResponseAction[] } { return 'response_actions' in rule; } function ruleObjectContainsResponseActions( rule?: RuleAlertType -): rule is Rule { +): rule is Rule<{ response_actions: ResponseAction[] }> { return rule != null && 'params' in rule && 'responseActions' in rule?.params; } From e9b272c4eff6a2a6b3a209e200870ad752e04571 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Mon, 2 Sep 2024 12:17:11 +0200 Subject: [PATCH 04/34] fix types --- .../model/rule_schema/rule_schemas.gen.ts | 7 +++++-- .../rule_management/utils/validate.ts | 13 ++++++++++--- .../endpoint_response_action.ts | 2 -- .../rule_schema/model/rule_schemas.ts | 2 ++ .../lib/detection_engine/rule_types/eql/eql.ts | 4 ++++ 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts index a06151fd0cee5..084183968cbd0 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts @@ -117,7 +117,6 @@ export const BaseOptionalFields = z.object({ meta: RuleMetadata.optional(), investigation_fields: InvestigationFields.optional(), throttle: RuleActionThrottle.optional(), - response_actions: z.array(ResponseAction).optional(), }); export type BaseDefaultableFields = z.infer; @@ -225,6 +224,7 @@ export const EqlOptionalFields = z.object({ tiebreaker_field: TiebreakerField.optional(), timestamp_field: TimestampField.optional(), alert_suppression: AlertSuppression.optional(), + response_actions: z.array(ResponseAction).optional(), }); export type EqlRuleCreateFields = z.infer; @@ -262,6 +262,7 @@ export const QueryRuleOptionalFields = z.object({ data_view_id: DataViewId.optional(), filters: RuleFilterArray.optional(), saved_id: SavedQueryId.optional(), + response_actions: z.array(ResponseAction).optional(), alert_suppression: AlertSuppression.optional(), }); @@ -312,6 +313,7 @@ export const SavedQueryRuleOptionalFields = z.object({ index: IndexPatternArray.optional(), data_view_id: DataViewId.optional(), filters: RuleFilterArray.optional(), + response_actions: z.array(ResponseAction).optional(), alert_suppression: AlertSuppression.optional(), query: RuleQuery.optional(), }); @@ -573,6 +575,7 @@ export const EsqlRuleRequiredFields = z.object({ export type EsqlRuleOptionalFields = z.infer; export const EsqlRuleOptionalFields = z.object({ alert_suppression: AlertSuppression.optional(), + response_actions: z.array(ResponseAction).optional(), }); export type EsqlRulePatchFields = z.infer; @@ -670,10 +673,10 @@ export const RulePatchProps = z.union([ export type RuleResponse = z.infer; export const RuleResponse = z.discriminatedUnion('type', [ + ThresholdRule, EqlRule, QueryRule, SavedQueryRule, - ThresholdRule, ThreatMatchRule, MachineLearningRule, NewTermsRule, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts index b4df420246432..939c0685dacc9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts @@ -9,6 +9,7 @@ import type { PartialRule } from '@kbn/alerting-plugin/server'; import type { Rule } from '@kbn/alerting-plugin/common'; import { isEqual, xorWith } from 'lodash'; import { stringifyZodError } from '@kbn/zod-helpers'; +import type { EqlRule, EsqlRule, QueryRule } from '../../../../../common/api/detection_engine'; import { type ResponseAction, type RuleCreateProps, @@ -23,7 +24,13 @@ import { import { isQueryRule, isEsqlRule, isEqlRule } from '../../../../../common/detection_engine/utils'; import type { SecuritySolutionApiRequestHandlerContext } from '../../../..'; import { CustomHttpRequestError } from '../../../../utils/custom_http_request_error'; -import { hasValidRuleType, type RuleAlertType, type RuleParams } from '../../rule_schema'; +import type { EqlRuleParams, EsqlRuleParams } from '../../rule_schema'; +import { + hasValidRuleType, + type RuleAlertType, + type RuleParams, + type UnifiedQueryRuleParams, +} from '../../rule_schema'; import { type BulkError, createBulkErrorObject } from '../../routes/utils'; import { internalRuleToAPIResponse } from '../logic/detection_rules_client/converters/internal_rule_to_api_response'; @@ -111,12 +118,12 @@ export const validateResponseActionsPermissions = async ( function rulePayloadContainsResponseActions( rule: RuleCreateProps | RuleUpdateProps -): rule is { response_actions: ResponseAction[] } { +): rule is QueryRule | EsqlRule | EqlRule { return 'response_actions' in rule; } function ruleObjectContainsResponseActions( rule?: RuleAlertType -): rule is Rule<{ response_actions: ResponseAction[] }> { +): rule is Rule { return rule != null && 'params' in rule && 'responseActions' in rule?.params; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/endpoint_response_action.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/endpoint_response_action.ts index 11d7ec28dc739..5d2c165161ec8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/endpoint_response_action.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/endpoint_response_action.ts @@ -29,8 +29,6 @@ export const endpointResponseAction = async ( 'ruleExecution', 'automatedResponseActions' ); - const ruleId = alerts[0][ALERT_RULE_UUID]; - const ruleName = alerts[0][ALERT_RULE_NAME]; // Query rules contain rule details with dotted syntax, while EQL/Esql rules contain rule details with nested syntax const ruleId = alerts[0][ALERT_RULE_UUID] ?? alerts[0].kibana?.alert?.rule.rule_id; const ruleName = alerts[0][ALERT_RULE_NAME] ?? alerts[0].kibana?.alert?.rule.name; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts index 632649f733473..a81732cfccf94 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts @@ -162,6 +162,7 @@ export const EqlSpecificRuleParams = z.object({ timestampField: TimestampField.optional(), tiebreakerField: TiebreakerField.optional(), alertSuppression: AlertSuppressionCamel.optional(), + responseActions: z.array(RuleResponseAction).optional(), }); export type EqlRuleParams = BaseRuleParams & EqlSpecificRuleParams; @@ -172,6 +173,7 @@ export const EsqlSpecificRuleParams = z.object({ type: z.literal('esql'), language: z.literal('esql'), query: RuleQuery, + responseActions: z.array(RuleResponseAction).optional(), alertSuppression: AlertSuppressionCamel.optional(), }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts index 62d57b38b261c..40dc28f8dd067 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts @@ -14,6 +14,7 @@ import type { } from '@kbn/alerting-plugin/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { Filter } from '@kbn/es-query'; +import { expandDottedObject } from '../../../../../common/utils/expand_dotted'; import { buildEqlSearchRequest } from './build_eql_search_request'; import { createEnrichEventsFunction } from '../utils/enrichments'; @@ -26,6 +27,7 @@ import type { SearchAfterAndBulkCreateReturnType, SignalSource, WrapSuppressedHits, + CreateQueryRuleAdditionalOptions, } from '../types'; import { addToSearchAfterReturn, @@ -189,6 +191,7 @@ export const eqlExecutor = async ({ result.warningMessages.push(maxSignalsWarning); } + if ( completeRule.ruleParams.responseActions?.length && result.createdSignalsCount && @@ -199,6 +202,7 @@ export const eqlExecutor = async ({ responseActions: completeRule.ruleParams.responseActions, }); } + return result; } catch (error) { if ( From 45c6f9a949da5aab35d06e6ed36fe7256a5ae0fc Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Mon, 2 Sep 2024 12:56:01 +0200 Subject: [PATCH 05/34] fix cy test --- .../public/management/cypress/tasks/response_actions.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts index f2c4800206659..757a27eccea29 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts @@ -76,9 +76,7 @@ export const fillUpNewEsqlRule = (name = 'Test', description = 'Test') => { cy.getByTestSubj('stepDefineRule').within(() => { cy.getByTestSubj('esqlRuleType').click(); cy.getByTestSubj('globalQueryBar').first().click(); - cy.getByTestSubj('kibanaCodeEditor').type( - 'FROM logs-* METADATA _index, _id {backspace}{enter}' - ); + cy.getByTestSubj('kibanaCodeEditor').type('FROM * METADATA _index, _id {backspace}{enter}'); }); cy.getByTestSubj('define-continue').click(); cy.getByTestSubj('detectionEngineStepAboutRuleName').within(() => { From 90990df33ddae0c1fa782316ef63ef2d0cd96b31 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 2 Sep 2024 12:57:43 +0000 Subject: [PATCH 06/34] [CI] Auto-commit changed files from 'yarn openapi:bundle' --- ...ution_detections_api_2023_10_31.bundled.schema.yaml | 10 +++++++++- ...ution_detections_api_2023_10_31.bundled.schema.yaml | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml index dcee1694a4aeb..5e63009461437 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -2042,6 +2042,10 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array tiebreaker_field: $ref: '#/components/schemas/TiebreakerField' timestamp_field: @@ -2729,6 +2733,10 @@ components: properties: alert_suppression: $ref: '#/components/schemas/AlertSuppression' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array EsqlRulePatchProps: allOf: - type: object @@ -5205,10 +5213,10 @@ components: type: array RuleResponse: anyOf: + - $ref: '#/components/schemas/ThresholdRule' - $ref: '#/components/schemas/EqlRule' - $ref: '#/components/schemas/QueryRule' - $ref: '#/components/schemas/SavedQueryRule' - - $ref: '#/components/schemas/ThresholdRule' - $ref: '#/components/schemas/ThreatMatchRule' - $ref: '#/components/schemas/MachineLearningRule' - $ref: '#/components/schemas/NewTermsRule' diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml index e3a294c9f92a5..47a41cee0fe23 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -1316,6 +1316,10 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array tiebreaker_field: $ref: '#/components/schemas/TiebreakerField' timestamp_field: @@ -2003,6 +2007,10 @@ components: properties: alert_suppression: $ref: '#/components/schemas/AlertSuppression' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array EsqlRulePatchProps: allOf: - type: object @@ -4358,10 +4366,10 @@ components: type: array RuleResponse: anyOf: + - $ref: '#/components/schemas/ThresholdRule' - $ref: '#/components/schemas/EqlRule' - $ref: '#/components/schemas/QueryRule' - $ref: '#/components/schemas/SavedQueryRule' - - $ref: '#/components/schemas/ThresholdRule' - $ref: '#/components/schemas/ThreatMatchRule' - $ref: '#/components/schemas/MachineLearningRule' - $ref: '#/components/schemas/NewTermsRule' From 5c3701bd7c8589188f6d8c5b779cbc0650187a52 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 2 Sep 2024 13:01:28 +0000 Subject: [PATCH 07/34] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../cypress/e2e/automated_response_actions/form.cy.ts | 5 ++--- .../public/management/cypress/tasks/response_actions.ts | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index d33b5531a9350..8559d875a6ea2 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -1,9 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import { diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts index 757a27eccea29..c4be7c2dd204c 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts @@ -1,9 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import { inputConsoleCommand, submitCommand } from './response_console'; From 3a983f9dad1e7227406fe89bad81c0c55e757036 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Mon, 2 Sep 2024 15:48:57 +0200 Subject: [PATCH 08/34] snapshots --- ...s_upgrade_and_rollback_checks.test.ts.snap | 169 ++++++++++++++++++ .../rule_schema/rule_response_schema.test.ts | 2 +- .../bulk_crud/response_schema.test.ts | 2 +- 3 files changed, 171 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap index c84a3565d48f6..d150da5cefe2d 100644 --- a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap +++ b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap @@ -6135,6 +6135,175 @@ Object { "query": Object { "type": "string", }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/1/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + ], + }, + "type": "array", + }, "tiebreakerField": Object { "type": "string", }, diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts index 30fe84514e05a..a8a51199e24af 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts @@ -41,7 +41,7 @@ describe('Rule response schema', () => { const result = RuleResponse.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'"` + `"type: Invalid discriminator value. Expected 'threshold' | 'eql' | 'query' | 'saved_query' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'"` ); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts index 2d4af1c18f6d1..555900fe4049a 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts @@ -59,7 +59,7 @@ describe('Bulk CRUD rules response schema', () => { const result = BulkCrudRulesResponse.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql', 0.error: Required"` + `"0.type: Invalid discriminator value. Expected 'threshold' | 'eql' | 'query' | 'saved_query' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql', 0.error: Required"` ); }); From e3cef1a3e59f1f63155a758252cc53466fc85f16 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Tue, 3 Sep 2024 10:46:47 +0200 Subject: [PATCH 09/34] fix --- .../api/detection_engine/model/rule_schema/rule_schemas.gen.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts index f7e83937c9a4e..ed253dc6aff01 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts @@ -686,6 +686,7 @@ export type RulePatchProps = z.infer; export const RulePatchProps = RulePatchPropsInternal as z.ZodType; const RuleResponseInternal = z.discriminatedUnion('type', [ + ThresholdRule, EqlRule, QueryRule, SavedQueryRule, From 28a93d2e984d134d8c981a4ad6a233c4669f3c05 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Tue, 3 Sep 2024 10:54:50 +0200 Subject: [PATCH 10/34] rename type --- .../rule_types/eql/create_eql_alert_type.ts | 4 ++-- .../server/lib/detection_engine/rule_types/eql/eql.ts | 4 ++-- .../rule_types/esql/create_esql_alert_type.ts | 8 ++------ .../server/lib/detection_engine/rule_types/esql/esql.ts | 4 ++-- .../server/lib/detection_engine/rule_types/query/query.ts | 4 ++-- .../server/lib/detection_engine/rule_types/types.ts | 7 ++----- x-pack/plugins/security_solution/server/plugin.ts | 4 ++-- 7 files changed, 14 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts index 2497d7efea710..ca16b38404e48 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts @@ -15,7 +15,7 @@ import type { CreateRuleOptions, SecurityAlertType, SignalSourceHit, - CreateQueryRuleAdditionalOptions, + CreateRuleAdditionalOptions, } from '../types'; import { validateIndexPatterns } from '../utils'; import type { BuildReasonMessage } from '../utils/reason_formatters'; @@ -23,7 +23,7 @@ import { wrapSuppressedAlerts } from '../utils/wrap_suppressed_alerts'; import { getIsAlertSuppressionActive } from '../utils/get_is_alert_suppression_active'; export const createEqlAlertType = ( - createOptions: CreateRuleOptions & CreateQueryRuleAdditionalOptions + createOptions: CreateRuleOptions & CreateRuleAdditionalOptions ): SecurityAlertType => { const { experimentalFeatures, version, licensing, scheduleNotificationResponseActionsService } = createOptions; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts index 40dc28f8dd067..53ee1e70284d4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts @@ -27,7 +27,7 @@ import type { SearchAfterAndBulkCreateReturnType, SignalSource, WrapSuppressedHits, - CreateQueryRuleAdditionalOptions, + CreateRuleAdditionalOptions, } from '../types'; import { addToSearchAfterReturn, @@ -68,7 +68,7 @@ interface EqlExecutorParams { alertWithSuppression: SuppressedAlertService; isAlertSuppressionActive: boolean; experimentalFeatures: ExperimentalFeatures; - scheduleNotificationResponseActionsService?: CreateQueryRuleAdditionalOptions['scheduleNotificationResponseActionsService']; + scheduleNotificationResponseActionsService?: CreateRuleAdditionalOptions['scheduleNotificationResponseActionsService']; } export const eqlExecutor = async ({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts index 83b3c554cb20e..31afe8d2a191f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts @@ -11,14 +11,10 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; import { EsqlRuleParams } from '../../rule_schema'; import { esqlExecutor } from './esql'; -import type { - CreateRuleOptions, - SecurityAlertType, - CreateQueryRuleAdditionalOptions, -} from '../types'; +import type { CreateRuleOptions, SecurityAlertType, CreateRuleAdditionalOptions } from '../types'; export const createEsqlAlertType = ( - createOptions: CreateRuleOptions & CreateQueryRuleAdditionalOptions + createOptions: CreateRuleOptions & CreateRuleAdditionalOptions ): SecurityAlertType => { const { version, experimentalFeatures, licensing, scheduleNotificationResponseActionsService } = createOptions; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts index 77602bf15c135..cbba3ec5114dc 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts @@ -29,7 +29,7 @@ import { rowToDocument } from './utils'; import { fetchSourceDocuments } from './fetch_source_documents'; import { buildReasonMessageForEsqlAlert } from '../utils/reason_formatters'; -import type { RunOpts, SignalSource, CreateQueryRuleAdditionalOptions } from '../types'; +import type { RunOpts, SignalSource, CreateRuleAdditionalOptions } from '../types'; import { addToSearchAfterReturn, createSearchAfterReturnType, @@ -72,7 +72,7 @@ export const esqlExecutor = async ({ version: string; experimentalFeatures: ExperimentalFeatures; licensing: LicensingPluginSetup; - scheduleNotificationResponseActionsService?: CreateQueryRuleAdditionalOptions['scheduleNotificationResponseActionsService']; + scheduleNotificationResponseActionsService?: CreateRuleAdditionalOptions['scheduleNotificationResponseActionsService']; }) => { const ruleParams = completeRule.ruleParams; /** diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts index 272184dbf1e58..525a171cf4364 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts @@ -22,7 +22,7 @@ import type { UnifiedQueryRuleParams } from '../../rule_schema'; import type { ExperimentalFeatures } from '../../../../../common/experimental_features'; import { buildReasonMessageForQueryAlert } from '../utils/reason_formatters'; import { withSecuritySpan } from '../../../../utils/with_security_span'; -import type { CreateQueryRuleAdditionalOptions, RunOpts } from '../types'; +import type { CreateRuleAdditionalOptions, RunOpts } from '../types'; export const queryExecutor = async ({ runOpts, @@ -42,7 +42,7 @@ export const queryExecutor = async ({ version: string; spaceId: string; bucketHistory?: BucketHistory[]; - scheduleNotificationResponseActionsService?: CreateQueryRuleAdditionalOptions['scheduleNotificationResponseActionsService']; + scheduleNotificationResponseActionsService?: CreateRuleAdditionalOptions['scheduleNotificationResponseActionsService']; licensing: LicensingPluginSetup; }) => { const completeRule = runOpts.completeRule; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts index d3d649722bb60..b4273d975b7bc 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts @@ -164,14 +164,11 @@ export interface ScheduleNotificationActions { responseActions: RuleResponseAction[]; } -// TODO TC: Rename - it's not about QueryRule anymore -export interface CreateQueryRuleAdditionalOptions { +export interface CreateRuleAdditionalOptions { scheduleNotificationResponseActionsService?: (params: ScheduleNotificationActions) => void; } -export interface CreateQueryRuleOptions - extends CreateRuleOptions, - CreateQueryRuleAdditionalOptions { +export interface CreateQueryRuleOptions extends CreateRuleOptions, CreateRuleAdditionalOptions { id: typeof QUERY_RULE_TYPE_ID | typeof SAVED_QUERY_RULE_TYPE_ID; name: 'Custom Query Rule' | 'Saved Query Rule'; } diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index cc324c18e1597..5cb0a94c7690a 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -78,7 +78,7 @@ import type { IRuleMonitoringService } from './lib/detection_engine/rule_monitor import { createRuleMonitoringService } from './lib/detection_engine/rule_monitoring'; import { EndpointMetadataService } from './endpoint/services/metadata'; import type { - CreateQueryRuleAdditionalOptions, + CreateRuleAdditionalOptions, CreateRuleOptions, } from './lib/detection_engine/rule_types/types'; // eslint-disable-next-line no-restricted-imports @@ -311,7 +311,7 @@ export class Plugin implements ISecuritySolutionPlugin { analytics: core.analytics, }; - const queryRuleAdditionalOptions: CreateQueryRuleAdditionalOptions = { + const queryRuleAdditionalOptions: CreateRuleAdditionalOptions = { scheduleNotificationResponseActionsService: getScheduleNotificationResponseActionsService({ endpointAppContextService: this.endpointAppContextService, osqueryCreateActionService: plugins.osquery.createActionService, From f5660430990480ae28cd1f330d21f659ebdabe95 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Tue, 3 Sep 2024 11:04:22 +0200 Subject: [PATCH 11/34] roll back ThresholdRule position --- .../rule_schema/rule_response_schema.test.ts | 2 +- .../model/rule_schema/rule_schemas.gen.ts | 2 +- .../rule_schema/rule_schemas.schema.yaml | 20 +++++++++---------- .../bulk_crud/response_schema.test.ts | 2 +- ...ections_api_2023_10_31.bundled.schema.yaml | 2 +- ...ections_api_2023_10_31.bundled.schema.yaml | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts index a8a51199e24af..30fe84514e05a 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts @@ -41,7 +41,7 @@ describe('Rule response schema', () => { const result = RuleResponse.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid discriminator value. Expected 'threshold' | 'eql' | 'query' | 'saved_query' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'"` + `"type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'"` ); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts index ed253dc6aff01..83ee742e13c59 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts @@ -686,10 +686,10 @@ export type RulePatchProps = z.infer; export const RulePatchProps = RulePatchPropsInternal as z.ZodType; const RuleResponseInternal = z.discriminatedUnion('type', [ - ThresholdRule, EqlRule, QueryRule, SavedQueryRule, + ThresholdRule, ThreatMatchRule, MachineLearningRule, NewTermsRule, diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml index 3123f9c5e225f..5ea301773a605 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: title: Security Rule Schema version: 'not applicable' -paths: { } +paths: {} components: x-codegen-enabled: true schemas: @@ -262,7 +262,7 @@ components: properties: type: type: string - enum: [ eql ] + enum: [eql] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -342,7 +342,7 @@ components: properties: type: type: string - enum: [ query ] + enum: [query] description: Rule type required: - type @@ -422,7 +422,7 @@ components: properties: type: type: string - enum: [ saved_query ] + enum: [saved_query] description: Rule type saved_id: $ref: './common_attributes.schema.yaml#/components/schemas/SavedQueryId' @@ -503,7 +503,7 @@ components: properties: type: type: string - enum: [ threshold ] + enum: [threshold] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -583,7 +583,7 @@ components: properties: type: type: string - enum: [ threat_match ] + enum: [threat_match] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -679,7 +679,7 @@ components: properties: type: type: string - enum: [ machine_learning ] + enum: [machine_learning] description: Rule type anomaly_threshold: $ref: './specific_attributes/ml_attributes.schema.yaml#/components/schemas/AnomalyThreshold' @@ -741,7 +741,7 @@ components: properties: type: type: string - enum: [ new_terms ] + enum: [new_terms] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -827,7 +827,7 @@ components: properties: type: type: string - enum: [ esql ] + enum: [esql] description: Rule type language: $ref: '#/components/schemas/EsqlQueryLanguage' @@ -968,10 +968,10 @@ components: discriminator: propertyName: type anyOf: - - $ref: '#/components/schemas/ThresholdRule' - $ref: '#/components/schemas/EqlRule' - $ref: '#/components/schemas/QueryRule' - $ref: '#/components/schemas/SavedQueryRule' + - $ref: '#/components/schemas/ThresholdRule' - $ref: '#/components/schemas/ThreatMatchRule' - $ref: '#/components/schemas/MachineLearningRule' - $ref: '#/components/schemas/NewTermsRule' diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts index 555900fe4049a..2d4af1c18f6d1 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts @@ -59,7 +59,7 @@ describe('Bulk CRUD rules response schema', () => { const result = BulkCrudRulesResponse.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.type: Invalid discriminator value. Expected 'threshold' | 'eql' | 'query' | 'saved_query' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql', 0.error: Required"` + `"0.type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql', 0.error: Required"` ); }); diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml index 5e63009461437..c9f17ef28239d 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -5213,10 +5213,10 @@ components: type: array RuleResponse: anyOf: - - $ref: '#/components/schemas/ThresholdRule' - $ref: '#/components/schemas/EqlRule' - $ref: '#/components/schemas/QueryRule' - $ref: '#/components/schemas/SavedQueryRule' + - $ref: '#/components/schemas/ThresholdRule' - $ref: '#/components/schemas/ThreatMatchRule' - $ref: '#/components/schemas/MachineLearningRule' - $ref: '#/components/schemas/NewTermsRule' diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml index 47a41cee0fe23..bad22a1b80f36 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -4366,10 +4366,10 @@ components: type: array RuleResponse: anyOf: - - $ref: '#/components/schemas/ThresholdRule' - $ref: '#/components/schemas/EqlRule' - $ref: '#/components/schemas/QueryRule' - $ref: '#/components/schemas/SavedQueryRule' + - $ref: '#/components/schemas/ThresholdRule' - $ref: '#/components/schemas/ThreatMatchRule' - $ref: '#/components/schemas/MachineLearningRule' - $ref: '#/components/schemas/NewTermsRule' From 4e3be88bdd3f414f84f4b23b2875b2f806c9ec40 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Mon, 9 Sep 2024 17:34:23 +0200 Subject: [PATCH 12/34] pass response actions to more rules --- .../model/rule_schema/rule_schemas.gen.ts | 7 ++---- .../rule_schema/rule_schemas.schema.yaml | 22 +++++-------------- .../common/detection_engine/utils.ts | 3 +++ .../components/step_rule_actions/index.tsx | 4 ++-- .../e2e/automated_response_actions/form.cy.ts | 6 ++--- .../common_params_camel_to_snake.ts | 2 ++ .../convert_rule_response_to_alerting_rule.ts | 15 +++---------- .../type_specific_camel_to_snake.ts | 5 ----- .../mergers/apply_rule_defaults.ts | 5 +---- .../mergers/apply_rule_patch.ts | 5 +---- .../rule_management/utils/validate.ts | 21 +++++++++--------- .../endpoint_response_action.ts | 6 ++--- .../schedule_notification_response_actions.ts | 7 ++++-- .../rule_response_actions/types.ts | 2 +- .../rule_schema/model/rule_schemas.ts | 5 +---- .../detection_engine/rule_types/eql/eql.ts | 3 +-- .../detection_engine/rule_types/esql/esql.ts | 5 +++-- .../new_terms/create_new_terms_alert_type.ts | 18 +++++++++++++-- .../security_solution/server/plugin.ts | 16 +++++++------- 19 files changed, 71 insertions(+), 86 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts index ed253dc6aff01..d4418e0371295 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts @@ -68,13 +68,13 @@ import { SavedQueryId, KqlQueryLanguage, } from './common_attributes.gen'; +import { ResponseAction } from '../rule_response_actions/response_actions.gen'; import { RuleExecutionSummary } from '../../rule_monitoring/model/execution_summary.gen'; import { EventCategoryOverride, TiebreakerField, TimestampField, } from './specific_attributes/eql_attributes.gen'; -import { ResponseAction } from '../rule_response_actions/response_actions.gen'; import { Threshold, ThresholdAlertSuppression, @@ -117,6 +117,7 @@ export const BaseOptionalFields = z.object({ meta: RuleMetadata.optional(), investigation_fields: InvestigationFields.optional(), throttle: RuleActionThrottle.optional(), + response_actions: z.array(ResponseAction).optional(), }); export type BaseDefaultableFields = z.infer; @@ -224,7 +225,6 @@ export const EqlOptionalFields = z.object({ tiebreaker_field: TiebreakerField.optional(), timestamp_field: TimestampField.optional(), alert_suppression: AlertSuppression.optional(), - response_actions: z.array(ResponseAction).optional(), }); export type EqlRuleCreateFields = z.infer; @@ -262,7 +262,6 @@ export const QueryRuleOptionalFields = z.object({ data_view_id: DataViewId.optional(), filters: RuleFilterArray.optional(), saved_id: SavedQueryId.optional(), - response_actions: z.array(ResponseAction).optional(), alert_suppression: AlertSuppression.optional(), }); @@ -313,7 +312,6 @@ export const SavedQueryRuleOptionalFields = z.object({ index: IndexPatternArray.optional(), data_view_id: DataViewId.optional(), filters: RuleFilterArray.optional(), - response_actions: z.array(ResponseAction).optional(), alert_suppression: AlertSuppression.optional(), query: RuleQuery.optional(), }); @@ -575,7 +573,6 @@ export const EsqlRuleRequiredFields = z.object({ export type EsqlRuleOptionalFields = z.infer; export const EsqlRuleOptionalFields = z.object({ alert_suppression: AlertSuppression.optional(), - response_actions: z.array(ResponseAction).optional(), }); export type EsqlRulePatchFields = z.infer; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml index 3123f9c5e225f..e468d54b14de7 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml @@ -73,6 +73,12 @@ components: # Throttle throttle: $ref: './common_attributes.schema.yaml#/components/schemas/RuleActionThrottle' + # Response Actions + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' + BaseDefaultableFields: x-inline: true @@ -292,10 +298,6 @@ components: $ref: './specific_attributes/eql_attributes.schema.yaml#/components/schemas/TimestampField' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' - response_actions: - type: array - items: - $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' EqlRuleCreateFields: allOf: @@ -358,10 +360,6 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' saved_id: $ref: './common_attributes.schema.yaml#/components/schemas/SavedQueryId' - response_actions: - type: array - items: - $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' @@ -439,10 +437,6 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/DataViewId' filters: $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' - response_actions: - type: array - items: - $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' query: @@ -844,10 +838,6 @@ components: properties: alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' - response_actions: - type: array - items: - $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' EsqlRulePatchFields: allOf: diff --git a/x-pack/plugins/security_solution/common/detection_engine/utils.ts b/x-pack/plugins/security_solution/common/detection_engine/utils.ts index e0cefdebecd93..71780e31f6369 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/utils.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/utils.ts @@ -93,3 +93,6 @@ export const isSuppressionRuleConfiguredWithMissingFields = (ruleType: Type) => export const isSuppressionRuleInGA = (ruleType: Type): boolean => { return isSuppressibleAlertRule(ruleType) && SUPPRESSIBLE_ALERT_RULES_GA.includes(ruleType); }; + +export const shouldShowResponseActions = (ruleType: Type | undefined) => + isQueryRule(ruleType) || isEsqlRule(ruleType) || isEqlRule(ruleType) || isNewTermsRule(ruleType); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx index 33c86e87d364e..7e1b6b3d8f74c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx @@ -16,8 +16,8 @@ import type { } from '@kbn/triggers-actions-ui-plugin/public'; import { UseArray } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; +import { shouldShowResponseActions } from '../../../../../common/detection_engine/utils'; import type { RuleObjectId } from '../../../../../common/api/detection_engine/model/rule_schema'; -import { isQueryRule, isEsqlRule, isEqlRule } from '../../../../../common/detection_engine/utils'; import { ResponseActionsForm } from '../../../rule_response_actions/response_actions_form'; import type { RuleStepProps, @@ -101,7 +101,7 @@ const StepRuleActionsComponent: FC = ({ [actionMessageParams, summaryActionMessageParams] ); const displayResponseActionsOptions = useMemo(() => { - if (isQueryRule(ruleType) || isEsqlRule(ruleType) || isEqlRule(ruleType)) { + if (shouldShowResponseActions(ruleType)) { return ( {ResponseActionsForm} diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index 8559d875a6ea2..707f0a90d42d2 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -1,8 +1,9 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import { @@ -204,7 +205,6 @@ describe( }); describe('User should be able to add response action to ESQL rule', () => { - let ruleId: string; const [ruleName, ruleDescription] = generateRandomStringName(2); beforeEach(() => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts index 6f98230043e74..bd942385e984a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { transformAlertToRuleResponseAction } from '../../../../../../../common/detection_engine/transform_actions'; import { convertObjectKeysToSnakeCase } from '../../../../../../utils/object_case_converters'; import type { BaseRuleParams } from '../../../../rule_schema'; import { migrateLegacyInvestigationFields } from '../../../utils/utils'; @@ -43,5 +44,6 @@ export const commonParamsCamelToSnake = (params: BaseRuleParams) => { related_integrations: params.relatedIntegrations ?? [], required_fields: params.requiredFields ?? [], setup: params.setup ?? '', + response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts index 76ad36da0443c..dbf2b1b1360c9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts @@ -93,6 +93,9 @@ export const convertRuleResponseToAlertingRule = ( note: rule.note, version: rule.version, exceptionsList: rule.exceptions_list, + responseActions: rule.response_actions?.map((responseAction) => + transformRuleToAlertResponseAction(responseAction) + ), ...typeSpecificParams, }, schedule: { interval: rule.interval }, @@ -117,9 +120,6 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific timestampField: params.timestamp_field, eventCategoryOverride: params.event_category_override, tiebreakerField: params.tiebreaker_field, - responseActions: params.response_actions?.map((rule) => - transformRuleToAlertResponseAction(rule) - ), alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), }; } @@ -128,9 +128,6 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific type: params.type, language: params.language, query: params.query, - responseActions: params.response_actions?.map((rule) => - transformRuleToAlertResponseAction(rule) - ), alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), }; } @@ -163,9 +160,6 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific query: params.query ?? '', filters: params.filters, savedId: params.saved_id, - responseActions: params.response_actions?.map((rule) => - transformRuleToAlertResponseAction(rule) - ), alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), }; } @@ -178,9 +172,6 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific filters: params.filters, savedId: params.saved_id, dataViewId: params.data_view_id, - responseActions: params.response_actions?.map((rule) => - transformRuleToAlertResponseAction(rule) - ), alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), }; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts index 5e1faca1f7bc3..5a2f7ba0d3548 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts @@ -7,7 +7,6 @@ import type { RequiredOptional } from '@kbn/zod-helpers'; import type { TypeSpecificResponse } from '../../../../../../../common/api/detection_engine/model/rule_schema'; -import { transformAlertToRuleResponseAction } from '../../../../../../../common/detection_engine/transform_actions'; import { assertUnreachable } from '../../../../../../../common/utility_types'; import { convertObjectKeysToSnakeCase } from '../../../../../../utils/object_case_converters'; import type { TypeSpecificRuleParams } from '../../../../rule_schema'; @@ -28,7 +27,6 @@ export const typeSpecificCamelToSnake = ( event_category_override: params.eventCategoryOverride, tiebreaker_field: params.tiebreakerField, alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), - response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; } case 'esql': { @@ -37,7 +35,6 @@ export const typeSpecificCamelToSnake = ( language: params.language, query: params.query, alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), - response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; } case 'threat_match': { @@ -69,7 +66,6 @@ export const typeSpecificCamelToSnake = ( query: params.query, filters: params.filters, saved_id: params.savedId, - response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), }; } @@ -82,7 +78,6 @@ export const typeSpecificCamelToSnake = ( filters: params.filters, saved_id: params.savedId, data_view_id: params.dataViewId, - response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), }; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts index a5dd806322bc7..7b4c6024bc75a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts @@ -56,6 +56,7 @@ export function applyRuleDefaults(rule: RuleCreateProps & { immutable?: boolean immutable, rule_source: convertImmutableToRuleSource(immutable), required_fields: addEcsToRequiredFields(rule.required_fields), + response_actions: rule.response_actions, }; } @@ -86,7 +87,6 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { event_category_override: props.event_category_override, tiebreaker_field: props.tiebreaker_field, alert_suppression: props.alert_suppression, - response_actions: props.response_actions, }; } case 'esql': { @@ -95,7 +95,6 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { language: props.language, query: props.query, alert_suppression: props.alert_suppression, - response_actions: props.response_actions, }; } case 'threat_match': { @@ -127,7 +126,6 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { query: props.query ?? '', filters: props.filters, saved_id: props.saved_id, - response_actions: props.response_actions, alert_suppression: props.alert_suppression, }; } @@ -140,7 +138,6 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { filters: props.filters, saved_id: props.saved_id, data_view_id: props.data_view_id, - response_actions: props.response_actions, alert_suppression: props.alert_suppression, }; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts index 3d85cd367f10e..72264dc7efc44 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts @@ -111,6 +111,7 @@ export const applyRulePatch = async ({ interval: rulePatch.interval ?? existingRule.interval, throttle: rulePatch.throttle ?? existingRule.throttle, actions: rulePatch.actions ?? existingRule.actions, + response_actions: rulePatch.response_actions ?? existingRule.response_actions, ...typeSpecificParams, }; @@ -138,7 +139,6 @@ const patchEqlParams = ( rulePatch.event_category_override ?? existingRule.event_category_override, tiebreaker_field: rulePatch.tiebreaker_field ?? existingRule.tiebreaker_field, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, - response_actions: rulePatch.response_actions ?? existingRule.response_actions, }; }; @@ -151,7 +151,6 @@ const patchEsqlParams = ( language: rulePatch.language ?? existingRule.language, query: rulePatch.query ?? existingRule.query, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, - response_actions: rulePatch.response_actions ?? existingRule.response_actions, }; }; @@ -191,7 +190,6 @@ const patchQueryParams = ( query: rulePatch.query ?? existingRule.query, filters: rulePatch.filters ?? existingRule.filters, saved_id: rulePatch.saved_id ?? existingRule.saved_id, - response_actions: rulePatch.response_actions ?? existingRule.response_actions, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, }; }; @@ -208,7 +206,6 @@ const patchSavedQueryParams = ( query: rulePatch.query ?? existingRule.query, filters: rulePatch.filters ?? existingRule.filters, saved_id: rulePatch.saved_id ?? existingRule.saved_id, - response_actions: rulePatch.response_actions ?? existingRule.response_actions, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts index 939c0685dacc9..96aaef64b57c9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts @@ -9,7 +9,12 @@ import type { PartialRule } from '@kbn/alerting-plugin/server'; import type { Rule } from '@kbn/alerting-plugin/common'; import { isEqual, xorWith } from 'lodash'; import { stringifyZodError } from '@kbn/zod-helpers'; -import type { EqlRule, EsqlRule, QueryRule } from '../../../../../common/api/detection_engine'; +import type { + EqlRule, + EsqlRule, + NewTermsRule, + QueryRule, +} from '../../../../../common/api/detection_engine'; import { type ResponseAction, type RuleCreateProps, @@ -21,10 +26,10 @@ import { RESPONSE_ACTION_API_COMMAND_TO_CONSOLE_COMMAND_MAP, RESPONSE_CONSOLE_ACTION_COMMANDS_TO_REQUIRED_AUTHZ, } from '../../../../../common/endpoint/service/response_actions/constants'; -import { isQueryRule, isEsqlRule, isEqlRule } from '../../../../../common/detection_engine/utils'; +import { shouldShowResponseActions } from '../../../../../common/detection_engine/utils'; import type { SecuritySolutionApiRequestHandlerContext } from '../../../..'; import { CustomHttpRequestError } from '../../../../utils/custom_http_request_error'; -import type { EqlRuleParams, EsqlRuleParams } from '../../rule_schema'; +import type { EqlRuleParams, EsqlRuleParams, NewTermsRuleParams } from '../../rule_schema'; import { hasValidRuleType, type RuleAlertType, @@ -65,11 +70,7 @@ export const validateResponseActionsPermissions = async ( ruleUpdate: RuleCreateProps | RuleUpdateProps, existingRule?: RuleAlertType | null ): Promise => { - if ( - !isQueryRule(ruleUpdate.type) && - !isEsqlRule(ruleUpdate.type) && - !isEqlRule(ruleUpdate.type) - ) { + if (!shouldShowResponseActions(ruleUpdate.type)) { return; } @@ -118,12 +119,12 @@ export const validateResponseActionsPermissions = async ( function rulePayloadContainsResponseActions( rule: RuleCreateProps | RuleUpdateProps -): rule is QueryRule | EsqlRule | EqlRule { +): rule is QueryRule | EsqlRule | EqlRule | NewTermsRule { return 'response_actions' in rule; } function ruleObjectContainsResponseActions( rule?: RuleAlertType -): rule is Rule { +): rule is Rule { return rule != null && 'params' in rule && 'responseActions' in rule?.params; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/endpoint_response_action.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/endpoint_response_action.ts index 5d2c165161ec8..040433789ecd7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/endpoint_response_action.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/endpoint_response_action.ts @@ -6,7 +6,6 @@ */ import { each } from 'lodash'; -import { ALERT_RULE_NAME, ALERT_RULE_UUID } from '@kbn/rule-data-utils'; import { stringify } from '../../../endpoint/utils/stringify'; import type { RuleResponseEndpointAction, @@ -29,9 +28,8 @@ export const endpointResponseAction = async ( 'ruleExecution', 'automatedResponseActions' ); - // Query rules contain rule details with dotted syntax, while EQL/Esql rules contain rule details with nested syntax - const ruleId = alerts[0][ALERT_RULE_UUID] ?? alerts[0].kibana?.alert?.rule.rule_id; - const ruleName = alerts[0][ALERT_RULE_NAME] ?? alerts[0].kibana?.alert?.rule.name; + const ruleId = alerts[0].kibana.alert?.rule.uuid; + const ruleName = alerts[0].kibana.alert?.rule.name; const logMsgPrefix = `Rule [${ruleName}][${ruleId}]:`; const { comment, command } = responseAction.params; const errors: string[] = []; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts index 2fcf09d6cfbb4..31f8ef6b70079 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts @@ -5,13 +5,14 @@ * 2.0. */ +import { expandDottedObject } from '../../../../common/utils/expand_dotted'; import type { EndpointAppContextService } from '../../../endpoint/endpoint_app_context_services'; import type { SetupPlugins } from '../../../plugin_contract'; import { ResponseActionTypesEnum } from '../../../../common/api/detection_engine/model/rule_response_actions'; import { osqueryResponseAction } from './osquery_response_action'; import { endpointResponseAction } from './endpoint_response_action'; import type { ScheduleNotificationActions } from '../rule_types/types'; -import type { AlertWithAgent, Alert } from './types'; +import type { Alert, AlertWithAgent } from './types'; interface ScheduleNotificationResponseActionsService { endpointAppContextService: EndpointAppContextService; @@ -24,7 +25,9 @@ export const getScheduleNotificationResponseActionsService = endpointAppContextService, }: ScheduleNotificationResponseActionsService) => async ({ signals, responseActions }: ScheduleNotificationActions) => { - const alerts = (signals as Alert[]).filter((alert) => alert.agent?.id) as AlertWithAgent[]; + // expandDottedObject is needed eg in ESQL rule because it's alerts come without nested agent, host etc data but everything is dotted + const nestedAlerts = signals.map((signal) => expandDottedObject(signal as object)) as Alert[]; + const alerts = nestedAlerts.filter((alert) => alert.agent?.id) as AlertWithAgent[]; await Promise.all( responseActions.map(async (responseAction) => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/types.ts index 2f23ee6a6ac6c..a72e813dcb6a7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/types.ts @@ -22,8 +22,8 @@ export type Alert = ParsedTechnicalFields & { kibana: { alert?: { rule: { + uuid: string; name: string; - rule_id: string; }; }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts index a81732cfccf94..c1192e9a75fd1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts @@ -148,6 +148,7 @@ export const BaseRuleParams = z.object({ relatedIntegrations: RelatedIntegrationArray.optional(), requiredFields: RequiredFieldArray.optional(), setup: SetupGuide.optional(), + responseActions: z.array(RuleResponseAction).optional(), }); export type EqlSpecificRuleParams = z.infer; @@ -162,7 +163,6 @@ export const EqlSpecificRuleParams = z.object({ timestampField: TimestampField.optional(), tiebreakerField: TiebreakerField.optional(), alertSuppression: AlertSuppressionCamel.optional(), - responseActions: z.array(RuleResponseAction).optional(), }); export type EqlRuleParams = BaseRuleParams & EqlSpecificRuleParams; @@ -173,7 +173,6 @@ export const EsqlSpecificRuleParams = z.object({ type: z.literal('esql'), language: z.literal('esql'), query: RuleQuery, - responseActions: z.array(RuleResponseAction).optional(), alertSuppression: AlertSuppressionCamel.optional(), }); @@ -212,7 +211,6 @@ export const QuerySpecificRuleParams = z.object({ filters: RuleFilterArray.optional(), savedId: SavedQueryId.optional(), dataViewId: DataViewId.optional(), - responseActions: z.array(RuleResponseAction).optional(), alertSuppression: AlertSuppressionCamel.optional(), }); @@ -228,7 +226,6 @@ export const SavedQuerySpecificRuleParams = z.object({ query: RuleQuery.optional(), filters: RuleFilterArray.optional(), savedId: SavedQueryId, - responseActions: z.array(RuleResponseAction).optional(), alertSuppression: AlertSuppressionCamel.optional(), }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts index 53ee1e70284d4..02d7914562ee5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts @@ -14,7 +14,6 @@ import type { } from '@kbn/alerting-plugin/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { Filter } from '@kbn/es-query'; -import { expandDottedObject } from '../../../../../common/utils/expand_dotted'; import { buildEqlSearchRequest } from './build_eql_search_request'; import { createEnrichEventsFunction } from '../utils/enrichments'; @@ -198,7 +197,7 @@ export const eqlExecutor = async ({ scheduleNotificationResponseActionsService ) { scheduleNotificationResponseActionsService({ - signals: result.createdSignals.map((signal) => expandDottedObject(signal as object)), + signals: result.createdSignals, responseActions: completeRule.ruleParams.responseActions, }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts index cbba3ec5114dc..bf2dbac729827 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts @@ -19,7 +19,6 @@ import { } from '@kbn/securitysolution-utils'; import type { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { buildEsqlSearchRequest } from './build_esql_search_request'; -import { expandDottedObject } from '../../../../../common/utils/expand_dotted'; import { performEsqlRequest } from './esql_request'; import { wrapEsqlAlerts } from './wrap_esql_alerts'; import { wrapSuppressedEsqlAlerts } from './wrap_suppressed_esql_alerts'; @@ -232,12 +231,14 @@ export const esqlExecutor = async ({ result.createdSignalsCount && scheduleNotificationResponseActionsService ) { + console.log('123'); scheduleNotificationResponseActionsService({ - signals: result.createdSignals.map((signal) => expandDottedObject(signal as object)), + signals: result.createdSignals, responseActions: completeRule.ruleParams.responseActions, }); } + console.log('234'); // no more results will be found if (response.values.length < size) { ruleExecutionLogger.debug( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts index 74c7d9437851e..b6dcb136ac510 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts @@ -44,11 +44,13 @@ import { createEnrichEventsFunction } from '../utils/enrichments'; import { getIsAlertSuppressionActive } from '../utils/get_is_alert_suppression_active'; import { multiTermsComposite } from './multi_terms_composite'; import type { GenericBulkCreateResponse } from '../utils/bulk_create_with_suppression'; +import type { CreateRuleAdditionalOptions } from '../types'; export const createNewTermsAlertType = ( - createOptions: CreateRuleOptions + createOptions: CreateRuleOptions & CreateRuleAdditionalOptions ): SecurityAlertType => { - const { logger, licensing, experimentalFeatures } = createOptions; + const { logger, licensing, experimentalFeatures, scheduleNotificationResponseActionsService } = + createOptions; return { id: NEW_TERMS_RULE_TYPE_ID, name: 'New Terms Rule', @@ -414,6 +416,18 @@ export const createNewTermsAlertType = ( afterKey = searchResultWithAggs.aggregations.new_terms.after_key; } + + if ( + completeRule.ruleParams.responseActions?.length && + result.createdSignalsCount && + scheduleNotificationResponseActionsService + ) { + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + responseActions: completeRule.ruleParams.responseActions, + }); + } + return { ...result, state }; }, }; diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 5cb0a94c7690a..a46863c78c25e 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -311,7 +311,7 @@ export class Plugin implements ISecuritySolutionPlugin { analytics: core.analytics, }; - const queryRuleAdditionalOptions: CreateRuleAdditionalOptions = { + const ruleAdditionalOptions: CreateRuleAdditionalOptions = { scheduleNotificationResponseActionsService: getScheduleNotificationResponseActionsService({ endpointAppContextService: this.endpointAppContextService, osqueryCreateActionService: plugins.osquery.createActionService, @@ -321,20 +321,18 @@ export class Plugin implements ISecuritySolutionPlugin { const securityRuleTypeWrapper = createSecurityRuleTypeWrapper(securityRuleTypeOptions); plugins.alerting.registerType( - securityRuleTypeWrapper(createEqlAlertType({ ...ruleOptions, ...queryRuleAdditionalOptions })) + securityRuleTypeWrapper(createEqlAlertType({ ...ruleOptions, ...ruleAdditionalOptions })) ); if (!experimentalFeatures.esqlRulesDisabled) { plugins.alerting.registerType( - securityRuleTypeWrapper( - createEsqlAlertType({ ...ruleOptions, ...queryRuleAdditionalOptions }) - ) + securityRuleTypeWrapper(createEsqlAlertType({ ...ruleOptions, ...ruleAdditionalOptions })) ); } plugins.alerting.registerType( securityRuleTypeWrapper( createQueryAlertType({ ...ruleOptions, - ...queryRuleAdditionalOptions, + ...ruleAdditionalOptions, id: SAVED_QUERY_RULE_TYPE_ID, name: 'Saved Query Rule', }) @@ -348,14 +346,16 @@ export class Plugin implements ISecuritySolutionPlugin { securityRuleTypeWrapper( createQueryAlertType({ ...ruleOptions, - ...queryRuleAdditionalOptions, + ...ruleAdditionalOptions, id: QUERY_RULE_TYPE_ID, name: 'Custom Query Rule', }) ) ); plugins.alerting.registerType(securityRuleTypeWrapper(createThresholdAlertType(ruleOptions))); - plugins.alerting.registerType(securityRuleTypeWrapper(createNewTermsAlertType(ruleOptions))); + plugins.alerting.registerType( + securityRuleTypeWrapper(createNewTermsAlertType({ ...ruleOptions, ...ruleAdditionalOptions })) + ); // TODO We need to get the endpoint routes inside of initRoutes initRoutes( From 945312748549dfb675ef39f66a695eb508900e4c Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 9 Sep 2024 19:09:42 +0000 Subject: [PATCH 13/34] [CI] Auto-commit changed files from 'yarn openapi:bundle' --- ...ections_api_2023_10_31.bundled.schema.yaml | 144 ++++++++++++++++-- ...ections_api_2023_10_31.bundled.schema.yaml | 144 ++++++++++++++++-- 2 files changed, 256 insertions(+), 32 deletions(-) diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml index c9f17ef28239d..81ed59b13fceb 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -2042,10 +2042,6 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array tiebreaker_field: $ref: '#/components/schemas/TiebreakerField' timestamp_field: @@ -2128,6 +2124,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2243,6 +2243,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2355,6 +2359,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2450,6 +2458,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2575,6 +2587,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2690,6 +2706,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2733,10 +2753,6 @@ components: properties: alert_suppression: $ref: '#/components/schemas/AlertSuppression' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array EsqlRulePatchProps: allOf: - type: object @@ -2800,6 +2816,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2917,6 +2937,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3169,6 +3193,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3284,6 +3312,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3399,6 +3431,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3510,6 +3546,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3711,6 +3751,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3827,6 +3871,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3956,6 +4004,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4076,6 +4128,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4299,6 +4355,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4415,6 +4475,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4471,10 +4535,6 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array saved_id: $ref: '#/components/schemas/SavedQueryId' QueryRulePatchFields: @@ -4546,6 +4606,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4660,6 +4724,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5330,6 +5398,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5446,6 +5518,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5502,10 +5578,6 @@ components: $ref: '#/components/schemas/IndexPatternArray' query: $ref: '#/components/schemas/RuleQuery' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array SavedQueryRulePatchFields: allOf: - type: object @@ -5577,6 +5649,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5691,6 +5767,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5938,6 +6018,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6054,6 +6138,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6197,6 +6285,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6320,6 +6412,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6509,6 +6605,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6625,6 +6725,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6754,6 +6858,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6871,6 +6979,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml index bad22a1b80f36..c5c4f40916b05 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -1316,10 +1316,6 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array tiebreaker_field: $ref: '#/components/schemas/TiebreakerField' timestamp_field: @@ -1402,6 +1398,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1517,6 +1517,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1629,6 +1633,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1724,6 +1732,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1849,6 +1861,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1964,6 +1980,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2007,10 +2027,6 @@ components: properties: alert_suppression: $ref: '#/components/schemas/AlertSuppression' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array EsqlRulePatchProps: allOf: - type: object @@ -2074,6 +2090,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2191,6 +2211,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2420,6 +2444,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2535,6 +2563,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2650,6 +2682,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2761,6 +2797,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2864,6 +2904,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2980,6 +3024,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3109,6 +3157,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3229,6 +3281,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3452,6 +3508,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3568,6 +3628,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3624,10 +3688,6 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array saved_id: $ref: '#/components/schemas/SavedQueryId' QueryRulePatchFields: @@ -3699,6 +3759,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3813,6 +3877,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4483,6 +4551,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4599,6 +4671,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4655,10 +4731,6 @@ components: $ref: '#/components/schemas/IndexPatternArray' query: $ref: '#/components/schemas/RuleQuery' - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array SavedQueryRulePatchFields: allOf: - type: object @@ -4730,6 +4802,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4844,6 +4920,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5084,6 +5164,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5200,6 +5284,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5343,6 +5431,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5466,6 +5558,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5655,6 +5751,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5771,6 +5871,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5900,6 +6004,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6017,6 +6125,10 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: From a73360be17031ec3f3814f2c6b8acc569c8c2e25 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 9 Sep 2024 19:11:21 +0000 Subject: [PATCH 14/34] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../cypress/e2e/automated_response_actions/form.cy.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index 707f0a90d42d2..30301742f2411 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -1,9 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import { From 8cd270d68f815d178d0195ebfc136081e2356d85 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Mon, 9 Sep 2024 22:14:13 +0200 Subject: [PATCH 15/34] fix tests, remove TypeSpecificFields filter --- ...s_upgrade_and_rollback_checks.test.ts.snap | 2128 +++++++++++------ .../e2e/automated_response_actions/form.cy.ts | 17 +- .../cypress/tasks/response_actions.ts | 12 +- .../rule_assets/prebuilt_rule_asset.mock.ts | 1 + .../rule_assets/prebuilt_rule_asset.test.ts | 11 - .../model/rule_assets/prebuilt_rule_asset.ts | 23 +- .../api/rules/create_rule/route.test.ts | 60 +- .../api/rules/update_rule/route.test.ts | 64 +- .../detection_engine/rule_types/esql/esql.ts | 2 - 9 files changed, 1458 insertions(+), 860 deletions(-) diff --git a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap index d150da5cefe2d..c283cc1087682 100644 --- a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap +++ b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap @@ -5829,6 +5829,175 @@ Object { }, "type": "array", }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + ], + }, + "type": "array", + }, "riskScore": Object { "maximum": 100, "minimum": 0, @@ -6135,204 +6304,35 @@ Object { "query": Object { "type": "string", }, - "responseActions": Object { - "items": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".osquery", - "type": "string", - }, - "params": Object { - "additionalProperties": false, - "properties": Object { - "ecsMapping": Object { - "additionalProperties": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "value": Object { - "anyOf": Array [ - Object { - "type": "string", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - }, - "type": "object", - }, - "properties": Object {}, - "type": "object", - }, - "packId": Object { - "type": "string", - }, - "queries": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs_mapping": Object { - "$ref": "#/allOf/1/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", - }, - "id": Object { - "type": "string", - }, - "platform": Object { - "type": "string", - }, - "query": Object { - "type": "string", - }, - "removed": Object { - "type": "boolean", - }, - "snapshot": Object { - "type": "boolean", - }, - "version": Object { - "type": "string", - }, - }, - "required": Array [ - "id", - "query", - ], - "type": "object", - }, - "type": "array", - }, - "query": Object { - "type": "string", - }, - "savedQueryId": Object { - "type": "string", - }, - "timeout": Object { - "type": "number", - }, - }, - "type": "object", - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".endpoint", - "type": "string", - }, - "params": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "const": "isolate", - "type": "string", - }, - "comment": Object { - "type": "string", - }, - }, - "required": Array [ - "command", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "enum": Array [ - "kill-process", - "suspend-process", - ], - "type": "string", - }, - "comment": Object { - "type": "string", - }, - "config": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "overwrite": Object { - "default": true, - "type": "boolean", - }, - }, - "required": Array [ - "field", - ], - "type": "object", - }, - }, - "required": Array [ - "command", - "config", - ], - "type": "object", - }, - ], - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - ], - }, - "type": "array", - }, - "tiebreakerField": Object { - "type": "string", - }, - "timestampField": Object { - "type": "string", - }, - "type": Object { - "const": "eql", - "type": "string", - }, - }, - "required": Array [ - "type", - "language", - "query", - ], - "type": "object", - }, - ], -} -`; - -exports[`Serverless upgrade and rollback checks detect param changes to review for: siem.indicatorRule 1`] = ` -Object { - "$schema": "http://json-schema.org/draft-07/schema#", - "allOf": Array [ - Object { - "properties": Object { - "author": Object { + "tiebreakerField": Object { + "type": "string", + }, + "timestampField": Object { + "type": "string", + }, + "type": Object { + "const": "eql", + "type": "string", + }, + }, + "required": Array [ + "type", + "language", + "query", + ], + "type": "object", + }, + ], +} +`; + +exports[`Serverless upgrade and rollback checks detect param changes to review for: siem.indicatorRule 1`] = ` +Object { + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": Array [ + Object { + "properties": Object { + "author": Object { "items": Object { "type": "string", }, @@ -6497,6 +6497,175 @@ Object { }, "type": "array", }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + ], + }, + "type": "array", + }, "riskScore": Object { "maximum": 100, "minimum": 0, @@ -7049,13 +7218,182 @@ Object { "type": Object { "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", }, - }, - "required": Array [ - "name", - "type", - "ecs", + }, + "required": Array [ + "name", + "type", + "ecs", + ], + "type": "object", + }, + "type": "array", + }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, ], - "type": "object", }, "type": "array", }, @@ -7450,92 +7788,261 @@ Object { "pattern": "^(?! *$).+$", "type": "string", }, - "minItems": 1, - "type": "array", + "minItems": 1, + "type": "array", + }, + }, + "required": Array [ + "field_names", + ], + "type": "object", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + "license": Object { + "type": "string", + }, + "maxSignals": Object { + "minimum": 1, + "type": "integer", + }, + "meta": Object { + "additionalProperties": Object {}, + "properties": Object {}, + "type": "object", + }, + "namespace": Object { + "type": "string", + }, + "note": Object { + "type": "string", + }, + "outputIndex": Object { + "type": "string", + }, + "references": Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + "relatedIntegrations": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "integration": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "package": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "version": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + }, + "required": Array [ + "package", + "version", + ], + "type": "object", + }, + "type": "array", + }, + "requiredFields": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs": Object { + "type": "boolean", + }, + "name": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "type": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + }, + "required": Array [ + "name", + "type", + "ecs", + ], + "type": "object", + }, + "type": "array", + }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", }, - "required": Array [ - "field_names", - ], - "type": "object", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - "license": Object { - "type": "string", - }, - "maxSignals": Object { - "minimum": 1, - "type": "integer", - }, - "meta": Object { - "additionalProperties": Object {}, - "properties": Object {}, - "type": "object", - }, - "namespace": Object { - "type": "string", - }, - "note": Object { - "type": "string", - }, - "outputIndex": Object { - "type": "string", - }, - "references": Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - "relatedIntegrations": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "integration": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "package": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "version": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - }, - "required": Array [ - "package", - "version", - ], - "type": "object", - }, - "type": "array", - }, - "requiredFields": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs": Object { - "type": "boolean", - }, - "name": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "type": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - }, - "required": Array [ - "name", - "type", - "ecs", ], - "type": "object", }, "type": "array", }, @@ -8064,13 +8571,182 @@ Object { "type": Object { "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", }, - }, - "required": Array [ - "name", - "type", - "ecs", + }, + "required": Array [ + "name", + "type", + "ecs", + ], + "type": "object", + }, + "type": "array", + }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, ], - "type": "object", }, "type": "array", }, @@ -8383,175 +9059,6 @@ Object { "query": Object { "type": "string", }, - "responseActions": Object { - "items": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".osquery", - "type": "string", - }, - "params": Object { - "additionalProperties": false, - "properties": Object { - "ecsMapping": Object { - "additionalProperties": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "value": Object { - "anyOf": Array [ - Object { - "type": "string", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - }, - "type": "object", - }, - "properties": Object {}, - "type": "object", - }, - "packId": Object { - "type": "string", - }, - "queries": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs_mapping": Object { - "$ref": "#/allOf/1/anyOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", - }, - "id": Object { - "type": "string", - }, - "platform": Object { - "type": "string", - }, - "query": Object { - "type": "string", - }, - "removed": Object { - "type": "boolean", - }, - "snapshot": Object { - "type": "boolean", - }, - "version": Object { - "type": "string", - }, - }, - "required": Array [ - "id", - "query", - ], - "type": "object", - }, - "type": "array", - }, - "query": Object { - "type": "string", - }, - "savedQueryId": Object { - "type": "string", - }, - "timeout": Object { - "type": "number", - }, - }, - "type": "object", - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".endpoint", - "type": "string", - }, - "params": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "const": "isolate", - "type": "string", - }, - "comment": Object { - "type": "string", - }, - }, - "required": Array [ - "command", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "enum": Array [ - "kill-process", - "suspend-process", - ], - "type": "string", - }, - "comment": Object { - "type": "string", - }, - "config": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "overwrite": Object { - "default": true, - "type": "boolean", - }, - }, - "required": Array [ - "field", - ], - "type": "object", - }, - }, - "required": Array [ - "command", - "config", - ], - "type": "object", - }, - ], - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - ], - }, - "type": "array", - }, "savedId": Object { "type": "string", }, @@ -8588,12 +9095,6 @@ Object { "query": Object { "$ref": "#/allOf/1/anyOf/0/properties/query", }, - "responseActions": Object { - "items": Object { - "$ref": "#/allOf/1/anyOf/0/properties/responseActions/items", - }, - "type": "array", - }, "savedId": Object { "$ref": "#/allOf/1/anyOf/0/properties/savedId", }, @@ -8773,16 +9274,185 @@ Object { "name": Object { "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", }, - "type": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + "type": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + }, + "required": Array [ + "name", + "type", + "ecs", + ], + "type": "object", + }, + "type": "array", + }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", }, - }, - "required": Array [ - "name", - "type", - "ecs", ], - "type": "object", }, "type": "array", }, @@ -9009,261 +9679,92 @@ Object { "immutable", "outputIndex", "maxSignals", - "riskScore", - "riskScoreMapping", - "severity", - "severityMapping", - "threat", - "to", - "references", - "version", - "exceptionsList", - ], - "type": "object", - }, - Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "alertSuppression": Object { - "additionalProperties": false, - "properties": Object { - "duration": Object { - "additionalProperties": false, - "properties": Object { - "unit": Object { - "enum": Array [ - "s", - "m", - "h", - ], - "type": "string", - }, - "value": Object { - "minimum": 1, - "type": "integer", - }, - }, - "required": Array [ - "value", - "unit", - ], - "type": "object", - }, - "groupBy": Object { - "items": Object { - "type": "string", - }, - "maxItems": 3, - "minItems": 1, - "type": "array", - }, - "missingFieldsStrategy": Object { - "enum": Array [ - "doNotSuppress", - "suppress", - ], - "type": "string", - }, - }, - "required": Array [ - "groupBy", - ], - "type": "object", - }, - "dataViewId": Object { - "type": "string", - }, - "filters": Object { - "items": Object {}, - "type": "array", - }, - "index": Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - "language": Object { - "enum": Array [ - "kuery", - "lucene", - ], - "type": "string", - }, - "query": Object { - "type": "string", - }, - "responseActions": Object { - "items": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".osquery", - "type": "string", - }, - "params": Object { - "additionalProperties": false, - "properties": Object { - "ecsMapping": Object { - "additionalProperties": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "value": Object { - "anyOf": Array [ - Object { - "type": "string", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - }, - "type": "object", - }, - "properties": Object {}, - "type": "object", - }, - "packId": Object { - "type": "string", - }, - "queries": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs_mapping": Object { - "$ref": "#/allOf/1/anyOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", - }, - "id": Object { - "type": "string", - }, - "platform": Object { - "type": "string", - }, - "query": Object { - "type": "string", - }, - "removed": Object { - "type": "boolean", - }, - "snapshot": Object { - "type": "boolean", - }, - "version": Object { - "type": "string", - }, - }, - "required": Array [ - "id", - "query", - ], - "type": "object", - }, - "type": "array", - }, - "query": Object { - "type": "string", - }, - "savedQueryId": Object { - "type": "string", - }, - "timeout": Object { - "type": "number", - }, - }, - "type": "object", - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".endpoint", - "type": "string", - }, - "params": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "const": "isolate", - "type": "string", - }, - "comment": Object { - "type": "string", - }, - }, - "required": Array [ - "command", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "enum": Array [ - "kill-process", - "suspend-process", - ], - "type": "string", - }, - "comment": Object { - "type": "string", - }, - "config": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "overwrite": Object { - "default": true, - "type": "boolean", - }, - }, - "required": Array [ - "field", - ], - "type": "object", - }, - }, - "required": Array [ - "command", - "config", - ], - "type": "object", - }, - ], - }, + "riskScore", + "riskScoreMapping", + "severity", + "severityMapping", + "threat", + "to", + "references", + "version", + "exceptionsList", + ], + "type": "object", + }, + Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "alertSuppression": Object { + "additionalProperties": false, + "properties": Object { + "duration": Object { + "additionalProperties": false, + "properties": Object { + "unit": Object { + "enum": Array [ + "s", + "m", + "h", + ], + "type": "string", + }, + "value": Object { + "minimum": 1, + "type": "integer", }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", }, - ], + "required": Array [ + "value", + "unit", + ], + "type": "object", + }, + "groupBy": Object { + "items": Object { + "type": "string", + }, + "maxItems": 3, + "minItems": 1, + "type": "array", + }, + "missingFieldsStrategy": Object { + "enum": Array [ + "doNotSuppress", + "suppress", + ], + "type": "string", + }, + }, + "required": Array [ + "groupBy", + ], + "type": "object", + }, + "dataViewId": Object { + "type": "string", + }, + "filters": Object { + "items": Object {}, + "type": "array", + }, + "index": Object { + "items": Object { + "type": "string", }, "type": "array", }, + "language": Object { + "enum": Array [ + "kuery", + "lucene", + ], + "type": "string", + }, + "query": Object { + "type": "string", + }, "savedId": Object { "type": "string", }, @@ -9300,12 +9801,6 @@ Object { "query": Object { "$ref": "#/allOf/1/anyOf/0/properties/query", }, - "responseActions": Object { - "items": Object { - "$ref": "#/allOf/1/anyOf/0/properties/responseActions/items", - }, - "type": "array", - }, "savedId": Object { "$ref": "#/allOf/1/anyOf/0/properties/savedId", }, @@ -9498,6 +9993,175 @@ Object { }, "type": "array", }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + ], + }, + "type": "array", + }, "riskScore": Object { "maximum": 100, "minimum": 0, diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index 707f0a90d42d2..ecdbf29582d89 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -1,9 +1,10 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import { @@ -210,14 +211,10 @@ describe( beforeEach(() => { login(ROLE.soc_manager); }); - afterEach(() => { - if (ruleId) { - cleanupRule(ruleId); - } - }); it('create and save endpoint response action inside of a rule', () => { - fillUpNewEsqlRule(ruleName, ruleDescription); + const query = 'FROM * METADATA _index, _id {backspace}{enter}'; + fillUpNewEsqlRule(ruleName, ruleDescription, query); addEndpointResponseAction(); focusAndOpenCommandDropdown(); validateAvailableCommands(); diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts index c4be7c2dd204c..ebd666e3684d3 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts @@ -1,8 +1,10 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import { inputConsoleCommand, submitCommand } from './response_console'; @@ -69,13 +71,13 @@ export const fillUpNewRule = (name = 'Test', description = 'Test') => { cy.getByTestSubj('about-continue').click(); cy.getByTestSubj('schedule-continue').click(); }; -export const fillUpNewEsqlRule = (name = 'Test', description = 'Test') => { +export const fillUpNewEsqlRule = (name = 'Test', description = 'Test', query: string) => { loadPage('app/security/rules/management'); cy.getByTestSubj('create-new-rule').click(); cy.getByTestSubj('stepDefineRule').within(() => { cy.getByTestSubj('esqlRuleType').click(); cy.getByTestSubj('globalQueryBar').first().click(); - cy.getByTestSubj('kibanaCodeEditor').type('FROM * METADATA _index, _id {backspace}{enter}'); + cy.getByTestSubj('kibanaCodeEditor').type(query); }); cy.getByTestSubj('define-continue').click(); cy.getByTestSubj('detectionEngineStepAboutRuleName').within(() => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.mock.ts index c73203c2871ab..e29a255fa3184 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.mock.ts @@ -18,6 +18,7 @@ export const getPrebuiltRuleMock = (rewrites?: Partial): Preb language: 'kuery', rule_id: 'rule-1', version: 1, + response_actions: [{ action_type_id: `.osquery`, params: {} }], ...rewrites, } as PrebuiltRuleAsset); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts index 9190bb873e81b..54f602eddb3b4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts @@ -60,17 +60,6 @@ describe('Prebuilt rule asset schema', () => { expect(result.data).toEqual(getPrebuiltRuleMock()); } ); - - test('ignores the type specific response_actions field since it`s an omitted field', () => { - const payload: Partial & Record = { - ...getPrebuiltRuleMock(), - response_actions: [{ action_type_id: `.osquery`, params: {} }], - }; - - const result = PrebuiltRuleAsset.safeParse(payload); - expectParseSuccess(result); - expect(result.data).toEqual(getPrebuiltRuleMock()); - }); }); test('[rule_id] does not validate', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts index fa6c78bb7a8c1..9171304abe44a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts @@ -30,27 +30,6 @@ const BASE_PROPS_REMOVED_FROM_PREBUILT_RULE_ASSET = zodMaskFor( 'outcome', ]); -/** - * Aditionally remove fields which are part only of the optional fields in the rule types that make up - * the TypeSpecificCreateProps discriminatedUnion, by using a Zod transformation which extracts out the - * necessary fields in the rules types where they exist. Fields to extract: - * - response_actions: from Query and SavedQuery rules - */ -const TypeSpecificFields = TypeSpecificCreateProps.transform((val) => { - switch (val.type) { - case 'query': { - const { response_actions: _, ...rest } = val; - return rest; - } - case 'saved_query': { - const { response_actions: _, ...rest } = val; - return rest; - } - default: - return val; - } -}); - function zodMaskFor() { return function (props: U[]): Record { type PropObject = Record; @@ -76,7 +55,7 @@ function zodMaskFor() { */ export type PrebuiltRuleAsset = z.infer; export const PrebuiltRuleAsset = BaseCreateProps.omit(BASE_PROPS_REMOVED_FROM_PREBUILT_RULE_ASSET) - .and(TypeSpecificFields) + .and(TypeSpecificCreateProps) .and( z.object({ rule_id: RuleSignatureId, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts index e76933f612885..b0d0b202341d3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts @@ -19,6 +19,7 @@ import { createRuleRoute } from './route'; import { getCreateEqlRuleSchemaMock, getCreateEsqlRulesSchemaMock, + getCreateNewTermsRulesSchemaMock, getCreateRulesSchemaMock, } from '../../../../../../../common/api/detection_engine/model/rule_schema/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; @@ -185,46 +186,29 @@ describe('Create rule route', () => { }, }); const defaultAction = getResponseAction(); + const ruleTypes: Array<[string, () => object]> = [ + ['query', getCreateRulesSchemaMock], + ['esql', getCreateEsqlRulesSchemaMock], + ['eql', getCreateEqlRuleSchemaMock], + ['new_terms', getCreateNewTermsRulesSchemaMock], + ]; - test('is successful in query rule', async () => { - const request = requestMock.create({ - method: 'post', - path: DETECTION_ENGINE_RULES_URL, - body: { - ...getCreateRulesSchemaMock(), - response_actions: [defaultAction], - }, - }); - - const response = await server.inject(request, requestContextMock.convertContext(context)); - expect(response.status).toEqual(200); - }); - test('is successful in esql rule', async () => { - const request = requestMock.create({ - method: 'post', - path: DETECTION_ENGINE_RULES_URL, - body: { - ...getCreateEsqlRulesSchemaMock('rule-2'), - response_actions: [defaultAction], - }, - }); + test.each(ruleTypes)( + 'is successful for %s rule', + async (ruleType: string, schemaMock: (ruleId: string) => object) => { + const request = requestMock.create({ + method: 'post', + path: DETECTION_ENGINE_RULES_URL, + body: { + ...schemaMock(`rule-${ruleType}`), + response_actions: [defaultAction], + }, + }); - const response = await server.inject(request, requestContextMock.convertContext(context)); - expect(response.status).toEqual(200); - }); - test('is successful in eql rule', async () => { - const request = requestMock.create({ - method: 'post', - path: DETECTION_ENGINE_RULES_URL, - body: { - ...getCreateEqlRuleSchemaMock('rule-3'), - response_actions: [defaultAction], - }, - }); - - const response = await server.inject(request, requestContextMock.convertContext(context)); - expect(response.status).toEqual(200); - }); + const response = await server.inject(request, requestContextMock.convertContext(context)); + expect(response.status).toEqual(200); + } + ); test('fails when isolate rbac is set to false', async () => { (context.securitySolution.getEndpointAuthz as jest.Mock).mockReturnValue(() => ({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts index 8456ce573d3ba..315ab9e80a5de 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts @@ -19,6 +19,7 @@ import { updateRuleRoute } from './route'; import { getCreateEqlRuleSchemaMock, getCreateEsqlRulesSchemaMock, + getCreateNewTermsRulesSchemaMock, getCreateRulesSchemaMock, getUpdateRulesSchemaMock, } from '../../../../../../../common/api/detection_engine/model/rule_schema/mocks'; @@ -191,46 +192,29 @@ describe('Update rule route', () => { }); const defaultAction = getResponseAction(); - test('is successful for query rule', async () => { - const request = requestMock.create({ - method: 'post', - path: DETECTION_ENGINE_RULES_URL, - body: { - ...getCreateRulesSchemaMock(), - response_actions: [defaultAction], - }, - }); - - const response = await server.inject(request, requestContextMock.convertContext(context)); - expect(response.status).toEqual(200); - }); - test('is successful for esql rule', async () => { - const request = requestMock.create({ - method: 'post', - path: DETECTION_ENGINE_RULES_URL, - body: { - ...getCreateEsqlRulesSchemaMock('rule-2'), - response_actions: [defaultAction], - }, - }); - - const response = await server.inject(request, requestContextMock.convertContext(context)); - expect(response.status).toEqual(200); - }); - - test('is successful for eql rule', async () => { - const request = requestMock.create({ - method: 'post', - path: DETECTION_ENGINE_RULES_URL, - body: { - ...getCreateEqlRuleSchemaMock('rule-3'), - response_actions: [defaultAction], - }, - }); - - const response = await server.inject(request, requestContextMock.convertContext(context)); - expect(response.status).toEqual(200); - }); + const ruleTypes: Array<[string, () => object]> = [ + ['query', () => getCreateRulesSchemaMock()], + ['esql', getCreateEsqlRulesSchemaMock], + ['eql', getCreateEqlRuleSchemaMock], + ['new_terms', getCreateNewTermsRulesSchemaMock], + ]; + + test.each(ruleTypes)( + 'is successful for %s rule', + async (ruleType: string, schemaMock: (ruleId: string) => object) => { + const request = requestMock.create({ + method: 'post', + path: DETECTION_ENGINE_RULES_URL, + body: { + ...schemaMock(`rule-${ruleType}`), + response_actions: [defaultAction], + }, + }); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + expect(response.status).toEqual(200); + } + ); test('fails when isolate rbac is set to false', async () => { (context.securitySolution.getEndpointAuthz as jest.Mock).mockReturnValue(() => ({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts index bf2dbac729827..79f9ff2c4439a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts @@ -231,14 +231,12 @@ export const esqlExecutor = async ({ result.createdSignalsCount && scheduleNotificationResponseActionsService ) { - console.log('123'); scheduleNotificationResponseActionsService({ signals: result.createdSignals, responseActions: completeRule.ruleParams.responseActions, }); } - console.log('234'); // no more results will be found if (response.values.length < size) { ruleExecutionLogger.debug( From 64dffe102853decebd2d587e21d02999ae78b5f8 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Tue, 10 Sep 2024 10:26:48 +0200 Subject: [PATCH 16/34] fix e2e --- .../e2e/automated_response_actions/form.cy.ts | 6 ++---- .../management/cypress/tasks/response_actions.ts | 12 ++++++++++-- .../new_terms/create_new_terms_alert_type.ts | 3 +-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index d7fdc98c56ffa..16c001c6f1861 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -13,6 +13,7 @@ import { tryAddingDisabledResponseAction, validateAvailableCommands, visitRuleActions, + selectIsolateAndSaveWithoutEnabling, } from '../../tasks/response_actions'; import { cleanupRule, generateRandomStringName, loadRule } from '../../tasks/api_fixtures'; import { ResponseActionTypesEnum } from '../../../../../common/api/detection_engine'; @@ -216,10 +217,7 @@ describe( addEndpointResponseAction(); focusAndOpenCommandDropdown(); validateAvailableCommands(); - cy.getByTestSubj(`command-type-isolate`).click(); - - cy.getByTestSubj('create-enabled-false').click(); - cy.contains(`${ruleName} was created`); + selectIsolateAndSaveWithoutEnabling(ruleName); }); }); diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts index ebd666e3684d3..ec9220a4dab5a 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts @@ -44,6 +44,12 @@ export const validateAvailableCommands = () => { cy.getByTestSubj(`command-type-${command}`); }); }; +export const selectIsolateAndSaveWithoutEnabling = (ruleName: string) => { + cy.getByTestSubj(`command-type-isolate`).click(); + cy.getByTestSubj('create-enabled-false').click(); + cy.contains(`${ruleName} was created`); +}; + export const addEndpointResponseAction = () => { cy.getByTestSubj('response-actions-wrapper').within(() => { cy.getByTestSubj('Elastic Defend-response-action-type-selection-option').click(); @@ -76,8 +82,10 @@ export const fillUpNewEsqlRule = (name = 'Test', description = 'Test', query: st cy.getByTestSubj('create-new-rule').click(); cy.getByTestSubj('stepDefineRule').within(() => { cy.getByTestSubj('esqlRuleType').click(); - cy.getByTestSubj('globalQueryBar').first().click(); - cy.getByTestSubj('kibanaCodeEditor').type(query); + cy.getByTestSubj('detectionEngineStepDefineRuleEsqlQueryBar').within(() => { + cy.getByTestSubj('globalQueryBar').click(); + cy.getByTestSubj('kibanaCodeEditor').type(query); + }); }); cy.getByTestSubj('define-continue').click(); cy.getByTestSubj('detectionEngineStepAboutRuleName').within(() => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts index b6dcb136ac510..7aa168484f09b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts @@ -12,7 +12,7 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; import { NewTermsRuleParams } from '../../rule_schema'; -import type { CreateRuleOptions, SecurityAlertType } from '../types'; +import type { CreateRuleOptions, SecurityAlertType, CreateRuleAdditionalOptions } from '../types'; import { singleSearchAfter } from '../utils/single_search_after'; import { getFilter } from '../utils/get_filter'; import { wrapNewTermsAlerts } from './wrap_new_terms_alerts'; @@ -44,7 +44,6 @@ import { createEnrichEventsFunction } from '../utils/enrichments'; import { getIsAlertSuppressionActive } from '../utils/get_is_alert_suppression_active'; import { multiTermsComposite } from './multi_terms_composite'; import type { GenericBulkCreateResponse } from '../utils/bulk_create_with_suppression'; -import type { CreateRuleAdditionalOptions } from '../types'; export const createNewTermsAlertType = ( createOptions: CreateRuleOptions & CreateRuleAdditionalOptions From 3e46918a32bb34056a24dddeaf1d9b809a1619e2 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Tue, 10 Sep 2024 11:37:45 +0200 Subject: [PATCH 17/34] fix header --- .../public/management/cypress/tasks/response_actions.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts index ec9220a4dab5a..715f8adc972f5 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts @@ -1,10 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import { inputConsoleCommand, submitCommand } from './response_console'; From 3977af5012146740482a2b5655d02ce568ca7c74 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Wed, 11 Sep 2024 15:31:42 +0200 Subject: [PATCH 18/34] temporary hide other rule types - intermediate release --- .../security_solution/common/detection_engine/utils.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/utils.ts b/x-pack/plugins/security_solution/common/detection_engine/utils.ts index 71780e31f6369..66311043e8c68 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/utils.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/utils.ts @@ -94,5 +94,8 @@ export const isSuppressionRuleInGA = (ruleType: Type): boolean => { return isSuppressibleAlertRule(ruleType) && SUPPRESSIBLE_ALERT_RULES_GA.includes(ruleType); }; -export const shouldShowResponseActions = (ruleType: Type | undefined) => - isQueryRule(ruleType) || isEsqlRule(ruleType) || isEqlRule(ruleType) || isNewTermsRule(ruleType); +export const shouldShowResponseActions = (ruleType: Type | undefined) => { + return isQueryRule(ruleType); + // When adding new parameters to rules, we have to follow intermediate release steps - functionality hidden from UI + // || isEsqlRule(ruleType) || isEqlRule(ruleType) || isNewTermsRule(ruleType) +}; From eac4b453e7541330167a1b4d088551294f4fcdf2 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Wed, 11 Sep 2024 15:38:45 +0200 Subject: [PATCH 19/34] intermediate release - comment out e2e test --- .../e2e/automated_response_actions/form.cy.ts | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index 16c001c6f1861..6bbab461f937e 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -1,19 +1,19 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import { addEndpointResponseAction, - fillUpNewEsqlRule, fillUpNewRule, focusAndOpenCommandDropdown, tryAddingDisabledResponseAction, validateAvailableCommands, visitRuleActions, - selectIsolateAndSaveWithoutEnabling, } from '../../tasks/response_actions'; import { cleanupRule, generateRandomStringName, loadRule } from '../../tasks/api_fixtures'; import { ResponseActionTypesEnum } from '../../../../../common/api/detection_engine'; @@ -204,22 +204,23 @@ describe( }); }); - describe('User should be able to add response action to ESQL rule', () => { - const [ruleName, ruleDescription] = generateRandomStringName(2); - - beforeEach(() => { - login(ROLE.soc_manager); - }); - - it('create and save endpoint response action inside of a rule', () => { - const query = 'FROM * METADATA _index, _id {backspace}{enter}'; - fillUpNewEsqlRule(ruleName, ruleDescription, query); - addEndpointResponseAction(); - focusAndOpenCommandDropdown(); - validateAvailableCommands(); - selectIsolateAndSaveWithoutEnabling(ruleName); - }); - }); + // TODO: uncomment the test after another serverless release - intermediate release + // describe('User should be able to add response action to ESQL rule', () => { + // const [ruleName, ruleDescription] = generateRandomStringName(2); + // + // beforeEach(() => { + // login(ROLE.soc_manager); + // }); + // + // it('create and save endpoint response action inside of a rule', () => { + // const query = 'FROM * METADATA _index, _id {backspace}{enter}'; + // fillUpNewEsqlRule(ruleName, ruleDescription, query); + // addEndpointResponseAction(); + // focusAndOpenCommandDropdown(); + // validateAvailableCommands(); + // selectIsolateAndSaveWithoutEnabling(ruleName); + // }); + // }); describe('User should not see endpoint action when no rbac', () => { const [ruleName, ruleDescription] = generateRandomStringName(2); From cab1f84bcccf6f59ef696402b9142475a0ee41f9 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Wed, 11 Sep 2024 17:43:18 +0200 Subject: [PATCH 20/34] Update form.cy.ts license header --- .../cypress/e2e/automated_response_actions/form.cy.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index 6bbab461f937e..8eb880fc1325c 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -1,10 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import { From 3fc2bcf696877eeed88ce5d6bb0e7945057eba03 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Thu, 12 Sep 2024 16:18:02 +0200 Subject: [PATCH 21/34] feature flag --- .../common/detection_engine/utils.ts | 11 +++--- .../common/experimental_features.ts | 5 +++ .../components/step_rule_actions/index.tsx | 6 +++- .../e2e/automated_response_actions/form.cy.ts | 36 ++++++++++--------- .../rule_management/utils/validate.ts | 9 ++++- 5 files changed, 44 insertions(+), 23 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/utils.ts b/x-pack/plugins/security_solution/common/detection_engine/utils.ts index 66311043e8c68..1d39734ab7732 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/utils.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/utils.ts @@ -94,8 +94,11 @@ export const isSuppressionRuleInGA = (ruleType: Type): boolean => { return isSuppressibleAlertRule(ruleType) && SUPPRESSIBLE_ALERT_RULES_GA.includes(ruleType); }; -export const shouldShowResponseActions = (ruleType: Type | undefined) => { - return isQueryRule(ruleType); - // When adding new parameters to rules, we have to follow intermediate release steps - functionality hidden from UI - // || isEsqlRule(ruleType) || isEqlRule(ruleType) || isNewTermsRule(ruleType) +export const shouldShowResponseActions = (ruleType: Type | undefined, featureFlag: boolean) => { + return featureFlag + ? isQueryRule(ruleType) || + isEsqlRule(ruleType) || + isEqlRule(ruleType) || + isNewTermsRule(ruleType) + : isQueryRule(ruleType); }; diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 7d3edafedd1a9..2fab62310ba27 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -52,6 +52,11 @@ export const allowedExperimentalValues = Object.freeze({ */ automatedProcessActionsEnabled: true, + /** + * Temporary feature flag to enable the Response Actions in Rules UI - intermediate release + */ + rulesResponseActionsTemporaryFlagEnabled: false, + /** * Enables the ability to send Response actions to SentinelOne and persist the results * in ES. Adds API changes to support `agentType` and supports `isolate` and `release` diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx index 7e1b6b3d8f74c..5949666195852 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx @@ -16,6 +16,7 @@ import type { } from '@kbn/triggers-actions-ui-plugin/public'; import { UseArray } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; +import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { shouldShowResponseActions } from '../../../../../common/detection_engine/utils'; import type { RuleObjectId } from '../../../../../common/api/detection_engine/model/rule_schema'; import { ResponseActionsForm } from '../../../rule_response_actions/response_actions_form'; @@ -101,7 +102,7 @@ const StepRuleActionsComponent: FC = ({ [actionMessageParams, summaryActionMessageParams] ); const displayResponseActionsOptions = useMemo(() => { - if (shouldShowResponseActions(ruleType)) { + if (shouldShowResponseActions(ruleType, rulesResponseActionsTemporaryFlagEnabled)) { return ( {ResponseActionsForm} @@ -153,6 +154,9 @@ const StepRuleActionsReadOnlyComponent: FC = ({ const { services: { triggersActionsUi }, } = useKibana(); + const rulesResponseActionsTemporaryFlagEnabled = useIsExperimentalFeatureEnabled( + 'rulesResponseActionsTemporaryFlagEnabled' + ); const actionTypeRegistry = triggersActionsUi.actionTypeRegistry as ActionTypeRegistryContract; diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index 8eb880fc1325c..b6fd78b515917 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -12,6 +12,8 @@ import { tryAddingDisabledResponseAction, validateAvailableCommands, visitRuleActions, + selectIsolateAndSaveWithoutEnabling, + fillUpNewEsqlRule, } from '../../tasks/response_actions'; import { cleanupRule, generateRandomStringName, loadRule } from '../../tasks/api_fixtures'; import { ResponseActionTypesEnum } from '../../../../../common/api/detection_engine'; @@ -28,6 +30,7 @@ describe( kbnServerArgs: [ `--xpack.securitySolution.enableExperimental=${JSON.stringify([ 'automatedProcessActionsEnabled', + 'rulesResponseActionsTemporaryFlagEnabled', ])}`, ], }, @@ -202,23 +205,22 @@ describe( }); }); - // TODO: uncomment the test after another serverless release - intermediate release - // describe('User should be able to add response action to ESQL rule', () => { - // const [ruleName, ruleDescription] = generateRandomStringName(2); - // - // beforeEach(() => { - // login(ROLE.soc_manager); - // }); - // - // it('create and save endpoint response action inside of a rule', () => { - // const query = 'FROM * METADATA _index, _id {backspace}{enter}'; - // fillUpNewEsqlRule(ruleName, ruleDescription, query); - // addEndpointResponseAction(); - // focusAndOpenCommandDropdown(); - // validateAvailableCommands(); - // selectIsolateAndSaveWithoutEnabling(ruleName); - // }); - // }); + describe('User should be able to add response action to ESQL rule', () => { + const [ruleName, ruleDescription] = generateRandomStringName(2); + + beforeEach(() => { + login(ROLE.soc_manager); + }); + + it('create and save endpoint response action inside of a rule', () => { + const query = 'FROM * METADATA _index, _id {backspace}{enter}'; + fillUpNewEsqlRule(ruleName, ruleDescription, query); + addEndpointResponseAction(); + focusAndOpenCommandDropdown(); + validateAvailableCommands(); + selectIsolateAndSaveWithoutEnabling(ruleName); + }); + }); describe('User should not see endpoint action when no rbac', () => { const [ruleName, ruleDescription] = generateRandomStringName(2); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts index 96aaef64b57c9..96980acb2d731 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts @@ -70,7 +70,14 @@ export const validateResponseActionsPermissions = async ( ruleUpdate: RuleCreateProps | RuleUpdateProps, existingRule?: RuleAlertType | null ): Promise => { - if (!shouldShowResponseActions(ruleUpdate.type)) { + const { experimentalFeatures } = await securitySolution.getConfig(); + + if ( + !shouldShowResponseActions( + ruleUpdate.type, + experimentalFeatures.rulesResponseActionsTemporaryFlagEnabled + ) + ) { return; } From 708905ad4ce92ee12f0380f1313a81c2ce80ba8b Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Thu, 12 Sep 2024 18:07:32 +0200 Subject: [PATCH 22/34] fix --- .../rule_creation/components/step_rule_actions/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx index 5949666195852..ccd0379fe0800 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx @@ -85,6 +85,9 @@ const StepRuleActionsComponent: FC = ({ const { services: { application }, } = useKibana(); + const rulesResponseActionsTemporaryFlagEnabled = useIsExperimentalFeatureEnabled( + 'rulesResponseActionsTemporaryFlagEnabled' + ); const displayActionsOptions = useMemo( () => ( <> @@ -110,7 +113,7 @@ const StepRuleActionsComponent: FC = ({ ); } return null; - }, [ruleType]); + }, [ruleType, rulesResponseActionsTemporaryFlagEnabled]); // only display the actions dropdown if the user has "read" privileges for actions const displayActionsDropDown = useMemo(() => { return application.capabilities.actions.show ? ( @@ -154,9 +157,6 @@ const StepRuleActionsReadOnlyComponent: FC = ({ const { services: { triggersActionsUi }, } = useKibana(); - const rulesResponseActionsTemporaryFlagEnabled = useIsExperimentalFeatureEnabled( - 'rulesResponseActionsTemporaryFlagEnabled' - ); const actionTypeRegistry = triggersActionsUi.actionTypeRegistry as ActionTypeRegistryContract; From 28e37f2789a869fea65c8954a79970b29dd6d945 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Thu, 12 Sep 2024 19:21:22 +0200 Subject: [PATCH 23/34] fixes --- .../security_solution/common/detection_engine/utils.ts | 7 +++++-- .../security_solution/common/experimental_features.ts | 2 +- .../components/step_rule_actions/index.tsx | 8 ++++---- .../cypress/e2e/automated_response_actions/form.cy.ts | 10 ++++++---- .../model/rule_assets/prebuilt_rule_asset.ts | 1 + .../detection_engine/rule_management/utils/validate.ts | 2 +- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/utils.ts b/x-pack/plugins/security_solution/common/detection_engine/utils.ts index 1d39734ab7732..509d38d026e60 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/utils.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/utils.ts @@ -94,8 +94,11 @@ export const isSuppressionRuleInGA = (ruleType: Type): boolean => { return isSuppressibleAlertRule(ruleType) && SUPPRESSIBLE_ALERT_RULES_GA.includes(ruleType); }; -export const shouldShowResponseActions = (ruleType: Type | undefined, featureFlag: boolean) => { - return featureFlag +export const shouldShowResponseActions = ( + ruleType: Type | undefined, + automatedResponseActionsForMoreRulesEnabled: boolean +) => { + return automatedResponseActionsForMoreRulesEnabled ? isQueryRule(ruleType) || isEsqlRule(ruleType) || isEqlRule(ruleType) || diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 2fab62310ba27..15ad47d5e6c5c 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -55,7 +55,7 @@ export const allowedExperimentalValues = Object.freeze({ /** * Temporary feature flag to enable the Response Actions in Rules UI - intermediate release */ - rulesResponseActionsTemporaryFlagEnabled: false, + automatedResponseActionsForMoreRulesEnabled: false, /** * Enables the ability to send Response actions to SentinelOne and persist the results diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx index ccd0379fe0800..5838c85281123 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx @@ -85,8 +85,8 @@ const StepRuleActionsComponent: FC = ({ const { services: { application }, } = useKibana(); - const rulesResponseActionsTemporaryFlagEnabled = useIsExperimentalFeatureEnabled( - 'rulesResponseActionsTemporaryFlagEnabled' + const automatedResponseActionsForMoreRulesEnabled = useIsExperimentalFeatureEnabled( + 'automatedResponseActionsForMoreRulesEnabled' ); const displayActionsOptions = useMemo( () => ( @@ -105,7 +105,7 @@ const StepRuleActionsComponent: FC = ({ [actionMessageParams, summaryActionMessageParams] ); const displayResponseActionsOptions = useMemo(() => { - if (shouldShowResponseActions(ruleType, rulesResponseActionsTemporaryFlagEnabled)) { + if (shouldShowResponseActions(ruleType, automatedResponseActionsForMoreRulesEnabled)) { return ( {ResponseActionsForm} @@ -113,7 +113,7 @@ const StepRuleActionsComponent: FC = ({ ); } return null; - }, [ruleType, rulesResponseActionsTemporaryFlagEnabled]); + }, [ruleType, automatedResponseActionsForMoreRulesEnabled]); // only display the actions dropdown if the user has "read" privileges for actions const displayActionsDropDown = useMemo(() => { return application.capabilities.actions.show ? ( diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index b6fd78b515917..8fc601f747768 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -1,8 +1,10 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import { @@ -30,7 +32,7 @@ describe( kbnServerArgs: [ `--xpack.securitySolution.enableExperimental=${JSON.stringify([ 'automatedProcessActionsEnabled', - 'rulesResponseActionsTemporaryFlagEnabled', + 'automatedResponseActionsForMoreRulesEnabled', ])}`, ], }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts index 9171304abe44a..1a9ca6c9abe31 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts @@ -21,6 +21,7 @@ import { */ const BASE_PROPS_REMOVED_FROM_PREBUILT_RULE_ASSET = zodMaskFor()([ 'actions', + 'response_actions', 'throttle', 'meta', 'output_index', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts index 96980acb2d731..1274a2d7e7cad 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts @@ -75,7 +75,7 @@ export const validateResponseActionsPermissions = async ( if ( !shouldShowResponseActions( ruleUpdate.type, - experimentalFeatures.rulesResponseActionsTemporaryFlagEnabled + experimentalFeatures.automatedResponseActionsForMoreRulesEnabled ) ) { return; From 07a573c2258e00ec179ba74c0fdf0003236d7840 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 12 Sep 2024 18:17:27 +0000 Subject: [PATCH 24/34] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../cypress/e2e/automated_response_actions/form.cy.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index 8fc601f747768..d984f4052a979 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -1,10 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import { From 16a534c7f00d91d75c4f36625b600873be8cd234 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Thu, 12 Sep 2024 20:42:10 +0200 Subject: [PATCH 25/34] fix --- .../prebuilt_rules/model/rule_assets/prebuilt_rule_asset.mock.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.mock.ts index e29a255fa3184..c73203c2871ab 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.mock.ts @@ -18,7 +18,6 @@ export const getPrebuiltRuleMock = (rewrites?: Partial): Preb language: 'kuery', rule_id: 'rule-1', version: 1, - response_actions: [{ action_type_id: `.osquery`, params: {} }], ...rewrites, } as PrebuiltRuleAsset); From 6f0e36e6f167ca91bc50bc1167f4478a5aab42a2 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Fri, 13 Sep 2024 08:46:34 +0200 Subject: [PATCH 26/34] use TypeSpecificCreatePropsInternal instead of TypeSpecificFields --- .../rule_assets/prebuilt_rule_asset.test.ts | 16 ++------- .../model/rule_assets/prebuilt_rule_asset.ts | 35 +++---------------- 2 files changed, 6 insertions(+), 45 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts index c256530871337..745610d9035f3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts @@ -7,23 +7,10 @@ import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; import { getListArrayMock } from '../../../../../../common/detection_engine/schemas/types/lists.mock'; -import { PrebuiltRuleAsset, TypeSpecificFields } from './prebuilt_rule_asset'; +import { PrebuiltRuleAsset } from './prebuilt_rule_asset'; import { getPrebuiltRuleMock, getPrebuiltThreatMatchRuleMock } from './prebuilt_rule_asset.mock'; -import { TypeSpecificCreatePropsInternal } from '../../../../../../common/api/detection_engine'; describe('Prebuilt rule asset schema', () => { - it('can be of all rule types that are supported', () => { - // Check that the discriminated union TypeSpecificFields, which is used to create - // the PrebuiltRuleAsset schema, contains all the rule types that are supported. - const createPropsTypes = TypeSpecificCreatePropsInternal.options.map( - (option) => option.shape.type.value - ); - const fieldsTypes = TypeSpecificFields.options.map((option) => option.shape.type.value); - - expect(createPropsTypes).toHaveLength(fieldsTypes.length); - expect(new Set(createPropsTypes)).toEqual(new Set(fieldsTypes)); - }); - test('empty objects do not validate', () => { const payload: Partial = {}; @@ -51,6 +38,7 @@ describe('Prebuilt rule asset schema', () => { // See: detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts const omittedBaseFields = [ 'actions', + 'response_actions', 'throttle', 'meta', 'output_index', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts index 249e4d8ed6930..8a27d90680240 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts @@ -6,20 +6,11 @@ */ import * as z from '@kbn/zod'; -import type { IsEqual } from 'type-fest'; -import type { TypeSpecificCreateProps } from '../../../../../../common/api/detection_engine/model/rule_schema'; import { RuleSignatureId, RuleVersion, BaseCreateProps, - EqlRuleCreateFields, - EsqlRuleCreateFields, - MachineLearningRuleCreateFields, - NewTermsRuleCreateFields, - QueryRuleCreateFields, - SavedQueryRuleCreateFields, - ThreatMatchRuleCreateFields, - ThresholdRuleCreateFields, + TypeSpecificCreatePropsInternal, } from '../../../../../../common/api/detection_engine/model/rule_schema'; function zodMaskFor() { @@ -48,25 +39,6 @@ const BASE_PROPS_REMOVED_FROM_PREBUILT_RULE_ASSET = zodMaskFor( 'outcome', ]); -export const TypeSpecificFields = z.discriminatedUnion('type', [ - EqlRuleCreateFields, - QueryRuleCreateFields, - SavedQueryRuleCreateFields, - ThresholdRuleCreateFields, - ThreatMatchRuleCreateFields, - MachineLearningRuleCreateFields, - NewTermsRuleCreateFields, - EsqlRuleCreateFields, -]); - -// Make sure the type-specific fields contain all the same rule types as the type-specific rule params. -// TS will throw a type error if the types are not equal (for example, if a new rule type is added to -// the TypeSpecificCreateProps and the new type is not reflected in TypeSpecificFields). -export const areTypesEqual: IsEqual< - typeof TypeSpecificCreateProps._type.type, - typeof TypeSpecificFields._type.type -> = true; - export const PrebuiltAssetBaseProps = BaseCreateProps.omit( BASE_PROPS_REMOVED_FROM_PREBUILT_RULE_ASSET ); @@ -87,7 +59,8 @@ export const PrebuiltAssetBaseProps = BaseCreateProps.omit( * - some fields are omitted because they are not present in https://github.com/elastic/detection-rules */ export type PrebuiltRuleAsset = z.infer; -export const PrebuiltRuleAsset = PrebuiltAssetBaseProps.and(TypeSpecificFields).and( + +export const PrebuiltRuleAsset = PrebuiltAssetBaseProps.and(TypeSpecificCreatePropsInternal).and( z.object({ rule_id: RuleSignatureId, version: RuleVersion, @@ -98,7 +71,7 @@ function createUpgradableRuleFieldsPayloadByType() { const baseFields = Object.keys(PrebuiltAssetBaseProps.shape); return new Map( - TypeSpecificFields.options.map((option) => { + TypeSpecificCreatePropsInternal.options.map((option) => { const typeName = option.shape.type.value; const typeSpecificFieldsForType = Object.keys(option.shape); From ee68d55552489af62bd80ae11f032723aaae0122 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Wed, 18 Sep 2024 09:54:53 +0200 Subject: [PATCH 27/34] move back response_actions to typespecific rules --- .../model/rule_schema/rule_schemas.gen.ts | 8 ++- .../rule_schema/rule_schemas.schema.yaml | 44 ++++++++++------ .../common/detection_engine/utils.ts | 11 ++-- .../rule_assets/prebuilt_rule_asset.test.ts | 26 +++++++++- .../model/rule_assets/prebuilt_rule_asset.ts | 51 +++++++++++++++++-- .../common_params_camel_to_snake.ts | 2 - .../convert_rule_response_to_alerting_rule.ts | 15 ++++-- .../type_specific_camel_to_snake.ts | 6 +++ .../mergers/apply_rule_defaults.ts | 6 ++- .../mergers/apply_rule_patch.ts | 6 ++- .../rule_schema/model/rule_schemas.ts | 6 ++- 11 files changed, 144 insertions(+), 37 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts index b01dac90a1d9f..a723eb8e7da89 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts @@ -68,13 +68,13 @@ import { SavedQueryId, KqlQueryLanguage, } from './common_attributes.gen'; -import { ResponseAction } from '../rule_response_actions/response_actions.gen'; import { RuleExecutionSummary } from '../../rule_monitoring/model/execution_summary.gen'; import { EventCategoryOverride, TiebreakerField, TimestampField, } from './specific_attributes/eql_attributes.gen'; +import { ResponseAction } from '../rule_response_actions/response_actions.gen'; import { Threshold, ThresholdAlertSuppression, @@ -117,7 +117,6 @@ export const BaseOptionalFields = z.object({ meta: RuleMetadata.optional(), investigation_fields: InvestigationFields.optional(), throttle: RuleActionThrottle.optional(), - response_actions: z.array(ResponseAction).optional(), }); export type BaseDefaultableFields = z.infer; @@ -225,6 +224,7 @@ export const EqlOptionalFields = z.object({ tiebreaker_field: TiebreakerField.optional(), timestamp_field: TimestampField.optional(), alert_suppression: AlertSuppression.optional(), + response_actions: z.array(ResponseAction).optional(), }); export type EqlRuleCreateFields = z.infer; @@ -262,6 +262,7 @@ export const QueryRuleOptionalFields = z.object({ data_view_id: DataViewId.optional(), filters: RuleFilterArray.optional(), saved_id: SavedQueryId.optional(), + response_actions: z.array(ResponseAction).optional(), alert_suppression: AlertSuppression.optional(), }); @@ -312,6 +313,7 @@ export const SavedQueryRuleOptionalFields = z.object({ index: IndexPatternArray.optional(), data_view_id: DataViewId.optional(), filters: RuleFilterArray.optional(), + response_actions: z.array(ResponseAction).optional(), alert_suppression: AlertSuppression.optional(), query: RuleQuery.optional(), }); @@ -520,6 +522,7 @@ export const NewTermsRuleOptionalFields = z.object({ data_view_id: DataViewId.optional(), filters: RuleFilterArray.optional(), alert_suppression: AlertSuppression.optional(), + response_actions: z.array(ResponseAction).optional(), }); export type NewTermsRuleDefaultableFields = z.infer; @@ -573,6 +576,7 @@ export const EsqlRuleRequiredFields = z.object({ export type EsqlRuleOptionalFields = z.infer; export const EsqlRuleOptionalFields = z.object({ alert_suppression: AlertSuppression.optional(), + response_actions: z.array(ResponseAction).optional(), }); export type EsqlRulePatchFields = z.infer; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml index 7cd51e64fc0c1..3ba9cfba39154 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: title: Security Rule Schema version: 'not applicable' -paths: {} +paths: { } components: x-codegen-enabled: true schemas: @@ -73,12 +73,6 @@ components: # Throttle throttle: $ref: './common_attributes.schema.yaml#/components/schemas/RuleActionThrottle' - # Response Actions - response_actions: - type: array - items: - $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' - BaseDefaultableFields: x-inline: true @@ -268,7 +262,7 @@ components: properties: type: type: string - enum: [eql] + enum: [ eql ] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -298,6 +292,10 @@ components: $ref: './specific_attributes/eql_attributes.schema.yaml#/components/schemas/TimestampField' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' EqlRuleCreateFields: allOf: @@ -344,7 +342,7 @@ components: properties: type: type: string - enum: [query] + enum: [ query ] description: Rule type required: - type @@ -360,6 +358,10 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' saved_id: $ref: './common_attributes.schema.yaml#/components/schemas/SavedQueryId' + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' @@ -420,7 +422,7 @@ components: properties: type: type: string - enum: [saved_query] + enum: [ saved_query ] description: Rule type saved_id: $ref: './common_attributes.schema.yaml#/components/schemas/SavedQueryId' @@ -437,6 +439,10 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/DataViewId' filters: $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' query: @@ -497,7 +503,7 @@ components: properties: type: type: string - enum: [threshold] + enum: [ threshold ] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -577,7 +583,7 @@ components: properties: type: type: string - enum: [threat_match] + enum: [ threat_match ] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -673,7 +679,7 @@ components: properties: type: type: string - enum: [machine_learning] + enum: [ machine_learning ] description: Rule type anomaly_threshold: $ref: './specific_attributes/ml_attributes.schema.yaml#/components/schemas/AnomalyThreshold' @@ -735,7 +741,7 @@ components: properties: type: type: string - enum: [new_terms] + enum: [ new_terms ] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -760,6 +766,10 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' NewTermsRuleDefaultableFields: type: object @@ -821,7 +831,7 @@ components: properties: type: type: string - enum: [esql] + enum: [ esql ] description: Rule type language: $ref: '#/components/schemas/EsqlQueryLanguage' @@ -838,6 +848,10 @@ components: properties: alert_suppression: $ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression' + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' EsqlRulePatchFields: allOf: diff --git a/x-pack/plugins/security_solution/common/detection_engine/utils.ts b/x-pack/plugins/security_solution/common/detection_engine/utils.ts index 509d38d026e60..503e0c58ff46e 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/utils.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/utils.ts @@ -98,10 +98,9 @@ export const shouldShowResponseActions = ( ruleType: Type | undefined, automatedResponseActionsForMoreRulesEnabled: boolean ) => { - return automatedResponseActionsForMoreRulesEnabled - ? isQueryRule(ruleType) || - isEsqlRule(ruleType) || - isEqlRule(ruleType) || - isNewTermsRule(ruleType) - : isQueryRule(ruleType); + return ( + isQueryRule(ruleType) || + (automatedResponseActionsForMoreRulesEnabled && + (isEsqlRule(ruleType) || isEqlRule(ruleType) || isNewTermsRule(ruleType))) + ); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts index 745610d9035f3..45a561996e0a9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts @@ -7,10 +7,23 @@ import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; import { getListArrayMock } from '../../../../../../common/detection_engine/schemas/types/lists.mock'; -import { PrebuiltRuleAsset } from './prebuilt_rule_asset'; +import { PrebuiltRuleAsset, TypeSpecificFields } from './prebuilt_rule_asset'; import { getPrebuiltRuleMock, getPrebuiltThreatMatchRuleMock } from './prebuilt_rule_asset.mock'; +import { TypeSpecificCreatePropsInternal } from '../../../../../../common/api/detection_engine'; describe('Prebuilt rule asset schema', () => { + it('can be of all rule types that are supported', () => { + // Check that the discriminated union TypeSpecificFields, which is used to create + // the PrebuiltRuleAsset schema, contains all the rule types that are supported. + const createPropsTypes = TypeSpecificCreatePropsInternal.options.map( + (option) => option.shape.type.value + ); + const fieldsTypes = TypeSpecificFields.options.map((option) => option.shape.type.value); + + expect(createPropsTypes).toHaveLength(fieldsTypes.length); + expect(new Set(createPropsTypes)).toEqual(new Set(fieldsTypes)); + }); + test('empty objects do not validate', () => { const payload: Partial = {}; @@ -61,6 +74,17 @@ describe('Prebuilt rule asset schema', () => { expect(result.data).toEqual(getPrebuiltRuleMock()); } ); + + test('ignores the type specific response_actions field since it`s an omitted field', () => { + const payload: Partial & Record = { + ...getPrebuiltRuleMock(), + response_actions: [{ action_type_id: `.osquery`, params: {} }], + }; + + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(getPrebuiltRuleMock()); + }); }); test('[rule_id] does not validate', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts index 8a27d90680240..2d7b056f86248 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts @@ -6,11 +6,20 @@ */ import * as z from '@kbn/zod'; +import type { IsEqual } from 'type-fest'; +import type { TypeSpecificCreateProps } from '../../../../../../common/api/detection_engine/model/rule_schema'; import { RuleSignatureId, RuleVersion, BaseCreateProps, - TypeSpecificCreatePropsInternal, + EqlRuleCreateFields, + EsqlRuleCreateFields, + MachineLearningRuleCreateFields, + NewTermsRuleCreateFields, + QueryRuleCreateFields, + SavedQueryRuleCreateFields, + ThreatMatchRuleCreateFields, + ThresholdRuleCreateFields, } from '../../../../../../common/api/detection_engine/model/rule_schema'; function zodMaskFor() { @@ -29,7 +38,6 @@ function zodMaskFor() { */ const BASE_PROPS_REMOVED_FROM_PREBUILT_RULE_ASSET = zodMaskFor()([ 'actions', - 'response_actions', 'throttle', 'meta', 'output_index', @@ -39,6 +47,40 @@ const BASE_PROPS_REMOVED_FROM_PREBUILT_RULE_ASSET = zodMaskFor( 'outcome', ]); +/** + * Aditionally remove fields which are part only of the optional fields in the rule types that make up + * the TypeSpecificCreateProps discriminatedUnion, by recreating a discriminated union of the types, but + * with the necessary fields omitted, in the types where they exist. Fields to extract: + * - response_actions: from Query and SavedQuery rules + */ +const TYPE_SPECIFIC_FIELDS_TO_OMIT = ['response_actions'] as const; + +const TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_QUERY_RULES = zodMaskFor()([ + ...TYPE_SPECIFIC_FIELDS_TO_OMIT, +]); +const TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_SAVED_QUERY_RULES = + zodMaskFor()([...TYPE_SPECIFIC_FIELDS_TO_OMIT]); + +export type TypeSpecificFields = z.infer; +export const TypeSpecificFields = z.discriminatedUnion('type', [ + EqlRuleCreateFields.omit(TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_QUERY_RULES), + QueryRuleCreateFields.omit(TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_QUERY_RULES), + SavedQueryRuleCreateFields.omit(TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_SAVED_QUERY_RULES), + ThresholdRuleCreateFields, + ThreatMatchRuleCreateFields, + MachineLearningRuleCreateFields, + NewTermsRuleCreateFields.omit(TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_QUERY_RULES), + EsqlRuleCreateFields.omit(TYPE_SPECIFIC_FIELDS_TO_OMIT_FROM_QUERY_RULES), +]); + +// Make sure the type-specific fields contain all the same rule types as the type-specific rule params. +// TS will throw a type error if the types are not equal (for example, if a new rule type is added to +// the TypeSpecificCreateProps and the new type is not reflected in TypeSpecificFields). +export const areTypesEqual: IsEqual< + typeof TypeSpecificCreateProps._type.type, + typeof TypeSpecificFields._type.type +> = true; + export const PrebuiltAssetBaseProps = BaseCreateProps.omit( BASE_PROPS_REMOVED_FROM_PREBUILT_RULE_ASSET ); @@ -59,8 +101,7 @@ export const PrebuiltAssetBaseProps = BaseCreateProps.omit( * - some fields are omitted because they are not present in https://github.com/elastic/detection-rules */ export type PrebuiltRuleAsset = z.infer; - -export const PrebuiltRuleAsset = PrebuiltAssetBaseProps.and(TypeSpecificCreatePropsInternal).and( +export const PrebuiltRuleAsset = PrebuiltAssetBaseProps.and(TypeSpecificFields).and( z.object({ rule_id: RuleSignatureId, version: RuleVersion, @@ -71,7 +112,7 @@ function createUpgradableRuleFieldsPayloadByType() { const baseFields = Object.keys(PrebuiltAssetBaseProps.shape); return new Map( - TypeSpecificCreatePropsInternal.options.map((option) => { + TypeSpecificFields.options.map((option) => { const typeName = option.shape.type.value; const typeSpecificFieldsForType = Object.keys(option.shape); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts index bd942385e984a..6f98230043e74 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/common_params_camel_to_snake.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { transformAlertToRuleResponseAction } from '../../../../../../../common/detection_engine/transform_actions'; import { convertObjectKeysToSnakeCase } from '../../../../../../utils/object_case_converters'; import type { BaseRuleParams } from '../../../../rule_schema'; import { migrateLegacyInvestigationFields } from '../../../utils/utils'; @@ -44,6 +43,5 @@ export const commonParamsCamelToSnake = (params: BaseRuleParams) => { related_integrations: params.relatedIntegrations ?? [], required_fields: params.requiredFields ?? [], setup: params.setup ?? '', - response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts index 1f0a37f5c232d..2348c11027c65 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/convert_rule_response_to_alerting_rule.ts @@ -94,9 +94,6 @@ export const convertRuleResponseToAlertingRule = ( note: rule.note, version: rule.version, exceptionsList: rule.exceptions_list, - responseActions: rule.response_actions?.map((responseAction) => - transformRuleToAlertResponseAction(responseAction) - ), ...typeSpecificParams, }, schedule: { interval: rule.interval }, @@ -122,6 +119,9 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific eventCategoryOverride: params.event_category_override, tiebreakerField: params.tiebreaker_field, alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), + responseActions: params.response_actions?.map((rule) => + transformRuleToAlertResponseAction(rule) + ), }; } case 'esql': { @@ -130,6 +130,9 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific language: params.language, query: params.query, alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), + responseActions: params.response_actions?.map((rule) => + transformRuleToAlertResponseAction(rule) + ), }; } case 'threat_match': { @@ -161,6 +164,9 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific query: params.query ?? '', filters: params.filters, savedId: params.saved_id, + responseActions: params.response_actions?.map((rule) => + transformRuleToAlertResponseAction(rule) + ), alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), }; } @@ -210,6 +216,9 @@ const typeSpecificSnakeToCamel = (params: TypeSpecificCreateProps): TypeSpecific language: params.language ?? 'kuery', dataViewId: params.data_view_id, alertSuppression: convertObjectKeysToCamelCase(params.alert_suppression), + responseActions: params.response_actions?.map((rule) => + transformRuleToAlertResponseAction(rule) + ), }; } default: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts index 5a2f7ba0d3548..a4b74e31ba291 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/converters/type_specific_camel_to_snake.ts @@ -6,6 +6,7 @@ */ import type { RequiredOptional } from '@kbn/zod-helpers'; +import { transformAlertToRuleResponseAction } from '../../../../../../../common/detection_engine/transform_actions'; import type { TypeSpecificResponse } from '../../../../../../../common/api/detection_engine/model/rule_schema'; import { assertUnreachable } from '../../../../../../../common/utility_types'; import { convertObjectKeysToSnakeCase } from '../../../../../../utils/object_case_converters'; @@ -27,6 +28,7 @@ export const typeSpecificCamelToSnake = ( event_category_override: params.eventCategoryOverride, tiebreaker_field: params.tiebreakerField, alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), + response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; } case 'esql': { @@ -35,6 +37,7 @@ export const typeSpecificCamelToSnake = ( language: params.language, query: params.query, alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), + response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; } case 'threat_match': { @@ -66,6 +69,7 @@ export const typeSpecificCamelToSnake = ( query: params.query, filters: params.filters, saved_id: params.savedId, + response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), }; } @@ -78,6 +82,7 @@ export const typeSpecificCamelToSnake = ( filters: params.filters, saved_id: params.savedId, data_view_id: params.dataViewId, + response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), }; } @@ -115,6 +120,7 @@ export const typeSpecificCamelToSnake = ( language: params.language, data_view_id: params.dataViewId, alert_suppression: convertObjectKeysToSnakeCase(params.alertSuppression), + response_actions: params.responseActions?.map(transformAlertToRuleResponseAction), }; } default: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts index 43177a367a1c2..388b1ab695269 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_defaults.ts @@ -56,7 +56,6 @@ export function applyRuleDefaults(rule: RuleCreateProps & { immutable?: boolean immutable, rule_source: convertImmutableToRuleSource(immutable), required_fields: addEcsToRequiredFields(rule.required_fields), - response_actions: rule.response_actions, }; } @@ -87,6 +86,7 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { event_category_override: props.event_category_override, tiebreaker_field: props.tiebreaker_field, alert_suppression: props.alert_suppression, + response_actions: props.response_actions, }; } case 'esql': { @@ -95,6 +95,7 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { language: props.language, query: props.query, alert_suppression: props.alert_suppression, + response_actions: props.response_actions, }; } case 'threat_match': { @@ -126,6 +127,7 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { query: props.query ?? '', filters: props.filters, saved_id: props.saved_id, + response_actions: props.response_actions, alert_suppression: props.alert_suppression, }; } @@ -138,6 +140,7 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { filters: props.filters, saved_id: props.saved_id, data_view_id: props.data_view_id, + response_actions: props.response_actions, alert_suppression: props.alert_suppression, }; } @@ -175,6 +178,7 @@ export const setTypeSpecificDefaults = (props: TypeSpecificCreateProps) => { language: props.language ?? 'kuery', data_view_id: props.data_view_id, alert_suppression: props.alert_suppression, + response_actions: props.response_actions, }; } default: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts index ba21037ba376f..d864170746ed3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/mergers/apply_rule_patch.ts @@ -111,7 +111,6 @@ export const applyRulePatch = async ({ interval: rulePatch.interval ?? existingRule.interval, throttle: rulePatch.throttle ?? existingRule.throttle, actions: rulePatch.actions ?? existingRule.actions, - response_actions: rulePatch.response_actions ?? existingRule.response_actions, ...typeSpecificParams, }; @@ -139,6 +138,7 @@ const patchEqlParams = ( rulePatch.event_category_override ?? existingRule.event_category_override, tiebreaker_field: rulePatch.tiebreaker_field ?? existingRule.tiebreaker_field, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, + response_actions: rulePatch.response_actions ?? existingRule.response_actions, }; }; @@ -151,6 +151,7 @@ const patchEsqlParams = ( language: rulePatch.language ?? existingRule.language, query: rulePatch.query ?? existingRule.query, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, + response_actions: rulePatch.response_actions ?? existingRule.response_actions, }; }; @@ -190,6 +191,7 @@ const patchQueryParams = ( query: rulePatch.query ?? existingRule.query, filters: rulePatch.filters ?? existingRule.filters, saved_id: rulePatch.saved_id ?? existingRule.saved_id, + response_actions: rulePatch.response_actions ?? existingRule.response_actions, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, }; }; @@ -206,6 +208,7 @@ const patchSavedQueryParams = ( query: rulePatch.query ?? existingRule.query, filters: rulePatch.filters ?? existingRule.filters, saved_id: rulePatch.saved_id ?? existingRule.saved_id, + response_actions: rulePatch.response_actions ?? existingRule.response_actions, alert_suppression: rulePatch.alert_suppression ?? existingRule.alert_suppression, }; }; @@ -257,6 +260,7 @@ const patchNewTermsParams = ( new_terms_fields: params.new_terms_fields ?? existingRule.new_terms_fields, history_window_start: params.history_window_start ?? existingRule.history_window_start, alert_suppression: params.alert_suppression ?? existingRule.alert_suppression, + response_actions: params.response_actions ?? existingRule.response_actions, }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts index c1192e9a75fd1..e651ffeebaf49 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts @@ -148,7 +148,6 @@ export const BaseRuleParams = z.object({ relatedIntegrations: RelatedIntegrationArray.optional(), requiredFields: RequiredFieldArray.optional(), setup: SetupGuide.optional(), - responseActions: z.array(RuleResponseAction).optional(), }); export type EqlSpecificRuleParams = z.infer; @@ -163,6 +162,7 @@ export const EqlSpecificRuleParams = z.object({ timestampField: TimestampField.optional(), tiebreakerField: TiebreakerField.optional(), alertSuppression: AlertSuppressionCamel.optional(), + responseActions: z.array(RuleResponseAction).optional(), }); export type EqlRuleParams = BaseRuleParams & EqlSpecificRuleParams; @@ -174,6 +174,7 @@ export const EsqlSpecificRuleParams = z.object({ language: z.literal('esql'), query: RuleQuery, alertSuppression: AlertSuppressionCamel.optional(), + responseActions: z.array(RuleResponseAction).optional(), }); export type EsqlRuleParams = BaseRuleParams & EsqlSpecificRuleParams; @@ -211,6 +212,7 @@ export const QuerySpecificRuleParams = z.object({ filters: RuleFilterArray.optional(), savedId: SavedQueryId.optional(), dataViewId: DataViewId.optional(), + responseActions: z.array(RuleResponseAction).optional(), alertSuppression: AlertSuppressionCamel.optional(), }); @@ -226,6 +228,7 @@ export const SavedQuerySpecificRuleParams = z.object({ query: RuleQuery.optional(), filters: RuleFilterArray.optional(), savedId: SavedQueryId, + responseActions: z.array(RuleResponseAction).optional(), alertSuppression: AlertSuppressionCamel.optional(), }); @@ -279,6 +282,7 @@ export const NewTermsSpecificRuleParams = z.object({ language: KqlQueryLanguage, dataViewId: DataViewId.optional(), alertSuppression: AlertSuppressionCamel.optional(), + responseActions: z.array(RuleResponseAction).optional(), }); export type NewTermsRuleParams = BaseRuleParams & NewTermsSpecificRuleParams; From 1dc5cf4b8463e5d8d75e684950a6e4b6d8fa6f71 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Wed, 18 Sep 2024 10:58:16 +0200 Subject: [PATCH 28/34] move condition logic to scheduleNotificationResponseActionsService --- .../schedule_notification_response_actions.ts | 5 ++++- .../lib/detection_engine/rule_types/eql/eql.ts | 17 ++++++----------- .../detection_engine/rule_types/esql/esql.ts | 17 ++++++----------- .../new_terms/create_new_terms_alert_type.ts | 15 +++++---------- .../detection_engine/rule_types/query/query.ts | 17 ++++++----------- .../lib/detection_engine/rule_types/types.ts | 3 ++- 6 files changed, 29 insertions(+), 45 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts index 31f8ef6b70079..18d93697a2d99 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts @@ -24,7 +24,10 @@ export const getScheduleNotificationResponseActionsService = osqueryCreateActionService, endpointAppContextService, }: ScheduleNotificationResponseActionsService) => - async ({ signals, responseActions }: ScheduleNotificationActions) => { + async ({ signals, signalsCount, responseActions }: ScheduleNotificationActions) => { + if (!signalsCount || !responseActions?.length) { + return; + } // expandDottedObject is needed eg in ESQL rule because it's alerts come without nested agent, host etc data but everything is dotted const nestedAlerts = signals.map((signal) => expandDottedObject(signal as object)) as Alert[]; const alerts = nestedAlerts.filter((alert) => alert.agent?.id) as AlertWithAgent[]; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts index 02d7914562ee5..156d0347b5484 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts @@ -67,7 +67,7 @@ interface EqlExecutorParams { alertWithSuppression: SuppressedAlertService; isAlertSuppressionActive: boolean; experimentalFeatures: ExperimentalFeatures; - scheduleNotificationResponseActionsService?: CreateRuleAdditionalOptions['scheduleNotificationResponseActionsService']; + scheduleNotificationResponseActionsService: CreateRuleAdditionalOptions['scheduleNotificationResponseActionsService']; } export const eqlExecutor = async ({ @@ -191,16 +191,11 @@ export const eqlExecutor = async ({ result.warningMessages.push(maxSignalsWarning); } - if ( - completeRule.ruleParams.responseActions?.length && - result.createdSignalsCount && - scheduleNotificationResponseActionsService - ) { - scheduleNotificationResponseActionsService({ - signals: result.createdSignals, - responseActions: completeRule.ruleParams.responseActions, - }); - } + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); return result; } catch (error) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts index 79f9ff2c4439a..ce9ee8505a963 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts @@ -71,7 +71,7 @@ export const esqlExecutor = async ({ version: string; experimentalFeatures: ExperimentalFeatures; licensing: LicensingPluginSetup; - scheduleNotificationResponseActionsService?: CreateRuleAdditionalOptions['scheduleNotificationResponseActionsService']; + scheduleNotificationResponseActionsService: CreateRuleAdditionalOptions['scheduleNotificationResponseActionsService']; }) => { const ruleParams = completeRule.ruleParams; /** @@ -226,16 +226,11 @@ export const esqlExecutor = async ({ break; } } - if ( - completeRule.ruleParams.responseActions?.length && - result.createdSignalsCount && - scheduleNotificationResponseActionsService - ) { - scheduleNotificationResponseActionsService({ - signals: result.createdSignals, - responseActions: completeRule.ruleParams.responseActions, - }); - } + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); // no more results will be found if (response.values.length < size) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts index 7aa168484f09b..7815342ed5fdb 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts @@ -416,16 +416,11 @@ export const createNewTermsAlertType = ( afterKey = searchResultWithAggs.aggregations.new_terms.after_key; } - if ( - completeRule.ruleParams.responseActions?.length && - result.createdSignalsCount && - scheduleNotificationResponseActionsService - ) { - scheduleNotificationResponseActionsService({ - signals: result.createdSignals, - responseActions: completeRule.ruleParams.responseActions, - }); - } + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); return { ...result, state }; }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts index 525a171cf4364..4f5155c8401bc 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts @@ -42,7 +42,7 @@ export const queryExecutor = async ({ version: string; spaceId: string; bucketHistory?: BucketHistory[]; - scheduleNotificationResponseActionsService?: CreateRuleAdditionalOptions['scheduleNotificationResponseActionsService']; + scheduleNotificationResponseActionsService: CreateRuleAdditionalOptions['scheduleNotificationResponseActionsService']; licensing: LicensingPluginSetup; }) => { const completeRule = runOpts.completeRule; @@ -99,16 +99,11 @@ export const queryExecutor = async ({ state: {}, }; - if ( - completeRule.ruleParams.responseActions?.length && - result.createdSignalsCount && - scheduleNotificationResponseActionsService - ) { - scheduleNotificationResponseActionsService({ - signals: result.createdSignals, - responseActions: completeRule.ruleParams.responseActions, - }); - } + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); return result; }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts index b4273d975b7bc..5c1be0bb925ee 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts @@ -161,11 +161,12 @@ export interface CreateRuleOptions { export interface ScheduleNotificationActions { signals: unknown[]; + signalsCount: number; responseActions: RuleResponseAction[]; } export interface CreateRuleAdditionalOptions { - scheduleNotificationResponseActionsService?: (params: ScheduleNotificationActions) => void; + scheduleNotificationResponseActionsService: (params: ScheduleNotificationActions) => void; } export interface CreateQueryRuleOptions extends CreateRuleOptions, CreateRuleAdditionalOptions { From 69d9cd0c58ffc136f2a1399614d81930ae3b1e96 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Wed, 18 Sep 2024 12:05:41 +0200 Subject: [PATCH 29/34] tests --- ...dule_notification_response_actions.test.ts | 59 +++++++++++++++++-- .../schedule_notification_response_actions.ts | 2 +- .../rule_types/eql/eql.test.ts | 36 +++++++++++ 3 files changed, 90 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.test.ts index 4dccc9ad0aae7..d98dc0782b796 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.test.ts @@ -96,8 +96,13 @@ describe('ScheduleNotificationResponseActions', () => { }, }, ]; - await scheduleNotificationResponseActions({ signals, responseActions }); + const response = await scheduleNotificationResponseActions({ + signals, + signalsCount: signals.length, + responseActions, + }); + expect(response).not.toBeUndefined(); expect(osqueryActionMock.create).toHaveBeenCalledWith({ ...defaultQueryResultParams, query: simpleQuery, @@ -123,8 +128,13 @@ describe('ScheduleNotificationResponseActions', () => { }, }, ]; - await scheduleNotificationResponseActions({ signals, responseActions }); + const response = await scheduleNotificationResponseActions({ + signals, + signalsCount: signals.length, + responseActions, + }); + expect(response).not.toBeUndefined(); expect(osqueryActionMock.create).toHaveBeenCalledWith({ ...defaultPackResultParams, queries: [{ ...defaultQueries, id: 'query-1', query: simpleQuery }], @@ -149,8 +159,12 @@ describe('ScheduleNotificationResponseActions', () => { }, }, ]; - await scheduleNotificationResponseActions({ signals, responseActions }); - + const response = await scheduleNotificationResponseActions({ + signals, + signalsCount: signals.length, + responseActions, + }); + expect(response).not.toBeUndefined(); expect(endpointActionMock.getInternalResponseActionsClient).toHaveBeenCalledTimes(1); expect(endpointActionMock.getInternalResponseActionsClient).toHaveBeenCalledWith({ agentType: 'endpoint', @@ -188,11 +202,14 @@ describe('ScheduleNotificationResponseActions', () => { }, }, ]; - await scheduleNotificationResponseActions({ + const response = await scheduleNotificationResponseActions({ signals, + signalsCount: signals.length, responseActions, }); + expect(response).not.toBeUndefined(); + expect(mockedResponseActionsClient.killProcess).toHaveBeenCalledWith( { alert_ids: ['alert-id-1'], @@ -223,12 +240,42 @@ describe('ScheduleNotificationResponseActions', () => { }, }, ]; - await scheduleNotificationResponseActions({ + const response = await scheduleNotificationResponseActions({ signals, + signalsCount: signals.length, responseActions, }); + expect(response).not.toBeUndefined(); expect(mockedResponseActionsClient.isolate).toHaveBeenCalledTimes(signals.length - 1); }); + it('should not call any action service if no response actions are provided', async () => { + const response = await scheduleNotificationResponseActions({ + signals: getSignals(), + signalsCount: 2, + responseActions: [], + }); + expect(response).toBeUndefined(); + }); + it('should not call any action service if signalsCount is 0', async () => { + const signals = getSignals(); + const responseActions: RuleResponseAction[] = [ + { + actionTypeId: ResponseActionTypesEnum['.endpoint'], + params: { + command: 'isolate', + comment: 'test process comment', + }, + }, + ]; + + const response = await scheduleNotificationResponseActions({ + signals, + signalsCount: 0, + responseActions, + }); + + expect(response).toBeUndefined(); + }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts index 18d93697a2d99..b4f4689fed0ff 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts @@ -32,7 +32,7 @@ export const getScheduleNotificationResponseActionsService = const nestedAlerts = signals.map((signal) => expandDottedObject(signal as object)) as Alert[]; const alerts = nestedAlerts.filter((alert) => alert.agent?.id) as AlertWithAgent[]; - await Promise.all( + return Promise.all( responseActions.map(async (responseAction) => { if ( responseAction.actionTypeId === ResponseActionTypesEnum['.osquery'] && diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.test.ts index c16d61d3b0ea5..9ef9faeb9de3a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.test.ts @@ -37,6 +37,7 @@ describe('eql_executor', () => { maxSignals: params.maxSignals, }; const mockExperimentalFeatures = {} as ExperimentalFeatures; + const mockScheduleNotificationResponseActionsService = jest.fn(); beforeEach(() => { jest.clearAllMocks(); @@ -72,6 +73,8 @@ describe('eql_executor', () => { alertWithSuppression: jest.fn(), isAlertSuppressionActive: false, experimentalFeatures: mockExperimentalFeatures, + scheduleNotificationResponseActionsService: + mockScheduleNotificationResponseActionsService, }); expect(result.warningMessages).toEqual([ `The following exceptions won't be applied to rule execution: ${ @@ -121,6 +124,8 @@ describe('eql_executor', () => { alertWithSuppression: jest.fn(), isAlertSuppressionActive: true, experimentalFeatures: mockExperimentalFeatures, + scheduleNotificationResponseActionsService: + mockScheduleNotificationResponseActionsService, }); expect(result.warningMessages).toContain( @@ -154,10 +159,40 @@ describe('eql_executor', () => { alertWithSuppression: jest.fn(), isAlertSuppressionActive: true, experimentalFeatures: mockExperimentalFeatures, + scheduleNotificationResponseActionsService: mockScheduleNotificationResponseActionsService, }); expect(result.userError).toEqual(true); }); + it('should handle scheduleNotificationResponseActionsService call', async () => { + const result = await eqlExecutor({ + inputIndex: DEFAULT_INDEX_PATTERN, + runtimeMappings: {}, + completeRule: eqlCompleteRule, + tuple, + ruleExecutionLogger, + services: alertServices, + version, + bulkCreate: jest.fn(), + wrapHits: jest.fn(), + wrapSequences: jest.fn(), + primaryTimestamp: '@timestamp', + exceptionFilter: undefined, + unprocessedExceptions: [], + wrapSuppressedHits: jest.fn(), + alertTimestampOverride: undefined, + alertWithSuppression: jest.fn(), + isAlertSuppressionActive: false, + experimentalFeatures: mockExperimentalFeatures, + scheduleNotificationResponseActionsService: mockScheduleNotificationResponseActionsService, + }); + expect(mockScheduleNotificationResponseActionsService).toBeCalledWith({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: eqlCompleteRule.ruleParams.responseActions, + }); + }); + it('should pass frozen tier filters in eql search request', async () => { getDataTierFilterMock.mockResolvedValue([ { @@ -189,6 +224,7 @@ describe('eql_executor', () => { alertWithSuppression: jest.fn(), isAlertSuppressionActive: true, experimentalFeatures: mockExperimentalFeatures, + scheduleNotificationResponseActionsService: mockScheduleNotificationResponseActionsService, }); const searchArgs = From d787d0a0b6cb241e74dcaa09c6bfdb4b3447e33f Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:35:32 +0000 Subject: [PATCH 30/34] [CI] Auto-commit changed files from 'yarn openapi:bundle' --- ...ections_api_2023_10_31.bundled.schema.yaml | 148 +++--------------- ...ections_api_2023_10_31.bundled.schema.yaml | 148 +++--------------- 2 files changed, 40 insertions(+), 256 deletions(-) diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml index 81ed59b13fceb..8642113778fe0 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -2042,6 +2042,10 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array tiebreaker_field: $ref: '#/components/schemas/TiebreakerField' timestamp_field: @@ -2124,10 +2128,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2243,10 +2243,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2359,10 +2355,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2458,10 +2450,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2587,10 +2575,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2706,10 +2690,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2753,6 +2733,10 @@ components: properties: alert_suppression: $ref: '#/components/schemas/AlertSuppression' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array EsqlRulePatchProps: allOf: - type: object @@ -2816,10 +2800,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2937,10 +2917,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3193,10 +3169,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3312,10 +3284,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3431,10 +3399,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3546,10 +3510,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3751,10 +3711,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3871,10 +3827,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3929,6 +3881,10 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array NewTermsRulePatchFields: allOf: - type: object @@ -4004,10 +3960,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4128,10 +4080,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4355,10 +4303,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4475,10 +4419,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4535,6 +4475,10 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array saved_id: $ref: '#/components/schemas/SavedQueryId' QueryRulePatchFields: @@ -4606,10 +4550,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4724,10 +4664,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5398,10 +5334,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5518,10 +5450,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5578,6 +5506,10 @@ components: $ref: '#/components/schemas/IndexPatternArray' query: $ref: '#/components/schemas/RuleQuery' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array SavedQueryRulePatchFields: allOf: - type: object @@ -5649,10 +5581,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5767,10 +5695,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6018,10 +5942,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6138,10 +6058,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6285,10 +6201,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6412,10 +6324,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6605,10 +6513,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6725,10 +6629,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6858,10 +6758,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6979,10 +6875,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml index c5c4f40916b05..514c4c87405cd 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -1316,6 +1316,10 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array tiebreaker_field: $ref: '#/components/schemas/TiebreakerField' timestamp_field: @@ -1398,10 +1402,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1517,10 +1517,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1633,10 +1629,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1732,10 +1724,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1861,10 +1849,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -1980,10 +1964,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2027,6 +2007,10 @@ components: properties: alert_suppression: $ref: '#/components/schemas/AlertSuppression' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array EsqlRulePatchProps: allOf: - type: object @@ -2090,10 +2074,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2211,10 +2191,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2444,10 +2420,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2563,10 +2535,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2682,10 +2650,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2797,10 +2761,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -2904,10 +2864,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3024,10 +2980,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3082,6 +3034,10 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array NewTermsRulePatchFields: allOf: - type: object @@ -3157,10 +3113,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3281,10 +3233,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3508,10 +3456,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3628,10 +3572,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3688,6 +3628,10 @@ components: $ref: '#/components/schemas/RuleFilterArray' index: $ref: '#/components/schemas/IndexPatternArray' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array saved_id: $ref: '#/components/schemas/SavedQueryId' QueryRulePatchFields: @@ -3759,10 +3703,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -3877,10 +3817,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4551,10 +4487,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4671,10 +4603,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4731,6 +4659,10 @@ components: $ref: '#/components/schemas/IndexPatternArray' query: $ref: '#/components/schemas/RuleQuery' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array SavedQueryRulePatchFields: allOf: - type: object @@ -4802,10 +4734,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -4920,10 +4848,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5164,10 +5088,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5284,10 +5204,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5431,10 +5347,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5558,10 +5470,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5751,10 +5659,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -5871,10 +5775,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6004,10 +5904,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: @@ -6125,10 +6021,6 @@ components: items: $ref: '#/components/schemas/RequiredFieldInput' type: array - response_actions: - items: - $ref: '#/components/schemas/ResponseAction' - type: array risk_score: $ref: '#/components/schemas/RiskScore' risk_score_mapping: From e2680e9cc26e1ff4a2b093e716682cbb000a78d8 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Wed, 18 Sep 2024 13:26:54 +0200 Subject: [PATCH 31/34] fix --- .../lib/detection_engine/rule_types/eql/eql.ts | 12 +++++++----- .../lib/detection_engine/rule_types/esql/esql.ts | 12 +++++++----- .../new_terms/create_new_terms_alert_type.ts | 12 +++++++----- .../lib/detection_engine/rule_types/query/query.ts | 12 +++++++----- .../server/lib/detection_engine/rule_types/types.ts | 4 ++-- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts index 156d0347b5484..3379d0a0c6867 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/eql.ts @@ -191,11 +191,13 @@ export const eqlExecutor = async ({ result.warningMessages.push(maxSignalsWarning); } - scheduleNotificationResponseActionsService({ - signals: result.createdSignals, - signalsCount: result.createdSignalsCount, - responseActions: completeRule.ruleParams.responseActions, - }); + if (scheduleNotificationResponseActionsService) { + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); + } return result; } catch (error) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts index ce9ee8505a963..0dd2b0e50d4ba 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts @@ -226,11 +226,13 @@ export const esqlExecutor = async ({ break; } } - scheduleNotificationResponseActionsService({ - signals: result.createdSignals, - signalsCount: result.createdSignalsCount, - responseActions: completeRule.ruleParams.responseActions, - }); + if (scheduleNotificationResponseActionsService) { + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); + } // no more results will be found if (response.values.length < size) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts index 7815342ed5fdb..e33f580388f98 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts @@ -416,11 +416,13 @@ export const createNewTermsAlertType = ( afterKey = searchResultWithAggs.aggregations.new_terms.after_key; } - scheduleNotificationResponseActionsService({ - signals: result.createdSignals, - signalsCount: result.createdSignalsCount, - responseActions: completeRule.ruleParams.responseActions, - }); + if (scheduleNotificationResponseActionsService) { + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); + } return { ...result, state }; }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts index 4f5155c8401bc..5915447e5a541 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts @@ -99,11 +99,13 @@ export const queryExecutor = async ({ state: {}, }; - scheduleNotificationResponseActionsService({ - signals: result.createdSignals, - signalsCount: result.createdSignalsCount, - responseActions: completeRule.ruleParams.responseActions, - }); + if (scheduleNotificationResponseActionsService) { + scheduleNotificationResponseActionsService({ + signals: result.createdSignals, + signalsCount: result.createdSignalsCount, + responseActions: completeRule.ruleParams.responseActions, + }); + } return result; }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts index 5c1be0bb925ee..a29beef7bbb20 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts @@ -162,11 +162,11 @@ export interface CreateRuleOptions { export interface ScheduleNotificationActions { signals: unknown[]; signalsCount: number; - responseActions: RuleResponseAction[]; + responseActions: RuleResponseAction[] | undefined; } export interface CreateRuleAdditionalOptions { - scheduleNotificationResponseActionsService: (params: ScheduleNotificationActions) => void; + scheduleNotificationResponseActionsService?: (params: ScheduleNotificationActions) => void; } export interface CreateQueryRuleOptions extends CreateRuleOptions, CreateRuleAdditionalOptions { From 87c0c8b5cbea6264eddf8725d2bf987b637cd34d Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Wed, 18 Sep 2024 16:22:28 +0200 Subject: [PATCH 32/34] fix tests --- ...s_upgrade_and_rollback_checks.test.ts.snap | 2343 +++++++---------- .../e2e/automated_response_actions/form.cy.ts | 10 +- 2 files changed, 930 insertions(+), 1423 deletions(-) diff --git a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap index c283cc1087682..4dc2abbc5f6a8 100644 --- a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap +++ b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap @@ -5829,175 +5829,6 @@ Object { }, "type": "array", }, - "responseActions": Object { - "items": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".osquery", - "type": "string", - }, - "params": Object { - "additionalProperties": false, - "properties": Object { - "ecsMapping": Object { - "additionalProperties": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "value": Object { - "anyOf": Array [ - Object { - "type": "string", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - }, - "type": "object", - }, - "properties": Object {}, - "type": "object", - }, - "packId": Object { - "type": "string", - }, - "queries": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs_mapping": Object { - "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", - }, - "id": Object { - "type": "string", - }, - "platform": Object { - "type": "string", - }, - "query": Object { - "type": "string", - }, - "removed": Object { - "type": "boolean", - }, - "snapshot": Object { - "type": "boolean", - }, - "version": Object { - "type": "string", - }, - }, - "required": Array [ - "id", - "query", - ], - "type": "object", - }, - "type": "array", - }, - "query": Object { - "type": "string", - }, - "savedQueryId": Object { - "type": "string", - }, - "timeout": Object { - "type": "number", - }, - }, - "type": "object", - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".endpoint", - "type": "string", - }, - "params": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "const": "isolate", - "type": "string", - }, - "comment": Object { - "type": "string", - }, - }, - "required": Array [ - "command", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "enum": Array [ - "kill-process", - "suspend-process", - ], - "type": "string", - }, - "comment": Object { - "type": "string", - }, - "config": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "overwrite": Object { - "default": true, - "type": "boolean", - }, - }, - "required": Array [ - "field", - ], - "type": "object", - }, - }, - "required": Array [ - "command", - "config", - ], - "type": "object", - }, - ], - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - ], - }, - "type": "array", - }, "riskScore": Object { "maximum": 100, "minimum": 0, @@ -6304,200 +6135,7 @@ Object { "query": Object { "type": "string", }, - "tiebreakerField": Object { - "type": "string", - }, - "timestampField": Object { - "type": "string", - }, - "type": Object { - "const": "eql", - "type": "string", - }, - }, - "required": Array [ - "type", - "language", - "query", - ], - "type": "object", - }, - ], -} -`; - -exports[`Serverless upgrade and rollback checks detect param changes to review for: siem.indicatorRule 1`] = ` -Object { - "$schema": "http://json-schema.org/draft-07/schema#", - "allOf": Array [ - Object { - "properties": Object { - "author": Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - "buildingBlockType": Object { - "type": "string", - }, - "description": Object { - "minLength": 1, - "type": "string", - }, - "exceptionsList": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "id": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "list_id": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "namespace_type": Object { - "enum": Array [ - "agnostic", - "single", - ], - "type": "string", - }, - "type": Object { - "enum": Array [ - "detection", - "rule_default", - "endpoint", - "endpoint_trusted_apps", - "endpoint_events", - "endpoint_host_isolation_exceptions", - "endpoint_blocklists", - ], - "type": "string", - }, - }, - "required": Array [ - "id", - "list_id", - "type", - "namespace_type", - ], - "type": "object", - }, - "type": "array", - }, - "falsePositives": Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - "from": Object { - "type": "string", - }, - "immutable": Object { - "type": "boolean", - }, - "investigationFields": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "field_names": Object { - "items": Object { - "minLength": 1, - "pattern": "^(?! *$).+$", - "type": "string", - }, - "minItems": 1, - "type": "array", - }, - }, - "required": Array [ - "field_names", - ], - "type": "object", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - "license": Object { - "type": "string", - }, - "maxSignals": Object { - "minimum": 1, - "type": "integer", - }, - "meta": Object { - "additionalProperties": Object {}, - "properties": Object {}, - "type": "object", - }, - "namespace": Object { - "type": "string", - }, - "note": Object { - "type": "string", - }, - "outputIndex": Object { - "type": "string", - }, - "references": Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - "relatedIntegrations": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "integration": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "package": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "version": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - }, - "required": Array [ - "package", - "version", - ], - "type": "object", - }, - "type": "array", - }, - "requiredFields": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs": Object { - "type": "boolean", - }, - "name": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "type": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - }, - "required": Array [ - "name", - "type", - "ecs", - ], - "type": "object", - }, - "type": "array", - }, - "responseActions": Object { + "responseActions": Object { "items": Object { "anyOf": Array [ Object { @@ -6544,7 +6182,7 @@ Object { "additionalProperties": false, "properties": Object { "ecs_mapping": Object { - "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + "$ref": "#/allOf/1/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", }, "id": Object { "type": "string", @@ -6666,95 +6304,288 @@ Object { }, "type": "array", }, - "riskScore": Object { - "maximum": 100, - "minimum": 0, - "type": "integer", + "tiebreakerField": Object { + "type": "string", }, - "riskScoreMapping": Object { + "timestampField": Object { + "type": "string", + }, + "type": Object { + "const": "eql", + "type": "string", + }, + }, + "required": Array [ + "type", + "language", + "query", + ], + "type": "object", + }, + ], +} +`; + +exports[`Serverless upgrade and rollback checks detect param changes to review for: siem.indicatorRule 1`] = ` +Object { + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": Array [ + Object { + "properties": Object { + "author": Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + "buildingBlockType": Object { + "type": "string", + }, + "description": Object { + "minLength": 1, + "type": "string", + }, + "exceptionsList": Object { "items": Object { "additionalProperties": false, "properties": Object { - "field": Object { - "type": "string", + "id": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", }, - "operator": Object { - "const": "equals", - "type": "string", + "list_id": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", }, - "risk_score": Object { - "$ref": "#/allOf/0/properties/riskScore", + "namespace_type": Object { + "enum": Array [ + "agnostic", + "single", + ], + "type": "string", }, - "value": Object { + "type": Object { + "enum": Array [ + "detection", + "rule_default", + "endpoint", + "endpoint_trusted_apps", + "endpoint_events", + "endpoint_host_isolation_exceptions", + "endpoint_blocklists", + ], "type": "string", }, }, "required": Array [ - "field", - "operator", - "value", + "id", + "list_id", + "type", + "namespace_type", ], "type": "object", }, "type": "array", }, - "ruleId": Object { - "type": "string", + "falsePositives": Object { + "items": Object { + "type": "string", + }, + "type": "array", }, - "ruleNameOverride": Object { + "from": Object { "type": "string", }, - "ruleSource": Object { + "immutable": Object { + "type": "boolean", + }, + "investigationFields": Object { "anyOf": Array [ Object { "additionalProperties": false, "properties": Object { - "isCustomized": Object { - "type": "boolean", - }, - "type": Object { - "const": "external", - "type": "string", + "field_names": Object { + "items": Object { + "minLength": 1, + "pattern": "^(?! *$).+$", + "type": "string", + }, + "minItems": 1, + "type": "array", }, }, "required": Array [ - "type", - "isCustomized", + "field_names", ], "type": "object", }, Object { - "additionalProperties": false, - "properties": Object { - "type": Object { - "const": "internal", - "type": "string", - }, + "items": Object { + "type": "string", }, - "required": Array [ - "type", - ], - "type": "object", + "type": "array", }, ], }, - "setup": Object { + "license": Object { "type": "string", }, - "severity": Object { - "enum": Array [ - "low", - "medium", - "high", - "critical", - ], + "maxSignals": Object { + "minimum": 1, + "type": "integer", + }, + "meta": Object { + "additionalProperties": Object {}, + "properties": Object {}, + "type": "object", + }, + "namespace": Object { "type": "string", }, - "severityMapping": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { + "note": Object { + "type": "string", + }, + "outputIndex": Object { + "type": "string", + }, + "references": Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + "relatedIntegrations": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "integration": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "package": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "version": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + }, + "required": Array [ + "package", + "version", + ], + "type": "object", + }, + "type": "array", + }, + "requiredFields": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs": Object { + "type": "boolean", + }, + "name": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "type": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + }, + "required": Array [ + "name", + "type", + "ecs", + ], + "type": "object", + }, + "type": "array", + }, + "riskScore": Object { + "maximum": 100, + "minimum": 0, + "type": "integer", + }, + "riskScoreMapping": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "operator": Object { + "const": "equals", + "type": "string", + }, + "risk_score": Object { + "$ref": "#/allOf/0/properties/riskScore", + }, + "value": Object { + "type": "string", + }, + }, + "required": Array [ + "field", + "operator", + "value", + ], + "type": "object", + }, + "type": "array", + }, + "ruleId": Object { + "type": "string", + }, + "ruleNameOverride": Object { + "type": "string", + }, + "ruleSource": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "isCustomized": Object { + "type": "boolean", + }, + "type": Object { + "const": "external", + "type": "string", + }, + }, + "required": Array [ + "type", + "isCustomized", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "type": Object { + "const": "internal", + "type": "string", + }, + }, + "required": Array [ + "type", + ], + "type": "object", + }, + ], + }, + "setup": Object { + "type": "string", + }, + "severity": Object { + "enum": Array [ + "low", + "medium", + "high", + "critical", + ], + "type": "string", + }, + "severityMapping": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { "type": "string", }, "operator": Object { @@ -7228,186 +7059,17 @@ Object { }, "type": "array", }, - "responseActions": Object { + "riskScore": Object { + "maximum": 100, + "minimum": 0, + "type": "integer", + }, + "riskScoreMapping": Object { "items": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".osquery", - "type": "string", - }, - "params": Object { - "additionalProperties": false, - "properties": Object { - "ecsMapping": Object { - "additionalProperties": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "value": Object { - "anyOf": Array [ - Object { - "type": "string", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - }, - "type": "object", - }, - "properties": Object {}, - "type": "object", - }, - "packId": Object { - "type": "string", - }, - "queries": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs_mapping": Object { - "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", - }, - "id": Object { - "type": "string", - }, - "platform": Object { - "type": "string", - }, - "query": Object { - "type": "string", - }, - "removed": Object { - "type": "boolean", - }, - "snapshot": Object { - "type": "boolean", - }, - "version": Object { - "type": "string", - }, - }, - "required": Array [ - "id", - "query", - ], - "type": "object", - }, - "type": "array", - }, - "query": Object { - "type": "string", - }, - "savedQueryId": Object { - "type": "string", - }, - "timeout": Object { - "type": "number", - }, - }, - "type": "object", - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".endpoint", - "type": "string", - }, - "params": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "const": "isolate", - "type": "string", - }, - "comment": Object { - "type": "string", - }, - }, - "required": Array [ - "command", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "enum": Array [ - "kill-process", - "suspend-process", - ], - "type": "string", - }, - "comment": Object { - "type": "string", - }, - "config": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "overwrite": Object { - "default": true, - "type": "boolean", - }, - }, - "required": Array [ - "field", - ], - "type": "object", - }, - }, - "required": Array [ - "command", - "config", - ], - "type": "object", - }, - ], - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - ], - }, - "type": "array", - }, - "riskScore": Object { - "maximum": 100, - "minimum": 0, - "type": "integer", - }, - "riskScoreMapping": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", }, "operator": Object { "const": "equals", @@ -7877,175 +7539,6 @@ Object { }, "type": "array", }, - "responseActions": Object { - "items": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".osquery", - "type": "string", - }, - "params": Object { - "additionalProperties": false, - "properties": Object { - "ecsMapping": Object { - "additionalProperties": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "value": Object { - "anyOf": Array [ - Object { - "type": "string", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - }, - "type": "object", - }, - "properties": Object {}, - "type": "object", - }, - "packId": Object { - "type": "string", - }, - "queries": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs_mapping": Object { - "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", - }, - "id": Object { - "type": "string", - }, - "platform": Object { - "type": "string", - }, - "query": Object { - "type": "string", - }, - "removed": Object { - "type": "boolean", - }, - "snapshot": Object { - "type": "boolean", - }, - "version": Object { - "type": "string", - }, - }, - "required": Array [ - "id", - "query", - ], - "type": "object", - }, - "type": "array", - }, - "query": Object { - "type": "string", - }, - "savedQueryId": Object { - "type": "string", - }, - "timeout": Object { - "type": "number", - }, - }, - "type": "object", - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".endpoint", - "type": "string", - }, - "params": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "const": "isolate", - "type": "string", - }, - "comment": Object { - "type": "string", - }, - }, - "required": Array [ - "command", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "enum": Array [ - "kill-process", - "suspend-process", - ], - "type": "string", - }, - "comment": Object { - "type": "string", - }, - "config": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "overwrite": Object { - "default": true, - "type": "boolean", - }, - }, - "required": Array [ - "field", - ], - "type": "object", - }, - }, - "required": Array [ - "command", - "config", - ], - "type": "object", - }, - ], - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - ], - }, - "type": "array", - }, "riskScore": Object { "maximum": 100, "minimum": 0, @@ -8363,16 +7856,185 @@ Object { "query": Object { "type": "string", }, - "type": Object { - "const": "new_terms", - "type": "string", - }, - }, - "required": Array [ - "type", - "query", - "newTermsFields", - "historyWindowStart", + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/1/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + ], + }, + "type": "array", + }, + "type": Object { + "const": "new_terms", + "type": "string", + }, + }, + "required": Array [ + "type", + "query", + "newTermsFields", + "historyWindowStart", "language", ], "type": "object", @@ -8581,181 +8243,12 @@ Object { }, "type": "array", }, - "responseActions": Object { - "items": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".osquery", - "type": "string", - }, - "params": Object { - "additionalProperties": false, - "properties": Object { - "ecsMapping": Object { - "additionalProperties": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "value": Object { - "anyOf": Array [ - Object { - "type": "string", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - }, - "type": "object", - }, - "properties": Object {}, - "type": "object", - }, - "packId": Object { - "type": "string", - }, - "queries": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs_mapping": Object { - "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", - }, - "id": Object { - "type": "string", - }, - "platform": Object { - "type": "string", - }, - "query": Object { - "type": "string", - }, - "removed": Object { - "type": "boolean", - }, - "snapshot": Object { - "type": "boolean", - }, - "version": Object { - "type": "string", - }, - }, - "required": Array [ - "id", - "query", - ], - "type": "object", - }, - "type": "array", - }, - "query": Object { - "type": "string", - }, - "savedQueryId": Object { - "type": "string", - }, - "timeout": Object { - "type": "number", - }, - }, - "type": "object", - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".endpoint", - "type": "string", - }, - "params": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "const": "isolate", - "type": "string", - }, - "comment": Object { - "type": "string", - }, - }, - "required": Array [ - "command", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "enum": Array [ - "kill-process", - "suspend-process", - ], - "type": "string", - }, - "comment": Object { - "type": "string", - }, - "config": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "overwrite": Object { - "default": true, - "type": "boolean", - }, - }, - "required": Array [ - "field", - ], - "type": "object", - }, - }, - "required": Array [ - "command", - "config", - ], - "type": "object", - }, - ], - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - ], - }, - "type": "array", - }, - "riskScore": Object { - "maximum": 100, - "minimum": 0, - "type": "integer", - }, - "riskScoreMapping": Object { + "riskScore": Object { + "maximum": 100, + "minimum": 0, + "type": "integer", + }, + "riskScoreMapping": Object { "items": Object { "additionalProperties": false, "properties": Object { @@ -9059,6 +8552,175 @@ Object { "query": Object { "type": "string", }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/1/anyOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + ], + }, + "type": "array", + }, "savedId": Object { "type": "string", }, @@ -9095,6 +8757,12 @@ Object { "query": Object { "$ref": "#/allOf/1/anyOf/0/properties/query", }, + "responseActions": Object { + "items": Object { + "$ref": "#/allOf/1/anyOf/0/properties/responseActions/items", + }, + "type": "array", + }, "savedId": Object { "$ref": "#/allOf/1/anyOf/0/properties/savedId", }, @@ -9193,266 +8861,97 @@ Object { "additionalProperties": false, "properties": Object { "field_names": Object { - "items": Object { - "minLength": 1, - "pattern": "^(?! *$).+$", - "type": "string", - }, - "minItems": 1, - "type": "array", - }, - }, - "required": Array [ - "field_names", - ], - "type": "object", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - "license": Object { - "type": "string", - }, - "maxSignals": Object { - "minimum": 1, - "type": "integer", - }, - "meta": Object { - "additionalProperties": Object {}, - "properties": Object {}, - "type": "object", - }, - "namespace": Object { - "type": "string", - }, - "note": Object { - "type": "string", - }, - "outputIndex": Object { - "type": "string", - }, - "references": Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - "relatedIntegrations": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "integration": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "package": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "version": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - }, - "required": Array [ - "package", - "version", - ], - "type": "object", - }, - "type": "array", - }, - "requiredFields": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs": Object { - "type": "boolean", - }, - "name": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - "type": Object { - "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", - }, - }, - "required": Array [ - "name", - "type", - "ecs", - ], - "type": "object", - }, - "type": "array", - }, - "responseActions": Object { - "items": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".osquery", - "type": "string", - }, - "params": Object { - "additionalProperties": false, - "properties": Object { - "ecsMapping": Object { - "additionalProperties": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "value": Object { - "anyOf": Array [ - Object { - "type": "string", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - }, - "type": "object", - }, - "properties": Object {}, - "type": "object", - }, - "packId": Object { - "type": "string", - }, - "queries": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs_mapping": Object { - "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", - }, - "id": Object { - "type": "string", - }, - "platform": Object { - "type": "string", - }, - "query": Object { - "type": "string", - }, - "removed": Object { - "type": "boolean", - }, - "snapshot": Object { - "type": "boolean", - }, - "version": Object { - "type": "string", - }, - }, - "required": Array [ - "id", - "query", - ], - "type": "object", - }, - "type": "array", - }, - "query": Object { - "type": "string", - }, - "savedQueryId": Object { - "type": "string", - }, - "timeout": Object { - "type": "number", - }, - }, - "type": "object", - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".endpoint", + "items": Object { + "minLength": 1, + "pattern": "^(?! *$).+$", "type": "string", }, - "params": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "const": "isolate", - "type": "string", - }, - "comment": Object { - "type": "string", - }, - }, - "required": Array [ - "command", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "enum": Array [ - "kill-process", - "suspend-process", - ], - "type": "string", - }, - "comment": Object { - "type": "string", - }, - "config": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "overwrite": Object { - "default": true, - "type": "boolean", - }, - }, - "required": Array [ - "field", - ], - "type": "object", - }, - }, - "required": Array [ - "command", - "config", - ], - "type": "object", - }, - ], - }, + "minItems": 1, + "type": "array", }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", }, + "required": Array [ + "field_names", + ], + "type": "object", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + "license": Object { + "type": "string", + }, + "maxSignals": Object { + "minimum": 1, + "type": "integer", + }, + "meta": Object { + "additionalProperties": Object {}, + "properties": Object {}, + "type": "object", + }, + "namespace": Object { + "type": "string", + }, + "note": Object { + "type": "string", + }, + "outputIndex": Object { + "type": "string", + }, + "references": Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + "relatedIntegrations": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "integration": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "package": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "version": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + }, + "required": Array [ + "package", + "version", + ], + "type": "object", + }, + "type": "array", + }, + "requiredFields": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs": Object { + "type": "boolean", + }, + "name": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + "type": Object { + "$ref": "#/allOf/0/properties/investigationFields/anyOf/0/properties/field_names/items", + }, + }, + "required": Array [ + "name", + "type", + "ecs", ], + "type": "object", }, "type": "array", }, @@ -9715,56 +9214,225 @@ Object { "type": "integer", }, }, - "required": Array [ - "value", - "unit", - ], - "type": "object", - }, - "groupBy": Object { - "items": Object { - "type": "string", - }, - "maxItems": 3, - "minItems": 1, - "type": "array", - }, - "missingFieldsStrategy": Object { - "enum": Array [ - "doNotSuppress", - "suppress", - ], - "type": "string", - }, - }, - "required": Array [ - "groupBy", - ], - "type": "object", - }, - "dataViewId": Object { - "type": "string", - }, - "filters": Object { - "items": Object {}, - "type": "array", - }, - "index": Object { - "items": Object { - "type": "string", + "required": Array [ + "value", + "unit", + ], + "type": "object", + }, + "groupBy": Object { + "items": Object { + "type": "string", + }, + "maxItems": 3, + "minItems": 1, + "type": "array", + }, + "missingFieldsStrategy": Object { + "enum": Array [ + "doNotSuppress", + "suppress", + ], + "type": "string", + }, + }, + "required": Array [ + "groupBy", + ], + "type": "object", + }, + "dataViewId": Object { + "type": "string", + }, + "filters": Object { + "items": Object {}, + "type": "array", + }, + "index": Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + "language": Object { + "enum": Array [ + "kuery", + "lucene", + ], + "type": "string", + }, + "query": Object { + "type": "string", + }, + "responseActions": Object { + "items": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".osquery", + "type": "string", + }, + "params": Object { + "additionalProperties": false, + "properties": Object { + "ecsMapping": Object { + "additionalProperties": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "value": Object { + "anyOf": Array [ + Object { + "type": "string", + }, + Object { + "items": Object { + "type": "string", + }, + "type": "array", + }, + ], + }, + }, + "type": "object", + }, + "properties": Object {}, + "type": "object", + }, + "packId": Object { + "type": "string", + }, + "queries": Object { + "items": Object { + "additionalProperties": false, + "properties": Object { + "ecs_mapping": Object { + "$ref": "#/allOf/1/anyOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", + }, + "id": Object { + "type": "string", + }, + "platform": Object { + "type": "string", + }, + "query": Object { + "type": "string", + }, + "removed": Object { + "type": "boolean", + }, + "snapshot": Object { + "type": "boolean", + }, + "version": Object { + "type": "string", + }, + }, + "required": Array [ + "id", + "query", + ], + "type": "object", + }, + "type": "array", + }, + "query": Object { + "type": "string", + }, + "savedQueryId": Object { + "type": "string", + }, + "timeout": Object { + "type": "number", + }, + }, + "type": "object", + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "actionTypeId": Object { + "const": ".endpoint", + "type": "string", + }, + "params": Object { + "anyOf": Array [ + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "const": "isolate", + "type": "string", + }, + "comment": Object { + "type": "string", + }, + }, + "required": Array [ + "command", + ], + "type": "object", + }, + Object { + "additionalProperties": false, + "properties": Object { + "command": Object { + "enum": Array [ + "kill-process", + "suspend-process", + ], + "type": "string", + }, + "comment": Object { + "type": "string", + }, + "config": Object { + "additionalProperties": false, + "properties": Object { + "field": Object { + "type": "string", + }, + "overwrite": Object { + "default": true, + "type": "boolean", + }, + }, + "required": Array [ + "field", + ], + "type": "object", + }, + }, + "required": Array [ + "command", + "config", + ], + "type": "object", + }, + ], + }, + }, + "required": Array [ + "actionTypeId", + "params", + ], + "type": "object", + }, + ], }, "type": "array", }, - "language": Object { - "enum": Array [ - "kuery", - "lucene", - ], - "type": "string", - }, - "query": Object { - "type": "string", - }, "savedId": Object { "type": "string", }, @@ -9801,6 +9469,12 @@ Object { "query": Object { "$ref": "#/allOf/1/anyOf/0/properties/query", }, + "responseActions": Object { + "items": Object { + "$ref": "#/allOf/1/anyOf/0/properties/responseActions/items", + }, + "type": "array", + }, "savedId": Object { "$ref": "#/allOf/1/anyOf/0/properties/savedId", }, @@ -9993,175 +9667,6 @@ Object { }, "type": "array", }, - "responseActions": Object { - "items": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".osquery", - "type": "string", - }, - "params": Object { - "additionalProperties": false, - "properties": Object { - "ecsMapping": Object { - "additionalProperties": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "value": Object { - "anyOf": Array [ - Object { - "type": "string", - }, - Object { - "items": Object { - "type": "string", - }, - "type": "array", - }, - ], - }, - }, - "type": "object", - }, - "properties": Object {}, - "type": "object", - }, - "packId": Object { - "type": "string", - }, - "queries": Object { - "items": Object { - "additionalProperties": false, - "properties": Object { - "ecs_mapping": Object { - "$ref": "#/allOf/0/properties/responseActions/items/anyOf/0/properties/params/properties/ecsMapping", - }, - "id": Object { - "type": "string", - }, - "platform": Object { - "type": "string", - }, - "query": Object { - "type": "string", - }, - "removed": Object { - "type": "boolean", - }, - "snapshot": Object { - "type": "boolean", - }, - "version": Object { - "type": "string", - }, - }, - "required": Array [ - "id", - "query", - ], - "type": "object", - }, - "type": "array", - }, - "query": Object { - "type": "string", - }, - "savedQueryId": Object { - "type": "string", - }, - "timeout": Object { - "type": "number", - }, - }, - "type": "object", - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "actionTypeId": Object { - "const": ".endpoint", - "type": "string", - }, - "params": Object { - "anyOf": Array [ - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "const": "isolate", - "type": "string", - }, - "comment": Object { - "type": "string", - }, - }, - "required": Array [ - "command", - ], - "type": "object", - }, - Object { - "additionalProperties": false, - "properties": Object { - "command": Object { - "enum": Array [ - "kill-process", - "suspend-process", - ], - "type": "string", - }, - "comment": Object { - "type": "string", - }, - "config": Object { - "additionalProperties": false, - "properties": Object { - "field": Object { - "type": "string", - }, - "overwrite": Object { - "default": true, - "type": "boolean", - }, - }, - "required": Array [ - "field", - ], - "type": "object", - }, - }, - "required": Array [ - "command", - "config", - ], - "type": "object", - }, - ], - }, - }, - "required": Array [ - "actionTypeId", - "params", - ], - "type": "object", - }, - ], - }, - "type": "array", - }, "riskScore": Object { "maximum": 100, "minimum": 0, diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index d984f4052a979..dc3691595e4ab 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -1,8 +1,10 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import { @@ -213,7 +215,7 @@ describe( }); it('create and save endpoint response action inside of a rule', () => { - const query = 'FROM * METADATA _index, _id {backspace}{enter}'; + const query = 'FROM * METADATA _index, _id'; fillUpNewEsqlRule(ruleName, ruleDescription, query); addEndpointResponseAction(); focusAndOpenCommandDropdown(); From 2b7c7f4fde4d7b8c045390dfa71224a43f8f052e Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Wed, 18 Sep 2024 16:44:35 +0200 Subject: [PATCH 33/34] fix license header again --- .../cypress/e2e/automated_response_actions/form.cy.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts index dc3691595e4ab..4b1b8e728e8c2 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts @@ -1,10 +1,8 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import { From ade46fd863719f9ed0d59b6703bc2987ac2d9aa1 Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Wed, 18 Sep 2024 16:46:17 +0200 Subject: [PATCH 34/34] remove redundant spaces --- .../model/rule_schema/rule_schemas.schema.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml index 3ba9cfba39154..ca2f325c8f713 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: title: Security Rule Schema version: 'not applicable' -paths: { } +paths: {} components: x-codegen-enabled: true schemas: @@ -262,7 +262,7 @@ components: properties: type: type: string - enum: [ eql ] + enum: [eql] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -342,7 +342,7 @@ components: properties: type: type: string - enum: [ query ] + enum: [query] description: Rule type required: - type @@ -422,7 +422,7 @@ components: properties: type: type: string - enum: [ saved_query ] + enum: [saved_query] description: Rule type saved_id: $ref: './common_attributes.schema.yaml#/components/schemas/SavedQueryId' @@ -503,7 +503,7 @@ components: properties: type: type: string - enum: [ threshold ] + enum: [threshold] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -583,7 +583,7 @@ components: properties: type: type: string - enum: [ threat_match ] + enum: [threat_match] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -679,7 +679,7 @@ components: properties: type: type: string - enum: [ machine_learning ] + enum: [machine_learning] description: Rule type anomaly_threshold: $ref: './specific_attributes/ml_attributes.schema.yaml#/components/schemas/AnomalyThreshold' @@ -741,7 +741,7 @@ components: properties: type: type: string - enum: [ new_terms ] + enum: [new_terms] description: Rule type query: $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' @@ -831,7 +831,7 @@ components: properties: type: type: string - enum: [ esql ] + enum: [esql] description: Rule type language: $ref: '#/components/schemas/EsqlQueryLanguage'