mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Security Solutions][Detection Engine] Fixes bug with not being able to duplicate indicator matches (#92565)
## Summary Fixes an unreleased regression bug where indicator rules could not be be duplicated. https://github.com/elastic/kibana/issues/90356 - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
510bc698ff
commit
ebb0435401
6 changed files with 113 additions and 3 deletions
|
@ -60,12 +60,15 @@ import {
|
|||
} from '../../tasks/alerts';
|
||||
import {
|
||||
changeRowsPerPageTo300,
|
||||
duplicateFirstRule,
|
||||
duplicateRuleFromMenu,
|
||||
filterByCustomRules,
|
||||
goToCreateNewRule,
|
||||
goToRuleDetails,
|
||||
waitForRulesTableToBeLoaded,
|
||||
} from '../../tasks/alerts_detection_rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { createCustomIndicatorRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana, reload } from '../../tasks/common';
|
||||
import {
|
||||
createAndActivateRule,
|
||||
fillAboutRuleAndContinue,
|
||||
|
@ -92,8 +95,10 @@ import {
|
|||
waitForAlertsToPopulate,
|
||||
waitForTheRuleToBeExecuted,
|
||||
} from '../../tasks/create_new_rule';
|
||||
import { waitForKibana } from '../../tasks/edit_rule';
|
||||
import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver';
|
||||
import { loginAndWaitForPageWithoutDateRange } from '../../tasks/login';
|
||||
import { goBackToAllRulesTable } from '../../tasks/rule_details';
|
||||
|
||||
import { DETECTIONS_URL, RULE_CREATION } from '../../urls/navigation';
|
||||
|
||||
|
@ -465,5 +470,30 @@ describe('indicator match', () => {
|
|||
cy.get(ALERT_RULE_RISK_SCORE).first().should('have.text', newThreatIndicatorRule.riskScore);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Duplicates the indicator rule', () => {
|
||||
beforeEach(() => {
|
||||
cleanKibana();
|
||||
loginAndWaitForPageWithoutDateRange(DETECTIONS_URL);
|
||||
goToManageAlertsDetectionRules();
|
||||
createCustomIndicatorRule(newThreatIndicatorRule);
|
||||
reload();
|
||||
});
|
||||
|
||||
it('Allows the rule to be duplicated from the table', () => {
|
||||
waitForKibana();
|
||||
duplicateFirstRule();
|
||||
cy.contains(RULE_NAME, `${newThreatIndicatorRule.name} [Duplicate]`);
|
||||
});
|
||||
|
||||
it('Allows the rule to be duplicated from the edit screen', () => {
|
||||
waitForKibana();
|
||||
goToRuleDetails();
|
||||
duplicateRuleFromMenu();
|
||||
goBackToAllRulesTable();
|
||||
reload();
|
||||
cy.contains(RULE_NAME, `${newThreatIndicatorRule.name} [Duplicate]`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,6 +17,12 @@ export const DELETE_RULE_ACTION_BTN = '[data-test-subj="deleteRuleAction"]';
|
|||
|
||||
export const EDIT_RULE_ACTION_BTN = '[data-test-subj="editRuleAction"]';
|
||||
|
||||
export const DUPLICATE_RULE_ACTION_BTN = '[data-test-subj="duplicateRuleAction"]';
|
||||
|
||||
export const DUPLICATE_RULE_MENU_PANEL_BTN = '[data-test-subj="rules-details-duplicate-rule"]';
|
||||
|
||||
export const REFRESH_BTN = '[data-test-subj="refreshRulesAction"] button';
|
||||
|
||||
export const DELETE_RULE_BULK_BTN = '[data-test-subj="deleteRuleBulk"]';
|
||||
|
||||
export const ELASTIC_RULES_BTN = '[data-test-subj="showElasticRulesFilterButton"]';
|
||||
|
|
|
@ -31,6 +31,8 @@ import {
|
|||
RULE_AUTO_REFRESH_IDLE_MODAL_CONTINUE,
|
||||
rowsPerPageSelector,
|
||||
pageSelector,
|
||||
DUPLICATE_RULE_ACTION_BTN,
|
||||
DUPLICATE_RULE_MENU_PANEL_BTN,
|
||||
} from '../screens/alerts_detection_rules';
|
||||
import { ALL_ACTIONS, DELETE_RULE } from '../screens/rule_details';
|
||||
|
||||
|
@ -45,6 +47,33 @@ export const editFirstRule = () => {
|
|||
cy.get(EDIT_RULE_ACTION_BTN).click();
|
||||
};
|
||||
|
||||
export const duplicateFirstRule = () => {
|
||||
cy.get(COLLAPSED_ACTION_BTN).should('be.visible');
|
||||
cy.get(COLLAPSED_ACTION_BTN).first().click({ force: true });
|
||||
cy.get(DUPLICATE_RULE_ACTION_BTN).should('be.visible');
|
||||
cy.get(DUPLICATE_RULE_ACTION_BTN).click();
|
||||
};
|
||||
|
||||
/**
|
||||
* Duplicates the rule from the menu and does additional
|
||||
* pipes and checking that the elements are present on the
|
||||
* page as well as removed when doing the clicks to help reduce
|
||||
* flake.
|
||||
*/
|
||||
export const duplicateRuleFromMenu = () => {
|
||||
cy.get(ALL_ACTIONS).should('be.visible');
|
||||
cy.root()
|
||||
.pipe(($el) => {
|
||||
$el.find(ALL_ACTIONS).trigger('click');
|
||||
return $el.find(DUPLICATE_RULE_MENU_PANEL_BTN);
|
||||
})
|
||||
.should(($el) => expect($el).to.be.visible);
|
||||
// Because of a fade effect and fast clicking this can produce more than one click
|
||||
cy.get(DUPLICATE_RULE_MENU_PANEL_BTN)
|
||||
.pipe(($el) => $el.trigger('click'))
|
||||
.should('not.be.visible');
|
||||
};
|
||||
|
||||
export const deleteFirstRule = () => {
|
||||
cy.get(COLLAPSED_ACTION_BTN).first().click({ force: true });
|
||||
cy.get(DELETE_RULE_ACTION_BTN).click();
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { CustomRule } from '../../objects/rule';
|
||||
import { CustomRule, ThreatIndicatorRule } from '../../objects/rule';
|
||||
|
||||
export const createCustomRule = (rule: CustomRule, ruleId = 'rule_testing') =>
|
||||
cy.request({
|
||||
|
@ -29,6 +29,44 @@ export const createCustomRule = (rule: CustomRule, ruleId = 'rule_testing') =>
|
|||
failOnStatusCode: false,
|
||||
});
|
||||
|
||||
export const createCustomIndicatorRule = (rule: ThreatIndicatorRule, ruleId = 'rule_testing') =>
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: 'api/detection_engine/rules',
|
||||
body: {
|
||||
rule_id: ruleId,
|
||||
risk_score: parseInt(rule.riskScore, 10),
|
||||
description: rule.description,
|
||||
interval: '10s',
|
||||
name: rule.name,
|
||||
severity: rule.severity.toLocaleLowerCase(),
|
||||
type: 'threat_match',
|
||||
threat_mapping: [
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
field: rule.indicatorMapping,
|
||||
type: 'mapping',
|
||||
value: rule.indicatorMapping,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
threat_query: '*:*',
|
||||
threat_language: 'kuery',
|
||||
threat_filters: [],
|
||||
threat_index: ['mock*'],
|
||||
threat_indicator_path: '',
|
||||
from: 'now-17520h',
|
||||
index: ['exceptions-*'],
|
||||
query: rule.customQuery || '*:*',
|
||||
language: 'kuery',
|
||||
enabled: false,
|
||||
},
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
failOnStatusCode: false,
|
||||
});
|
||||
|
||||
export const createCustomRuleActivated = (rule: CustomRule, ruleId = '1') =>
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import * as H from 'history';
|
||||
import React, { Dispatch } from 'react';
|
||||
|
||||
import { CreateRulesSchema } from '../../../../../../common/detection_engine/schemas/request';
|
||||
import {
|
||||
deleteRules,
|
||||
duplicateRules,
|
||||
|
@ -28,6 +29,7 @@ import { track, METRIC_TYPE, TELEMETRY_EVENT } from '../../../../../common/lib/t
|
|||
|
||||
import * as i18n from '../translations';
|
||||
import { bucketRulesResponse } from './helpers';
|
||||
import { transformOutput } from '../../../../containers/detection_engine/rules/transforms';
|
||||
|
||||
export const editRuleAction = (rule: Rule, history: H.History) => {
|
||||
history.push(getEditRuleUrl(rule.id));
|
||||
|
@ -41,7 +43,11 @@ export const duplicateRulesAction = async (
|
|||
) => {
|
||||
try {
|
||||
dispatch({ type: 'loadingRuleIds', ids: ruleIds, actionType: 'duplicate' });
|
||||
const response = await duplicateRules({ rules });
|
||||
const response = await duplicateRules({
|
||||
// We cast this back and forth here as the front end types are not really the right io-ts ones
|
||||
// and the two types conflict with each other.
|
||||
rules: rules.map((rule) => transformOutput(rule as CreateRulesSchema) as Rule),
|
||||
});
|
||||
const { errors } = bucketRulesResponse(response);
|
||||
if (errors.length > 0) {
|
||||
displayErrorToast(
|
||||
|
|
|
@ -67,6 +67,7 @@ export const getActions = (
|
|||
enabled: (rowItem: Rule) => canEditRuleWithActions(rowItem, actionsPrivileges),
|
||||
},
|
||||
{
|
||||
'data-test-subj': 'duplicateRuleAction',
|
||||
description: i18n.DUPLICATE_RULE,
|
||||
icon: 'copy',
|
||||
name: !actionsPrivileges ? (
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue