mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[8.12] [Security Solution][Detection Engine] fixes alert suppression define step preview on rule creation (#173145) (#173599)
# Backport This will backport the following commits from `main` to `8.12`: - [[Security Solution][Detection Engine] fixes alert suppression define step preview on rule creation (#173145)](https://github.com/elastic/kibana/pull/173145) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Vitalii Dmyterko","email":"92328789+vitaliidm@users.noreply.github.com"},"sourceCommit":{"committedDate":"2023-12-19T10:14:52Z","message":"[Security Solution][Detection Engine] fixes alert suppression define step preview on rule creation (#173145)\n\n## Summary\r\n\r\n- fixes alert suppression fields that appear on define step preview\r\nduring rule creation\r\nOnly `query` and `threshold` rule type support alert suppression, but\r\nsuppression fields can appear for other rule types when switching\r\nbetween them, while suppression was configured\r\n- fixes Define step for `threshold` rule, when suppression duration\r\nwasn't showing\r\n\r\n### Steps to reproduce\r\n\r\n1. Go to create rule form\r\n2. Select query rule type\r\n3. Configure alert suppression for it\r\n4. Switch to any other rule type\r\n5. Complete define step\r\n6. Spot, suppression fields on Define step\r\n\r\n#### Leaking suppression fields to other rule types\r\n\r\na472daf0
-bb74-4a6b-841b-3b0097eb4503\r\n\r\n#### Missing duration for threshold\r\n\r\n\r\n\r\n7df8431d
-3ee0-482a-9e06-cb87656f48e0\r\n\r\n\r\n### Fixed UI\r\n\r\n#### Leaking suppression fields to other rule types\r\n\r\n03057dc6
-c007-4b17-8f8b-30e78923f037\r\n\r\n#### Missing duration for threshold\r\n\r\n\r\n7f64c79f
-7a51-4d43-bd62-b10eefe15c46\r\n\r\n\r\n\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Ryland Herrick <ryalnd@gmail.com>","sha":"dee5acb17ed643f1cf432b032f4305ba51e5799f","branchLabelMapping":{"^v8.13.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:Detections and Resp","Team: SecuritySolution","backport:prev-minor","Team:Detection Engine","v8.12.0","v8.13.0"],"number":173145,"url":"https://github.com/elastic/kibana/pull/173145","mergeCommit":{"message":"[Security Solution][Detection Engine] fixes alert suppression define step preview on rule creation (#173145)\n\n## Summary\r\n\r\n- fixes alert suppression fields that appear on define step preview\r\nduring rule creation\r\nOnly `query` and `threshold` rule type support alert suppression, but\r\nsuppression fields can appear for other rule types when switching\r\nbetween them, while suppression was configured\r\n- fixes Define step for `threshold` rule, when suppression duration\r\nwasn't showing\r\n\r\n### Steps to reproduce\r\n\r\n1. Go to create rule form\r\n2. Select query rule type\r\n3. Configure alert suppression for it\r\n4. Switch to any other rule type\r\n5. Complete define step\r\n6. Spot, suppression fields on Define step\r\n\r\n#### Leaking suppression fields to other rule types\r\n\r\na472daf0
-bb74-4a6b-841b-3b0097eb4503\r\n\r\n#### Missing duration for threshold\r\n\r\n\r\n\r\n7df8431d
-3ee0-482a-9e06-cb87656f48e0\r\n\r\n\r\n### Fixed UI\r\n\r\n#### Leaking suppression fields to other rule types\r\n\r\n03057dc6
-c007-4b17-8f8b-30e78923f037\r\n\r\n#### Missing duration for threshold\r\n\r\n\r\n7f64c79f
-7a51-4d43-bd62-b10eefe15c46\r\n\r\n\r\n\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Ryland Herrick <ryalnd@gmail.com>","sha":"dee5acb17ed643f1cf432b032f4305ba51e5799f"}},"sourceBranch":"main","suggestedTargetBranches":["8.12"],"targetPullRequestStates":[{"branch":"8.12","label":"v8.12.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.13.0","labelRegex":"^v8.13.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/173145","number":173145,"mergeCommit":{"message":"[Security Solution][Detection Engine] fixes alert suppression define step preview on rule creation (#173145)\n\n## Summary\r\n\r\n- fixes alert suppression fields that appear on define step preview\r\nduring rule creation\r\nOnly `query` and `threshold` rule type support alert suppression, but\r\nsuppression fields can appear for other rule types when switching\r\nbetween them, while suppression was configured\r\n- fixes Define step for `threshold` rule, when suppression duration\r\nwasn't showing\r\n\r\n### Steps to reproduce\r\n\r\n1. Go to create rule form\r\n2. Select query rule type\r\n3. Configure alert suppression for it\r\n4. Switch to any other rule type\r\n5. Complete define step\r\n6. Spot, suppression fields on Define step\r\n\r\n#### Leaking suppression fields to other rule types\r\n\r\na472daf0
-bb74-4a6b-841b-3b0097eb4503\r\n\r\n#### Missing duration for threshold\r\n\r\n\r\n\r\n7df8431d
-3ee0-482a-9e06-cb87656f48e0\r\n\r\n\r\n### Fixed UI\r\n\r\n#### Leaking suppression fields to other rule types\r\n\r\n03057dc6
-c007-4b17-8f8b-30e78923f037\r\n\r\n#### Missing duration for threshold\r\n\r\n\r\n7f64c79f
-7a51-4d43-bd62-b10eefe15c46\r\n\r\n\r\n\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Ryland Herrick <ryalnd@gmail.com>","sha":"dee5acb17ed643f1cf432b032f4305ba51e5799f"}}]}] BACKPORT--> Co-authored-by: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com>
This commit is contained in:
parent
8ec5588603
commit
a1f2e91676
3 changed files with 231 additions and 1 deletions
|
@ -14,6 +14,7 @@ import {
|
|||
buildListItems,
|
||||
getDescriptionItem,
|
||||
} from '.';
|
||||
import type { Type } from '@kbn/securitysolution-io-ts-alerting-types';
|
||||
|
||||
import { FilterManager, UI_SETTINGS } from '@kbn/data-plugin/public';
|
||||
import type { Filter } from '@kbn/es-query';
|
||||
|
@ -534,5 +535,207 @@ describe('description_step', () => {
|
|||
expect(React.isValidElement(result[0].description)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('alert suppression', () => {
|
||||
const ruleTypesWithoutSuppression: Type[] = [
|
||||
'eql',
|
||||
'esql',
|
||||
'machine_learning',
|
||||
'new_terms',
|
||||
'threat_match',
|
||||
];
|
||||
const suppressionFields = {
|
||||
groupByDuration: {
|
||||
unit: 'm',
|
||||
value: 50,
|
||||
},
|
||||
groupByRadioSelection: 'per-time-period',
|
||||
enableThresholdSuppression: true,
|
||||
groupByFields: ['agent.name'],
|
||||
suppressionMissingFields: 'suppress',
|
||||
};
|
||||
describe('groupByDuration', () => {
|
||||
ruleTypesWithoutSuppression.forEach((ruleType) => {
|
||||
test(`should be empty if rule is ${ruleType}`, () => {
|
||||
const result: ListItems[] = getDescriptionItem(
|
||||
'groupByDuration',
|
||||
'label',
|
||||
{
|
||||
ruleType,
|
||||
...suppressionFields,
|
||||
},
|
||||
mockFilterManager,
|
||||
mockLicenseService
|
||||
);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
['query', 'saved_query'].forEach((ruleType) => {
|
||||
test(`should be empty if groupByFields empty for ${ruleType} rule`, () => {
|
||||
const result: ListItems[] = getDescriptionItem(
|
||||
'groupByDuration',
|
||||
'label',
|
||||
{
|
||||
ruleType: 'query',
|
||||
...suppressionFields,
|
||||
groupByFields: [],
|
||||
},
|
||||
mockFilterManager,
|
||||
mockLicenseService
|
||||
);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
test(`should return item for ${ruleType} rule`, () => {
|
||||
const result: ListItems[] = getDescriptionItem(
|
||||
'groupByDuration',
|
||||
'label',
|
||||
{
|
||||
ruleType: 'query',
|
||||
...suppressionFields,
|
||||
},
|
||||
mockFilterManager,
|
||||
mockLicenseService
|
||||
);
|
||||
|
||||
expect(result[0].description).toBe('50m');
|
||||
});
|
||||
});
|
||||
|
||||
test('should return item for threshold rule', () => {
|
||||
const result: ListItems[] = getDescriptionItem(
|
||||
'groupByDuration',
|
||||
'label',
|
||||
{
|
||||
ruleType: 'threshold',
|
||||
...suppressionFields,
|
||||
},
|
||||
mockFilterManager,
|
||||
mockLicenseService
|
||||
);
|
||||
|
||||
expect(result[0].description).toBe('50m');
|
||||
});
|
||||
|
||||
test('should return item for threshold rule if groupByFields empty', () => {
|
||||
const result: ListItems[] = getDescriptionItem(
|
||||
'groupByDuration',
|
||||
'label',
|
||||
{
|
||||
ruleType: 'threshold',
|
||||
...suppressionFields,
|
||||
groupByFields: [],
|
||||
},
|
||||
mockFilterManager,
|
||||
mockLicenseService
|
||||
);
|
||||
|
||||
expect(result[0].description).toBe('50m');
|
||||
});
|
||||
|
||||
test('should be empty for threshold rule if suppression not enabled', () => {
|
||||
const result: ListItems[] = getDescriptionItem(
|
||||
'groupByDuration',
|
||||
'label',
|
||||
{
|
||||
ruleType: 'threshold',
|
||||
...suppressionFields,
|
||||
enableThresholdSuppression: false,
|
||||
},
|
||||
mockFilterManager,
|
||||
mockLicenseService
|
||||
);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('groupByFields', () => {
|
||||
[...ruleTypesWithoutSuppression, 'threshold'].forEach((ruleType) => {
|
||||
test(`should be empty if rule is ${ruleType}`, () => {
|
||||
const result: ListItems[] = getDescriptionItem(
|
||||
'groupByFields',
|
||||
'label',
|
||||
{
|
||||
ruleType,
|
||||
...suppressionFields,
|
||||
},
|
||||
mockFilterManager,
|
||||
mockLicenseService
|
||||
);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
['query', 'saved_query'].forEach((ruleType) => {
|
||||
test(`should return item for ${ruleType} rule`, () => {
|
||||
const result: ListItems[] = getDescriptionItem(
|
||||
'groupByFields',
|
||||
'label',
|
||||
{
|
||||
ruleType,
|
||||
...suppressionFields,
|
||||
},
|
||||
mockFilterManager,
|
||||
mockLicenseService
|
||||
);
|
||||
expect(mount(result[0].description as React.ReactElement).text()).toBe('agent.name');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('suppressionMissingFields', () => {
|
||||
[...ruleTypesWithoutSuppression, 'threshold'].forEach((ruleType) => {
|
||||
test(`should be empty if rule is ${ruleType}`, () => {
|
||||
const result: ListItems[] = getDescriptionItem(
|
||||
'suppressionMissingFields',
|
||||
'label',
|
||||
{
|
||||
ruleType,
|
||||
...suppressionFields,
|
||||
},
|
||||
mockFilterManager,
|
||||
mockLicenseService
|
||||
);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
['query', 'saved_query'].forEach((ruleType) => {
|
||||
test(`should return item for ${ruleType} rule`, () => {
|
||||
const result: ListItems[] = getDescriptionItem(
|
||||
'suppressionMissingFields',
|
||||
'label',
|
||||
{
|
||||
ruleType,
|
||||
...suppressionFields,
|
||||
},
|
||||
mockFilterManager,
|
||||
mockLicenseService
|
||||
);
|
||||
expect(result[0].description).toContain('Suppress');
|
||||
});
|
||||
|
||||
test(`should be empty if groupByFields empty for ${ruleType} rule`, () => {
|
||||
const result: ListItems[] = getDescriptionItem(
|
||||
'suppressionMissingFields',
|
||||
'label',
|
||||
{
|
||||
ruleType: 'query',
|
||||
...suppressionFields,
|
||||
groupByFields: [],
|
||||
},
|
||||
mockFilterManager,
|
||||
mockLicenseService
|
||||
);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -56,6 +56,7 @@ import { THREAT_QUERY_LABEL } from './translations';
|
|||
import { filterEmptyThreats } from '../../../../detection_engine/rule_creation_ui/pages/rule_creation/helpers';
|
||||
import { useLicense } from '../../../../common/hooks/use_license';
|
||||
import type { LicenseService } from '../../../../../common/license';
|
||||
import { isThresholdRule, isQueryRule } from '../../../../../common/detection_engine/utils';
|
||||
|
||||
const DescriptionListContainer = styled(EuiDescriptionList)`
|
||||
max-width: 600px;
|
||||
|
@ -204,12 +205,29 @@ export const getDescriptionItem = (
|
|||
} else if (field === 'responseActions') {
|
||||
return [];
|
||||
} else if (field === 'groupByFields') {
|
||||
const ruleType: Type = get('ruleType', data);
|
||||
const ruleCanHaveGroupByFields = isQueryRule(ruleType);
|
||||
if (!ruleCanHaveGroupByFields) {
|
||||
return [];
|
||||
}
|
||||
const values: string[] = get(field, data);
|
||||
return buildAlertSuppressionDescription(label, values);
|
||||
} else if (field === 'groupByRadioSelection') {
|
||||
return [];
|
||||
} else if (field === 'groupByDuration') {
|
||||
if (get('groupByFields', data).length > 0) {
|
||||
const ruleType: Type = get('ruleType', data);
|
||||
const ruleCanHaveDuration = isQueryRule(ruleType) || isThresholdRule(ruleType);
|
||||
if (!ruleCanHaveDuration) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// threshold rule has suppression duration without grouping fields, but suppression should be explicitly enabled by user
|
||||
// query rule have suppression duration only if group by fields selected
|
||||
const showDuration = isThresholdRule(ruleType)
|
||||
? get('enableThresholdSuppression', data) === true
|
||||
: get('groupByFields', data).length > 0;
|
||||
|
||||
if (showDuration) {
|
||||
const value: Duration = get(field, data);
|
||||
return buildAlertSuppressionWindowDescription(
|
||||
label,
|
||||
|
@ -220,6 +238,11 @@ export const getDescriptionItem = (
|
|||
return [];
|
||||
}
|
||||
} else if (field === 'suppressionMissingFields') {
|
||||
const ruleType: Type = get('ruleType', data);
|
||||
const ruleCanHaveSuppressionMissingFields = isQueryRule(ruleType);
|
||||
if (!ruleCanHaveSuppressionMissingFields) {
|
||||
return [];
|
||||
}
|
||||
if (get('groupByFields', data).length > 0) {
|
||||
const value = get(field, data);
|
||||
return buildAlertSuppressionMissingFieldsDescription(label, value);
|
||||
|
|
|
@ -163,6 +163,10 @@ describe(
|
|||
|
||||
enablesAndPopulatesThresholdSuppression(5, 'h');
|
||||
fillDefineThresholdRuleAndContinue(rule);
|
||||
// ensures duration displayed on define step in preview mode
|
||||
cy.get(DEFINITION_DETAILS).within(() => {
|
||||
getDetails(SUPPRESS_FOR_DETAILS).should('have.text', '5h');
|
||||
});
|
||||
|
||||
fillAboutRuleMinimumAndContinue(rule);
|
||||
skipScheduleRuleAction();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue