Skip to content

Commit

Permalink
[RAM][SECURITYSOLUTION][ALERTS] - Integrate per-action frequency UI i…
Browse files Browse the repository at this point in the history
…n security solution (elastic#154534)
  • Loading branch information
e40pud committed Apr 9, 2023
1 parent 5a2aafe commit 1b8133d
Show file tree
Hide file tree
Showing 27 changed files with 200 additions and 284 deletions.
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 @@ -74,14 +76,19 @@ describe('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 @@ -119,7 +126,11 @@ describe('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 @@ -130,33 +141,35 @@ describe('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 @@ -177,23 +190,27 @@ describe('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

0 comments on commit 1b8133d

Please sign in to comment.