[8.10] [Security Solution] Fix the rules coverage overview API contract (#163838) (#164505)

# Backport

This will backport the following commits from `main` to `8.10`:
- [[Security Solution] Fix the rules coverage overview API contract
(#163838)](https://github.com/elastic/kibana/pull/163838)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Georgii
Gorbachev","email":"georgii.gorbachev@elastic.co"},"sourceCommit":{"committedDate":"2023-08-22T19:46:32Z","message":"[Security
Solution] Fix the rules coverage overview API contract
(#163838)\n\n**Epic:**
https://github.com/elastic/security-team/issues/2905\r\n(internal)\r\n\r\n##
Summary\r\n\r\nIn our API endpoints, we shouldn't expose parameters for
features we\r\ndon't support yet.\r\n\r\nThis PR:\r\n\r\n- Removes the
`CoverageOverviewRuleActivity.Available`
and\r\n`CoverageOverviewRuleSource.Customized` enum values from the
coverage\r\nendpoint's request schema.\r\n- Does some additional
cleanup.\r\n\r\nWe will add the removed parameters back when we add the
corresponding\r\nenhancements to the
feature.","sha":"9b489edbae6c7c7acdabe88182a5c64e1967b9fa","branchLabelMapping":{"^v8.11.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:skip","Team:Detections
and Resp","Team: SecuritySolution","Feature:Rule
Management","Team:Detection Rule
Management","v8.10.0","v8.11.0"],"number":163838,"url":"https://github.com/elastic/kibana/pull/163838","mergeCommit":{"message":"[Security
Solution] Fix the rules coverage overview API contract
(#163838)\n\n**Epic:**
https://github.com/elastic/security-team/issues/2905\r\n(internal)\r\n\r\n##
Summary\r\n\r\nIn our API endpoints, we shouldn't expose parameters for
features we\r\ndon't support yet.\r\n\r\nThis PR:\r\n\r\n- Removes the
`CoverageOverviewRuleActivity.Available`
and\r\n`CoverageOverviewRuleSource.Customized` enum values from the
coverage\r\nendpoint's request schema.\r\n- Does some additional
cleanup.\r\n\r\nWe will add the removed parameters back when we add the
corresponding\r\nenhancements to the
feature.","sha":"9b489edbae6c7c7acdabe88182a5c64e1967b9fa"}},"sourceBranch":"main","suggestedTargetBranches":["8.10"],"targetPullRequestStates":[{"branch":"8.10","label":"v8.10.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.11.0","labelRegex":"^v8.11.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/163838","number":163838,"mergeCommit":{"message":"[Security
Solution] Fix the rules coverage overview API contract
(#163838)\n\n**Epic:**
https://github.com/elastic/security-team/issues/2905\r\n(internal)\r\n\r\n##
Summary\r\n\r\nIn our API endpoints, we shouldn't expose parameters for
features we\r\ndon't support yet.\r\n\r\nThis PR:\r\n\r\n- Removes the
`CoverageOverviewRuleActivity.Available`
and\r\n`CoverageOverviewRuleSource.Customized` enum values from the
coverage\r\nendpoint's request schema.\r\n- Does some additional
cleanup.\r\n\r\nWe will add the removed parameters back when we add the
corresponding\r\nenhancements to the
feature.","sha":"9b489edbae6c7c7acdabe88182a5c64e1967b9fa"}}]}]
BACKPORT-->

Co-authored-by: Georgii Gorbachev <georgii.gorbachev@elastic.co>
This commit is contained in:
Kibana Machine 2023-08-22 17:10:03 -04:00 committed by GitHub
parent a95427813a
commit eae43a3434
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 56 additions and 56 deletions

View file

@ -9,24 +9,18 @@ import * as t from 'io-ts';
import { enumeration, NonEmptyArray, NonEmptyString } from '@kbn/securitysolution-io-ts-types';
/**
* Rule activity (status) filter applicable to two groups of rules
* - installed from a Fleet package, custom and customized which are installed but customized later on which
* can be either enabled or disabled
* - available to be installed from a Fleet package rules
* Rule activity (status) filter, which now can filter enabled and disabled rules.
* Later we're going to support available rules as well (prebuilt rules that are not yet installed).
*/
export enum CoverageOverviewRuleActivity {
/**
* Enabled rules (installed from a Fleet package, custom or customized)
* Enabled rules (prebuilt and custom)
*/
Enabled = 'enabled',
/**
* Disabled rules (installed from a Fleet package, custom or customized)
* Disabled rules (prebuilt and custom)
*/
Disabled = 'disabled',
/**
* Available to be installed from a Fleet package rules (Elastic prebuilt rules)
*/
Available = 'available',
}
export const CoverageOverviewRuleActivitySchema = enumeration(
'CoverageOverviewRuleActivity',
@ -45,10 +39,6 @@ export enum CoverageOverviewRuleSource {
* Rules created manually
*/
Custom = 'custom',
/**
* Rules installed from a Fleet package but modified later on
*/
Customized = 'customized',
}
export const CoverageOverviewRuleSourceSchema = enumeration(
'CoverageOverviewRuleSource',

View file

@ -115,10 +115,13 @@ function addRule(
id: ruleId,
name: ruleData.name,
});
} else if (ruleData.activity === CoverageOverviewRuleActivity.Available) {
container.availableRules.push({
id: ruleId,
name: ruleData.name,
});
}
// When we add support for available (not installed) rules to this feature, add the following here:
// else if (ruleData.activity === CoverageOverviewRuleActivity.Available) {
// container.availableRules.push({
// id: ruleId,
// name: ruleData.name,
// });
// }
}

View file

@ -39,13 +39,7 @@ export async function handleCoverageOverviewRequest({
filter: filter.search_term,
showCustomRules: filter.source?.includes(CoverageOverviewRuleSource.Custom) ?? false,
showElasticRules: filter.source?.includes(CoverageOverviewRuleSource.Prebuilt) ?? false,
enabled:
(activitySet.has(CoverageOverviewRuleActivity.Enabled) &&
activitySet.has(CoverageOverviewRuleActivity.Disabled)) ||
(!activitySet.has(CoverageOverviewRuleActivity.Enabled) &&
!activitySet.has(CoverageOverviewRuleActivity.Disabled))
? undefined
: activitySet.has(CoverageOverviewRuleActivity.Enabled),
enabled: getIsEnabledFilter(activitySet),
})
: undefined;
@ -69,6 +63,47 @@ export async function handleCoverageOverviewRequest({
} as CoverageOverviewResponse);
}
function getIsEnabledFilter(activitySet: Set<CoverageOverviewRuleActivity>): boolean | undefined {
const bothSpecified =
activitySet.has(CoverageOverviewRuleActivity.Enabled) &&
activitySet.has(CoverageOverviewRuleActivity.Disabled);
const noneSpecified =
!activitySet.has(CoverageOverviewRuleActivity.Enabled) &&
!activitySet.has(CoverageOverviewRuleActivity.Disabled);
return bothSpecified || noneSpecified
? undefined
: activitySet.has(CoverageOverviewRuleActivity.Enabled);
}
function appendRuleToResponse(
response: CoverageOverviewResponse,
rule: SanitizedRule<CoverageOverviewRuleParams>
): CoverageOverviewResponse {
const categories = extractRuleMitreCategories(rule);
for (const category of categories) {
if (!response.coverage[category]) {
response.coverage[category] = [rule.id];
} else {
response.coverage[category].push(rule.id);
}
}
if (categories.length === 0) {
response.unmapped_rule_ids.push(rule.id);
}
response.rules_data[rule.id] = {
name: rule.name,
activity: rule.enabled
? CoverageOverviewRuleActivity.Enabled
: CoverageOverviewRuleActivity.Disabled,
};
return response;
}
/**
* Extracts rule's MITRE ATT&CK tactics, techniques and subtechniques
*
@ -101,31 +136,3 @@ function extractRuleMitreCategories(rule: SanitizedRule<CoverageOverviewRulePara
return Array.from(categories);
}
function appendRuleToResponse(
response: CoverageOverviewResponse,
rule: SanitizedRule<CoverageOverviewRuleParams>
): CoverageOverviewResponse {
const categories = extractRuleMitreCategories(rule);
for (const category of categories) {
if (!response.coverage[category]) {
response.coverage[category] = [rule.id];
} else {
response.coverage[category].push(rule.id);
}
}
if (categories.length === 0) {
response.unmapped_rule_ids.push(rule.id);
}
response.rules_data[rule.id] = {
name: rule.name,
activity: rule.enabled
? CoverageOverviewRuleActivity.Enabled
: CoverageOverviewRuleActivity.Disabled,
};
return response;
}

View file

@ -342,9 +342,9 @@ export default ({ getService }: FtrProviderContext): void => {
});
});
it('returns response filtered by enabled and disabled rules equal to response if enabled and disabled are not set', async () => {
it('returns all rules if both enabled and disabled filters are specified in the request', async () => {
const expectedRule1 = await createRule(supertest, log, {
...getSimpleRule('rule-1'),
...getSimpleRule('rule-1', false),
name: 'Disabled rule',
threat: generateThreatArray(1),
});