Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RAM][SECURITYSOLUTION][ALERTS] - Integrate per-action frequency UI in security solution #154637

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import type { RuleActionArray } from '@kbn/securitysolution-io-ts-alerting-types';
import { ROLES } from '../../../common/test';

import {
Expand All @@ -15,11 +16,14 @@ import {
import { actionFormSelector } from '../../screens/common/rule_actions';

import { cleanKibana, deleteAlertsAndRules, deleteConnectors } from '../../tasks/common';
import type { RuleActionFrequency } from '../../tasks/common/rule_actions';
import {
addSlackRuleAction,
assertSlackRuleAction,
addEmailConnectorAndRuleAction,
assertEmailRuleAction,
assertSelectedActionFrequency,
pickActionFrequency,
} from '../../tasks/common/rule_actions';
import {
waitForRulesTableToBeLoaded,
Expand All @@ -32,10 +36,8 @@ import {
submitBulkEditForm,
checkOverwriteRuleActionsCheckbox,
openBulkEditRuleActionsForm,
pickActionFrequency,
openBulkActionsMenu,
} from '../../tasks/rules_bulk_edit';
import { assertSelectedActionFrequency } from '../../tasks/edit_rule';
import { login, visitWithoutDateRange } from '../../tasks/login';
import { esArchiverResetKibana } from '../../tasks/es_archiver';

Expand Down Expand Up @@ -75,14 +77,19 @@ describe.skip('Detection rules, bulk edit of rule actions', () => {
esArchiverResetKibana();

createSlackConnector().then(({ body }) => {
const actions = [
const actions: RuleActionArray = [
{
id: body.id,
action_type_id: '.slack',
group: 'default',
params: {
message: expectedExistingSlackMessage,
},
frequency: {
summary: true,
throttle: null,
notifyWhen: 'onActiveAlert',
},
},
];

Expand Down Expand Up @@ -120,7 +127,11 @@ describe.skip('Detection rules, bulk edit of rule actions', () => {
});

it('Add a rule action to rules (existing connector)', () => {
const expectedActionFrequency = 'Daily';
const expectedActionFrequency: RuleActionFrequency = {
customFrequency: 'Custom frequency',
throttle: 1,
throttleUnit: 'd',
};

loadPrebuiltDetectionRulesFromHeaderBtn();

Expand All @@ -131,33 +142,35 @@ describe.skip('Detection rules, bulk edit of rule actions', () => {
// ensure rule actions info callout displayed on the form
cy.get(RULES_BULK_EDIT_ACTIONS_INFO).should('be.visible');

pickActionFrequency(expectedActionFrequency);
addSlackRuleAction(expectedSlackMessage);
pickActionFrequency(expectedActionFrequency);

submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfRulesToBeEdited });

// check if rule has been updated
goToEditRuleActionsSettingsOf(ruleNameToAssert);

assertSelectedActionFrequency(expectedActionFrequency);
assertSelectedActionFrequency(expectedActionFrequency, 1);
assertSlackRuleAction(expectedExistingSlackMessage, 0);
assertSlackRuleAction(expectedSlackMessage, 1);
// ensure there is no third action
cy.get(actionFormSelector(2)).should('not.exist');
});

it('Overwrite rule actions in rules', () => {
const expectedActionFrequency = 'On each rule execution';
const expectedActionFrequency: RuleActionFrequency = {
customFrequency: 'Per rule run',
};

loadPrebuiltDetectionRulesFromHeaderBtn();

// select both custom and prebuilt rules
selectNumberOfRules(expectedNumberOfRulesToBeEdited);
openBulkEditRuleActionsForm();

pickActionFrequency(expectedActionFrequency);
addSlackRuleAction(expectedSlackMessage);
pickActionFrequency(expectedActionFrequency);

// check overwrite box, ensure warning is displayed
checkOverwriteRuleActionsCheckbox();
Expand All @@ -178,23 +191,27 @@ describe.skip('Detection rules, bulk edit of rule actions', () => {
});

it('Add a rule action to rules (new connector)', () => {
const expectedActionFrequency = 'Hourly';
const expectedActionFrequency: RuleActionFrequency = {
customFrequency: 'Custom frequency',
throttle: 2,
throttleUnit: 'h',
};
const expectedEmail = '[email protected]';
const expectedSubject = 'Subject';

selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
openBulkEditRuleActionsForm();

pickActionFrequency(expectedActionFrequency);
addEmailConnectorAndRuleAction(expectedEmail, expectedSubject);
pickActionFrequency(expectedActionFrequency);

submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });

// check if rule has been updated
goToEditRuleActionsSettingsOf(ruleNameToAssert);

assertSelectedActionFrequency(expectedActionFrequency);
assertSelectedActionFrequency(expectedActionFrequency, 1);
assertEmailRuleAction(expectedEmail, expectedSubject);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ import {
RULE_SWITCH,
SEVERITY,
} from '../../screens/alerts_detection_rules';
import {
ACTIONS_NOTIFY_WHEN_BUTTON,
ACTIONS_SUMMARY_BUTTON,
} from '../../screens/common/rule_actions';
import {
ABOUT_CONTINUE_BTN,
ABOUT_EDIT_BUTTON,
ACTIONS_THROTTLE_INPUT,
CUSTOM_QUERY_INPUT,
DEFINE_CONTINUE_BUTTON,
DEFINE_EDIT_BUTTON,
Expand Down Expand Up @@ -401,12 +404,11 @@ describe('Custom query rules', () => {

goToActionsStepTab();

cy.get(ACTIONS_THROTTLE_INPUT).invoke('val').should('eql', 'no_actions');

cy.get(ACTIONS_THROTTLE_INPUT).select('Weekly');

addEmailConnectorAndRuleAction('[email protected]', 'Subject');

cy.get(ACTIONS_SUMMARY_BUTTON).should('have.text', 'Summary of alerts');
cy.get(ACTIONS_NOTIFY_WHEN_BUTTON).should('have.text', 'Per rule run');

goToAboutStepTab();
cy.get(TAGS_CLEAR_BUTTON).click({ force: true });
fillAboutRule(getEditedRule());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('Rule actions during detection rule creation', () => {
});

const rule = getSimpleCustomQueryRule();
const actions = { throttle: 'rule', connectors: [indexConnector] };
const actions = { connectors: [indexConnector] };
const index = actions.connectors[0].index;
const initialNumberOfDocuments = 0;
const expectedJson = JSON.parse(actions.connectors[0].document);
Expand Down
3 changes: 0 additions & 3 deletions x-pack/plugins/security_solution/cypress/objects/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,10 @@
* 2.0.
*/

import type { RuleActionThrottle } from '@kbn/securitysolution-io-ts-alerting-types';

import type { Connectors } from './connector';

export type CreateRulePropsRewrites<CreateRuleProps> = Partial<Exclude<CreateRuleProps, 'type'>>;

export interface Actions {
throttle: RuleActionThrottle;
connectors: Connectors[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,20 @@ export const INDEX_SELECTOR = "[data-test-subj='.index-siem-ActionTypeSelectOpti

export const actionFormSelector = (position: number) =>
`[data-test-subj="alertActionAccordion-${position}"]`;

export const ACTIONS_SUMMARY_BUTTON = '[data-test-subj="summaryOrPerRuleSelect"]';

export const ACTIONS_NOTIFY_WHEN_BUTTON = '[data-test-subj="notifyWhenSelect"]';

export const ACTIONS_NOTIFY_PER_RULE_RUN_BUTTON = '[data-test-subj="onActiveAlert"]';

export const ACTIONS_NOTIFY_CUSTOM_FREQUENCY_BUTTON = '[data-test-subj="onThrottleInterval"]';

export const ACTIONS_THROTTLE_INPUT = '[data-test-subj="throttleInput"]';

export const ACTIONS_THROTTLE_UNIT_INPUT = '[data-test-subj="throttleUnitInput"]';

export const ACTIONS_SUMMARY_ALERT_BUTTON = '[data-test-subj="actionNotifyWhen-option-summary"]';

export const ACTIONS_SUMMARY_FOR_EACH_ALERT_BUTTON =
'[data-test-subj="actionNotifyWhen-option-for_each"]';
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ export const ABOUT_EDIT_TAB = '[data-test-subj="edit-rule-about-tab"]';

export const ACTIONS_EDIT_TAB = '[data-test-subj="edit-rule-actions-tab"]';

export const ACTIONS_THROTTLE_INPUT =
'[data-test-subj="stepRuleActions"] [data-test-subj="select"]';

export const ADD_FALSE_POSITIVE_BTN =
'[data-test-subj="detectionEngineStepAboutRuleFalsePositives"] .euiButtonEmpty__text';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ export const UPDATE_SCHEDULE_LOOKBACK_INPUT =

export const UPDATE_SCHEDULE_TIME_UNIT_SELECT = '[data-test-subj="timeType"]';

export const RULES_BULK_EDIT_ACTIONS_THROTTLE_INPUT =
'[data-test-subj="bulkEditRulesRuleActionThrottle"] [data-test-subj="select"]';

export const RULES_BULK_EDIT_ACTIONS_INFO = '[data-test-subj="bulkEditRulesRuleActionInfo"]';

export const RULES_BULK_EDIT_ACTIONS_WARNING = '[data-test-subj="bulkEditRulesRuleActionsWarning"]';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ import {
EMAIL_CONNECTOR_PASSWORD_INPUT,
FORM_VALIDATION_ERROR,
JSON_EDITOR,
ACTIONS_SUMMARY_BUTTON,
ACTIONS_NOTIFY_WHEN_BUTTON,
ACTIONS_THROTTLE_INPUT,
ACTIONS_THROTTLE_UNIT_INPUT,
ACTIONS_SUMMARY_ALERT_BUTTON,
ACTIONS_SUMMARY_FOR_EACH_ALERT_BUTTON,
ACTIONS_NOTIFY_CUSTOM_FREQUENCY_BUTTON,
actionFormSelector,
} from '../../screens/common/rule_actions';
import { COMBO_BOX_INPUT, COMBO_BOX_SELECTION } from '../../screens/common/controls';
import type { EmailConnector, IndexConnector } from '../../objects/connector';
Expand Down Expand Up @@ -84,3 +92,60 @@ export const fillIndexConnectorForm = (connector: IndexConnector = getIndexConne
parseSpecialCharSequences: false,
});
};

export interface RuleActionFrequency {
summary?: 'Summary of alerts' | 'For each alert';
customFrequency?: 'Per rule run' | 'Custom frequency';
throttle?: number;
throttleUnit?: 's' | 'm' | 'h' | 'd';
}

export const pickActionFrequency = (
{
summary = 'Summary of alerts',
customFrequency = 'Per rule run',
throttle = 1,
throttleUnit = 'h',
}: RuleActionFrequency,
index = 0
) => {
const form = cy.get(actionFormSelector(index));
form.within(() => {
cy.get(ACTIONS_SUMMARY_BUTTON).click();
});
if (summary === 'Summary of alerts') {
cy.get(ACTIONS_SUMMARY_ALERT_BUTTON).click();
} else {
cy.get(ACTIONS_SUMMARY_FOR_EACH_ALERT_BUTTON).click();
}
if (customFrequency === 'Custom frequency') {
form.within(() => {
cy.get(ACTIONS_NOTIFY_WHEN_BUTTON).click();
});
cy.get(ACTIONS_NOTIFY_CUSTOM_FREQUENCY_BUTTON).click();
form.within(() => {
cy.get(ACTIONS_THROTTLE_INPUT).type(`{selectAll}${throttle}`);
cy.get(ACTIONS_THROTTLE_UNIT_INPUT).select(throttleUnit);
});
}
};

export const assertSelectedActionFrequency = (
{
summary = 'Summary of alerts',
customFrequency = 'Per rule run',
throttle = 1,
throttleUnit = 'h',
}: RuleActionFrequency,
index = 0
) => {
const form = cy.get(actionFormSelector(index));
form.within(() => {
cy.get(ACTIONS_SUMMARY_BUTTON).should('have.text', summary);
cy.get(ACTIONS_NOTIFY_WHEN_BUTTON).should('have.text', customFrequency);
if (customFrequency === 'Custom frequency') {
cy.get(ACTIONS_THROTTLE_INPUT).should('have.value', throttle);
cy.get(ACTIONS_THROTTLE_UNIT_INPUT).should('have.value', throttleUnit);
}
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ import {
NEW_TERMS_HISTORY_SIZE,
NEW_TERMS_HISTORY_TIME_TYPE,
NEW_TERMS_INPUT_AREA,
ACTIONS_THROTTLE_INPUT,
CONTINUE_BUTTON,
CREATE_WITHOUT_ENABLING_BTN,
RULE_INDICES,
Expand Down Expand Up @@ -407,7 +406,6 @@ export const fillFrom = (from: RuleIntervalFrom = ruleFields.ruleIntervalFrom) =
};

export const fillRuleAction = (actions: Actions) => {
cy.get(ACTIONS_THROTTLE_INPUT).select(actions.throttle);
actions.connectors.forEach((connector) => {
switch (connector.type) {
case 'index':
Expand Down
5 changes: 0 additions & 5 deletions x-pack/plugins/security_solution/cypress/tasks/edit_rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/

import { BACK_TO_RULE_DETAILS, EDIT_SUBMIT_BUTTON } from '../screens/edit_rule';
import { ACTIONS_THROTTLE_INPUT } from '../screens/create_new_rule';

export const saveEditedRule = () => {
cy.get(EDIT_SUBMIT_BUTTON).should('exist').click({ force: true });
Expand All @@ -17,7 +16,3 @@ export const goBackToRuleDetails = () => {
cy.get(BACK_TO_RULE_DETAILS).should('exist').click();
cy.get(BACK_TO_RULE_DETAILS).should('not.exist');
};

export const assertSelectedActionFrequency = (frequency: string) => {
cy.get(ACTIONS_THROTTLE_INPUT).find('option:selected').should('have.text', frequency);
};
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import {
UPDATE_SCHEDULE_LOOKBACK_INPUT,
RULES_BULK_EDIT_SCHEDULES_WARNING,
RULES_BULK_EDIT_OVERWRITE_ACTIONS_CHECKBOX,
RULES_BULK_EDIT_ACTIONS_THROTTLE_INPUT,
} from '../screens/rules_bulk_edit';
import { SCHEDULE_DETAILS } from '../screens/rule_details';

Expand Down Expand Up @@ -292,7 +291,3 @@ export const assertRuleScheduleValues = ({ interval, lookback }: RuleSchedule) =
cy.get('dd').eq(1).should('contain.text', lookback);
});
};

export const pickActionFrequency = (frequency: string) => {
cy.get(RULES_BULK_EDIT_ACTIONS_THROTTLE_INPUT).select(frequency);
};
Loading