From 6799dd94d2c2c3e4a568f77e4fa449a2dc2e07cc Mon Sep 17 00:00:00 2001 From: Davis Plumlee Date: Fri, 21 Feb 2025 18:49:02 -0500 Subject: [PATCH] moves tests from prev pr --- .../customized_prebuilt_rule_badge.tsx | 6 +- .../prebuilt_rules/rule_customization.cy.ts | 348 ++++++++++++++++++ .../cypress/screens/alerts_detection_rules.ts | 2 + .../cypress/screens/create_new_rule.ts | 2 + .../cypress/screens/rule_details.ts | 2 + .../cypress/tasks/alerts_detection_rules.ts | 29 +- .../cypress/tasks/edit_rule.ts | 2 +- 7 files changed, 388 insertions(+), 3 deletions(-) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/rule_customization.cy.ts diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/customized_prebuilt_rule_badge.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/customized_prebuilt_rule_badge.tsx index 49defd1e39a95..3a5a9fa6b8c94 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/customized_prebuilt_rule_badge.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/customized_prebuilt_rule_badge.tsx @@ -34,5 +34,9 @@ export const CustomizedPrebuiltRuleBadge: React.FC{i18n.MODIFIED_PREBUILT_RULE_LABEL}; + return ( + + {i18n.MODIFIED_PREBUILT_RULE_LABEL} + + ); }; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/rule_customization.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/rule_customization.cy.ts new file mode 100644 index 0000000000000..55d67428fae8f --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/rule_customization.cy.ts @@ -0,0 +1,348 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { clickRuleUpdatesTab } from '../../../../tasks/prebuilt_rules'; +import { + clickUpdateScheduleMenuItem, + openBulkEditAddIndexPatternsForm, + openBulkEditAddInvestigationFieldsForm, + openBulkEditAddTagsForm, + openBulkEditDeleteIndexPatternsForm, + openBulkEditDeleteInvestigationFieldsForm, + openBulkEditDeleteTagsForm, + setScheduleIntervalTimeUnit, + setScheduleLookbackTimeUnit, + submitBulkEditForm, + typeIndexPatterns, + typeInvestigationFields, + typeScheduleInterval, + typeScheduleLookback, + typeTags, + waitForBulkEditActionToFinish, +} from '../../../../tasks/rules_bulk_actions'; +import { + ABOUT_EDIT_TAB, + ACTIONS_EDIT_TAB, + DEFINITION_EDIT_TAB, + SCHEDULE_EDIT_TAB, +} from '../../../../screens/create_new_rule'; +import { ABOUT_RULE_DESCRIPTION } from '../../../../screens/rule_details'; +import { goToRuleEditSettings } from '../../../../tasks/rule_details'; +import { getIndexPatterns, getNewRule } from '../../../../objects/rule'; +import { + editFirstRule, + expectModifiedBadgeToBeDisplayed, + expectModifiedBadgeToNotBeDisplayed, + expectToContainModifiedBadge, + expectToNotContainModifiedBadge, + filterByCustomRules, + filterByElasticRules, + selectAllRules, +} from '../../../../tasks/alerts_detection_rules'; +import { MODIFIED_RULE_BADGE, RULE_NAME } from '../../../../screens/alerts_detection_rules'; +import { createRuleAssetSavedObject } from '../../../../helpers/rules'; +import { + deleteAlertsAndRules, + deletePrebuiltRulesAssets, +} from '../../../../tasks/api_calls/common'; +import { + createAndInstallMockedPrebuiltRules, + installPrebuiltRuleAssets, + preventPrebuiltRulesPackageInstallation, +} from '../../../../tasks/api_calls/prebuilt_rules'; +import { createRule, patchRule } from '../../../../tasks/api_calls/rules'; + +import { login } from '../../../../tasks/login'; + +import { visitRulesManagementTable } from '../../../../tasks/rules_management'; +import { fillDescription, goToAboutStepTab } from '../../../../tasks/create_new_rule'; +import { saveEditedRule } from '../../../../tasks/edit_rule'; +describe( + 'Detection rules, Prebuilt Rules Customization workflow', + { + tags: ['@ess', '@serverless', '@skipInServerlessMKI'], + env: { + ftrConfig: { + kbnServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify([ + 'prebuiltRulesCustomizationEnabled', + ])}`, + ], + }, + }, + }, + + () => { + describe('Customizing prebuilt rules', () => { + const testTags = ['tag 1', 'tag 2']; + const PREBUILT_RULE = createRuleAssetSavedObject({ + name: 'Non-customized prebuilt rule', + rule_id: 'rule_1', + version: 1, + index: getIndexPatterns(), + tags: testTags, + investigation_fields: { field_names: ['source.ip'] }, + }); + + beforeEach(() => { + login(); + deleteAlertsAndRules(); + deletePrebuiltRulesAssets(); + preventPrebuiltRulesPackageInstallation(); + /* Create a new rule and install it */ + createAndInstallMockedPrebuiltRules([PREBUILT_RULE]); + visitRulesManagementTable(); + createRule( + getNewRule({ + name: 'Custom rule', + index: getIndexPatterns(), + tags: testTags, + enabled: false, + }) + ); + }); + + it('user can navigate to rule editing page from the rule details page', function () { + cy.get(RULE_NAME).contains('Non-customized prebuilt rule').click(); + + goToRuleEditSettings(); + cy.get(DEFINITION_EDIT_TAB).should('be.enabled'); + cy.get(ABOUT_EDIT_TAB).should('be.enabled'); + cy.get(SCHEDULE_EDIT_TAB).should('be.enabled'); + cy.get(ACTIONS_EDIT_TAB).should('be.enabled'); + }); + + it('user can edit a non-customized prebuilt rule from the rule edit page', function () { + const newDescriptionValue = 'New rule description'; + cy.get(RULE_NAME).contains('Non-customized prebuilt rule').click(); + + goToRuleEditSettings(); + goToAboutStepTab(); + fillDescription(newDescriptionValue); + saveEditedRule(); + + expectModifiedBadgeToBeDisplayed(); + cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', newDescriptionValue); + }); + + it('user can edit a customized prebuilt rule from the rule edit page', function () { + const newDescriptionValue = 'New rule description'; + patchRule('rule_1', { name: 'Customized prebuilt rule' }); // We want to make this a customized prebuilt rule + visitRulesManagementTable(); + + cy.get(RULE_NAME).contains('Customized prebuilt rule').click(); + expectModifiedBadgeToBeDisplayed(); // Expect modified badge to already be displayed + + goToRuleEditSettings(); + goToAboutStepTab(); + fillDescription(newDescriptionValue); + saveEditedRule(); + + expectModifiedBadgeToBeDisplayed(); + cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', newDescriptionValue); + }); + + it('user can navigate to rule editing page from the rule management page', function () { + filterByElasticRules(); + editFirstRule(); + + cy.get(DEFINITION_EDIT_TAB).should('be.enabled'); + cy.get(ABOUT_EDIT_TAB).should('be.enabled'); + cy.get(SCHEDULE_EDIT_TAB).should('be.enabled'); + cy.get(ACTIONS_EDIT_TAB).should('be.enabled'); + }); + + describe('user can bulk edit prebuilt rules from rules management page', () => { + it('add index patterns', () => { + filterByElasticRules(); + selectAllRules(); + + openBulkEditAddIndexPatternsForm(); + typeIndexPatterns(['test-pattern']); + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ + updatedCount: 1, + }); + + expectToContainModifiedBadge('Non-customized prebuilt rule'); + }); + + it('delete index patterns', () => { + filterByElasticRules(); + selectAllRules(); + + openBulkEditDeleteIndexPatternsForm(); + typeIndexPatterns([getIndexPatterns()[0]]); + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ + updatedCount: 1, + }); + + expectToContainModifiedBadge('Non-customized prebuilt rule'); + }); + + it('add tags', () => { + filterByElasticRules(); + selectAllRules(); + + openBulkEditAddTagsForm(); + typeTags(['custom-tag']); + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ + updatedCount: 1, + }); + + expectToContainModifiedBadge('Non-customized prebuilt rule'); + }); + + it('delete tags', () => { + filterByElasticRules(); + selectAllRules(); + + openBulkEditDeleteTagsForm(); + typeTags([testTags[0]]); + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ + updatedCount: 1, + }); + + expectToContainModifiedBadge('Non-customized prebuilt rule'); + }); + + it('add custom highlighted fields', () => { + filterByElasticRules(); + selectAllRules(); + + openBulkEditAddInvestigationFieldsForm(); + typeInvestigationFields(['host.name']); + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ + updatedCount: 1, + }); + + expectToContainModifiedBadge('Non-customized prebuilt rule'); + }); + + it('delete custom highlighted fields', () => { + filterByElasticRules(); + selectAllRules(); + + openBulkEditDeleteInvestigationFieldsForm(); + typeInvestigationFields(['source.ip']); + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ + updatedCount: 1, + }); + + expectToContainModifiedBadge('Non-customized prebuilt rule'); + }); + + it('modify rule schedules', () => { + filterByElasticRules(); + selectAllRules(); + + clickUpdateScheduleMenuItem(); + + typeScheduleInterval('20'); + setScheduleIntervalTimeUnit('Hours'); + + typeScheduleLookback('10'); + setScheduleLookbackTimeUnit('Minutes'); + + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ + updatedCount: 1, + }); + + expectToContainModifiedBadge('Non-customized prebuilt rule'); + }); + }); + + describe('calculating the Modified badge', () => { + it('modified badge should appear on the rule details page when prebuilt rule is customized', function () { + patchRule('rule_1', { name: 'Customized prebuilt rule' }); // We want to make this a customized prebuilt rule + visitRulesManagementTable(); + + cy.get(RULE_NAME).contains('Customized prebuilt rule').click(); + expectModifiedBadgeToBeDisplayed(); // Expect modified badge to be displayed + }); + + it("modified badge should not appear on the rule details page when prebuilt rule isn't customized", function () { + visitRulesManagementTable(); + + cy.get(RULE_NAME).contains('Non-customized prebuilt rule').click(); + expectModifiedBadgeToNotBeDisplayed(); // Expect modified badge to not be displayed + }); + + it("modified badge should not appear on a custom rule's rule details page", function () { + visitRulesManagementTable(); + + cy.get(RULE_NAME).contains('Custom rule').click(); + expectModifiedBadgeToNotBeDisplayed(); // Expect modified badge to not be displayed + }); + + it('modified badge should appear on the rule management table when prebuilt rule is modified', function () { + patchRule('rule_1', { name: 'Customized prebuilt rule' }); // We want to make this a customized prebuilt rule + visitRulesManagementTable(); + + filterByElasticRules(); + expectToContainModifiedBadge('Customized prebuilt rule'); + }); + + it("modified badge should not appear on the rule management table when prebuilt rule isn't customized", function () { + visitRulesManagementTable(); + + filterByElasticRules(); + expectToNotContainModifiedBadge('Non-customized prebuilt rule'); + }); + + it('modified badge should not appear on the rule management table when row is a custom rule', function () { + visitRulesManagementTable(); + + filterByCustomRules(); + expectToNotContainModifiedBadge('Custom rule'); + }); + + it('modified badge should appear on the rule updates table when prebuilt rule is customized', function () { + // Create a new version of the rule to trigger the rule update logic + installPrebuiltRuleAssets([ + { + ...PREBUILT_RULE, + 'security-rule': { ...PREBUILT_RULE['security-rule'], version: 2 }, + }, + ]); + patchRule('rule_1', { name: 'Customized prebuilt rule' }); // We want to make this a customized prebuilt rule + visitRulesManagementTable(); + clickRuleUpdatesTab(); + + cy.get(MODIFIED_RULE_BADGE).should('exist'); + }); + + it("Modified badge should not appear on the rule updates table when prebuilt rule isn't customized", function () { + // Create a new version of the rule to trigger the rule update logic + installPrebuiltRuleAssets([ + { + ...PREBUILT_RULE, + 'security-rule': { ...PREBUILT_RULE['security-rule'], version: 2 }, + }, + ]); + visitRulesManagementTable(); + clickRuleUpdatesTab(); + + cy.get(MODIFIED_RULE_BADGE).should('not.exist'); + }); + }); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/alerts_detection_rules.ts b/x-pack/test/security_solution_cypress/cypress/screens/alerts_detection_rules.ts index f6f1bae56bfce..05fdca4201851 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/alerts_detection_rules.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/alerts_detection_rules.ts @@ -351,3 +351,5 @@ export const PER_FIELD_DIFF_WRAPPER = '[data-test-subj="ruleUpgradePerFieldDiffW export const PER_FIELD_DIFF_DEFINITION_SECTION = '[data-test-subj="perFieldDiffDefinitionSection"]'; export const MODIFIED_RULE_BADGE = '[data-test-subj="upgradeRulesTableModifiedColumnBadge"]'; + +export const RULES_TABLE_MODIFIED_RULE_BADGE = '[data-test-subj="rulesTableModifiedColumnBadge"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts b/x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts index ad66955a6e244..d5da762ee202f 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts @@ -9,6 +9,8 @@ export const ABOUT_CONTINUE_BTN = '[data-test-subj="about-continue"]'; export const ABOUT_EDIT_BUTTON = '[data-test-subj="edit-about-rule"]'; +export const DEFINITION_EDIT_TAB = '[data-test-subj="edit-rule-define-tab"]'; + export const ABOUT_EDIT_TAB = '[data-test-subj="edit-rule-about-tab"]'; export const ACTIONS_EDIT_TAB = '[data-test-subj="edit-rule-actions-tab"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/rule_details.ts b/x-pack/test/security_solution_cypress/cypress/screens/rule_details.ts index 6fa23a3fa34f8..41055bb523a99 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/rule_details.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/rule_details.ts @@ -201,3 +201,5 @@ export const RULE_GAPS_FILL_TOOLTIP = '[data-test-subj="rule-gaps-fill-gap-toolt export const RULE_GAPS_PROGRESS_BAR = '[data-test-subj="rule-gaps-progress-bar"]'; export const RULE_GAPS_DATE_PICKER = '[data-test-subj="rule-gaps-date-picker"]'; export const RULE_GAPS_DATE_PICKER_APPLY_REFRESH = `${RULE_GAPS_DATE_PICKER} .euiSuperUpdateButton`; + +export const MODIFIED_PREBUILT_RULE_BADGE = '[data-test-subj="modified-prebuilt-rule-badge"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/alerts_detection_rules.ts b/x-pack/test/security_solution_cypress/cypress/tasks/alerts_detection_rules.ts index 1d1d1f6fa6bab..c7728ade527a2 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/alerts_detection_rules.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/alerts_detection_rules.ts @@ -60,7 +60,11 @@ import { } from '../screens/alerts_detection_rules'; import type { RULES_MONITORING_TABLE } from '../screens/alerts_detection_rules'; import { EUI_CHECKBOX } from '../screens/common/controls'; -import { POPOVER_ACTIONS_TRIGGER_BUTTON, RULE_NAME_HEADER } from '../screens/rule_details'; +import { + MODIFIED_PREBUILT_RULE_BADGE, + 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'; @@ -394,6 +398,14 @@ export const expectToContainRule = ( cy.get(tableSelector).find(RULES_ROW).should('include.text', ruleName); }; +export const expectModifiedBadgeToBeDisplayed = () => { + cy.get(MODIFIED_PREBUILT_RULE_BADGE).should('exist'); +}; + +export const expectModifiedBadgeToNotBeDisplayed = () => { + cy.get(MODIFIED_PREBUILT_RULE_BADGE).should('not.exist'); +}; + const selectOverwriteRulesImport = () => { cy.get(RULE_IMPORT_OVERWRITE_CHECKBOX).check({ force: true }); cy.get(RULE_IMPORT_OVERWRITE_CHECKBOX).should('be.checked'); @@ -407,6 +419,21 @@ export const expectManagementTableRules = (ruleNames: string[]): void => { } }; +export const expectToContainModifiedBadge = (ruleName: string) => { + cy.get(RULES_MANAGEMENT_TABLE) + .find(RULES_ROW) + .should('include.text', ruleName) + .contains('Modified'); +}; + +export const expectToNotContainModifiedBadge = (ruleName: string) => { + cy.get(RULES_MANAGEMENT_TABLE) + .find(RULES_ROW) + .should('include.text', ruleName) + .contains('Modified') + .should('not.exist'); +}; + const selectOverwriteExceptionsRulesImport = () => { cy.get(RULE_IMPORT_OVERWRITE_EXCEPTIONS_CHECKBOX).check({ force: true }); cy.get(RULE_IMPORT_OVERWRITE_EXCEPTIONS_CHECKBOX).should('be.checked'); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/edit_rule.ts b/x-pack/test/security_solution_cypress/cypress/tasks/edit_rule.ts index 4ea919231e08f..194bbc482de84 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/edit_rule.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/edit_rule.ts @@ -18,7 +18,7 @@ export function visitEditRulePage(ruleId: string): void { } export const saveEditedRule = () => { - cy.get(EDIT_SUBMIT_BUTTON).should('exist').click({ force: true }); + cy.get(EDIT_SUBMIT_BUTTON).should('exist').click(); cy.get(EDIT_SUBMIT_BUTTON).should('not.exist'); };