[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:
Kibana Machine 2023-12-19 06:25:04 -05:00 committed by GitHub
parent 8ec5588603
commit a1f2e91676
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 231 additions and 1 deletions

View file

@ -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([]);
});
});
});
});
});
});

View file

@ -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);

View file

@ -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();