[ResponseOps][Security][Rules] Fix fields missing from Cases action in Security Solution rule form (#210547)

## Summary

Correctly forwards the selected rule type id to the actions form section
in the Security Solution rule creation/update flow.
Adds a functional test case to cover the bug.

## To verify

1. Navigate to `Security > Rules > Detection rules > Create new rule`
2. Fill in the first 3 steps
3. In the Actions step, select the Cases action
4. Check that the `Group by alert field` dropdown shows the correct
alert fields
5. Create the rule, then repeat point 5 in the rule editing UI

## References

Fixes #210209
This commit is contained in:
Umberto Pepato 2025-02-20 18:36:39 +01:00 committed by GitHub
parent 606022c12c
commit 0abbd173b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 51 additions and 4 deletions

View file

@ -78,6 +78,7 @@ const NOTIFY_WHEN_OPTIONS: NotifyWhenSelectOptions[] = [
];
interface Props {
ruleTypeId?: string;
field: FieldHook;
messageVariables: ActionVariables;
summaryMessageVariables: ActionVariables;
@ -113,6 +114,7 @@ const ContainerActions = styled.div.attrs(
`;
export const RuleActionsField: React.FC<Props> = ({
ruleTypeId,
field,
messageVariables,
summaryMessageVariables,
@ -246,6 +248,7 @@ export const RuleActionsField: React.FC<Props> = ({
setActionAlertsFilterProperty,
featureId: SecurityConnectorFeatureId,
producerId: AlertConsumers.SIEM,
ruleTypeId,
defaultActionMessage: FORM_FOR_EACH_ALERT_BODY_MESSAGE,
defaultSummaryMessage: FORM_SUMMARY_BODY_MESSAGE,
hideActionHeader: true,
@ -255,15 +258,16 @@ export const RuleActionsField: React.FC<Props> = ({
disableErrorMessages: !isFormValidated,
}),
[
actions,
getActionForm,
actions,
messageVariables,
summaryMessageVariables,
setActionFrequency,
setActionIdByIndex,
setActionParamsProperty,
setAlertActionsProperty,
setActionParamsProperty,
setActionFrequency,
setActionAlertsFilterProperty,
ruleTypeId,
isFormValidated,
]
);

View file

@ -35,6 +35,7 @@ import { ResponseAction } from './response_action';
interface StepRuleActionsProps extends RuleStepProps {
ruleId?: RuleObjectId; // Rule SO's id (not ruleId)
ruleTypeId?: string;
actionMessageParams: ActionVariables;
summaryActionMessageParams: ActionVariables;
form: FormHook<ActionsStepRule>;
@ -72,6 +73,7 @@ const DisplayActionsHeader = () => {
const StepRuleActionsComponent: FC<StepRuleActionsProps> = ({
ruleId,
ruleTypeId,
isUpdateView = false,
actionMessageParams,
summaryActionMessageParams,
@ -90,11 +92,12 @@ const StepRuleActionsComponent: FC<StepRuleActionsProps> = ({
componentProps={{
messageVariables: actionMessageParams,
summaryMessageVariables: summaryActionMessageParams,
ruleTypeId,
}}
/>
</>
),
[actionMessageParams, summaryActionMessageParams]
[actionMessageParams, ruleTypeId, summaryActionMessageParams]
);
const displayResponseActionsOptions = useMemo(() => {
return (

View file

@ -19,6 +19,7 @@ import {
import React, { memo, useCallback, useRef, useState, useMemo, useEffect } from 'react';
import styled from 'styled-components';
import { ruleTypeMappings } from '@kbn/securitysolution-rules';
import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
import {
isMlRule,
@ -731,6 +732,7 @@ const CreateRulePageComponent: React.FC = () => {
}}
>
<StepRuleActions
ruleTypeId={ruleTypeMappings[ruleType]}
isLoading={isCreateRuleLoading || loading || isStartingJobs}
actionMessageParams={actionMessageParams}
summaryActionMessageParams={actionMessageParams}
@ -785,6 +787,7 @@ const CreateRulePageComponent: React.FC = () => {
isCreateRuleLoading,
isStartingJobs,
loading,
ruleType,
submitRuleDisabled,
submitRuleEnabled,
]

View file

@ -22,6 +22,7 @@ import type { FC } from 'react';
import React, { memo, useCallback, useMemo, useRef, useState } from 'react';
import { useParams } from 'react-router-dom';
import { ruleTypeMappings } from '@kbn/securitysolution-rules';
import { useConfirmValidationErrorsModal } from '../../../../common/hooks/use_confirm_validation_errors_modal';
import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
import { isEsqlRule } from '../../../../../common/detection_engine/utils';
@ -338,6 +339,7 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => {
{actionsStepData != null && (
<StepRuleActions
ruleId={rule?.id}
ruleTypeId={ruleTypeMappings[rule?.type]}
isLoading={isLoading}
isUpdateView
actionMessageParams={actionMessageParams}
@ -372,6 +374,7 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => {
esqlQueryForAboutStep,
rule.rule_source,
rule?.id,
rule?.type,
scheduleStepData,
scheduleStepForm,
actionsStepData,

View file

@ -5,6 +5,10 @@
* 2.0.
*/
import {
CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_OPTIONS_LIST,
CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_SELECTOR,
} from '../../../../screens/common/rule_actions';
import { RULE_NAME_HEADER } from '../../../../screens/rule_details';
import { getIndexConnector } from '../../../../objects/connector';
import { getSimpleCustomQueryRule } from '../../../../objects/rule';
@ -21,6 +25,7 @@ import {
} from '../../../../tasks/api_calls/common';
import {
createAndEnableRule,
createCasesAction,
fillAboutRuleAndContinue,
fillDefineCustomRuleAndContinue,
fillRuleAction,
@ -106,5 +111,23 @@ describe(
// UI redirects to rule creation page of a created rule
cy.get(RULE_NAME_HEADER).should('contain', rule.name);
});
it('Forwards the correct rule type id to the Cases system action', () => {
visit(CREATE_RULE_URL);
fillDefineCustomRuleAndContinue(rule);
fillAboutRuleAndContinue(rule);
fillScheduleRuleAndContinue(rule);
createCasesAction();
cy.get(CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_SELECTOR).click();
cy.get(CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_OPTIONS_LIST).should('be.visible');
cy.waitUntil(() => {
return cy
.get(`${CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_OPTIONS_LIST} button[role=option]`)
.then(($items) => {
return $items.length > 0;
});
});
});
}
);

View file

@ -48,6 +48,12 @@ export const EMAIL_CONNECTOR_PASSWORD_INPUT = '[data-test-subj="emailPasswordInp
export const EMAIL_CONNECTOR_SERVICE_SELECTOR = '[data-test-subj="emailServiceSelectInput"]';
export const CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_SELECTOR =
'[data-test-subj=group-by-alert-field-combobox]';
export const CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_OPTIONS_LIST =
'[data-test-subj~=group-by-alert-field-combobox-optionsList]';
export const FORM_VALIDATION_ERROR = '.euiFormErrorText';
export const JSON_EDITOR = "[data-test-subj='documentToIndex']";

View file

@ -147,6 +147,7 @@ import {
ACTIONS_ALERTS_TIMEFRAME_START_INPUT,
ACTIONS_ALERTS_TIMEFRAME_END_INPUT,
ACTIONS_ALERTS_TIMEFRAME_TIMEZONE_INPUT,
CASES_SYSTEM_ACTION_BTN,
} from '../screens/common/rule_actions';
import { fillIndexConnectorForm, fillEmailConnectorForm } from './common/rule_actions';
import { TOAST_ERROR } from '../screens/shared';
@ -540,6 +541,10 @@ export const fillRuleAction = (actions: Actions) => {
});
};
export const createCasesAction = () => {
cy.get(CASES_SYSTEM_ACTION_BTN).click();
};
export const fillRuleActionFilters = (alertsFilter: AlertsFilter) => {
cy.get(ACTIONS_ALERTS_QUERY_FILTER_BUTTON).click();
cy.get(ACTIONS_ALERTS_QUERY_FILTER_INPUT()).type(alertsFilter.query.kql);