[8.9] [Security Solution] Reduce Rules Management e2e flakiness (#165468)

**NOTE: This is a manual backport of #164099**

**Original PR description:**
---

**Relates to: https://github.com/elastic/kibana/issues/161507**
**Fixes: https://github.com/elastic/kibana/issues/163704**
**Fixes: https://github.com/elastic/kibana/issues/163182**
**Fixes: https://github.com/elastic/kibana/issues/163558**
**Fixes: https://github.com/elastic/kibana/issues/163974**
**Fixes: https://github.com/elastic/kibana/issues/153914**
**Fixes: https://github.com/elastic/kibana/issues/164079**
**Fixes: https://github.com/elastic/kibana/issues/164279**

## Summary

While working on fixing Rules Management flaky tests I've noticed
similar fails in different tests. This PR addresses common pitfalls to
reduce a number of reasons causing e2e tests flakiness and as a result
reduce a number of flaky tests.

## Details

The common reasons causing e2e tests flakiness for the rules tables are

- Auto-refresh

Auto-refresh functionality is enabled by default and the table gets
auto-refreshed every 60 seconds. If a test takes more than 60 seconds
the table fetches updated rules. Having rules enabled by default and
sorted by `Enabled` column makes the sorting order undetermined and as
rules get updated due to execution ES return them in undetermined order.
This update can happen between commands working on the same element and
indexed access like `eq()` would access different elements.

- Missing selectors

Some tests or helper functions have expectations for an element absence
like `should('not.exist')` without checking an element is visible before
like `should('be.visible')`. This way a referenced element may disappear
from the codebase after refactoring and the expectation still fulfils.

- Checking for `should('not.visible')` while an element is removed from
the DOM

It most applicable to popovers as it first animates to be hidden and
then removed from the DOM. Cypress first need to find an element to
check its visibility. Replacing `should('not.visible')` with
`should('not.exist')` and taking into concern from the account previous
bullet fixes the problem.

- Modifying ES data without refreshing (`_delete_by_query` in
particular)

Due to high performance ES architecture data isn't updated instantly.
Having such behavior in tests leads to undetermined state depending on a
number of environmental factors. As UI doesn't always auto-refreshes to
fetch the recent updates in short period of time test fail.
`_delete_by_query` may take some time to update the data but it doesn't
support `refresh=wait_for` as it stated in
[docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html#_refreshing_shards).
Adding `?refresh=true` or just `?refresh` to `_delete_by_query` ES
request urls fixes the problem.

### What was done to address mentioned reasons above?

- Auto-refresh functionality disabled in tests where it's not necessary.
- `enabled: false` field was added to rule creators to have disabled
rules as the majority of tests don't need enabled rules.
- `waitForRulesTableToBeLoaded` was removed and replaced with
`expectManagementTableRules` at some tests.
- `should('not.visible')` replaced with `should('not.exist')` in
`deleteRuleFromDetailsPage()`
- `?refresh` added to `_delete_by_query` ES data update requests

The other changes get rid of global constants and improve readability.

## Flaky test runs

[All Cypress tests under `detection_response` folder (100
runs)](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2920)
(value lists export is flaky but it's out of scope of this PR)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Juan Pablo Djeredjian 2023-09-08 17:02:58 +02:00 committed by GitHub
parent cb8b5a9b59
commit 2c0c69a418
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 1194 additions and 1061 deletions

View file

@ -13,7 +13,6 @@ import {
RULE_NAME,
} from '../../screens/alerts_detection_rules';
import { VALUE_LISTS_MODAL_ACTIVATOR } from '../../screens/lists';
import { waitForRulesTableToBeLoaded } from '../../tasks/alerts_detection_rules';
import { createRule } from '../../tasks/api_calls/rules';
import { cleanKibana } from '../../tasks/common';
import {
@ -22,19 +21,17 @@ import {
waitForCallOutToBeShown,
MISSING_PRIVILEGES_CALLOUT,
} from '../../tasks/common/callouts';
import { login, visitWithoutDateRange } from '../../tasks/login';
import { SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
import { login, visitSecurityDetectionRulesPage } from '../../tasks/login';
describe('All rules - read only', () => {
before(() => {
cleanKibana();
createRule(getNewRule({ rule_id: '1' }));
createRule(getNewRule({ rule_id: '1', enabled: false }));
});
beforeEach(() => {
login(ROLES.reader);
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL, ROLES.reader);
waitForRulesTableToBeLoaded();
visitSecurityDetectionRulesPage(ROLES.reader);
cy.get(RULE_NAME).should('have.text', getNewRule().name);
});

View file

@ -5,33 +5,29 @@
* 2.0.
*/
import { getNewRule } from '../../objects/rule';
import { EXCEPTION_CARD_ITEM_NAME } from '../../screens/exceptions';
import {
waitForRulesTableToBeLoaded,
goToTheRuleDetailsOf,
selectNumberOfRules,
duplicateSelectedRulesWithoutExceptions,
disableAutoRefresh,
selectAllRules,
expectManagementTableRules,
duplicateSelectedRulesWithExceptions,
duplicateSelectedRulesWithNonExpiredExceptions,
goToTheRuleDetailsOf,
} from '../../tasks/alerts_detection_rules';
import { goToExceptionsTab, viewExpiredExceptionItems } from '../../tasks/rule_details';
import { login, visitWithoutDateRange } from '../../tasks/login';
import { SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
import { createRuleExceptionItem } from '../../tasks/api_calls/exceptions';
import { createRule } from '../../tasks/api_calls/rules';
import { cleanKibana, resetRulesTableState, deleteAlertsAndRules } from '../../tasks/common';
import { getNewRule } from '../../objects/rule';
import { esArchiverResetKibana } from '../../tasks/es_archiver';
import { createRuleExceptionItem } from '../../tasks/api_calls/exceptions';
import { EXCEPTION_CARD_ITEM_NAME } from '../../screens/exceptions';
import {
assertExceptionItemsExists,
assertNumberOfExceptionItemsExists,
} from '../../tasks/exceptions';
import { login, visitSecurityDetectionRulesPage } from '../../tasks/login';
import { goToExceptionsTab, viewExpiredExceptionItems } from '../../tasks/rule_details';
import {
duplicateSelectedRulesWithExceptions,
duplicateSelectedRulesWithNonExpiredExceptions,
duplicateSelectedRulesWithoutExceptions,
} from '../../tasks/rules_bulk_edit';
import { esArchiverResetKibana } from '../../tasks/es_archiver';
const RULE_NAME = 'Custom rule for bulk actions';
@ -61,55 +57,54 @@ describe('Detection rules, bulk duplicate', () => {
resetRulesTableState();
deleteAlertsAndRules();
esArchiverResetKibana();
createRule(getNewRule({ name: RULE_NAME, ...defaultRuleData, rule_id: '1' })).then(
(response) => {
createRuleExceptionItem(response.body.id, [
{
description: 'Exception item for rule default exception list',
entries: [
{
field: 'user.name',
operator: 'included',
type: 'match',
value: 'some value',
},
],
name: EXPIRED_EXCEPTION_ITEM_NAME,
type: 'simple',
expire_time: expiredDate,
},
{
description: 'Exception item for rule default exception list',
entries: [
{
field: 'user.name',
operator: 'included',
type: 'match',
value: 'some value',
},
],
name: NON_EXPIRED_EXCEPTION_ITEM_NAME,
type: 'simple',
expire_time: futureDate,
},
]);
}
);
createRule(
getNewRule({ name: RULE_NAME, ...defaultRuleData, rule_id: '1', enabled: false })
).then((response) => {
createRuleExceptionItem(response.body.id, [
{
description: 'Exception item for rule default exception list',
entries: [
{
field: 'user.name',
operator: 'included',
type: 'match',
value: 'some value',
},
],
name: EXPIRED_EXCEPTION_ITEM_NAME,
type: 'simple',
expire_time: expiredDate,
},
{
description: 'Exception item for rule default exception list',
entries: [
{
field: 'user.name',
operator: 'included',
type: 'match',
value: 'some value',
},
],
name: NON_EXPIRED_EXCEPTION_ITEM_NAME,
type: 'simple',
expire_time: futureDate,
},
]);
});
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
waitForRulesTableToBeLoaded();
visitSecurityDetectionRulesPage();
disableAutoRefresh();
});
it('Duplicates rules', () => {
selectNumberOfRules(1);
selectAllRules();
duplicateSelectedRulesWithoutExceptions();
expectManagementTableRules([`${RULE_NAME} [Duplicate]`]);
});
describe('With exceptions', () => {
it('Duplicates rules with expired exceptions', () => {
selectNumberOfRules(1);
selectAllRules();
duplicateSelectedRulesWithExceptions();
expectManagementTableRules([`${RULE_NAME} [Duplicate]`]);
goToTheRuleDetailsOf(`${RULE_NAME} [Duplicate]`);
@ -120,7 +115,7 @@ describe('Detection rules, bulk duplicate', () => {
});
it('Duplicates rules with exceptions, excluding expired exceptions', () => {
selectNumberOfRules(1);
selectAllRules();
duplicateSelectedRulesWithNonExpiredExceptions();
expectManagementTableRules([`${RULE_NAME} [Duplicate]`]);
goToTheRuleDetailsOf(`${RULE_NAME} [Duplicate]`);

View file

@ -5,95 +5,87 @@
* 2.0.
*/
import { createRuleAssetSavedObject } from '../../helpers/rules';
import {
getNewRule,
getEqlRule,
getMachineLearningRule,
getNewThreatIndicatorRule,
getNewThresholdRule,
getNewTermsRule,
} from '../../objects/rule';
import {
MODAL_CONFIRMATION_BTN,
MODAL_CONFIRMATION_BODY,
RULE_CHECKBOX,
RULES_TAGS_POPOVER_BTN,
MODAL_ERROR_BODY,
} from '../../screens/alerts_detection_rules';
import { EUI_CHECKBOX, EUI_FILTER_SELECT_ITEM } from '../../screens/common/controls';
import {
RULES_BULK_EDIT_INDEX_PATTERNS_WARNING,
RULES_BULK_EDIT_TAGS_WARNING,
RULES_BULK_EDIT_TIMELINE_TEMPLATES_WARNING,
TAGS_RULE_BULK_MENU_ITEM,
INDEX_PATTERNS_RULE_BULK_MENU_ITEM,
APPLY_TIMELINE_RULE_BULK_MENU_ITEM,
RULES_BULK_EDIT_TAGS_WARNING,
RULES_BULK_EDIT_INDEX_PATTERNS_WARNING,
RULES_BULK_EDIT_TIMELINE_TEMPLATES_WARNING,
} from '../../screens/rules_bulk_edit';
import { TIMELINE_TEMPLATE_DETAILS } from '../../screens/rule_details';
import { EUI_FILTER_SELECT_ITEM } from '../../screens/common/controls';
import {
waitForRulesTableToBeLoaded,
selectAllRules,
goToTheRuleDetailsOf,
selectNumberOfRules,
testAllTagsBadges,
testTagsBadge,
testMultipleSelectedRulesLabel,
disableAutoRefresh,
filterByElasticRules,
clickErrorToastBtn,
unselectRuleByName,
selectAllRulesOnPage,
getRulesManagementTableRows,
selectAllRules,
cancelConfirmationModal,
selectRulesByName,
testMultipleSelectedRulesLabel,
getRuleRow,
testTagsBadge,
testAllTagsBadges,
goToTheRuleDetailsOf,
clickErrorToastBtn,
} from '../../tasks/alerts_detection_rules';
import {
typeIndexPatterns,
waitForBulkEditActionToFinish,
submitBulkEditForm,
clickAddIndexPatternsMenuItem,
checkPrebuiltRulesCannotBeModified,
checkMachineLearningRulesCannotBeModified,
waitForMixedRulesBulkEditModal,
openBulkEditAddTagsForm,
openBulkEditDeleteTagsForm,
typeTags,
openTagsSelect,
openBulkActionsMenu,
clickApplyTimelineTemplatesMenuItem,
clickAddTagsMenuItem,
checkOverwriteTagsCheckbox,
checkOverwriteIndexPatternsCheckbox,
openBulkEditAddIndexPatternsForm,
openBulkEditDeleteIndexPatternsForm,
selectTimelineTemplate,
checkTagsInTagsFilter,
clickUpdateScheduleMenuItem,
typeScheduleInterval,
typeScheduleLookback,
setScheduleLookbackTimeUnit,
setScheduleIntervalTimeUnit,
assertRuleScheduleValues,
assertUpdateScheduleWarningExists,
assertDefaultValuesAreAppliedToScheduleFields,
} from '../../tasks/rules_bulk_edit';
import { hasIndexPatterns, getDetails } from '../../tasks/rule_details';
import { login, visitWithoutDateRange } from '../../tasks/login';
import { SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
createAndInstallMockedPrebuiltRules,
getAvailablePrebuiltRulesCount,
} from '../../tasks/api_calls/prebuilt_rules';
import { createRule } from '../../tasks/api_calls/rules';
import { loadPrepackagedTimelineTemplates } from '../../tasks/api_calls/timelines';
import { cleanKibana, resetRulesTableState, deleteAlertsAndRules } from '../../tasks/common';
import {
getEqlRule,
getNewThreatIndicatorRule,
getNewRule,
getNewThresholdRule,
getMachineLearningRule,
getNewTermsRule,
} from '../../objects/rule';
import { esArchiverResetKibana } from '../../tasks/es_archiver';
import { login, visitSecurityDetectionRulesPage } from '../../tasks/login';
import {
getAvailablePrebuiltRulesCount,
excessivelyInstallAllPrebuiltRules,
} from '../../tasks/api_calls/prebuilt_rules';
import { setRowsPerPageTo } from '../../tasks/table_pagination';
openBulkActionsMenu,
clickApplyTimelineTemplatesMenuItem,
checkPrebuiltRulesCannotBeModified,
clickAddTagsMenuItem,
waitForMixedRulesBulkEditModal,
typeTags,
submitBulkEditForm,
waitForBulkEditActionToFinish,
openBulkEditAddTagsForm,
openTagsSelect,
checkTagsInTagsFilter,
checkOverwriteTagsCheckbox,
openBulkEditDeleteTagsForm,
clickAddIndexPatternsMenuItem,
checkMachineLearningRulesCannotBeModified,
typeIndexPatterns,
openBulkEditAddIndexPatternsForm,
checkOverwriteIndexPatternsCheckbox,
openBulkEditDeleteIndexPatternsForm,
selectTimelineTemplate,
clickUpdateScheduleMenuItem,
assertUpdateScheduleWarningExists,
assertDefaultValuesAreAppliedToScheduleFields,
typeScheduleInterval,
setScheduleIntervalTimeUnit,
typeScheduleLookback,
setScheduleLookbackTimeUnit,
assertRuleScheduleValues,
} from '../../tasks/rules_bulk_edit';
import { hasIndexPatterns, getDetails } from '../../tasks/rule_details';
import { setRowsPerPageTo, sortByTableColumn } from '../../tasks/table_pagination';
const RULE_NAME = 'Custom rule for bulk actions';
const EUI_SELECTABLE_LIST_ITEM_SR_TEXT = '. To check this option, press Enter.';
@ -101,16 +93,8 @@ const EUI_SELECTABLE_LIST_ITEM_SR_TEXT = '. To check this option, press Enter.';
const prePopulatedIndexPatterns = ['index-1-*', 'index-2-*'];
const prePopulatedTags = ['test-default-tag-1', 'test-default-tag-2'];
const expectedNumberOfCustomRulesToBeEdited = 6;
const expectedNumberOfMachineLearningRulesToBeEdited = 1;
/**
* total number of custom rules that are not Machine learning
*/
const expectedNumberOfNotMLRules =
expectedNumberOfCustomRulesToBeEdited - expectedNumberOfMachineLearningRulesToBeEdited;
const numberOfRulesPerPage = 5;
const defaultRuleData = {
index: prePopulatedIndexPatterns,
tags: prePopulatedTags,
@ -128,19 +112,53 @@ describe('Detection rules, bulk edit', () => {
resetRulesTableState();
deleteAlertsAndRules();
esArchiverResetKibana();
createRule(getNewRule({ name: RULE_NAME, ...defaultRuleData, rule_id: '1' }));
createRule(getEqlRule({ ...defaultRuleData, rule_id: '2' }));
createRule(getMachineLearningRule({ tags: ['test-default-tag-1', 'test-default-tag-2'] }));
createRule(getNewThreatIndicatorRule({ ...defaultRuleData, rule_id: '4' }));
createRule(getNewThresholdRule({ ...defaultRuleData, rule_id: '5' }));
createRule(getNewTermsRule({ ...defaultRuleData, rule_id: '6' }));
createRule(getNewRule({ name: RULE_NAME, ...defaultRuleData, rule_id: '1', enabled: false }));
createRule(
getEqlRule({ ...defaultRuleData, rule_id: '2', name: 'New EQL Rule', enabled: false })
);
createRule(
getMachineLearningRule({
name: 'New ML Rule Test',
tags: ['test-default-tag-1', 'test-default-tag-2'],
enabled: false,
})
);
createRule(
getNewThreatIndicatorRule({
...defaultRuleData,
rule_id: '4',
name: 'Threat Indicator Rule Test',
enabled: false,
})
);
createRule(
getNewThresholdRule({
...defaultRuleData,
rule_id: '5',
name: 'Threshold Rule',
enabled: false,
})
);
createRule(
getNewTermsRule({ ...defaultRuleData, rule_id: '6', name: 'New Terms Rule', enabled: false })
);
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
waitForRulesTableToBeLoaded();
visitSecurityDetectionRulesPage();
disableAutoRefresh();
});
describe('Prerequisites', () => {
const PREBUILT_RULES = [
createRuleAssetSavedObject({
name: 'Prebuilt rule 1',
rule_id: 'rule_1',
}),
createRuleAssetSavedObject({
name: 'Prebuilt rule 2',
rule_id: 'rule_2',
}),
];
it('No rules selected', () => {
openBulkActionsMenu();
@ -151,80 +169,87 @@ describe('Detection rules, bulk edit', () => {
});
it('Only prebuilt rules selected', () => {
const expectedNumberOfSelectedRules = 10;
excessivelyInstallAllPrebuiltRules();
createAndInstallMockedPrebuiltRules({ rules: PREBUILT_RULES });
// select Elastic(prebuilt) rules, check if we can't proceed further, as Elastic rules are not editable
filterByElasticRules();
selectNumberOfRules(expectedNumberOfSelectedRules);
selectAllRulesOnPage();
clickApplyTimelineTemplatesMenuItem();
// check modal window for Elastic rule that can't be edited
checkPrebuiltRulesCannotBeModified(expectedNumberOfSelectedRules);
getRulesManagementTableRows().then((rows) => {
// check modal window for Elastic rule that can't be edited
checkPrebuiltRulesCannotBeModified(rows.length);
// the confirm button closes modal
cy.get(MODAL_CONFIRMATION_BTN).should('have.text', 'Close').click();
cy.get(MODAL_CONFIRMATION_BODY).should('not.exist');
// the confirm button closes modal
cy.get(MODAL_CONFIRMATION_BTN).should('have.text', 'Close').click();
cy.get(MODAL_CONFIRMATION_BODY).should('not.exist');
});
});
it('Prebuilt and custom rules selected: user proceeds with custom rules editing', () => {
excessivelyInstallAllPrebuiltRules();
getRulesManagementTableRows().then((existedRulesRows) => {
createAndInstallMockedPrebuiltRules({ rules: PREBUILT_RULES });
// modal window should show how many rules can be edit, how many not
selectAllRules();
clickAddTagsMenuItem();
waitForMixedRulesBulkEditModal(expectedNumberOfCustomRulesToBeEdited);
// modal window should show how many rules can be edit, how many not
selectAllRules();
clickAddTagsMenuItem();
getAvailablePrebuiltRulesCount().then((availablePrebuiltRulesCount) => {
checkPrebuiltRulesCannotBeModified(availablePrebuiltRulesCount);
waitForMixedRulesBulkEditModal(existedRulesRows.length);
getAvailablePrebuiltRulesCount().then((availablePrebuiltRulesCount) => {
checkPrebuiltRulesCannotBeModified(availablePrebuiltRulesCount);
});
// user can proceed with custom rule editing
cy.get(MODAL_CONFIRMATION_BTN)
.should('have.text', `Edit ${existedRulesRows.length} custom rules`)
.click();
// action should finish
typeTags(['test-tag']);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: existedRulesRows.length });
});
// user can proceed with custom rule editing
cy.get(MODAL_CONFIRMATION_BTN)
.should('have.text', `Edit ${expectedNumberOfCustomRulesToBeEdited} custom rules`)
.click();
// action should finish
typeTags(['test-tag']);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
});
it('Prebuilt and custom rules selected: user cancels action', () => {
excessivelyInstallAllPrebuiltRules();
createAndInstallMockedPrebuiltRules({ rules: PREBUILT_RULES });
// modal window should show how many rules can be edit, how many not
selectAllRules();
clickAddTagsMenuItem();
waitForMixedRulesBulkEditModal(expectedNumberOfCustomRulesToBeEdited);
getRulesManagementTableRows().then((rows) => {
// modal window should show how many rules can be edit, how many not
selectAllRules();
clickAddTagsMenuItem();
waitForMixedRulesBulkEditModal(rows.length);
getAvailablePrebuiltRulesCount().then((availablePrebuiltRulesCount) => {
checkPrebuiltRulesCannotBeModified(availablePrebuiltRulesCount);
getAvailablePrebuiltRulesCount().then((availablePrebuiltRulesCount) => {
checkPrebuiltRulesCannotBeModified(availablePrebuiltRulesCount);
});
// user cancels action and modal disappears
cancelConfirmationModal();
});
// user cancels action and modal disappears
cancelConfirmationModal();
});
it('should not lose rules selection after edit action', () => {
const rulesCount = 4;
const rulesToUpdate = [RULE_NAME, 'New EQL Rule', 'New Terms Rule'] as const;
// Switch to 5 rules per page, to have few pages in pagination(ideal way to test auto refresh and selection of few items)
setRowsPerPageTo(numberOfRulesPerPage);
selectNumberOfRules(rulesCount);
setRowsPerPageTo(5);
// and make the rules order isn't changing (set sorting by rule name) over time if rules are run
sortByTableColumn('Rule');
selectRulesByName(rulesToUpdate);
// open add tags form and add 2 new tags
openBulkEditAddTagsForm();
typeTags(['new-tag-1']);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: rulesCount });
waitForBulkEditActionToFinish({ updatedCount: rulesToUpdate.length });
testMultipleSelectedRulesLabel(rulesCount);
testMultipleSelectedRulesLabel(rulesToUpdate.length);
// check if first four(rulesCount) rules still selected and tags are updated
for (let i = 0; i < rulesCount; i += 1) {
cy.get(RULE_CHECKBOX).eq(i).should('be.checked');
cy.get(RULES_TAGS_POPOVER_BTN)
.eq(i)
for (const ruleName of rulesToUpdate) {
getRuleRow(ruleName).find(EUI_CHECKBOX).should('be.checked');
getRuleRow(ruleName)
.find(RULES_TAGS_POPOVER_BTN)
.each(($el) => {
testTagsBadge($el, prePopulatedTags.concat(['new-tag-1']));
});
@ -234,7 +259,7 @@ describe('Detection rules, bulk edit', () => {
describe('Tags actions', () => {
it('Display list of tags in tags select', () => {
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
selectAllRules();
openBulkEditAddTagsForm();
openTagsSelect();
@ -247,119 +272,131 @@ describe('Detection rules, bulk edit', () => {
});
it('Add tags to custom rules', () => {
const tagsToBeAdded = ['tag-to-add-1', 'tag-to-add-2'];
const resultingTags = [...prePopulatedTags, ...tagsToBeAdded];
getRulesManagementTableRows().then((rows) => {
const tagsToBeAdded = ['tag-to-add-1', 'tag-to-add-2'];
const resultingTags = [...prePopulatedTags, ...tagsToBeAdded];
// check if only pre-populated tags exist in the tags filter
checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
// check if only pre-populated tags exist in the tags filter
checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
selectAllRules();
// open add tags form and add 2 new tags
openBulkEditAddTagsForm();
typeTags(tagsToBeAdded);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
// open add tags form and add 2 new tags
openBulkEditAddTagsForm();
typeTags(tagsToBeAdded);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: rows.length });
// check if all rules have been updated with new tags
testAllTagsBadges(resultingTags);
// check if all rules have been updated with new tags
testAllTagsBadges(resultingTags);
// check that new tags were added to tags filter
// tags in tags filter sorted alphabetically
const resultingTagsInFilter = [...resultingTags].sort();
checkTagsInTagsFilter(resultingTagsInFilter, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
// check that new tags were added to tags filter
// tags in tags filter sorted alphabetically
const resultingTagsInFilter = [...resultingTags].sort();
checkTagsInTagsFilter(resultingTagsInFilter, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
});
});
it('Display success toast after adding tags', () => {
const tagsToBeAdded = ['tag-to-add-1', 'tag-to-add-2'];
getRulesManagementTableRows().then((rows) => {
const tagsToBeAdded = ['tag-to-add-1', 'tag-to-add-2'];
// check if only pre-populated tags exist in the tags filter
checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
// check if only pre-populated tags exist in the tags filter
checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
selectAllRules();
// open add tags form and add 2 new tags
openBulkEditAddTagsForm();
typeTags(tagsToBeAdded);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
// open add tags form and add 2 new tags
openBulkEditAddTagsForm();
typeTags(tagsToBeAdded);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: rows.length });
});
});
it('Overwrite tags in custom rules', () => {
const tagsToOverwrite = ['overwrite-tag-1'];
getRulesManagementTableRows().then((rows) => {
const tagsToOverwrite = ['overwrite-tag-1'];
// check if only pre-populated tags exist in the tags filter
checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
// check if only pre-populated tags exist in the tags filter
checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
selectAllRules();
// open add tags form, check overwrite tags and warning message, type tags
openBulkEditAddTagsForm();
checkOverwriteTagsCheckbox();
// open add tags form, check overwrite tags and warning message, type tags
openBulkEditAddTagsForm();
checkOverwriteTagsCheckbox();
cy.get(RULES_BULK_EDIT_TAGS_WARNING).should(
'have.text',
`Youre about to overwrite tags for ${expectedNumberOfCustomRulesToBeEdited} selected rules, press Save to apply changes.`
);
cy.get(RULES_BULK_EDIT_TAGS_WARNING).should(
'have.text',
`Youre about to overwrite tags for ${rows.length} selected rules, press Save to apply changes.`
);
typeTags(tagsToOverwrite);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
typeTags(tagsToOverwrite);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: rows.length });
// check if all rules have been updated with new tags
testAllTagsBadges(tagsToOverwrite);
// check if all rules have been updated with new tags
testAllTagsBadges(tagsToOverwrite);
// check that only new tags are in the tag filter
checkTagsInTagsFilter(tagsToOverwrite, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
// check that only new tags are in the tag filter
checkTagsInTagsFilter(tagsToOverwrite, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
});
});
it('Delete tags from custom rules', () => {
const tagsToDelete = prePopulatedTags.slice(0, 1);
const resultingTags = prePopulatedTags.slice(1);
getRulesManagementTableRows().then((rows) => {
const tagsToDelete = prePopulatedTags.slice(0, 1);
const resultingTags = prePopulatedTags.slice(1);
// check if only pre-populated tags exist in the tags filter
checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
// check if only pre-populated tags exist in the tags filter
checkTagsInTagsFilter(prePopulatedTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
selectAllRules();
// open add tags form, check overwrite tags, type tags
openBulkEditDeleteTagsForm();
typeTags(tagsToDelete);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
// open add tags form, check overwrite tags, type tags
openBulkEditDeleteTagsForm();
typeTags(tagsToDelete);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: rows.length });
// check tags has been removed from all rules
testAllTagsBadges(resultingTags);
// check tags has been removed from all rules
testAllTagsBadges(resultingTags);
// check that tags were removed from the tag filter
checkTagsInTagsFilter(resultingTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
// check that tags were removed from the tag filter
checkTagsInTagsFilter(resultingTags, EUI_SELECTABLE_LIST_ITEM_SR_TEXT);
});
});
});
describe('Index patterns', () => {
it('Index pattern action applied to custom rules, including machine learning: user proceeds with edit of custom non machine learning rule', () => {
const indexPattersToBeAdded = ['index-to-add-1-*', 'index-to-add-2-*'];
const resultingIndexPatterns = [...prePopulatedIndexPatterns, ...indexPattersToBeAdded];
getRulesManagementTableRows().then((rows) => {
const indexPattersToBeAdded = ['index-to-add-1-*', 'index-to-add-2-*'];
const resultingIndexPatterns = [...prePopulatedIndexPatterns, ...indexPattersToBeAdded];
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
clickAddIndexPatternsMenuItem();
selectAllRules();
clickAddIndexPatternsMenuItem();
// confirm editing custom rules, that are not Machine Learning
checkMachineLearningRulesCannotBeModified(expectedNumberOfMachineLearningRulesToBeEdited);
cy.get(MODAL_CONFIRMATION_BTN).click();
// confirm editing custom rules, that are not Machine Learning
checkMachineLearningRulesCannotBeModified(expectedNumberOfMachineLearningRulesToBeEdited);
cy.get(MODAL_CONFIRMATION_BTN).click();
typeIndexPatterns(indexPattersToBeAdded);
submitBulkEditForm();
typeIndexPatterns(indexPattersToBeAdded);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfNotMLRules });
waitForBulkEditActionToFinish({
updatedCount: rows.length - expectedNumberOfMachineLearningRulesToBeEdited,
});
// check if rule has been updated
goToTheRuleDetailsOf(RULE_NAME);
hasIndexPatterns(resultingIndexPatterns.join(''));
// check if rule has been updated
goToTheRuleDetailsOf(RULE_NAME);
hasIndexPatterns(resultingIndexPatterns.join(''));
});
});
it('Index pattern action applied to custom rules, including machine learning: user cancels action', () => {
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
selectAllRules();
clickAddIndexPatternsMenuItem();
// confirm editing custom rules, that are not Machine Learning
@ -370,46 +407,68 @@ describe('Detection rules, bulk edit', () => {
});
it('Add index patterns to custom rules', () => {
const indexPattersToBeAdded = ['index-to-add-1-*', 'index-to-add-2-*'];
const resultingIndexPatterns = [...prePopulatedIndexPatterns, ...indexPattersToBeAdded];
getRulesManagementTableRows().then((rows) => {
const indexPattersToBeAdded = ['index-to-add-1-*', 'index-to-add-2-*'];
const resultingIndexPatterns = [...prePopulatedIndexPatterns, ...indexPattersToBeAdded];
// select only rules that are not ML
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
unselectRuleByName(getMachineLearningRule().name);
// select only rules that are not ML
selectRulesByName([
RULE_NAME,
'New EQL Rule',
'Threat Indicator Rule Test',
'Threshold Rule',
'New Terms Rule',
]);
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(indexPattersToBeAdded);
submitBulkEditForm();
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(indexPattersToBeAdded);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfNotMLRules });
waitForBulkEditActionToFinish({
updatedCount: rows.length - expectedNumberOfMachineLearningRulesToBeEdited,
});
// check if rule has been updated
goToTheRuleDetailsOf(RULE_NAME);
hasIndexPatterns(resultingIndexPatterns.join(''));
// check if rule has been updated
goToTheRuleDetailsOf(RULE_NAME);
hasIndexPatterns(resultingIndexPatterns.join(''));
});
});
it('Display success toast after editing the index pattern', () => {
const indexPattersToBeAdded = ['index-to-add-1-*', 'index-to-add-2-*'];
getRulesManagementTableRows().then((rows) => {
const indexPattersToBeAdded = ['index-to-add-1-*', 'index-to-add-2-*'];
// select only rules that are not ML
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
unselectRuleByName(getMachineLearningRule().name);
// select only rules that are not ML
selectRulesByName([
RULE_NAME,
'New EQL Rule',
'Threat Indicator Rule Test',
'Threshold Rule',
'New Terms Rule',
]);
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(indexPattersToBeAdded);
submitBulkEditForm();
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(indexPattersToBeAdded);
submitBulkEditForm();
waitForBulkEditActionToFinish({
updatedCount: expectedNumberOfNotMLRules,
waitForBulkEditActionToFinish({
updatedCount: rows.length - expectedNumberOfMachineLearningRulesToBeEdited,
});
});
});
it('Overwrite index patterns in custom rules', () => {
const rulesToSelect = [
RULE_NAME,
'New EQL Rule',
'Threat Indicator Rule Test',
'Threshold Rule',
'New Terms Rule',
] as const;
const indexPattersToWrite = ['index-to-write-1-*', 'index-to-write-2-*'];
// select only rules that are not ML
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
unselectRuleByName(getMachineLearningRule().name);
selectRulesByName(rulesToSelect);
openBulkEditAddIndexPatternsForm();
@ -417,13 +476,13 @@ describe('Detection rules, bulk edit', () => {
checkOverwriteIndexPatternsCheckbox();
cy.get(RULES_BULK_EDIT_INDEX_PATTERNS_WARNING).should(
'have.text',
`Youre about to overwrite index patterns for ${expectedNumberOfNotMLRules} selected rules, press Save to apply changes.`
`Youre about to overwrite index patterns for ${rulesToSelect.length} selected rules, press Save to apply changes.`
);
typeIndexPatterns(indexPattersToWrite);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfNotMLRules });
waitForBulkEditActionToFinish({ updatedCount: rulesToSelect.length });
// check if rule has been updated
goToTheRuleDetailsOf(RULE_NAME);
@ -431,18 +490,24 @@ describe('Detection rules, bulk edit', () => {
});
it('Delete index patterns from custom rules', () => {
const rulesToSelect = [
RULE_NAME,
'New EQL Rule',
'Threat Indicator Rule Test',
'Threshold Rule',
'New Terms Rule',
] as const;
const indexPatternsToDelete = prePopulatedIndexPatterns.slice(0, 1);
const resultingIndexPatterns = prePopulatedIndexPatterns.slice(1);
// select only not ML rules
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
unselectRuleByName(getMachineLearningRule().name);
selectRulesByName(rulesToSelect);
openBulkEditDeleteIndexPatternsForm();
typeIndexPatterns(indexPatternsToDelete);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfNotMLRules });
waitForBulkEditActionToFinish({ updatedCount: rulesToSelect.length });
// check if rule has been updated
goToTheRuleDetailsOf(RULE_NAME);
@ -450,16 +515,23 @@ describe('Detection rules, bulk edit', () => {
});
it('Delete all index patterns from custom rules', () => {
const rulesToSelect = [
RULE_NAME,
'New EQL Rule',
'Threat Indicator Rule Test',
'Threshold Rule',
'New Terms Rule',
] as const;
// select only rules that are not ML
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
unselectRuleByName(getMachineLearningRule().name);
selectRulesByName(rulesToSelect);
openBulkEditDeleteIndexPatternsForm();
typeIndexPatterns(prePopulatedIndexPatterns);
submitBulkEditForm();
// error toast should be displayed that that rules edit failed
waitForBulkEditActionToFinish({ failedCount: expectedNumberOfNotMLRules });
waitForBulkEditActionToFinish({ failedCount: rulesToSelect.length });
// on error toast button click display error that index patterns can't be empty
clickErrorToastBtn();
@ -473,97 +545,107 @@ describe('Detection rules, bulk edit', () => {
});
it('Apply timeline template to custom rules', () => {
const timelineTemplateName = 'Generic Endpoint Timeline';
getRulesManagementTableRows().then((rows) => {
const timelineTemplateName = 'Generic Endpoint Timeline';
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
selectAllRules();
// open Timeline template form, check warning, select timeline template
clickApplyTimelineTemplatesMenuItem();
cy.get(RULES_BULK_EDIT_TIMELINE_TEMPLATES_WARNING).contains(
`You're about to apply changes to ${expectedNumberOfCustomRulesToBeEdited} selected rules. If you previously applied Timeline templates to these rules, they will be overwritten or (if you select 'None') reset to none.`
);
selectTimelineTemplate(timelineTemplateName);
// open Timeline template form, check warning, select timeline template
clickApplyTimelineTemplatesMenuItem();
cy.get(RULES_BULK_EDIT_TIMELINE_TEMPLATES_WARNING).contains(
`You're about to apply changes to ${rows.length} selected rules. If you previously applied Timeline templates to these rules, they will be overwritten or (if you select 'None') reset to none.`
);
selectTimelineTemplate(timelineTemplateName);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: rows.length });
// check if timeline template has been updated to selected one
goToTheRuleDetailsOf(RULE_NAME);
getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', timelineTemplateName);
// check if timeline template has been updated to selected one
goToTheRuleDetailsOf(RULE_NAME);
getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', timelineTemplateName);
});
});
it('Reset timeline template to None for custom rules', () => {
const noneTimelineTemplate = 'None';
getRulesManagementTableRows().then((rows) => {
const noneTimelineTemplate = 'None';
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
selectAllRules();
// open Timeline template form, submit form without picking timeline template as None is selected by default
clickApplyTimelineTemplatesMenuItem();
// open Timeline template form, submit form without picking timeline template as None is selected by default
clickApplyTimelineTemplatesMenuItem();
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: rows.length });
// check if timeline template has been updated to selected one, by opening rule that have had timeline prior to editing
goToTheRuleDetailsOf(RULE_NAME);
getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', noneTimelineTemplate);
// check if timeline template has been updated to selected one, by opening rule that have had timeline prior to editing
goToTheRuleDetailsOf(RULE_NAME);
getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', noneTimelineTemplate);
});
});
});
describe('Schedule', () => {
it('Default values are applied to bulk edit schedule fields', () => {
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
clickUpdateScheduleMenuItem();
getRulesManagementTableRows().then((rows) => {
selectAllRules();
clickUpdateScheduleMenuItem();
assertUpdateScheduleWarningExists(expectedNumberOfCustomRulesToBeEdited);
assertUpdateScheduleWarningExists(rows.length);
assertDefaultValuesAreAppliedToScheduleFields({
interval: 5,
lookback: 1,
assertDefaultValuesAreAppliedToScheduleFields({
interval: 5,
lookback: 1,
});
});
});
it('Updates schedule for custom rules', () => {
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
clickUpdateScheduleMenuItem();
getRulesManagementTableRows().then((rows) => {
selectAllRules();
clickUpdateScheduleMenuItem();
assertUpdateScheduleWarningExists(expectedNumberOfCustomRulesToBeEdited);
assertUpdateScheduleWarningExists(rows.length);
typeScheduleInterval('20');
setScheduleIntervalTimeUnit('Hours');
typeScheduleInterval('20');
setScheduleIntervalTimeUnit('Hours');
typeScheduleLookback('10');
setScheduleLookbackTimeUnit('Minutes');
typeScheduleLookback('10');
setScheduleLookbackTimeUnit('Minutes');
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: rows.length });
goToTheRuleDetailsOf(RULE_NAME);
goToTheRuleDetailsOf(RULE_NAME);
assertRuleScheduleValues({
interval: '20h',
lookback: '10m',
assertRuleScheduleValues({
interval: '20h',
lookback: '10m',
});
});
});
it('Validates invalid inputs when scheduling for custom rules', () => {
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
clickUpdateScheduleMenuItem();
getRulesManagementTableRows().then((rows) => {
selectAllRules();
clickUpdateScheduleMenuItem();
// Validate invalid values are corrected to minimumValue - for 0 and negative values
typeScheduleInterval('0');
setScheduleIntervalTimeUnit('Hours');
// Validate invalid values are corrected to minimumValue - for 0 and negative values
typeScheduleInterval('0');
setScheduleIntervalTimeUnit('Hours');
typeScheduleLookback('-5');
setScheduleLookbackTimeUnit('Seconds');
typeScheduleLookback('-5');
setScheduleLookbackTimeUnit('Seconds');
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: rows.length });
goToTheRuleDetailsOf(RULE_NAME);
goToTheRuleDetailsOf(RULE_NAME);
assertRuleScheduleValues({
interval: '1h',
lookback: '1s',
assertRuleScheduleValues({
interval: '1h',
lookback: '1s',
});
});
});
});

View file

@ -7,82 +7,70 @@
import type { RuleActionArray } from '@kbn/securitysolution-io-ts-alerting-types';
import { ROLES } from '../../../common/test';
import { createRuleAssetSavedObject } from '../../helpers/rules';
import {
getNewRule,
getEqlRule,
getMachineLearningRule,
getNewThreatIndicatorRule,
getNewThresholdRule,
getNewTermsRule,
} from '../../objects/rule';
import { actionFormSelector } from '../../screens/common/rule_actions';
import {
ADD_RULE_ACTIONS_MENU_ITEM,
RULES_BULK_EDIT_ACTIONS_INFO,
RULES_BULK_EDIT_ACTIONS_WARNING,
ADD_RULE_ACTIONS_MENU_ITEM,
} from '../../screens/rules_bulk_edit';
import { actionFormSelector } from '../../screens/common/rule_actions';
import {
expectManagementTableRules,
selectAllRules,
disableAutoRefresh,
getRulesManagementTableRows,
goToEditRuleActionsSettingsOf,
selectRulesByName,
} from '../../tasks/alerts_detection_rules';
import { createSlackConnector } from '../../tasks/api_calls/connectors';
import {
preventPrebuiltRulesPackageInstallation,
createAndInstallMockedPrebuiltRules,
excessivelyInstallAllPrebuiltRules,
} from '../../tasks/api_calls/prebuilt_rules';
import { createRule } from '../../tasks/api_calls/rules';
import { cleanKibana, deleteAlertsAndRules, deleteConnectors } from '../../tasks/common';
import { waitForCallOutToBeShown, MISSING_PRIVILEGES_CALLOUT } from '../../tasks/common/callouts';
import type { RuleActionCustomFrequency } from '../../tasks/common/rule_actions';
import {
addSlackRuleAction,
pickSummaryOfAlertsOption,
pickCustomFrequencyOption,
assertSelectedSummaryOfAlertsOption,
assertSelectedCustomFrequencyOption,
assertSlackRuleAction,
pickPerRuleRunFrequencyOption,
assertSelectedPerRuleRunFrequencyOption,
addEmailConnectorAndRuleAction,
assertEmailRuleAction,
assertSelectedCustomFrequencyOption,
assertSelectedPerRuleRunFrequencyOption,
assertSelectedSummaryOfAlertsOption,
pickCustomFrequencyOption,
pickPerRuleRunFrequencyOption,
pickSummaryOfAlertsOption,
} from '../../tasks/common/rule_actions';
import {
waitForRulesTableToBeLoaded,
selectNumberOfRules,
goToEditRuleActionsSettingsOf,
disableAutoRefresh,
} from '../../tasks/alerts_detection_rules';
import {
waitForBulkEditActionToFinish,
submitBulkEditForm,
checkOverwriteRuleActionsCheckbox,
openBulkEditRuleActionsForm,
openBulkActionsMenu,
} from '../../tasks/rules_bulk_edit';
import { login, visitWithoutDateRange } from '../../tasks/login';
import { esArchiverResetKibana } from '../../tasks/es_archiver';
import { SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
import { createRule } from '../../tasks/api_calls/rules';
import { createSlackConnector } from '../../tasks/api_calls/connectors';
import { login, visitSecurityDetectionRulesPage } from '../../tasks/login';
import {
getEqlRule,
getNewThreatIndicatorRule,
getNewRule,
getNewThresholdRule,
getMachineLearningRule,
getNewTermsRule,
} from '../../objects/rule';
import {
createAndInstallMockedPrebuiltRules,
excessivelyInstallAllPrebuiltRules,
preventPrebuiltRulesPackageInstallation,
} from '../../tasks/api_calls/prebuilt_rules';
import { MISSING_PRIVILEGES_CALLOUT, waitForCallOutToBeShown } from '../../tasks/common/callouts';
import { createRuleAssetSavedObject } from '../../helpers/rules';
openBulkActionsMenu,
openBulkEditRuleActionsForm,
submitBulkEditForm,
waitForBulkEditActionToFinish,
checkOverwriteRuleActionsCheckbox,
} from '../../tasks/rules_bulk_edit';
const ruleNameToAssert = 'Custom rule name with actions';
const expectedNumberOfCustomRulesToBeEdited = 7;
// 7 custom rules of different types + 3 prebuilt.
// number of selected rules doesn't matter, we only want to make sure they will be edited an no modal window displayed as for other actions
const expectedNumberOfRulesToBeEdited = expectedNumberOfCustomRulesToBeEdited + 3;
const expectedExistingSlackMessage = 'Existing slack action';
const expectedSlackMessage = 'Slack action test message';
// TODO: Fix flakiness and unskip https://github.com/elastic/kibana/issues/154721
describe.skip('Detection rules, bulk edit of rule actions', () => {
before(() => {
describe('Detection rules, bulk edit of rule actions', () => {
beforeEach(() => {
cleanKibana();
login();
});
beforeEach(() => {
deleteAlertsAndRules();
deleteConnectors();
esArchiverResetKibana();
@ -104,15 +92,31 @@ describe.skip('Detection rules, bulk edit of rule actions', () => {
},
];
createRule(getNewRule({ name: ruleNameToAssert, rule_id: '1', max_signals: 500, actions }));
createRule(
getNewRule({
rule_id: '1',
name: ruleNameToAssert,
max_signals: 500,
actions,
enabled: false,
})
);
});
createRule(getEqlRule({ rule_id: '2' }));
createRule(getMachineLearningRule({ rule_id: '3' }));
createRule(getNewThreatIndicatorRule({ rule_id: '4' }));
createRule(getNewThresholdRule({ rule_id: '5' }));
createRule(getNewTermsRule({ rule_id: '6' }));
createRule(getNewRule({ saved_id: 'mocked', rule_id: '7' }));
createRule(getEqlRule({ rule_id: '2', name: 'New EQL Rule', enabled: false }));
createRule(getMachineLearningRule({ rule_id: '3', name: 'New ML Rule Test', enabled: false }));
createRule(
getNewThreatIndicatorRule({
rule_id: '4',
name: 'Threat Indicator Rule Test',
enabled: false,
})
);
createRule(getNewThresholdRule({ rule_id: '5', name: 'Threshold Rule', enabled: false }));
createRule(getNewTermsRule({ rule_id: '6', name: 'New Terms Rule', enabled: false }));
createRule(
getNewRule({ saved_id: 'mocked', rule_id: '7', name: 'New Rule Test', enabled: false })
);
createSlackConnector();
@ -134,11 +138,22 @@ describe.skip('Detection rules, bulk edit of rule actions', () => {
context('Restricted action privileges', () => {
it("User with no privileges can't add rule actions", () => {
login(ROLES.hunter_no_actions);
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL, ROLES.hunter_no_actions);
waitForCallOutToBeShown(MISSING_PRIVILEGES_CALLOUT, 'primary');
waitForRulesTableToBeLoaded();
visitSecurityDetectionRulesPage(ROLES.hunter_no_actions);
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
expectManagementTableRules([
ruleNameToAssert,
'New EQL Rule',
'New ML Rule Test',
'Threat Indicator Rule Test',
'Threshold Rule',
'New Terms Rule',
'New Rule Test',
'Test rule 1',
'Test rule 2',
]);
waitForCallOutToBeShown(MISSING_PRIVILEGES_CALLOUT, 'primary');
selectAllRules();
openBulkActionsMenu();
@ -149,9 +164,20 @@ describe.skip('Detection rules, bulk edit of rule actions', () => {
context('All actions privileges', () => {
beforeEach(() => {
login();
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
waitForRulesTableToBeLoaded();
visitSecurityDetectionRulesPage();
disableAutoRefresh();
expectManagementTableRules([
ruleNameToAssert,
'New EQL Rule',
'New ML Rule Test',
'Threat Indicator Rule Test',
'Threshold Rule',
'New Terms Rule',
'New Rule Test',
'Test rule 1',
'Test rule 2',
]);
});
it('Add a rule action to rules (existing connector)', () => {
@ -162,62 +188,75 @@ describe.skip('Detection rules, bulk edit of rule actions', () => {
excessivelyInstallAllPrebuiltRules();
// select both custom and prebuilt rules
selectNumberOfRules(expectedNumberOfRulesToBeEdited);
openBulkEditRuleActionsForm();
getRulesManagementTableRows().then((rows) => {
// select both custom and prebuilt rules
selectAllRules();
openBulkEditRuleActionsForm();
// ensure rule actions info callout displayed on the form
cy.get(RULES_BULK_EDIT_ACTIONS_INFO).should('be.visible');
// ensure rule actions info callout displayed on the form
cy.get(RULES_BULK_EDIT_ACTIONS_INFO).should('be.visible');
addSlackRuleAction(expectedSlackMessage);
pickSummaryOfAlertsOption();
pickCustomFrequencyOption(expectedActionFrequency);
addSlackRuleAction(expectedSlackMessage);
pickSummaryOfAlertsOption();
pickCustomFrequencyOption(expectedActionFrequency);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfRulesToBeEdited });
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: rows.length });
// check if rule has been updated
goToEditRuleActionsSettingsOf(ruleNameToAssert);
// check if rule has been updated
goToEditRuleActionsSettingsOf(ruleNameToAssert);
assertSelectedSummaryOfAlertsOption();
assertSelectedCustomFrequencyOption(expectedActionFrequency, 1);
assertSlackRuleAction(expectedExistingSlackMessage, 0);
assertSlackRuleAction(expectedSlackMessage, 1);
// ensure there is no third action
cy.get(actionFormSelector(2)).should('not.exist');
assertSelectedSummaryOfAlertsOption();
assertSelectedCustomFrequencyOption(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', () => {
excessivelyInstallAllPrebuiltRules();
// select both custom and prebuilt rules
selectNumberOfRules(expectedNumberOfRulesToBeEdited);
openBulkEditRuleActionsForm();
getRulesManagementTableRows().then((rows) => {
// select both custom and prebuilt rules
selectAllRules();
openBulkEditRuleActionsForm();
addSlackRuleAction(expectedSlackMessage);
pickSummaryOfAlertsOption();
pickPerRuleRunFrequencyOption();
addSlackRuleAction(expectedSlackMessage);
pickSummaryOfAlertsOption();
pickPerRuleRunFrequencyOption();
// check overwrite box, ensure warning is displayed
checkOverwriteRuleActionsCheckbox();
cy.get(RULES_BULK_EDIT_ACTIONS_WARNING).contains(
`You're about to overwrite rule actions for ${expectedNumberOfRulesToBeEdited} selected rules`
);
// check overwrite box, ensure warning is displayed
checkOverwriteRuleActionsCheckbox();
cy.get(RULES_BULK_EDIT_ACTIONS_WARNING).contains(
`You're about to overwrite rule actions for ${rows.length} selected rules`
);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfRulesToBeEdited });
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: rows.length });
// check if rule has been updated
goToEditRuleActionsSettingsOf(ruleNameToAssert);
// check if rule has been updated
goToEditRuleActionsSettingsOf(ruleNameToAssert);
assertSelectedSummaryOfAlertsOption();
assertSelectedPerRuleRunFrequencyOption();
assertSlackRuleAction(expectedSlackMessage);
// ensure existing action was overwritten
cy.get(actionFormSelector(1)).should('not.exist');
assertSelectedSummaryOfAlertsOption();
assertSelectedPerRuleRunFrequencyOption();
assertSlackRuleAction(expectedSlackMessage);
// ensure existing action was overwritten
cy.get(actionFormSelector(1)).should('not.exist');
});
});
it('Add a rule action to rules (new connector)', () => {
const rulesToSelect = [
ruleNameToAssert,
'New EQL Rule',
'New ML Rule Test',
'Threat Indicator Rule Test',
'Threshold Rule',
'New Terms Rule',
'New Rule Test',
] as const;
const expectedActionFrequency: RuleActionCustomFrequency = {
throttle: 2,
throttleUnit: 'h',
@ -225,7 +264,7 @@ describe.skip('Detection rules, bulk edit of rule actions', () => {
const expectedEmail = 'test@example.com';
const expectedSubject = 'Subject';
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
selectRulesByName(rulesToSelect);
openBulkEditRuleActionsForm();
addEmailConnectorAndRuleAction(expectedEmail, expectedSubject);
@ -233,7 +272,7 @@ describe.skip('Detection rules, bulk edit of rule actions', () => {
pickCustomFrequencyOption(expectedActionFrequency);
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
waitForBulkEditActionToFinish({ updatedCount: rulesToSelect.length });
// check if rule has been updated
goToEditRuleActionsSettingsOf(ruleNameToAssert);

View file

@ -6,52 +6,44 @@
*/
import {
RULES_BULK_EDIT_DATA_VIEWS_WARNING,
RULES_BULK_EDIT_OVERWRITE_DATA_VIEW_CHECKBOX,
} from '../../screens/rules_bulk_edit';
import { DATA_VIEW_DETAILS, INDEX_PATTERNS_DETAILS } from '../../screens/rule_details';
import {
waitForRulesTableToBeLoaded,
goToRuleDetails,
selectNumberOfRules,
goToTheRuleDetailsOf,
} from '../../tasks/alerts_detection_rules';
import {
typeIndexPatterns,
waitForBulkEditActionToFinish,
submitBulkEditForm,
checkOverwriteDataViewCheckbox,
checkOverwriteIndexPatternsCheckbox,
openBulkEditAddIndexPatternsForm,
openBulkEditDeleteIndexPatternsForm,
} from '../../tasks/rules_bulk_edit';
import { hasIndexPatterns, getDetails, assertDetailsNotExist } from '../../tasks/rule_details';
import { login, visitWithoutDateRange } from '../../tasks/login';
import { SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
import { createRule } from '../../tasks/api_calls/rules';
import { cleanKibana, deleteAlertsAndRules, postDataView } from '../../tasks/common';
import {
getNewRule,
getEqlRule,
getNewThreatIndicatorRule,
getNewRule,
getNewThresholdRule,
getNewTermsRule,
} from '../../objects/rule';
import {
RULES_BULK_EDIT_DATA_VIEWS_WARNING,
RULES_BULK_EDIT_OVERWRITE_DATA_VIEW_CHECKBOX,
} from '../../screens/rules_bulk_edit';
import { DATA_VIEW_DETAILS, INDEX_PATTERNS_DETAILS } from '../../screens/rule_details';
import {
disableAutoRefresh,
expectManagementTableRules,
getRulesManagementTableRows,
selectAllRules,
goToRuleDetails,
goToTheRuleDetailsOf,
} from '../../tasks/alerts_detection_rules';
import { createRule } from '../../tasks/api_calls/rules';
import { cleanKibana, deleteAlertsAndRules, postDataView } from '../../tasks/common';
import { esArchiverResetKibana } from '../../tasks/es_archiver';
import { login, visitSecurityDetectionRulesPage } from '../../tasks/login';
import {
openBulkEditAddIndexPatternsForm,
typeIndexPatterns,
submitBulkEditForm,
waitForBulkEditActionToFinish,
checkOverwriteDataViewCheckbox,
checkOverwriteIndexPatternsCheckbox,
openBulkEditDeleteIndexPatternsForm,
} from '../../tasks/rules_bulk_edit';
import { getDetails, assertDetailsNotExist, hasIndexPatterns } from '../../tasks/rule_details';
const DATA_VIEW_ID = 'auditbeat';
const expectedIndexPatterns = ['index-1-*', 'index-2-*'];
const expectedNumberOfCustomRulesToBeEdited = 6;
describe('Bulk editing index patterns of rules with a data view only', () => {
before(() => {
cleanKibana();
@ -64,123 +56,184 @@ describe('Bulk editing index patterns of rules with a data view only', () => {
postDataView(DATA_VIEW_ID);
createRule(getNewRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '1' }));
createRule(getEqlRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '2' }));
createRule(
getNewThreatIndicatorRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '3' })
getNewRule({
index: undefined,
data_view_id: DATA_VIEW_ID,
rule_id: '1',
name: 'New Rule Test 1',
enabled: false,
})
);
createRule(getNewThresholdRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '4' }));
createRule(getNewTermsRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '5' }));
createRule(
getNewRule({ index: undefined, data_view_id: DATA_VIEW_ID, saved_id: 'mocked', rule_id: '6' })
getEqlRule({
index: undefined,
data_view_id: DATA_VIEW_ID,
rule_id: '2',
name: 'New EQL Rule',
enabled: false,
})
);
createRule(
getNewThreatIndicatorRule({
index: undefined,
data_view_id: DATA_VIEW_ID,
rule_id: '3',
name: 'Threat Indicator Rule Test',
enabled: false,
})
);
createRule(
getNewThresholdRule({
index: undefined,
data_view_id: DATA_VIEW_ID,
rule_id: '4',
name: 'Threshold Rule',
enabled: false,
})
);
createRule(
getNewTermsRule({
index: undefined,
data_view_id: DATA_VIEW_ID,
rule_id: '5',
name: 'New Terms Rule',
enabled: false,
})
);
createRule(
getNewRule({
index: undefined,
data_view_id: DATA_VIEW_ID,
saved_id: 'mocked',
rule_id: '6',
name: 'New Rule Test 2',
enabled: false,
})
);
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
visitSecurityDetectionRulesPage();
disableAutoRefresh();
waitForRulesTableToBeLoaded();
expectManagementTableRules([
'New Rule Test 1',
'New EQL Rule',
'Threat Indicator Rule Test',
'Threshold Rule',
'New Terms Rule',
'New Rule Test 2',
]);
});
it('Add index patterns to custom rules with configured data view: all rules are skipped', () => {
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
getRulesManagementTableRows().then((rows) => {
selectAllRules();
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(expectedIndexPatterns);
submitBulkEditForm();
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(expectedIndexPatterns);
submitBulkEditForm();
waitForBulkEditActionToFinish({
skippedCount: expectedNumberOfCustomRulesToBeEdited,
showDataViewsWarning: true,
waitForBulkEditActionToFinish({
skippedCount: rows.length,
showDataViewsWarning: true,
});
// check if rule still has data view and index patterns field does not exist
goToRuleDetails();
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
assertDetailsNotExist(INDEX_PATTERNS_DETAILS);
});
// check if rule still has data view and index patterns field does not exist
goToRuleDetails();
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
assertDetailsNotExist(INDEX_PATTERNS_DETAILS);
});
it('Add index patterns to custom rules with configured data view when data view checkbox is checked: rules are updated', () => {
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
getRulesManagementTableRows().then((rows) => {
selectAllRules();
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(expectedIndexPatterns);
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(expectedIndexPatterns);
// click on data view overwrite checkbox, ensure warning is displayed
cy.get(RULES_BULK_EDIT_DATA_VIEWS_WARNING).should('not.exist');
checkOverwriteDataViewCheckbox();
cy.get(RULES_BULK_EDIT_DATA_VIEWS_WARNING).should('be.visible');
// click on data view overwrite checkbox, ensure warning is displayed
cy.get(RULES_BULK_EDIT_DATA_VIEWS_WARNING).should('not.exist');
checkOverwriteDataViewCheckbox();
cy.get(RULES_BULK_EDIT_DATA_VIEWS_WARNING).should('be.visible');
submitBulkEditForm();
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
waitForBulkEditActionToFinish({ updatedCount: rows.length });
// check if rule has been updated with index patterns and data view does not exist
goToRuleDetails();
hasIndexPatterns(expectedIndexPatterns.join(''));
assertDetailsNotExist(DATA_VIEW_DETAILS);
// check if rule has been updated with index patterns and data view does not exist
goToRuleDetails();
hasIndexPatterns(expectedIndexPatterns.join(''));
assertDetailsNotExist(DATA_VIEW_DETAILS);
});
});
it('Overwrite index patterns in custom rules with configured data view when overwrite data view checkbox is NOT checked:: rules are skipped', () => {
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
getRulesManagementTableRows().then((rows) => {
selectAllRules();
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(expectedIndexPatterns);
checkOverwriteIndexPatternsCheckbox();
submitBulkEditForm();
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(expectedIndexPatterns);
checkOverwriteIndexPatternsCheckbox();
submitBulkEditForm();
waitForBulkEditActionToFinish({
skippedCount: expectedNumberOfCustomRulesToBeEdited,
showDataViewsWarning: true,
waitForBulkEditActionToFinish({
skippedCount: rows.length,
showDataViewsWarning: true,
});
// check if rule still has data view and index patterns field does not exist
goToRuleDetails();
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
assertDetailsNotExist(INDEX_PATTERNS_DETAILS);
});
// check if rule still has data view and index patterns field does not exist
goToRuleDetails();
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
assertDetailsNotExist(INDEX_PATTERNS_DETAILS);
});
it('Overwrite index patterns in custom rules with configured data view when overwrite data view checkbox is checked: rules are updated', () => {
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
getRulesManagementTableRows().then((rows) => {
selectAllRules();
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(expectedIndexPatterns);
checkOverwriteIndexPatternsCheckbox();
checkOverwriteDataViewCheckbox();
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(expectedIndexPatterns);
checkOverwriteIndexPatternsCheckbox();
checkOverwriteDataViewCheckbox();
submitBulkEditForm();
submitBulkEditForm();
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
waitForBulkEditActionToFinish({ updatedCount: rows.length });
// check if rule has been overwritten with index patterns and data view does not exist
goToRuleDetails();
hasIndexPatterns(expectedIndexPatterns.join(''));
assertDetailsNotExist(DATA_VIEW_DETAILS);
// check if rule has been overwritten with index patterns and data view does not exist
goToRuleDetails();
hasIndexPatterns(expectedIndexPatterns.join(''));
assertDetailsNotExist(DATA_VIEW_DETAILS);
});
});
it('Delete index patterns in custom rules with configured data view: rules are skipped', () => {
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
getRulesManagementTableRows().then((rows) => {
selectAllRules();
openBulkEditDeleteIndexPatternsForm();
typeIndexPatterns(expectedIndexPatterns);
openBulkEditDeleteIndexPatternsForm();
typeIndexPatterns(expectedIndexPatterns);
// in delete form data view checkbox is absent
cy.get(RULES_BULK_EDIT_OVERWRITE_DATA_VIEW_CHECKBOX).should('not.exist');
// in delete form data view checkbox is absent
cy.get(RULES_BULK_EDIT_OVERWRITE_DATA_VIEW_CHECKBOX).should('not.exist');
submitBulkEditForm();
submitBulkEditForm();
waitForBulkEditActionToFinish({
skippedCount: expectedNumberOfCustomRulesToBeEdited,
showDataViewsWarning: true,
waitForBulkEditActionToFinish({
skippedCount: rows.length,
showDataViewsWarning: true,
});
// check if rule still has data view and index patterns field does not exist
goToRuleDetails();
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
});
// check if rule still has data view and index patterns field does not exist
goToRuleDetails();
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
});
});
describe('Bulk editing index patterns of rules with index patterns and rules with a data view', () => {
const customRulesNumber = 2;
before(() => {
cleanKibana();
});
@ -197,13 +250,14 @@ describe('Bulk editing index patterns of rules with index patterns and rules wit
);
createRule(getNewRule({ name: 'no data view', index: ['test-index-1-*'], rule_id: '2' }));
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
visitSecurityDetectionRulesPage();
disableAutoRefresh();
waitForRulesTableToBeLoaded();
expectManagementTableRules(['with dataview', 'no data view']);
});
it('Add index patterns to custom rules: one rule is updated, one rule is skipped', () => {
selectNumberOfRules(customRulesNumber);
selectAllRules();
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(expectedIndexPatterns);
@ -222,7 +276,7 @@ describe('Bulk editing index patterns of rules with index patterns and rules wit
});
it('Add index patterns to custom rules when overwrite data view checkbox is checked: all rules are updated', () => {
selectNumberOfRules(customRulesNumber);
selectAllRules();
openBulkEditAddIndexPatternsForm();
typeIndexPatterns(expectedIndexPatterns);

View file

@ -5,118 +5,113 @@
* 2.0.
*/
import { removeExternalLinkText } from '@kbn/securitysolution-io-ts-utils';
import { ruleFields } from '../../data/detection_engine';
import { getNewRule, getExistingRule, getEditedRule, getNewOverrideRule } from '../../objects/rule';
import { getNewRule, getNewOverrideRule, getExistingRule, getEditedRule } from '../../objects/rule';
import { getTimeline } from '../../objects/timeline';
import { ALERTS_COUNT, ALERT_GRID_CELL } from '../../screens/alerts';
import {
CUSTOM_RULES_BTN,
RISK_SCORE,
RULE_NAME,
RULES_ROW,
RULES_MANAGEMENT_TABLE,
RULE_SWITCH,
RISK_SCORE,
SEVERITY,
} from '../../screens/alerts_detection_rules';
ALERTS_COUNT,
ALERT_GRID_CELL,
} from '../../screens/alerts';
import { CUSTOM_RULES_BTN, RULES_MANAGEMENT_TABLE } from '../../screens/alerts_detection_rules';
import {
ACTIONS_NOTIFY_WHEN_BUTTON,
ACTIONS_SUMMARY_BUTTON,
ACTIONS_NOTIFY_WHEN_BUTTON,
} from '../../screens/common/rule_actions';
import {
ABOUT_CONTINUE_BTN,
ABOUT_EDIT_BUTTON,
CUSTOM_QUERY_INPUT,
DEFINE_CONTINUE_BUTTON,
ABOUT_CONTINUE_BTN,
DEFINE_EDIT_BUTTON,
DEFINE_INDEX_INPUT,
DEFAULT_RISK_SCORE_INPUT,
RULE_DESCRIPTION_INPUT,
CUSTOM_QUERY_INPUT,
ABOUT_EDIT_BUTTON,
RULE_NAME_INPUT,
SCHEDULE_CONTINUE_BUTTON,
DEFINE_INDEX_INPUT,
RULE_DESCRIPTION_INPUT,
TAGS_FIELD,
SEVERITY_DROPDOWN,
DEFAULT_RISK_SCORE_INPUT,
SCHEDULE_INTERVAL_AMOUNT_INPUT,
SCHEDULE_INTERVAL_UNITS_INPUT,
SCHEDULE_CONTINUE_BUTTON,
SEVERITY_DROPDOWN,
TAGS_CLEAR_BUTTON,
TAGS_FIELD,
} from '../../screens/create_new_rule';
import {
ADDITIONAL_LOOK_BACK_DETAILS,
ABOUT_DETAILS,
ABOUT_INVESTIGATION_NOTES,
ABOUT_RULE_DESCRIPTION,
CUSTOM_QUERY_DETAILS,
DEFINITION_DETAILS,
FALSE_POSITIVES_DETAILS,
removeExternalLinkText,
INDEX_PATTERNS_DETAILS,
INVESTIGATION_NOTES_MARKDOWN,
INVESTIGATION_NOTES_TOGGLE,
REFERENCE_URLS_DETAILS,
RISK_SCORE_DETAILS,
RULE_SWITCH,
RULE_NAME_HEADER,
RULE_TYPE_DETAILS,
RUNS_EVERY_DETAILS,
SCHEDULE_DETAILS,
ABOUT_RULE_DESCRIPTION,
ABOUT_DETAILS,
SEVERITY_DETAILS,
RISK_SCORE_DETAILS,
REFERENCE_URLS_DETAILS,
FALSE_POSITIVES_DETAILS,
TAGS_DETAILS,
TIMELINE_TEMPLATE_DETAILS,
THREAT_TACTIC,
THREAT_TECHNIQUE,
THREAT_SUBTECHNIQUE,
INVESTIGATION_NOTES_TOGGLE,
ABOUT_INVESTIGATION_NOTES,
INVESTIGATION_NOTES_MARKDOWN,
DEFINITION_DETAILS,
INDEX_PATTERNS_DETAILS,
CUSTOM_QUERY_DETAILS,
RULE_TYPE_DETAILS,
TIMELINE_TEMPLATE_DETAILS,
SCHEDULE_DETAILS,
RUNS_EVERY_DETAILS,
ADDITIONAL_LOOK_BACK_DETAILS,
} from '../../screens/rule_details';
import {
deleteFirstRule,
deleteRuleFromDetailsPage,
deleteSelectedRules,
editFirstRule,
expectManagementTableRules,
goToRuleDetails,
selectNumberOfRules,
getRulesManagementTableRows,
deleteFirstRule,
selectRulesByName,
goToTheRuleDetailsOf,
deleteRuleFromDetailsPage,
editFirstRule,
} from '../../tasks/alerts_detection_rules';
import { createRule } from '../../tasks/api_calls/rules';
import { createTimeline } from '../../tasks/api_calls/timelines';
import { cleanKibana, deleteAlertsAndRules, deleteConnectors } from '../../tasks/common';
import { deleteAlertsAndRules, deleteConnectors } from '../../tasks/common';
import { addEmailConnectorAndRuleAction } from '../../tasks/common/rule_actions';
import {
createAndEnableRule,
expandAdvancedSettings,
fillAboutRule,
fillDescription,
fillFalsePositiveExamples,
fillFrom,
fillNote,
fillReferenceUrls,
fillRiskScore,
fillRuleName,
fillRuleTags,
fillSeverity,
fillThreat,
fillThreatSubtechnique,
fillThreatTechnique,
goToAboutStepTab,
goToActionsStepTab,
goToScheduleStepTab,
importSavedQuery,
fillRuleName,
fillDescription,
fillSeverity,
fillRiskScore,
fillRuleTags,
expandAdvancedSettings,
fillReferenceUrls,
fillFalsePositiveExamples,
fillThreat,
fillThreatTechnique,
fillThreatSubtechnique,
fillNote,
fillFrom,
createAndEnableRule,
waitForAlertsToPopulate,
waitForTheRuleToBeExecuted,
goToAboutStepTab,
goToScheduleStepTab,
goToActionsStepTab,
fillAboutRule,
} from '../../tasks/create_new_rule';
import { saveEditedRule } from '../../tasks/edit_rule';
import { login, visit } from '../../tasks/login';
import { enablesRule, getDetails } from '../../tasks/rule_details';
import { RULE_CREATION, DETECTIONS_RULE_MANAGEMENT_URL } from '../../urls/navigation';
import { login, visit, visitSecurityDetectionRulesPage } from '../../tasks/login';
import { deleteSelectedRules } from '../../tasks/rules_bulk_edit';
import { getDetails, waitForTheRuleToBeExecuted, enablesRule } from '../../tasks/rule_details';
import { RULE_CREATION } from '../../urls/navigation';
describe('Custom query rules', () => {
before(() => {
cleanKibana();
beforeEach(() => {
deleteAlertsAndRules();
});
describe('Custom detection rules creation', () => {
const expectedNumberOfRules = 1;
beforeEach(() => {
deleteAlertsAndRules();
createTimeline(getTimeline())
.then((response) => {
return response.body.data.persistTimeline.timeline.savedObjectId;
@ -133,7 +128,7 @@ describe('Custom query rules', () => {
cy.get(DEFINE_CONTINUE_BUTTON).click();
cy.log('Filling about section');
fillRuleName();
fillRuleName('Test Rule');
fillDescription();
fillSeverity();
fillRiskScore();
@ -167,7 +162,7 @@ describe('Custom query rules', () => {
cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)');
cy.log('Asserting rule view in rules list');
cy.get(RULES_MANAGEMENT_TABLE).find(RULES_ROW).should('have.length', expectedNumberOfRules);
expectManagementTableRules(['Test Rule']);
cy.get(RULE_NAME).should('have.text', ruleFields.ruleName);
cy.get(RISK_SCORE).should('have.text', ruleFields.riskScore);
cy.get(SEVERITY)
@ -234,109 +229,104 @@ describe('Custom query rules', () => {
describe('Custom detection rules deletion and edition', () => {
context('Deletion', () => {
beforeEach(() => {
deleteAlertsAndRules();
createRule(getNewRule({ rule_id: 'rule1', enabled: true, max_signals: 500 }));
createRule(getNewOverrideRule({ rule_id: 'rule2', enabled: true, max_signals: 500 }));
createRule(getExistingRule({ rule_id: 'rule3', enabled: true }));
createRule(
getNewRule({ rule_id: 'rule1', name: 'New Rule Test', enabled: false, max_signals: 500 })
);
createRule(
getNewOverrideRule({
rule_id: 'rule2',
name: 'Override Rule',
enabled: false,
max_signals: 500,
})
);
createRule(getExistingRule({ rule_id: 'rule3', name: 'Rule 1', enabled: false }));
login();
visit(DETECTIONS_RULE_MANAGEMENT_URL);
visitSecurityDetectionRulesPage();
});
it('Deletes one rule', () => {
cy.get(RULES_MANAGEMENT_TABLE)
.find(RULES_ROW)
.then((rules) => {
const initialNumberOfRules = rules.length;
const expectedNumberOfRulesAfterDeletion = initialNumberOfRules - 1;
getRulesManagementTableRows().then((rules) => {
const initialNumberOfRules = rules.length;
const expectedNumberOfRulesAfterDeletion = initialNumberOfRules - 1;
cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => {
const numberOfRules = body.data.length;
expect(numberOfRules).to.eql(initialNumberOfRules);
});
deleteFirstRule();
cy.get(RULES_MANAGEMENT_TABLE)
.find(RULES_ROW)
.should('have.length', expectedNumberOfRulesAfterDeletion);
cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => {
const numberOfRules = body.data.length;
expect(numberOfRules).to.eql(expectedNumberOfRulesAfterDeletion);
});
cy.get(CUSTOM_RULES_BTN).should(
'have.text',
`Custom rules (${expectedNumberOfRulesAfterDeletion})`
);
cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => {
const numberOfRules = body.data.length;
expect(numberOfRules).to.eql(initialNumberOfRules);
});
deleteFirstRule();
getRulesManagementTableRows().should('have.length', expectedNumberOfRulesAfterDeletion);
cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => {
const numberOfRules = body.data.length;
expect(numberOfRules).to.eql(expectedNumberOfRulesAfterDeletion);
});
cy.get(CUSTOM_RULES_BTN).should(
'have.text',
`Custom rules (${expectedNumberOfRulesAfterDeletion})`
);
});
});
it('Deletes more than one rule', () => {
cy.get(RULES_MANAGEMENT_TABLE)
.find(RULES_ROW)
.then((rules) => {
const initialNumberOfRules = rules.length;
const numberOfRulesToBeDeleted = 2;
const expectedNumberOfRulesAfterDeletion =
initialNumberOfRules - numberOfRulesToBeDeleted;
getRulesManagementTableRows().then((rules) => {
const rulesToDelete = ['New Rule Test', 'Override Rule'] as const;
const initialNumberOfRules = rules.length;
const numberOfRulesToBeDeleted = 2;
const expectedNumberOfRulesAfterDeletion =
initialNumberOfRules - numberOfRulesToBeDeleted;
selectNumberOfRules(numberOfRulesToBeDeleted);
deleteSelectedRules();
selectRulesByName(rulesToDelete);
deleteSelectedRules();
cy.get(RULES_MANAGEMENT_TABLE)
.get(RULES_ROW)
.first()
.within(() => {
cy.get(RULE_SWITCH).should('not.exist');
});
getRulesManagementTableRows()
.first()
.within(() => {
cy.get(RULE_SWITCH).should('not.exist');
});
cy.get(RULES_MANAGEMENT_TABLE)
.find(RULES_ROW)
.should('have.length', expectedNumberOfRulesAfterDeletion);
getRulesManagementTableRows().should('have.length', expectedNumberOfRulesAfterDeletion);
cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => {
const numberOfRules = body.data.length;
expect(numberOfRules).to.eql(expectedNumberOfRulesAfterDeletion);
});
getRulesManagementTableRows()
.first()
.within(() => {
cy.get(RULE_SWITCH).should('exist');
});
cy.get(CUSTOM_RULES_BTN).should(
'have.text',
`Custom rules (${expectedNumberOfRulesAfterDeletion})`
);
});
});
it('Deletes one rule from detail page', () => {
getRulesManagementTableRows().then((rules) => {
const initialNumberOfRules = rules.length;
const expectedNumberOfRulesAfterDeletion = initialNumberOfRules - 1;
goToTheRuleDetailsOf('New Rule Test');
cy.intercept('POST', '/api/detection_engine/rules/_bulk_delete').as('deleteRule');
deleteRuleFromDetailsPage();
// @ts-expect-error update types
cy.waitFor('@deleteRule').then(() => {
cy.get(RULES_MANAGEMENT_TABLE).should('exist');
getRulesManagementTableRows().should('have.length', expectedNumberOfRulesAfterDeletion);
cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => {
const numberOfRules = body.data.length;
expect(numberOfRules).to.eql(expectedNumberOfRulesAfterDeletion);
});
cy.get(RULES_MANAGEMENT_TABLE)
.get(RULES_ROW)
.first()
.within(() => {
cy.get(RULE_SWITCH).should('exist');
});
cy.get(CUSTOM_RULES_BTN).should(
'have.text',
`Custom rules (${expectedNumberOfRulesAfterDeletion})`
);
});
});
it('Deletes one rule from detail page', () => {
cy.get(RULES_MANAGEMENT_TABLE)
.find(RULES_ROW)
.then((rules) => {
const initialNumberOfRules = rules.length;
const expectedNumberOfRulesAfterDeletion = initialNumberOfRules - 1;
goToRuleDetails();
cy.intercept('POST', '/api/detection_engine/rules/_bulk_delete').as('deleteRule');
deleteRuleFromDetailsPage();
// @ts-expect-error update types
cy.waitFor('@deleteRule').then(() => {
cy.get(RULES_MANAGEMENT_TABLE).should('exist');
cy.get(RULES_MANAGEMENT_TABLE)
.find(RULES_ROW)
.should('have.length', expectedNumberOfRulesAfterDeletion);
cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => {
const numberOfRules = body.data.length;
expect(numberOfRules).to.eql(expectedNumberOfRulesAfterDeletion);
});
cy.get(CUSTOM_RULES_BTN).should(
'have.text',
`Custom rules (${expectedNumberOfRulesAfterDeletion})`
);
});
});
});
});
});
@ -345,15 +335,11 @@ describe('Custom query rules', () => {
const expectedEditedtags = rule.tags?.join('');
const expectedEditedIndexPatterns = rule.index;
before(() => {
deleteAlertsAndRules();
beforeEach(() => {
deleteConnectors();
createRule(getExistingRule({ rule_id: 'rule1', enabled: true }));
});
beforeEach(() => {
login();
visit(DETECTIONS_RULE_MANAGEMENT_URL);
visitSecurityDetectionRulesPage();
});
it('Only modifies rule active status on enable/disable', () => {

View file

@ -13,8 +13,6 @@ import {
CUSTOM_RULES_BTN,
RISK_SCORE,
RULE_NAME,
RULES_ROW,
RULES_MANAGEMENT_TABLE,
RULE_SWITCH,
SEVERITY,
} from '../../screens/alerts_detection_rules';
@ -50,7 +48,7 @@ import {
EDIT_RULE_SETTINGS_LINK,
} from '../../screens/rule_details';
import { goToRuleDetails } from '../../tasks/alerts_detection_rules';
import { getRulesManagementTableRows, goToRuleDetails } from '../../tasks/alerts_detection_rules';
import { postDataView } from '../../tasks/common';
import {
createAndEnableRule,
@ -99,7 +97,7 @@ describe('Custom query rules', () => {
cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)');
cy.get(RULES_MANAGEMENT_TABLE).find(RULES_ROW).should('have.length', expectedNumberOfRules);
getRulesManagementTableRows().should('have.length', expectedNumberOfRules);
cy.get(RULE_NAME).should('have.text', rule.name);
cy.get(RISK_SCORE).should('have.text', rule.risk_score);
cy.get(SEVERITY).should('have.text', 'High');

View file

@ -16,13 +16,12 @@ import {
} from '../../screens/alerts_detection_rules';
import {
filterByElasticRules,
selectNumberOfRules,
bulkExportRules,
selectAllRules,
waitForRuleExecution,
exportRule,
importRules,
expectManagementTableRules,
bulkExportRules,
} from '../../tasks/alerts_detection_rules';
import { createExceptionList, deleteExceptionList } from '../../tasks/api_calls/exceptions';
import { getExceptionList } from '../../objects/exception';
@ -70,7 +69,7 @@ describe('Export rules', () => {
// Prevent installation of whole prebuilt rules package, use mock prebuilt rules instead
preventPrebuiltRulesPackageInstallation();
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
createRule(getNewRule({ name: 'Rule to export' })).as('ruleResponse');
createRule(getNewRule({ name: 'Rule to export', enabled: false })).as('ruleResponse');
});
it('exports a custom rule', function () {
@ -102,7 +101,7 @@ describe('Export rules', () => {
createAndInstallMockedPrebuiltRules({ rules: prebuiltRules });
filterByElasticRules();
selectNumberOfRules(prebuiltRules.length);
selectAllRules();
bulkExportRules();
cy.get(MODAL_CONFIRMATION_BODY).contains(
@ -156,6 +155,7 @@ describe('Export rules', () => {
},
],
rule_id: '2',
enabled: false,
})
)
);

View file

@ -60,10 +60,9 @@ import {
duplicateFirstRule,
duplicateRuleFromMenu,
goToRuleDetails,
selectNumberOfRules,
checkDuplicatedRule,
expectNumberOfRules,
duplicateSelectedRulesWithExceptions,
selectAllRules,
} from '../../tasks/alerts_detection_rules';
import { createRule } from '../../tasks/api_calls/rules';
import { loadPrepackagedTimelineTemplates } from '../../tasks/api_calls/timelines';
@ -106,6 +105,7 @@ import { login, visit, visitWithoutDateRange } from '../../tasks/login';
import { goBackToRulesTable, getDetails } from '../../tasks/rule_details';
import { DETECTIONS_RULE_MANAGEMENT_URL, RULE_CREATION } from '../../urls/navigation';
import { duplicateSelectedRulesWithExceptions } from '../../tasks/rules_bulk_edit';
const DEFAULT_THREAT_MATCH_QUERY = '@timestamp >= "now-30d/d"';
@ -554,7 +554,7 @@ describe('indicator match', () => {
});
it("Allows the rule to be duplicated from the table's bulk actions", () => {
selectNumberOfRules(1);
selectAllRules();
duplicateSelectedRulesWithExceptions();
checkDuplicatedRule();
});

View file

@ -20,7 +20,7 @@ describe('Rules talbes links', () => {
beforeEach(() => {
login();
deleteAlertsAndRules();
createRule(getNewRule({ rule_id: 'rule1' }));
createRule(getNewRule({ rule_id: 'rule1', enabled: false }));
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
});

View file

@ -7,7 +7,6 @@
import { APP_PATH, RULES_ADD_PATH, RULES_UPDATES } from '../../../common/constants';
import { createRuleAssetSavedObject } from '../../helpers/rules';
import { waitForRulesTableToBeLoaded } from '../../tasks/alerts_detection_rules';
import { createAndInstallMockedPrebuiltRules } from '../../tasks/api_calls/prebuilt_rules';
import { resetRulesTableState, deleteAlertsAndRules } from '../../tasks/common';
import { esArchiverResetKibana } from '../../tasks/es_archiver';
@ -58,7 +57,6 @@ describe('Detection rules, Prebuilt Rules Installation and Update - Authorizatio
resetRulesTableState();
deleteAlertsAndRules();
esArchiverResetKibana();
waitForRulesTableToBeLoaded();
createAndInstallMockedPrebuiltRules({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
});
@ -75,7 +73,6 @@ describe('Detection rules, Prebuilt Rules Installation and Update - Authorizatio
// Now login with read-only user in preparation for test
createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false });
loadPageAsReadOnlyUser(SECURITY_DETECTIONS_RULES_URL);
waitForRulesTableToBeLoaded();
});
it('should not be able to install prebuilt rules', () => {
@ -103,7 +100,6 @@ describe('Detection rules, Prebuilt Rules Installation and Update - Authorizatio
});
// Now login with read-only user in preparation for test
loadPageAsReadOnlyUser(SECURITY_DETECTIONS_RULES_URL);
waitForRulesTableToBeLoaded();
});
it('should not be able to upgrade prebuilt rules', () => {

View file

@ -6,23 +6,21 @@
*/
import { createRuleAssetSavedObject } from '../../helpers/rules';
import { waitForRulesTableToBeLoaded } from '../../tasks/alerts_detection_rules';
import { createAndInstallMockedPrebuiltRules } from '../../tasks/api_calls/prebuilt_rules';
import { resetRulesTableState, deleteAlertsAndRules, reload } from '../../tasks/common';
import { esArchiverResetKibana } from '../../tasks/es_archiver';
import { login, visitWithoutDateRange } from '../../tasks/login';
import { SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
import { login, visitSecurityDetectionRulesPage } from '../../tasks/login';
import {
addElasticRulesButtonClick,
assertRuleAvailableForInstallAndInstallOne,
assertRuleAvailableForInstallAndInstallSelected,
assertRuleAvailableForInstallAndInstallAllInPage,
assertRuleAvailableForInstallAndInstallAll,
ruleUpdatesTabClick,
assertRuleUpgradeAvailableAndUpgradeOne,
assertRuleUpgradeAvailableAndUpgradeSelected,
assertRuleUpgradeAvailableAndUpgradeAllInPage,
assertRuleUpgradeAvailableAndUpgradeAll,
ruleUpdatesTabClick,
} from '../../tasks/prebuilt_rules';
describe('Detection rules, Prebuilt Rules Installation and Update - Error handling', () => {
@ -32,7 +30,7 @@ describe('Detection rules, Prebuilt Rules Installation and Update - Error handli
deleteAlertsAndRules();
esArchiverResetKibana();
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
visitSecurityDetectionRulesPage();
});
describe('Installation of prebuilt rules - Should fail gracefully with toast error message when', () => {
@ -46,7 +44,6 @@ describe('Detection rules, Prebuilt Rules Installation and Update - Error handli
});
beforeEach(() => {
createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false });
waitForRulesTableToBeLoaded();
});
it('installing prebuilt rules one by one', () => {
@ -72,7 +69,10 @@ describe('Detection rules, Prebuilt Rules Installation and Update - Error handli
it('installing all available rules at once', () => {
addElasticRulesButtonClick();
assertRuleAvailableForInstallAndInstallAll({ rules: [RULE_1, RULE_2], didRequestFail: true });
assertRuleAvailableForInstallAndInstallAll({
rules: [RULE_1, RULE_2],
didRequestFail: true,
});
});
});
@ -107,7 +107,6 @@ describe('Detection rules, Prebuilt Rules Installation and Update - Error handli
rules: [UPDATED_RULE_1, UPDATED_RULE_2],
installToKibana: false,
});
waitForRulesTableToBeLoaded();
reload();
});

View file

@ -9,37 +9,35 @@ import type { BulkInstallPackageInfo } from '@kbn/fleet-plugin/common';
import type { Rule } from '../../../public/detection_engine/rule_management/logic/types';
import { createRuleAssetSavedObject } from '../../helpers/rules';
import {
GO_BACK_TO_RULES_TABLE_BUTTON,
INSTALL_ALL_RULES_BUTTON,
INSTALL_SELECTED_RULES_BUTTON,
NO_RULES_AVAILABLE_FOR_INSTALL_MESSSAGE,
NO_RULES_AVAILABLE_FOR_UPGRADE_MESSSAGE,
RULES_UPDATES_TAB,
RULE_CHECKBOX,
SELECT_ALL_RULES_ON_PAGE_CHECKBOX,
TOASTER,
RULE_CHECKBOX,
NO_RULES_AVAILABLE_FOR_INSTALL_MESSSAGE,
GO_BACK_TO_RULES_TABLE_BUTTON,
SELECT_ALL_RULES_ON_PAGE_CHECKBOX,
INSTALL_SELECTED_RULES_BUTTON,
RULES_UPDATES_TAB,
NO_RULES_AVAILABLE_FOR_UPGRADE_MESSSAGE,
} from '../../screens/alerts_detection_rules';
import { waitForRulesTableToBeLoaded } from '../../tasks/alerts_detection_rules';
import {
createAndInstallMockedPrebuiltRules,
getRuleAssets,
createAndInstallMockedPrebuiltRules,
} from '../../tasks/api_calls/prebuilt_rules';
import { deleteAlertsAndRules, reload, resetRulesTableState } from '../../tasks/common';
import { resetRulesTableState, deleteAlertsAndRules, reload } from '../../tasks/common';
import { esArchiverResetKibana } from '../../tasks/es_archiver';
import { login, visitWithoutDateRange } from '../../tasks/login';
import { login, visitSecurityDetectionRulesPage } from '../../tasks/login';
import {
addElasticRulesButtonClick,
assertRuleAvailableForInstallAndInstallOne,
assertRuleAvailableForInstallAndInstallSelected,
assertRuleAvailableForInstallAndInstallAllInPage,
assertRuleAvailableForInstallAndInstallAll,
ruleUpdatesTabClick,
assertRuleUpgradeAvailableAndUpgradeOne,
assertRuleUpgradeAvailableAndUpgradeSelected,
assertRuleUpgradeAvailableAndUpgradeAllInPage,
assertRuleUpgradeAvailableAndUpgradeAll,
ruleUpdatesTabClick,
} from '../../tasks/prebuilt_rules';
import { SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
describe('Detection rules, Prebuilt Rules Installation and Update workflow', () => {
beforeEach(() => {
@ -48,7 +46,7 @@ describe('Detection rules, Prebuilt Rules Installation and Update workflow', ()
deleteAlertsAndRules();
esArchiverResetKibana();
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
visitSecurityDetectionRulesPage();
});
describe('Installation of prebuilt rules package via Fleet', () => {
@ -57,7 +55,6 @@ describe('Detection rules, Prebuilt Rules Installation and Update workflow', ()
cy.intercept('POST', '/api/fleet/epm/packages/security_detection_engine/*').as(
'installPackage'
);
waitForRulesTableToBeLoaded();
});
it('should install package from Fleet in the background', () => {
@ -146,7 +143,6 @@ describe('Detection rules, Prebuilt Rules Installation and Update workflow', ()
});
beforeEach(() => {
createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false });
waitForRulesTableToBeLoaded();
cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/installation/_perform').as(
'installPrebuiltRules'
);
@ -228,7 +224,6 @@ describe('Detection rules, Prebuilt Rules Installation and Update workflow', ()
rules: [UPDATED_RULE_1, UPDATED_RULE_2],
installToKibana: false,
});
waitForRulesTableToBeLoaded();
reload();
});
@ -244,7 +239,9 @@ describe('Detection rules, Prebuilt Rules Installation and Update workflow', ()
it('should upgrade multiple selected prebuilt rules by selecting all in page', () => {
ruleUpdatesTabClick();
assertRuleUpgradeAvailableAndUpgradeAllInPage({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
assertRuleUpgradeAvailableAndUpgradeAllInPage({
rules: [OUTDATED_RULE_1, OUTDATED_RULE_2],
});
});
it('should upgrade all rules with available upgrades at once', () => {

View file

@ -12,8 +12,6 @@ import {
ADD_ELASTIC_RULES_BTN,
RULES_EMPTY_PROMPT,
RULES_MONITORING_TAB,
RULES_ROW,
RULES_MANAGEMENT_TABLE,
RULE_SWITCH,
SELECT_ALL_RULES_ON_PAGE_CHECKBOX,
INSTALL_ALL_RULES_BUTTON,
@ -21,12 +19,10 @@ import {
import {
confirmRulesDelete,
deleteFirstRule,
deleteSelectedRules,
disableAutoRefresh,
disableSelectedRules,
enableSelectedRules,
getRulesManagementTableRows,
selectAllRules,
selectNumberOfRules,
selectRulesByName,
waitForPrebuiltDetectionRulesToBeLoaded,
waitForRuleToUpdate,
} from '../../tasks/alerts_detection_rules';
@ -37,6 +33,11 @@ import {
} from '../../tasks/api_calls/prebuilt_rules';
import { cleanKibana, deleteAlertsAndRules, deletePrebuiltRulesAssets } from '../../tasks/common';
import { login, visitWithoutDateRange } from '../../tasks/login';
import {
enableSelectedRules,
disableSelectedRules,
deleteSelectedRules,
} from '../../tasks/rules_bulk_edit';
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../urls/navigation';
const rules = Array.from(Array(5)).map((_, i) => {
@ -66,7 +67,7 @@ describe('Prebuilt rules', () => {
describe('Alerts rules, prebuilt rules', () => {
it('Loads prebuilt rules', () => {
// Check that the rules table contains rules
cy.get(RULES_MANAGEMENT_TABLE).find(RULES_ROW).should('have.length.gte', 1);
getRulesManagementTableRows().should('have.length.gte', 1);
// Check the correct count of prebuilt rules is displayed
getAvailablePrebuiltRulesCount().then((availablePrebuiltRulesCount) => {
@ -108,8 +109,7 @@ describe('Prebuilt rules', () => {
});
it('Does not allow to delete one rule when more than one is selected', () => {
const numberOfRulesToBeSelected = 2;
selectNumberOfRules(numberOfRulesToBeSelected);
selectAllRules();
cy.get(COLLAPSED_ACTION_BTN).each((collapsedItemActionBtn) => {
cy.wrap(collapsedItemActionBtn).should('have.attr', 'disabled');
@ -150,16 +150,16 @@ describe('Prebuilt rules', () => {
it('Deletes and recovers more than one rule', () => {
getAvailablePrebuiltRulesCount().then((availablePrebuiltRulesCount) => {
const numberOfRulesToBeSelected = 2;
const rulesToDelete = ['Test rule 1', 'Test rule 2'] as const;
const expectedNumberOfRulesAfterDeletion = availablePrebuiltRulesCount - 2;
const expectedNumberOfRulesAfterRecovering = availablePrebuiltRulesCount;
selectNumberOfRules(numberOfRulesToBeSelected);
selectRulesByName(rulesToDelete);
deleteSelectedRules();
cy.get(ADD_ELASTIC_RULES_BTN).should(
'have.text',
`Add Elastic rules${numberOfRulesToBeSelected}`
`Add Elastic rules${rulesToDelete.length}`
);
cy.get(ELASTIC_RULES_BTN).should(
'have.text',

View file

@ -6,20 +6,23 @@
*/
import { createRuleAssetSavedObject } from '../../helpers/rules';
import { ADD_ELASTIC_RULES_BTN, RULES_UPDATES_TAB } from '../../screens/alerts_detection_rules';
import { deleteFirstRule, waitForRulesTableToBeLoaded } from '../../tasks/alerts_detection_rules';
import {
installAllPrebuiltRulesRequest,
ADD_ELASTIC_RULES_EMPTY_PROMPT_BTN,
RULES_UPDATES_TAB,
ADD_ELASTIC_RULES_BTN,
} from '../../screens/alerts_detection_rules';
import { deleteFirstRule } from '../../tasks/alerts_detection_rules';
import {
createAndInstallMockedPrebuiltRules,
installAllPrebuiltRulesRequest,
} from '../../tasks/api_calls/prebuilt_rules';
import {
resetRulesTableState,
deleteAlertsAndRules,
reload,
deletePrebuiltRulesAssets,
reload,
} from '../../tasks/common';
import { login, visitWithoutDateRange } from '../../tasks/login';
import { SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
import { login, visitSecurityDetectionRulesPage } from '../../tasks/login';
const RULE_1 = createRuleAssetSavedObject({
name: 'Test rule 1',
@ -37,8 +40,10 @@ describe('Detection rules, Prebuilt Rules Installation and Update Notifications'
describe('No notifications', () => {
it('should NOT display install or update notifications when no prebuilt assets and no rules are installed', () => {
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
waitForRulesTableToBeLoaded();
visitSecurityDetectionRulesPage();
cy.get(ADD_ELASTIC_RULES_EMPTY_PROMPT_BTN).should('be.visible');
// TODO: test plan asserts "should NOT see a CTA to install prebuilt rules"
// but current behavior is to always show the CTA, even with no prebuilt rule assets installed
// Update that behaviour and then update this test.
@ -47,8 +52,7 @@ describe('Detection rules, Prebuilt Rules Installation and Update Notifications'
it('should NOT display install or update notifications when latest rules are installed', () => {
createAndInstallMockedPrebuiltRules({ rules: [RULE_1], installToKibana: true });
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
waitForRulesTableToBeLoaded();
visitSecurityDetectionRulesPage();
/* Assert that there are no installation or update notifications */
/* Add Elastic Rules button should not contain a number badge */
@ -65,7 +69,7 @@ describe('Detection rules, Prebuilt Rules Installation and Update Notifications'
describe('Rules installation notification when no rules have been installed', () => {
beforeEach(() => {
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
visitSecurityDetectionRulesPage();
});
it('should notify user about prebuilt rules available for installation', () => {
@ -89,9 +93,11 @@ describe('Detection rules, Prebuilt Rules Installation and Update Notifications'
rule_id: 'rule_3',
});
createAndInstallMockedPrebuiltRules({ rules: [RULE_2, RULE_3], installToKibana: false });
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
waitForRulesTableToBeLoaded();
createAndInstallMockedPrebuiltRules({
rules: [RULE_2, RULE_3],
installToKibana: false,
});
visitSecurityDetectionRulesPage();
});
});
@ -128,8 +134,7 @@ describe('Detection rules, Prebuilt Rules Installation and Update Notifications'
version: 2,
});
createAndInstallMockedPrebuiltRules({ rules: [UPDATED_RULE], installToKibana: false });
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
waitForRulesTableToBeLoaded();
visitSecurityDetectionRulesPage();
reload();
});
});
@ -163,8 +168,7 @@ describe('Detection rules, Prebuilt Rules Installation and Update Notifications'
rules: [RULE_2, UPDATED_RULE],
installToKibana: false,
});
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
waitForRulesTableToBeLoaded();
visitSecurityDetectionRulesPage();
});
});

View file

@ -6,7 +6,7 @@
*/
import { cleanKibana, resetRulesTableState, deleteAlertsAndRules } from '../../tasks/common';
import { login, visitWithoutDateRange } from '../../tasks/login';
import { login, visitSecurityDetectionRulesPage } from '../../tasks/login';
import { esArchiverResetKibana } from '../../tasks/es_archiver';
import {
expectRulesWithExecutionStatus,
@ -14,14 +14,10 @@ import {
expectNumberOfRulesShownOnPage,
} from '../../tasks/rule_filters';
import { SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
import { waitForRulesTableToBeLoaded } from '../../tasks/alerts_detection_rules';
import { createRule, waitForRulesToFinishExecution } from '../../tasks/api_calls/rules';
import { deleteIndex, createIndex, createDocument } from '../../tasks/api_calls/elasticsearch';
import { getNewRule } from '../../objects/rule';
import { disableAutoRefresh } from '../../tasks/alerts_detection_rules';
describe('Rule management filters', () => {
before(() => {
@ -53,6 +49,7 @@ describe('Rule management filters', () => {
name: 'Successful rule',
rule_id: 'successful_rule',
index: ['test_index'],
enabled: true,
})
);
@ -61,6 +58,7 @@ describe('Rule management filters', () => {
name: 'Warning rule',
rule_id: 'warning_rule',
index: ['non_existent_index'],
enabled: true,
})
);
@ -71,14 +69,14 @@ describe('Rule management filters', () => {
index: ['test_index'],
// Setting a crazy large "Additional look-back time" to force a failure
from: 'now-9007199254746990s',
enabled: true,
})
);
waitForRulesToFinishExecution(['successful_rule', 'warning_rule', 'failed_rule'], new Date());
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
waitForRulesTableToBeLoaded();
visitSecurityDetectionRulesPage();
disableAutoRefresh();
// Initial table state - before filtering by status
expectNumberOfRulesShownOnPage(3);

View file

@ -7,35 +7,39 @@
import { INTERNAL_ALERTING_API_FIND_RULES_PATH } from '@kbn/alerting-plugin/common';
import type { RuleResponse } from '../../../common/detection_engine/rule_schema';
import { getNewRule } from '../../objects/rule';
import { RULE_NAME } from '../../screens/alerts';
import { RULES_MANAGEMENT_TABLE } from '../../screens/alerts_detection_rules';
import { TOOLTIP } from '../../screens/common';
import { ACTIONS } from '../../screens/rule_details';
import { DISABLED_SNOOZE_BADGE } from '../../screens/rule_snoozing';
import {
disableAutoRefresh,
duplicateFirstRule,
importRules,
} from '../../tasks/alerts_detection_rules';
import { createSlackConnector } from '../../tasks/api_calls/connectors';
import { createRule, snoozeRule as snoozeRuleViaAPI } from '../../tasks/api_calls/rules';
import { cleanKibana, deleteAlertsAndRules, deleteConnectors } from '../../tasks/common';
import { login, visitWithoutDateRange } from '../../tasks/login';
import { getNewRule } from '../../objects/rule';
import { ruleDetailsUrl, ruleEditUrl, SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
import { internalAlertingSnoozeRule } from '../../urls/routes';
import { RULES_MANAGEMENT_TABLE, RULE_NAME } from '../../screens/alerts_detection_rules';
import {
expectRuleSnoozed,
expectRuleSnoozedInTable,
expectRuleUnsnoozed,
expectRuleUnsnoozedInTable,
expectSnoozeErrorToast,
expectSnoozeSuccessToast,
expectUnsnoozeSuccessToast,
snoozeRule,
snoozeRuleInTable,
unsnoozeRuleInTable,
} from '../../tasks/rule_snoozing';
import { createSlackConnector } from '../../tasks/api_calls/connectors';
import { duplicateFirstRule, importRules } from '../../tasks/alerts_detection_rules';
import { goToActionsStepTab } from '../../tasks/create_new_rule';
import { goToRuleEditSettings } from '../../tasks/rule_details';
import { actionFormSelector } from '../../screens/common/rule_actions';
import { RULE_INDICES } from '../../screens/create_new_rule';
import { addEmailConnectorAndRuleAction } from '../../tasks/common/rule_actions';
import { goToActionsStepTab } from '../../tasks/create_new_rule';
import { saveEditedRule } from '../../tasks/edit_rule';
import { DISABLED_SNOOZE_BADGE } from '../../screens/rule_snoozing';
import { TOOLTIP } from '../../screens/common';
import { login, visitSecurityDetectionRulesPage, visitWithoutDateRange } from '../../tasks/login';
import { goToRuleEditSettings } from '../../tasks/rule_details';
import {
snoozeRuleInTable,
expectRuleSnoozed,
expectSnoozeSuccessToast,
expectRuleSnoozedInTable,
unsnoozeRuleInTable,
expectUnsnoozeSuccessToast,
expectRuleUnsnoozedInTable,
snoozeRule,
expectSnoozeErrorToast,
expectRuleUnsnoozed,
} from '../../tasks/rule_snoozing';
import { ruleEditUrl, ruleDetailsUrl } from '../../urls/navigation';
import { internalAlertingSnoozeRule } from '../../urls/routes';
const RULES_TO_IMPORT_FILENAME = 'cypress/fixtures/7_16_rules.ndjson';
@ -50,9 +54,10 @@ describe('rule snoozing', () => {
});
it('ensures the rule is snoozed on the rules management page, rule details page and rule editing page', () => {
createRule(getNewRule({ name: 'Test on all pages' }));
createRule(getNewRule({ name: 'Test on all pages', enabled: false }));
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
visitSecurityDetectionRulesPage();
disableAutoRefresh();
snoozeRuleInTable({
tableSelector: RULES_MANAGEMENT_TABLE,
@ -74,9 +79,10 @@ describe('rule snoozing', () => {
describe('Rules management table', () => {
it('snoozes a rule without actions for 3 hours', () => {
createRule(getNewRule({ name: 'Test rule without actions' }));
createRule(getNewRule({ name: 'Test rule without actions', enabled: false }));
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
visitSecurityDetectionRulesPage();
disableAutoRefresh();
snoozeRuleInTable({
tableSelector: RULES_MANAGEMENT_TABLE,
@ -95,7 +101,8 @@ describe('rule snoozing', () => {
it('snoozes a rule with actions for 2 days', () => {
createRuleWithActions({ name: 'Test rule with actions' }, createRule);
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
visitSecurityDetectionRulesPage();
disableAutoRefresh();
snoozeRuleInTable({
tableSelector: RULES_MANAGEMENT_TABLE,
@ -114,7 +121,8 @@ describe('rule snoozing', () => {
it('unsnoozes a rule with actions', () => {
createSnoozedRule(getNewRule({ name: 'Snoozed rule' }));
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
visitSecurityDetectionRulesPage();
disableAutoRefresh();
unsnoozeRuleInTable({
tableSelector: RULES_MANAGEMENT_TABLE,
@ -129,9 +137,10 @@ describe('rule snoozing', () => {
});
it('ensures snooze settings persist after page reload', () => {
createRule(getNewRule({ name: 'Test persistence' }));
createRule(getNewRule({ name: 'Test persistence', enabled: false }));
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
visitSecurityDetectionRulesPage();
disableAutoRefresh();
snoozeRuleInTable({
tableSelector: RULES_MANAGEMENT_TABLE,
@ -149,14 +158,16 @@ describe('rule snoozing', () => {
});
it('ensures a duplicated rule is not snoozed', () => {
createRule(getNewRule({ name: 'Test rule' }));
createRule(getNewRule({ name: 'Test rule', enabled: false }));
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
visitSecurityDetectionRulesPage();
disableAutoRefresh();
duplicateFirstRule();
// Make sure rules table is shown as it navigates to rule editing page after successful duplication
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
visitSecurityDetectionRulesPage();
disableAutoRefresh();
expectRuleUnsnoozedInTable({
tableSelector: RULES_MANAGEMENT_TABLE,
@ -165,8 +176,7 @@ describe('rule snoozing', () => {
});
});
// SKIPPED: https://github.com/elastic/kibana/issues/159349
describe.skip('Rule editing page / actions tab', () => {
describe('Rule editing page / actions tab', () => {
beforeEach(() => {
deleteConnectors();
});
@ -174,17 +184,12 @@ describe('rule snoozing', () => {
it('adds an action to a snoozed rule', () => {
createSnoozedRule(getNewRule({ name: 'Snoozed rule' })).then(({ body: rule }) => {
visitWithoutDateRange(ruleEditUrl(rule.id));
// Wait for rule data being loaded
cy.get(RULE_INDICES).should('be.visible');
goToActionsStepTab();
addEmailConnectorAndRuleAction('abc@example.com', 'Test action');
saveEditedRule();
goToRuleEditSettings();
goToActionsStepTab();
cy.get(actionFormSelector(0)).should('be.visible');
cy.get(ACTIONS).should('be.visible');
});
});
});
@ -195,7 +200,7 @@ describe('rule snoozing', () => {
});
it('ensures imported rules are unsnoozed', () => {
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
visitSecurityDetectionRulesPage();
importRules(RULES_TO_IMPORT_FILENAME);
@ -212,7 +217,7 @@ describe('rule snoozing', () => {
describe('Handling errors', () => {
it('shows an error if unable to load snooze settings', () => {
createRule(getNewRule({ name: 'Test rule' })).then(({ body: rule }) => {
createRule(getNewRule({ name: 'Test rule', enabled: false })).then(({ body: rule }) => {
cy.intercept('GET', `${INTERNAL_ALERTING_API_FIND_RULES_PATH}*`, {
statusCode: 500,
});
@ -226,7 +231,7 @@ describe('rule snoozing', () => {
});
it('shows an error if unable to save snooze settings', () => {
createRule(getNewRule({ name: 'Test rule' })).then(({ body: rule }) => {
createRule(getNewRule({ name: 'Test rule', enabled: false })).then(({ body: rule }) => {
cy.intercept('POST', internalAlertingSnoozeRule(rule.id), { forceNetworkError: true });
visitWithoutDateRange(ruleDetailsUrl(rule.id));

View file

@ -4,6 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { createRuleAssetSavedObject } from '../../helpers/rules';
import {
SELECTED_RULES_NUMBER_LABEL,
@ -11,13 +12,13 @@ import {
SELECT_ALL_RULES_ON_PAGE_CHECKBOX,
} from '../../screens/alerts_detection_rules';
import {
selectNumberOfRules,
unselectNumberOfRules,
waitForPrebuiltDetectionRulesToBeLoaded,
selectRulesByName,
unselectRulesByName,
} from '../../tasks/alerts_detection_rules';
import {
getAvailablePrebuiltRulesCount,
createAndInstallMockedPrebuiltRules,
getAvailablePrebuiltRulesCount,
} from '../../tasks/api_calls/prebuilt_rules';
import { cleanKibana } from '../../tasks/common';
import { login, visitWithoutDateRange } from '../../tasks/login';
@ -32,7 +33,7 @@ const RULE_2 = createRuleAssetSavedObject({
rule_id: 'rule_2',
});
describe('Rules selection', () => {
describe('Rules table: selection', () => {
before(() => {
cleanKibana();
});
@ -48,11 +49,11 @@ describe('Rules selection', () => {
it('should correctly update the selection label when rules are individually selected and unselected', () => {
waitForPrebuiltDetectionRulesToBeLoaded();
selectNumberOfRules(2);
selectRulesByName(['Test rule 1', 'Test rule 2']);
cy.get(SELECTED_RULES_NUMBER_LABEL).should('contain.text', '2');
unselectNumberOfRules(2);
unselectRulesByName(['Test rule 1', 'Test rule 2']);
cy.get(SELECTED_RULES_NUMBER_LABEL).should('contain.text', '0');
});

View file

@ -5,29 +5,29 @@
* 2.0.
*/
import { getNewRule } from '../../objects/rule';
import {
RULE_CHECKBOX,
REFRESH_RULES_STATUS,
RULES_TABLE_AUTOREFRESH_INDICATOR,
RULES_MANAGEMENT_TABLE,
RULES_TABLE_AUTOREFRESH_INDICATOR,
REFRESH_RULES_STATUS,
} from '../../screens/alerts_detection_rules';
import { EUI_CHECKBOX } from '../../screens/common/controls';
import {
selectAllRules,
clearAllRuleSelection,
selectNumberOfRules,
mockGlobalClock,
expectNumberOfRules,
selectRulesByName,
getRuleRow,
expectAutoRefreshIsEnabled,
selectAllRules,
expectAutoRefreshIsDeactivated,
clearAllRuleSelection,
disableAutoRefresh,
expectAutoRefreshIsDisabled,
expectAutoRefreshIsEnabled,
expectAutoRefreshIsDeactivated,
expectNumberOfRules,
} from '../../tasks/alerts_detection_rules';
import { login, visit, visitWithoutDateRange } from '../../tasks/login';
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../urls/navigation';
import { createRule } from '../../tasks/api_calls/rules';
import { cleanKibana } from '../../tasks/common';
import { getNewRule } from '../../objects/rule';
import { login, visitWithoutDateRange, visit } from '../../tasks/login';
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../urls/navigation';
const DEFAULT_RULE_REFRESH_INTERVAL_VALUE = 60000;
const NUM_OF_TEST_RULES = 6;
@ -38,7 +38,7 @@ describe('Rules table: auto-refresh', () => {
login();
for (let i = 1; i <= NUM_OF_TEST_RULES; ++i) {
createRule(getNewRule({ name: `Test rule ${i}`, rule_id: `${i}` }));
createRule(getNewRule({ name: `Test rule ${i}`, rule_id: `${i}`, enabled: false }));
}
});
@ -66,7 +66,7 @@ describe('Rules table: auto-refresh', () => {
expectNumberOfRules(RULES_MANAGEMENT_TABLE, NUM_OF_TEST_RULES);
selectNumberOfRules(1);
selectRulesByName(['Test rule 1']);
// mock 1 minute passing to make sure refresh is not conducted
cy.get(RULES_TABLE_AUTOREFRESH_INDICATOR).should('not.exist');
@ -74,7 +74,7 @@ describe('Rules table: auto-refresh', () => {
cy.get(RULES_TABLE_AUTOREFRESH_INDICATOR).should('not.exist');
// ensure rule is still selected
cy.get(RULE_CHECKBOX).first().should('be.checked');
getRuleRow('Test rule 1').find(EUI_CHECKBOX).should('be.checked');
cy.get(REFRESH_RULES_STATUS).should('have.not.text', 'Updated now');
});

View file

@ -5,42 +5,40 @@
* 2.0.
*/
import {
FIRST_RULE,
RULE_NAME,
RULE_SWITCH,
SECOND_RULE,
FOURTH_RULE,
RULES_MANAGEMENT_TABLE,
RULES_ROW,
} from '../../screens/alerts_detection_rules';
import {
enableRule,
waitForRulesTableToBeLoaded,
waitForRuleToUpdate,
} from '../../tasks/alerts_detection_rules';
import { login, visit } from '../../tasks/login';
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../urls/navigation';
import { createRule } from '../../tasks/api_calls/rules';
import { cleanKibana } from '../../tasks/common';
import {
getExistingRule,
getNewOverrideRule,
getNewRule,
getNewThresholdRule,
} from '../../objects/rule';
import { goToTablePage, setRowsPerPageTo, sortByTableColumn } from '../../tasks/table_pagination';
import { RULE_NAME } from '../../screens/alerts';
import {
SECOND_RULE,
FOURTH_RULE,
FIRST_RULE,
RULES_MANAGEMENT_TABLE,
} from '../../screens/alerts_detection_rules';
import { RULE_SWITCH } from '../../screens/rule_details';
import { TABLE_FIRST_PAGE, TABLE_SECOND_PAGE } from '../../screens/table_pagination';
import {
enableRule,
waitForRuleToUpdate,
getRulesManagementTableRows,
} from '../../tasks/alerts_detection_rules';
import { createRule } from '../../tasks/api_calls/rules';
import { cleanKibana } from '../../tasks/common';
import { login, visit } from '../../tasks/login';
import { sortByTableColumn, setRowsPerPageTo, goToTablePage } from '../../tasks/table_pagination';
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../urls/navigation';
describe('Alerts detection rules', () => {
describe('Rules table: sorting', () => {
before(() => {
cleanKibana();
login();
createRule(getNewRule({ rule_id: '1' }));
createRule(getExistingRule({ rule_id: '2' }));
createRule(getNewOverrideRule({ rule_id: '3' }));
createRule(getNewThresholdRule({ rule_id: '4' }));
createRule(getNewRule({ name: 'New Rule', rule_id: '1', enabled: false }));
createRule(getExistingRule({ rule_id: '2', enabled: false }));
createRule(getNewOverrideRule({ rule_id: '3', enabled: false }));
createRule(getNewThresholdRule({ rule_id: '4', enabled: false }));
});
beforeEach(() => {
@ -49,7 +47,6 @@ describe('Alerts detection rules', () => {
it('Sorts by enabled rules', () => {
visit(DETECTIONS_RULE_MANAGEMENT_URL);
waitForRulesTableToBeLoaded();
enableRule(SECOND_RULE);
waitForRuleToUpdate();
@ -66,11 +63,10 @@ describe('Alerts detection rules', () => {
});
it('Pagination updates page number and results', () => {
createRule(getNewRule({ name: 'Test a rule', rule_id: '5' }));
createRule(getNewRule({ name: 'Not same as first rule', rule_id: '6' }));
createRule(getNewRule({ name: 'Test a rule', rule_id: '5', enabled: false }));
createRule(getNewRule({ name: 'Not same as first rule', rule_id: '6', enabled: false }));
visit(DETECTIONS_RULE_MANAGEMENT_URL);
waitForRulesTableToBeLoaded();
setRowsPerPageTo(5);
cy.get(RULES_MANAGEMENT_TABLE).find(TABLE_FIRST_PAGE).should('have.attr', 'aria-current');
@ -82,7 +78,7 @@ describe('Alerts detection rules', () => {
.then((ruleNameFirstPage) => {
goToTablePage(2);
// Check that the rules table shows at least one row
cy.get(RULES_MANAGEMENT_TABLE).find(RULES_ROW).should('have.length.gte', 1);
getRulesManagementTableRows().should('have.length.gte', 1);
// Check that the rules table doesn't show the rule from the first page
cy.get(RULES_MANAGEMENT_TABLE).should('not.contain', ruleNameFirstPage);
});

View file

@ -4,20 +4,15 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { ROLES } from '../../../../common/test';
import { getExceptionList } from '../../../objects/exception';
import { getNewRule } from '../../../objects/rule';
import { ROLES } from '../../../../common/test';
import { createRule } from '../../../tasks/api_calls/rules';
import { login, visitWithoutDateRange } from '../../../tasks/login';
import { login, visitSecurityDetectionRulesPage } from '../../../tasks/login';
import { goToExceptionsTab, goToAlertsTab } from '../../../tasks/rule_details';
import {
disableAutoRefresh,
goToRuleDetails,
waitForRulesTableToBeLoaded,
} from '../../../tasks/alerts_detection_rules';
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation';
import { cleanKibana, deleteAlertsAndRules } from '../../../tasks/common';
import { goToTheRuleDetailsOf } from '../../../tasks/alerts_detection_rules';
import { deleteAlertsAndRules } from '../../../tasks/common';
import {
NO_EXCEPTIONS_EXIST_PROMPT,
EXCEPTION_ITEM_VIEWER_CONTAINER,
@ -34,12 +29,15 @@ import {
describe('Exceptions viewer read only', () => {
const exceptionList = getExceptionList();
before(() => {
cleanKibana();
beforeEach(() => {
deleteAlertsAndRules();
deleteExceptionList(exceptionList.list_id, exceptionList.namespace_type);
// create rule with exceptions
createExceptionList(exceptionList, exceptionList.list_id).then((response) => {
createRule(
getNewRule({
name: 'Test exceptions rule',
query: 'agent.name:*',
index: ['exceptions*'],
exceptions_list: [
@ -54,22 +52,13 @@ describe('Exceptions viewer read only', () => {
})
);
});
});
beforeEach(() => {
login(ROLES.reader);
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL, ROLES.reader);
waitForRulesTableToBeLoaded();
disableAutoRefresh();
goToRuleDetails();
visitSecurityDetectionRulesPage(ROLES.reader);
goToTheRuleDetailsOf('Test exceptions rule');
goToExceptionsTab();
});
after(() => {
deleteAlertsAndRules();
deleteExceptionList(exceptionList.list_id, exceptionList.namespace_type);
});
it('Cannot add an exception from empty viewer screen', () => {
// when no exceptions exist, empty component shows with action to add exception
cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist');

View file

@ -85,9 +85,9 @@ export const MESSAGE = '[data-test-subj="formatted-field-message"]';
export const REASON =
'[data-test-subj="dataGridRowCell"][data-gridcell-column-id="kibana.alert.reason"]';
export const RISK_SCORE = '[data-test-subj^=formatted-field][data-test-subj$=risk_score]';
export const RISK_SCORE = '[data-test-subj$=riskScore]';
export const RULE_NAME = '[data-test-subj^=formatted-field][data-test-subj$=rule\\.name]';
export const RULE_NAME = '[data-test-subj$=ruleName]';
export const SELECTED_ALERTS = '[data-test-subj="selectedShowBulkActionsButton"]';
@ -99,7 +99,7 @@ export const OPEN_ANALYZER_BTN = '[data-test-subj="view-in-analyzer"]';
export const ANALYZER_NODE = '[data-test-subj="resolver:node"';
export const SEVERITY = '[data-test-subj^=formatted-field][data-test-subj$=severity]';
export const SEVERITY = '[data-test-subj$=severity]';
export const SOURCE_IP = '[data-test-subj^=formatted-field][data-test-subj$=source\\.ip]';

View file

@ -74,9 +74,6 @@ export const UPGRADE_SELECTED_RULES_BUTTON = '[data-test-subj="upgradeSelectedRu
export const GO_BACK_TO_RULES_TABLE_BUTTON = '[data-test-subj="addRulesGoBackToRulesTableBtn"]';
export const RULES_TABLE_INITIAL_LOADING_INDICATOR =
'[data-test-subj="initialLoadingPanelAllRulesTable"]';
export const RULES_TABLE_REFRESH_INDICATOR = '[data-test-subj="loading-spinner"]';
export const RULES_TABLE_AUTOREFRESH_INDICATOR = '[data-test-subj="loadingRulesInfoProgress"]';

View file

@ -10,3 +10,5 @@ export const PAGE_TITLE = '[data-test-subj="header-page-title"]';
export const NOT_FOUND = '[data-test-subj="notFoundPage"]';
export const LOADING_SPINNER = '.euiLoadingSpinner';
export const PAGE_CONTENT_SPINNER = `[data-test-subj="pageContainer"] ${LOADING_SPINNER}`;

View file

@ -5,7 +5,8 @@
* 2.0.
*/
export const ALL_ACTIONS = '[data-test-subj="rules-details-popover-button-icon"]';
export const POPOVER_ACTIONS_TRIGGER_BUTTON =
'[data-test-subj="rules-details-popover-button-icon"]';
export const ABOUT_INVESTIGATION_NOTES = '[data-test-subj="stepAboutDetailsNoteContent"]';
@ -14,6 +15,8 @@ export const ABOUT_RULE_DESCRIPTION = '[data-test-subj=stepAboutRuleDetailsToggl
export const ABOUT_DETAILS =
'[data-test-subj="aboutRule"] [data-test-subj="listItemColumnStepRuleDescription"]';
export const ACTIONS = '[data-test-subj="actions"]';
export const ADDITIONAL_LOOK_BACK_DETAILS = 'Additional look-back time';
export const ALERTS_TAB = '[data-test-subj="navigation-alerts"]';

View file

@ -7,15 +7,10 @@
import { duplicatedRuleName } from '../objects/rule';
import {
BULK_ACTIONS_BTN,
COLLAPSED_ACTION_BTN,
CUSTOM_RULES_BTN,
DELETE_RULE_ACTION_BTN,
DELETE_RULE_BULK_BTN,
RULES_SELECTED_TAG,
RULES_TABLE_INITIAL_LOADING_INDICATOR,
RULES_TABLE_AUTOREFRESH_INDICATOR,
RULE_CHECKBOX,
RULE_NAME,
RULE_SWITCH,
RULE_SWITCH_LOADER,
@ -24,14 +19,11 @@ import {
EDIT_RULE_ACTION_BTN,
DUPLICATE_RULE_ACTION_BTN,
DUPLICATE_RULE_MENU_PANEL_BTN,
DUPLICATE_RULE_BULK_BTN,
CONFIRM_DUPLICATE_RULE,
RULES_ROW,
SELECT_ALL_RULES_BTN,
MODAL_CONFIRMATION_BTN,
RULES_DELETE_CONFIRMATION_MODAL,
ENABLE_RULE_BULK_BTN,
DISABLE_RULE_BULK_BTN,
RULE_DETAILS_DELETE_BTN,
RULE_IMPORT_MODAL_BUTTON,
RULE_IMPORT_MODAL,
@ -44,7 +36,6 @@ import {
SELECTED_RULES_NUMBER_LABEL,
REFRESH_SETTINGS_SWITCH,
ELASTIC_RULES_BTN,
BULK_EXPORT_ACTION_BTN,
TOASTER_ERROR_BTN,
MODAL_CONFIRMATION_CANCEL_BTN,
MODAL_CONFIRMATION_BODY,
@ -59,22 +50,25 @@ import {
DISABLED_RULES_BTN,
REFRESH_RULES_TABLE_BUTTON,
RULE_LAST_RUN,
DUPLICATE_WITHOUT_EXCEPTIONS_OPTION,
DUPLICATE_WITH_EXCEPTIONS_OPTION,
DUPLICATE_WITH_EXCEPTIONS_WITHOUT_EXPIRED_OPTION,
TOASTER_CLOSE_ICON,
ADD_ELASTIC_RULES_EMPTY_PROMPT_BTN,
AUTO_REFRESH_POPOVER_TRIGGER_BUTTON,
SELECT_ALL_RULES_ON_PAGE_CHECKBOX,
BULK_ACTIONS_BTN,
BULK_EXPORT_ACTION_BTN,
} from '../screens/alerts_detection_rules';
import type { RULES_MONITORING_TABLE } from '../screens/alerts_detection_rules';
import { EUI_CHECKBOX } from '../screens/common/controls';
import { ALL_ACTIONS } from '../screens/rule_details';
import { POPOVER_ACTIONS_TRIGGER_BUTTON, RULE_NAME_HEADER } from '../screens/rule_details';
import { EDIT_SUBMIT_BUTTON } from '../screens/edit_rule';
import { LOADING_INDICATOR } from '../screens/security_header';
import { PAGE_CONTENT_SPINNER } from '../screens/common/page';
import { goToRuleEditSettings } from './rule_details';
import { goToActionsStepTab } from './create_new_rule';
export const getRulesManagementTableRows = () => cy.get(RULES_MANAGEMENT_TABLE).find(RULES_ROW);
export const enableRule = (rulePosition: number) => {
cy.get(RULE_SWITCH).eq(rulePosition).click();
};
@ -102,7 +96,7 @@ export const duplicateFirstRule = () => {
*/
export const duplicateRuleFromMenu = () => {
cy.get(LOADING_INDICATOR).should('not.exist');
cy.get(ALL_ACTIONS).click({ force: true });
cy.get(POPOVER_ACTIONS_TRIGGER_BUTTON).click({ force: true });
cy.get(DUPLICATE_RULE_MENU_PANEL_BTN).should('be.visible');
// Because of a fade effect and fast clicking this can produce more than one click
@ -126,59 +120,10 @@ export const deleteFirstRule = () => {
cy.get(DELETE_RULE_ACTION_BTN).click();
};
export const deleteSelectedRules = () => {
cy.get(BULK_ACTIONS_BTN).click();
cy.get(DELETE_RULE_BULK_BTN).click();
};
export const deleteRuleFromDetailsPage = () => {
cy.get(ALL_ACTIONS).should('be.visible');
// We cannot use cy.root().pipe($el) withing this function and instead have to use a cy.wait()
// for the click handler to be registered. If you see flake here because of click handler issues
// increase the cy.wait(). The reason we cannot use cypress pipe is because multiple clicks on ALL_ACTIONS
// causes the pop up to show and then the next click for it to hide. Multiple clicks can cause
// the DOM to queue up and once we detect that the element is visible it can then become invisible later
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000);
cy.get(ALL_ACTIONS).click();
cy.get(POPOVER_ACTIONS_TRIGGER_BUTTON).click();
cy.get(RULE_DETAILS_DELETE_BTN).click();
cy.get(RULE_DETAILS_DELETE_BTN).should('not.be.visible');
};
export const duplicateSelectedRulesWithoutExceptions = () => {
cy.log('Duplicate selected rules');
cy.get(BULK_ACTIONS_BTN).click();
cy.get(DUPLICATE_RULE_BULK_BTN).click();
cy.get(DUPLICATE_WITHOUT_EXCEPTIONS_OPTION).click();
cy.get(CONFIRM_DUPLICATE_RULE).click();
};
export const duplicateSelectedRulesWithExceptions = () => {
cy.log('Duplicate selected rules');
cy.get(BULK_ACTIONS_BTN).click();
cy.get(DUPLICATE_RULE_BULK_BTN).click();
cy.get(DUPLICATE_WITH_EXCEPTIONS_OPTION).click();
cy.get(CONFIRM_DUPLICATE_RULE).click();
};
export const duplicateSelectedRulesWithNonExpiredExceptions = () => {
cy.log('Duplicate selected rules');
cy.get(BULK_ACTIONS_BTN).click();
cy.get(DUPLICATE_RULE_BULK_BTN).click();
cy.get(DUPLICATE_WITH_EXCEPTIONS_WITHOUT_EXPIRED_OPTION).click();
cy.get(CONFIRM_DUPLICATE_RULE).click();
};
export const enableSelectedRules = () => {
cy.log('Enable selected rules');
cy.get(BULK_ACTIONS_BTN).click();
cy.get(ENABLE_RULE_BULK_BTN).click();
};
export const disableSelectedRules = () => {
cy.log('Disable selected rules');
cy.get(BULK_ACTIONS_BTN).click();
cy.get(DISABLE_RULE_BULK_BTN).click();
cy.get(RULE_DETAILS_DELETE_BTN).should('not.exist');
};
export const exportRule = (name: string) => {
@ -233,48 +178,34 @@ export const filterByDisabledRules = () => {
cy.get(DISABLED_RULES_BTN).click();
};
/**
* @deprecated use goToTheRuleDetailsOf
*/
export const goToRuleDetails = () => {
cy.get(RULE_NAME).first().click();
};
export const goToTheRuleDetailsOf = (ruleName: string) => {
cy.contains(RULE_NAME, ruleName).click();
cy.get(PAGE_CONTENT_SPINNER).should('be.visible');
cy.contains(RULE_NAME_HEADER, ruleName).should('be.visible');
cy.get(PAGE_CONTENT_SPINNER).should('not.exist');
};
export const openIntegrationsPopover = () => {
cy.get(INTEGRATIONS_POPOVER).click();
};
/**
* Selects the number of rules. Since there can be missing click handlers
* when the page loads at first, we use a pipe and a trigger of click
* on it and then check to ensure that it is checked before continuing
* with the tests.
* @param numberOfRules The number of rules to click/check
*/
export const selectNumberOfRules = (numberOfRules: number) => {
for (let i = 0; i < numberOfRules; i++) {
cy.get(RULE_CHECKBOX).eq(i).check();
cy.get(RULE_CHECKBOX).eq(i).should('be.checked');
export const selectRulesByName = (ruleNames: Readonly<string[]>) => {
for (const ruleName of ruleNames) {
selectRuleByName(ruleName);
}
};
export const unselectRuleByName = (ruleName: string) => {
cy.contains(RULE_NAME, ruleName).parents(RULES_ROW).find(EUI_CHECKBOX).uncheck();
cy.contains(RULE_NAME, ruleName).parents(RULES_ROW).find(EUI_CHECKBOX).should('not.be.checked');
};
/**
* Unselects a passed number of rules. To use together with selectNumberOfRules
* as this utility will expect and check the passed number of rules
* to have been previously checked.
* @param numberOfRules The number of rules to click/check
*/
export const unselectNumberOfRules = (numberOfRules: number) => {
for (let i = 0; i < numberOfRules; i++) {
cy.get(RULE_CHECKBOX).eq(i).should('be.checked');
cy.get(RULE_CHECKBOX).eq(i).uncheck();
cy.get(RULE_CHECKBOX).eq(i).should('not.be.checked');
export const unselectRulesByName = (ruleNames: Readonly<string[]>) => {
for (const ruleName of ruleNames) {
unselectRuleByName(ruleName);
}
};
@ -284,6 +215,12 @@ export const selectAllRules = () => {
cy.get(SELECT_ALL_RULES_BTN).contains('Clear');
};
export const selectAllRulesOnPage = () => {
cy.log('Select all rules on page');
cy.get(SELECT_ALL_RULES_ON_PAGE_CHECKBOX).check();
cy.get(SELECT_ALL_RULES_ON_PAGE_CHECKBOX).should('be.checked');
};
export const clearAllRuleSelection = () => {
cy.log('Clear all rules selection');
cy.get(SELECT_ALL_RULES_BTN).contains('Clear').click();
@ -314,21 +251,6 @@ export const waitForRulesTableToShow = () => {
cy.get(RULES_MANAGEMENT_TABLE, { timeout: 300000 }).should('exist');
};
/**
* Because the Rule Management page is relatively slow, in order to avoid timeouts and flakiness,
* we almost always want to wait until the Rules table is "loaded" before we do anything with it.
*
* This task can be needed for some tests that e.g. check the table load/refetch/pagination logic.
* It waits for the table's own loading indicator to show up and disappear.
*
* NOTE: Normally, we should not rely on loading indicators in tests, because due to their
* dynamic nature it's possible to introduce race conditions and flakiness.
*/
export const waitForRulesTableToBeLoaded = () => {
// Wait up to 5 minutes for the rules to load as in CI containers this can be very slow
cy.get(RULES_TABLE_INITIAL_LOADING_INDICATOR, { timeout: 300000 }).should('not.exist');
};
export const waitForRulesTableToBeRefreshed = () => {
cy.get(RULES_TABLE_REFRESH_INDICATOR).should('exist');
cy.get(RULES_TABLE_REFRESH_INDICATOR).should('not.exist');
@ -352,12 +274,6 @@ export const waitForRuleToUpdate = () => {
cy.get(RULE_SWITCH_LOADER, { timeout: 300000 }).should('not.exist');
};
export const checkAutoRefresh = (ms: number, condition: string) => {
cy.get(RULES_TABLE_AUTOREFRESH_INDICATOR).should('not.exist');
cy.tick(ms);
cy.get(RULES_TABLE_AUTOREFRESH_INDICATOR).should(condition);
};
export const importRules = (rulesFile: string) => {
cy.get(RULE_IMPORT_MODAL).click();
cy.get(INPUT_FILE).click({ force: true });
@ -582,3 +498,19 @@ export const goToEditRuleActionsSettingsOf = (name: string) => {
cy.get(EDIT_SUBMIT_BUTTON).should('be.enabled');
goToActionsStepTab();
};
export const getRuleRow = (ruleName: string) => cy.contains(RULE_NAME, ruleName).parents(RULES_ROW);
const selectRuleByName = (ruleName: string) => {
cy.log(`Select rule "${ruleName}"`);
getRuleRow(ruleName).find(EUI_CHECKBOX).check();
cy.log(`Make sure rule "${ruleName}" has been selected`);
getRuleRow(ruleName).find(EUI_CHECKBOX).should('be.checked');
};
const unselectRuleByName = (ruleName: string) => {
cy.log(`Unselect rule "${ruleName}"`);
getRuleRow(ruleName).find(EUI_CHECKBOX).uncheck();
cy.log(`Make sure rule "${ruleName}" has been unselected`);
getRuleRow(ruleName).find(EUI_CHECKBOX).should('not.be.checked');
};

View file

@ -83,7 +83,7 @@ export const createNewRuleAsset = ({
}) => {
const url = `${Cypress.env('ELASTICSEARCH_URL')}/${index}/_doc/security-rule:${
rule['security-rule'].rule_id
}`;
}&refresh`;
cy.waitUntil(
() => {
return cy
@ -188,14 +188,14 @@ export const createAndInstallMockedPrebuiltRules = ({
rules,
installToKibana = true,
}: {
rules?: Array<typeof SAMPLE_PREBUILT_RULE>;
rules: Array<typeof SAMPLE_PREBUILT_RULE>;
installToKibana?: boolean;
}) => {
cy.log('Install prebuilt rules');
preventPrebuiltRulesPackageInstallation();
// TODO: use this bulk method once the issue with Cypress is fixed
// bulkCreateRuleAssets({ rules });
rules?.forEach((rule) => {
rules.forEach((rule) => {
createNewRuleAsset({ rule });
});
if (installToKibana) {

View file

@ -117,7 +117,7 @@ export const deleteAlertsAndRules = () => {
rootRequest({
method: 'POST',
url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed`,
url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`,
body: {
query: {
bool: {
@ -137,7 +137,7 @@ export const deleteAlertsAndRules = () => {
method: 'POST',
url: `${Cypress.env(
'ELASTICSEARCH_URL'
)}/.lists-*,.items-*,.alerts-security.alerts-*/_delete_by_query?conflicts=proceed&scroll_size=10000`,
)}/.lists-*,.items-*,.alerts-security.alerts-*/_delete_by_query?conflicts=proceed&scroll_size=10000&refresh`,
body: {
query: {
match_all: {},
@ -150,7 +150,7 @@ export const deleteTimelines = () => {
const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`;
rootRequest({
method: 'POST',
url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed`,
url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`,
body: {
query: {
bool: {
@ -180,7 +180,7 @@ export const deleteCases = () => {
const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`;
rootRequest({
method: 'POST',
url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed`,
url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`,
body: {
query: {
bool: {
@ -201,7 +201,7 @@ export const deleteConnectors = () => {
const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`;
rootRequest({
method: 'POST',
url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed`,
url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`,
body: {
query: {
bool: {

View file

@ -12,8 +12,13 @@ import Url from 'url';
import type { ROLES } from '../../common/test';
import { NEW_FEATURES_TOUR_STORAGE_KEYS } from '../../common/constants';
import { hostDetailsUrl, LOGOUT_URL, userDetailsUrl } from '../urls/navigation';
import { waitForPageToBeLoaded } from './common';
import {
hostDetailsUrl,
LOGOUT_URL,
SECURITY_DETECTIONS_RULES_URL,
userDetailsUrl,
} from '../urls/navigation';
import { resetRulesTableState, waitForPageToBeLoaded } from './common';
/**
* Credentials in the `kibana.dev.yml` config file will be used to authenticate
@ -387,6 +392,11 @@ export const visitHostDetailsPage = (hostName = 'suricata-iowa') => {
cy.get('[data-test-subj="loading-spinner"]').should('not.exist');
};
export const visitSecurityDetectionRulesPage = (role?: ROLES) => {
resetRulesTableState(); // Clear persistent rules filter data before page loading
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL, role);
};
export const visitUserDetailsPage = (userName = 'test') => {
visit(userDetailsUrl(userName));
};

View file

@ -15,6 +15,14 @@ import {
MODAL_CONFIRMATION_BODY,
TOASTER_BODY,
RULES_TAGS_FILTER_BTN,
CONFIRM_DUPLICATE_RULE,
DELETE_RULE_BULK_BTN,
DISABLE_RULE_BULK_BTN,
DUPLICATE_RULE_BULK_BTN,
DUPLICATE_WITHOUT_EXCEPTIONS_OPTION,
DUPLICATE_WITH_EXCEPTIONS_OPTION,
DUPLICATE_WITH_EXCEPTIONS_WITHOUT_EXPIRED_OPTION,
ENABLE_RULE_BULK_BTN,
} from '../screens/alerts_detection_rules';
import {
@ -43,6 +51,50 @@ import {
} from '../screens/rules_bulk_edit';
import { SCHEDULE_DETAILS } from '../screens/rule_details';
// DELETE
export const deleteSelectedRules = () => {
cy.get(BULK_ACTIONS_BTN).click();
cy.get(DELETE_RULE_BULK_BTN).click();
};
// DUPLICATE
export const duplicateSelectedRulesWithoutExceptions = () => {
cy.log('Bulk duplicate selected rules without exceptions');
cy.get(BULK_ACTIONS_BTN).click();
cy.get(DUPLICATE_RULE_BULK_BTN).click();
cy.get(DUPLICATE_WITHOUT_EXCEPTIONS_OPTION).click();
cy.get(CONFIRM_DUPLICATE_RULE).click();
};
export const duplicateSelectedRulesWithExceptions = () => {
cy.log('Bulk duplicate selected rules with exceptions');
cy.get(BULK_ACTIONS_BTN).click();
cy.get(DUPLICATE_RULE_BULK_BTN).click();
cy.get(DUPLICATE_WITH_EXCEPTIONS_OPTION).click();
cy.get(CONFIRM_DUPLICATE_RULE).click();
};
export const duplicateSelectedRulesWithNonExpiredExceptions = () => {
cy.log('Bulk duplicate selected rules with non expired exceptions');
cy.get(BULK_ACTIONS_BTN).click();
cy.get(DUPLICATE_RULE_BULK_BTN).click();
cy.get(DUPLICATE_WITH_EXCEPTIONS_WITHOUT_EXPIRED_OPTION).click();
cy.get(CONFIRM_DUPLICATE_RULE).click();
};
// ENABLE/DISABLE
export const enableSelectedRules = () => {
cy.log('Bulk enable selected rules');
cy.get(BULK_ACTIONS_BTN).click();
cy.get(ENABLE_RULE_BULK_BTN).click();
};
export const disableSelectedRules = () => {
cy.log('Bulk disable selected rules');
cy.get(BULK_ACTIONS_BTN).click();
cy.get(DISABLE_RULE_BULK_BTN).click();
};
export const clickApplyTimelineTemplatesMenuItem = () => {
cy.get(BULK_ACTIONS_BTN).click();
cy.get(APPLY_TIMELINE_RULE_BULK_MENU_ITEM).click();

View file

@ -38,5 +38,6 @@
"@kbn/core-http-common",
"@kbn/data-views-plugin",
"@kbn/fleet-plugin",
"@kbn/securitysolution-io-ts-utils",
]
}