mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Security Solution] Adds telemetry for legacy notifications and regular notifications at a finer grained level (#123332) (#123388)
## Summary
Related and previous PR:
https://github.com/elastic/kibana/pull/122472
This removes the above structure from the PR above and instead opts to use a more finer grained level of telemetry. The new structure adds to each rule these four counters to the telemetry:
* legacy_notifications_enabled - The number of legacy notifications on rules that are enabled/active
* legacy_notifications_disabled - The number of legacy notifications on rules that are disabled/in-active
* notifications_enabled - The number of notifications on rules that are enabled/active
* notifications_disabled - The number of notifications on rules that are disabled/in-active
For pre-built rules you have these booleans:
* has_legacy_notification - True if the pre-built rule has a legacy notification attached, otherwise false.
* has_notification - True if the pre-built rule has a notification attached, otherwise false.
Note, both those booleans are `false` if the pre-built rule has no notifications attached and both can never be `true` together.
These will show up within each rule type like for example on a query rule it will look like:
```json
"detection_rule_usage": {
"query": {
"enabled": 2,
"disabled": 1,
"cases": 0,
"legacy_notifications_enabled": 1, <-- New
"legacy_notifications_disabled": 0, <-- New
"notifications_enabled": 1, <-- New
"notifications_disabled": 1 <-- New
}
```
Within the counts/total sections it will show up on both the `elastic` rules and the `custom` rules like so:
```json
"elastic_total": {
"enabled": 0,
"disabled": 0,
"alerts": 0,
"cases": 0,
"legacy_notifications_enabled": 0, <-- New
"legacy_notifications_disabled": 0, <-- New
"notifications_enabled": 0, <-- New
"notifications_disabled": 0 <-- New
},
"custom_total": {
"enabled": 2,
"disabled": 1,
"alerts": 7218,
"cases": 0,
"legacy_notifications_enabled": 1, <-- New
"legacy_notifications_disabled": 0, <-- New
"notifications_enabled": 1, <-- New
"notifications_disabled": 1 <-- New
}
```
For pre-built it will be:
```json
"detection_rule_detail": [
{
"rule_name": "Potential Evasion via Filter Manager",
"rule_id": "06dceabf-adca-48af-ac79-ffdf4c3b1e9a",
"rule_type": "eql",
"rule_version": 8,
"enabled": false,
"elastic_rule": true,
"created_on": "2022-01-19T01:29:25.540Z",
"updated_on": "2022-01-19T01:29:25.540Z",
"alert_count_daily": 0,
"cases_count_total": 0,
"has_legacy_notification": false, <-- New
"has_notification": false <-- New
},
```
Screen shot of it if you go to "Advanced settings -> cluster data":
<img width="802" alt="Screen Shot 2022-01-18 at 6 27 14 PM" src="https://user-images.githubusercontent.com/1151048/150046445-b1850b1c-bca6-41e0-b101-1bac5f67dbb3.png">
<img width="798" alt="Screen Shot 2022-01-18 at 6 30 33 PM" src="https://user-images.githubusercontent.com/1151048/150046808-1109a4c9-8a54-4da8-8b42-5f957a9d3ed5.png">
Follow the manual test instructions on https://github.com/elastic/kibana/pull/122472 for how to test this. The same manual testing applies here for seeing how these work out. You should be able to see a higher granularity with these stats.
### Checklist
- [ ] [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
(cherry picked from commit d2a8bb90be
)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
7d914cc12a
commit
f2473025f9
11 changed files with 1797 additions and 196 deletions
|
@ -3,7 +3,7 @@
|
|||
"interval": "1m",
|
||||
"actions": [
|
||||
{
|
||||
"id": "1fa31c30-3046-11ec-8971-1f3f7bae65af",
|
||||
"id": "0cae9900-6e54-11ec-a124-bfe603780ab8",
|
||||
"group": "default",
|
||||
"params": {
|
||||
"message": "Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts"
|
||||
|
|
|
@ -10,6 +10,8 @@ import { CollectorFetchContext } from '../../../../../src/plugins/usage_collecti
|
|||
import { CollectorDependencies } from './types';
|
||||
import { fetchDetectionsMetrics } from './detections';
|
||||
import { SAVED_OBJECT_TYPES } from '../../../cases/common/constants';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { legacyRuleActionsSavedObjectType } from '../lib/detection_engine/rule_actions/legacy_saved_object_mappings';
|
||||
|
||||
export type RegisterCollector = (deps: CollectorDependencies) => void;
|
||||
export interface UsageData {
|
||||
|
@ -19,7 +21,11 @@ export interface UsageData {
|
|||
export async function getInternalSavedObjectsClient(core: CoreSetup) {
|
||||
return core.getStartServices().then(async ([coreStart]) => {
|
||||
// note: we include the "cases" and "alert" hidden types here otherwise we would not be able to query them. If at some point cases and alert is not considered a hidden type this can be removed
|
||||
return coreStart.savedObjects.createInternalRepository(['alert', ...SAVED_OBJECT_TYPES]);
|
||||
return coreStart.savedObjects.createInternalRepository([
|
||||
'alert',
|
||||
legacyRuleActionsSavedObjectType,
|
||||
...SAVED_OBJECT_TYPES,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -51,6 +57,22 @@ export const registerCollector: RegisterCollector = ({
|
|||
type: 'long',
|
||||
_meta: { description: 'Number of cases attached to query detection rule alerts' },
|
||||
},
|
||||
legacy_notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications enabled' },
|
||||
},
|
||||
legacy_notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications disabled' },
|
||||
},
|
||||
notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
},
|
||||
threshold: {
|
||||
enabled: {
|
||||
|
@ -71,6 +93,22 @@ export const registerCollector: RegisterCollector = ({
|
|||
description: 'Number of cases attached to threshold detection rule alerts',
|
||||
},
|
||||
},
|
||||
legacy_notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications enabled' },
|
||||
},
|
||||
legacy_notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications disabled' },
|
||||
},
|
||||
notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
},
|
||||
eql: {
|
||||
enabled: { type: 'long', _meta: { description: 'Number of eql rules enabled' } },
|
||||
|
@ -83,6 +121,22 @@ export const registerCollector: RegisterCollector = ({
|
|||
type: 'long',
|
||||
_meta: { description: 'Number of cases attached to eql detection rule alerts' },
|
||||
},
|
||||
legacy_notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications enabled' },
|
||||
},
|
||||
legacy_notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications disabled' },
|
||||
},
|
||||
notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
},
|
||||
machine_learning: {
|
||||
enabled: {
|
||||
|
@ -103,6 +157,22 @@ export const registerCollector: RegisterCollector = ({
|
|||
description: 'Number of cases attached to machine_learning detection rule alerts',
|
||||
},
|
||||
},
|
||||
legacy_notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications enabled' },
|
||||
},
|
||||
legacy_notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications disabled' },
|
||||
},
|
||||
notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
},
|
||||
threat_match: {
|
||||
enabled: {
|
||||
|
@ -123,11 +193,21 @@ export const registerCollector: RegisterCollector = ({
|
|||
description: 'Number of cases attached to threat_match detection rule alerts',
|
||||
},
|
||||
},
|
||||
},
|
||||
legacy_notifications: {
|
||||
total: {
|
||||
legacy_notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications still in use' },
|
||||
_meta: { description: 'Number of legacy notifications enabled' },
|
||||
},
|
||||
legacy_notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications disabled' },
|
||||
},
|
||||
notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
},
|
||||
elastic_total: {
|
||||
|
@ -144,6 +224,22 @@ export const registerCollector: RegisterCollector = ({
|
|||
type: 'long',
|
||||
_meta: { description: 'Number of cases attached to elastic detection rule alerts' },
|
||||
},
|
||||
legacy_notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications enabled' },
|
||||
},
|
||||
legacy_notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications disabled' },
|
||||
},
|
||||
notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
},
|
||||
custom_total: {
|
||||
enabled: { type: 'long', _meta: { description: 'Number of custom rules enabled' } },
|
||||
|
@ -156,6 +252,22 @@ export const registerCollector: RegisterCollector = ({
|
|||
type: 'long',
|
||||
_meta: { description: 'Number of cases attached to custom detection rule alerts' },
|
||||
},
|
||||
legacy_notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications enabled' },
|
||||
},
|
||||
legacy_notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of legacy notifications disabled' },
|
||||
},
|
||||
notifications_enabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
notifications_disabled: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of notifications enabled' },
|
||||
},
|
||||
},
|
||||
},
|
||||
detection_rule_detail: {
|
||||
|
@ -198,6 +310,14 @@ export const registerCollector: RegisterCollector = ({
|
|||
type: 'long',
|
||||
_meta: { description: 'The number of total cases generated by a rule' },
|
||||
},
|
||||
has_legacy_notification: {
|
||||
type: 'boolean',
|
||||
_meta: { description: 'True if this rule has a legacy notification' },
|
||||
},
|
||||
has_notification: {
|
||||
type: 'boolean',
|
||||
_meta: { description: 'True if this rule has a notification' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -8,13 +8,25 @@
|
|||
import { initialDetectionRulesUsage, updateDetectionRuleUsage } from './detection_rule_helpers';
|
||||
import { DetectionRuleMetric, DetectionRulesTypeUsage } from './types';
|
||||
|
||||
const createStubRule = (
|
||||
ruleType: string,
|
||||
enabled: boolean,
|
||||
elasticRule: boolean,
|
||||
alertCount: number,
|
||||
caseCount: number
|
||||
): DetectionRuleMetric => ({
|
||||
interface StubRuleOptions {
|
||||
ruleType: string;
|
||||
enabled: boolean;
|
||||
elasticRule: boolean;
|
||||
alertCount: number;
|
||||
caseCount: number;
|
||||
hasLegacyNotification: boolean;
|
||||
hasNotification: boolean;
|
||||
}
|
||||
|
||||
const createStubRule = ({
|
||||
ruleType,
|
||||
enabled,
|
||||
elasticRule,
|
||||
alertCount,
|
||||
caseCount,
|
||||
hasLegacyNotification,
|
||||
hasNotification,
|
||||
}: StubRuleOptions): DetectionRuleMetric => ({
|
||||
rule_name: 'rule-name',
|
||||
rule_id: 'id-123',
|
||||
rule_type: ruleType,
|
||||
|
@ -25,12 +37,22 @@ const createStubRule = (
|
|||
updated_on: '2022-01-06T20:02:45.306Z',
|
||||
alert_count_daily: alertCount,
|
||||
cases_count_total: caseCount,
|
||||
has_legacy_notification: hasLegacyNotification,
|
||||
has_notification: hasNotification,
|
||||
});
|
||||
|
||||
describe('Detections Usage and Metrics', () => {
|
||||
describe('Update metrics with rule information', () => {
|
||||
it('Should update elastic and eql rule metric total', async () => {
|
||||
const stubRule = createStubRule('eql', true, true, 1, 1);
|
||||
const stubRule = createStubRule({
|
||||
ruleType: 'eql',
|
||||
enabled: true,
|
||||
elasticRule: true,
|
||||
alertCount: 1,
|
||||
caseCount: 1,
|
||||
hasLegacyNotification: false,
|
||||
hasNotification: false,
|
||||
});
|
||||
const usage = updateDetectionRuleUsage(stubRule, initialDetectionRulesUsage);
|
||||
|
||||
expect(usage).toEqual<DetectionRulesTypeUsage>({
|
||||
|
@ -40,22 +62,70 @@ describe('Detections Usage and Metrics', () => {
|
|||
cases: 1,
|
||||
disabled: 0,
|
||||
enabled: 1,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
eql: {
|
||||
alerts: 1,
|
||||
cases: 1,
|
||||
disabled: 0,
|
||||
enabled: 1,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Should update based on multiple metrics', async () => {
|
||||
const stubEqlRule = createStubRule('eql', true, true, 1, 1);
|
||||
const stubQueryRuleOne = createStubRule('query', true, true, 5, 2);
|
||||
const stubQueryRuleTwo = createStubRule('query', true, false, 5, 2);
|
||||
const stubMachineLearningOne = createStubRule('machine_learning', false, false, 0, 10);
|
||||
const stubMachineLearningTwo = createStubRule('machine_learning', true, true, 22, 44);
|
||||
const stubEqlRule = createStubRule({
|
||||
ruleType: 'eql',
|
||||
enabled: true,
|
||||
elasticRule: true,
|
||||
alertCount: 1,
|
||||
caseCount: 1,
|
||||
hasLegacyNotification: false,
|
||||
hasNotification: false,
|
||||
});
|
||||
const stubQueryRuleOne = createStubRule({
|
||||
ruleType: 'query',
|
||||
enabled: true,
|
||||
elasticRule: true,
|
||||
alertCount: 5,
|
||||
caseCount: 2,
|
||||
hasLegacyNotification: false,
|
||||
hasNotification: false,
|
||||
});
|
||||
const stubQueryRuleTwo = createStubRule({
|
||||
ruleType: 'query',
|
||||
enabled: true,
|
||||
elasticRule: false,
|
||||
alertCount: 5,
|
||||
caseCount: 2,
|
||||
hasLegacyNotification: false,
|
||||
hasNotification: false,
|
||||
});
|
||||
const stubMachineLearningOne = createStubRule({
|
||||
ruleType: 'machine_learning',
|
||||
enabled: false,
|
||||
elasticRule: false,
|
||||
alertCount: 0,
|
||||
caseCount: 10,
|
||||
hasLegacyNotification: false,
|
||||
hasNotification: false,
|
||||
});
|
||||
const stubMachineLearningTwo = createStubRule({
|
||||
ruleType: 'machine_learning',
|
||||
enabled: true,
|
||||
elasticRule: true,
|
||||
alertCount: 22,
|
||||
caseCount: 44,
|
||||
hasLegacyNotification: false,
|
||||
hasNotification: false,
|
||||
});
|
||||
|
||||
let usage = updateDetectionRuleUsage(stubEqlRule, initialDetectionRulesUsage);
|
||||
usage = updateDetectionRuleUsage(stubQueryRuleOne, usage);
|
||||
|
@ -70,32 +140,152 @@ describe('Detections Usage and Metrics', () => {
|
|||
cases: 12,
|
||||
disabled: 1,
|
||||
enabled: 1,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
elastic_total: {
|
||||
alerts: 28,
|
||||
cases: 47,
|
||||
disabled: 0,
|
||||
enabled: 3,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
eql: {
|
||||
alerts: 1,
|
||||
cases: 1,
|
||||
disabled: 0,
|
||||
enabled: 1,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
machine_learning: {
|
||||
alerts: 22,
|
||||
cases: 54,
|
||||
disabled: 1,
|
||||
enabled: 1,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
query: {
|
||||
alerts: 10,
|
||||
cases: 4,
|
||||
disabled: 0,
|
||||
enabled: 2,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
describe('table tests of "ruleType", "enabled", "elasticRule", and "legacyNotification"', () => {
|
||||
test.each`
|
||||
ruleType | enabled | hasLegacyNotification | hasNotification | expectedLegacyNotificationsEnabled | expectedLegacyNotificationsDisabled | expectedNotificationsEnabled | expectedNotificationsDisabled
|
||||
${'eql'} | ${true} | ${true} | ${false} | ${1} | ${0} | ${0} | ${0}
|
||||
${'eql'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0}
|
||||
${'eql'} | ${false} | ${false} | ${true} | ${0} | ${0} | ${0} | ${1}
|
||||
${'eql'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0}
|
||||
${'eql'} | ${false} | ${true} | ${false} | ${0} | ${1} | ${0} | ${0}
|
||||
${'eql'} | ${false} | ${false} | ${false} | ${0} | ${0} | ${0} | ${0}
|
||||
${'query'} | ${true} | ${true} | ${false} | ${1} | ${0} | ${0} | ${0}
|
||||
${'query'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0}
|
||||
${'query'} | ${false} | ${false} | ${true} | ${0} | ${0} | ${0} | ${1}
|
||||
${'query'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0}
|
||||
${'query'} | ${false} | ${true} | ${false} | ${0} | ${1} | ${0} | ${0}
|
||||
${'query'} | ${false} | ${false} | ${false} | ${0} | ${0} | ${0} | ${0}
|
||||
${'threshold'} | ${true} | ${true} | ${false} | ${1} | ${0} | ${0} | ${0}
|
||||
${'threshold'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0}
|
||||
${'threshold'} | ${false} | ${false} | ${true} | ${0} | ${0} | ${0} | ${1}
|
||||
${'threshold'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0}
|
||||
${'threshold'} | ${false} | ${true} | ${false} | ${0} | ${1} | ${0} | ${0}
|
||||
${'threshold'} | ${false} | ${false} | ${false} | ${0} | ${0} | ${0} | ${0}
|
||||
${'machine_learning'} | ${true} | ${true} | ${false} | ${1} | ${0} | ${0} | ${0}
|
||||
${'machine_learning'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0}
|
||||
${'machine_learning'} | ${false} | ${false} | ${true} | ${0} | ${0} | ${0} | ${1}
|
||||
${'machine_learning'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0}
|
||||
${'machine_learning'} | ${false} | ${true} | ${false} | ${0} | ${1} | ${0} | ${0}
|
||||
${'machine_learning'} | ${false} | ${false} | ${false} | ${0} | ${0} | ${0} | ${0}
|
||||
${'threat_match'} | ${true} | ${true} | ${false} | ${1} | ${0} | ${0} | ${0}
|
||||
${'threat_match'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0}
|
||||
${'threat_match'} | ${false} | ${false} | ${true} | ${0} | ${0} | ${0} | ${1}
|
||||
${'threat_match'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0}
|
||||
${'threat_match'} | ${false} | ${true} | ${false} | ${0} | ${1} | ${0} | ${0}
|
||||
${'threat_match'} | ${false} | ${false} | ${false} | ${0} | ${0} | ${0} | ${0}
|
||||
`(
|
||||
'expect { "ruleType": $ruleType, "enabled": $enabled, "hasLegacyNotification": $hasLegacyNotification, "hasNotification": $hasNotification } to equal { legacy_notifications_enabled: $expectedLegacyNotificationsEnabled, legacy_notifications_disabled: $expectedLegacyNotificationsDisabled, notifications_enabled: $expectedNotificationsEnabled, notifications_disabled, $expectedNotificationsDisabled }',
|
||||
({
|
||||
ruleType,
|
||||
enabled,
|
||||
hasLegacyNotification,
|
||||
hasNotification,
|
||||
expectedLegacyNotificationsEnabled,
|
||||
expectedLegacyNotificationsDisabled,
|
||||
expectedNotificationsEnabled,
|
||||
expectedNotificationsDisabled,
|
||||
}) => {
|
||||
const rule1 = createStubRule({
|
||||
ruleType,
|
||||
enabled,
|
||||
elasticRule: false,
|
||||
hasLegacyNotification,
|
||||
hasNotification,
|
||||
alertCount: 0,
|
||||
caseCount: 0,
|
||||
});
|
||||
const usage = updateDetectionRuleUsage(rule1, initialDetectionRulesUsage) as ReturnType<
|
||||
typeof updateDetectionRuleUsage
|
||||
> & { [key: string]: unknown };
|
||||
expect(usage[ruleType]).toEqual(
|
||||
expect.objectContaining({
|
||||
legacy_notifications_enabled: expectedLegacyNotificationsEnabled,
|
||||
legacy_notifications_disabled: expectedLegacyNotificationsDisabled,
|
||||
notifications_enabled: expectedNotificationsEnabled,
|
||||
notifications_disabled: expectedNotificationsDisabled,
|
||||
})
|
||||
);
|
||||
|
||||
// extra test where we add everything by 1 to ensure that the addition happens with the correct rule type
|
||||
const rule2 = createStubRule({
|
||||
ruleType,
|
||||
enabled,
|
||||
elasticRule: false,
|
||||
hasLegacyNotification,
|
||||
hasNotification,
|
||||
alertCount: 0,
|
||||
caseCount: 0,
|
||||
});
|
||||
const usageAddedByOne = updateDetectionRuleUsage(rule2, usage) as ReturnType<
|
||||
typeof updateDetectionRuleUsage
|
||||
> & { [key: string]: unknown };
|
||||
|
||||
expect(usageAddedByOne[ruleType]).toEqual(
|
||||
expect.objectContaining({
|
||||
legacy_notifications_enabled:
|
||||
expectedLegacyNotificationsEnabled !== 0
|
||||
? expectedLegacyNotificationsEnabled + 1
|
||||
: 0,
|
||||
legacy_notifications_disabled:
|
||||
expectedLegacyNotificationsDisabled !== 0
|
||||
? expectedLegacyNotificationsDisabled + 1
|
||||
: 0,
|
||||
notifications_enabled:
|
||||
expectedNotificationsEnabled !== 0 ? expectedNotificationsEnabled + 1 : 0,
|
||||
notifications_disabled:
|
||||
expectedNotificationsDisabled !== 0 ? expectedNotificationsDisabled + 1 : 0,
|
||||
})
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,7 +15,6 @@ import {
|
|||
SAVED_QUERY_RULE_TYPE_ID,
|
||||
} from '@kbn/securitysolution-rules';
|
||||
import { ALERT_RULE_UUID } from '@kbn/rule-data-utils';
|
||||
import { LEGACY_NOTIFICATIONS_ID } from '../../../common/constants';
|
||||
import { CASE_COMMENT_SAVED_OBJECT } from '../../../../cases/common/constants';
|
||||
|
||||
import { ElasticsearchClient, SavedObjectsClientContract } from '../../../../../../src/core/server';
|
||||
|
@ -30,6 +29,10 @@ import type {
|
|||
RuleSearchResult,
|
||||
DetectionMetrics,
|
||||
} from './types';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { legacyRuleActionsSavedObjectType } from '../../lib/detection_engine/rule_actions/legacy_saved_object_mappings';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { LegacyIRuleActionsAttributesSavedObjectAttributes } from '../../lib/detection_engine/rule_actions/legacy_types';
|
||||
|
||||
/**
|
||||
* Initial detection metrics initialized.
|
||||
|
@ -63,45 +66,70 @@ export const initialDetectionRulesUsage: DetectionRulesTypeUsage = {
|
|||
disabled: 0,
|
||||
alerts: 0,
|
||||
cases: 0,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
threshold: {
|
||||
enabled: 0,
|
||||
disabled: 0,
|
||||
alerts: 0,
|
||||
cases: 0,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
eql: {
|
||||
enabled: 0,
|
||||
disabled: 0,
|
||||
alerts: 0,
|
||||
cases: 0,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
machine_learning: {
|
||||
enabled: 0,
|
||||
disabled: 0,
|
||||
alerts: 0,
|
||||
cases: 0,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
threat_match: {
|
||||
enabled: 0,
|
||||
disabled: 0,
|
||||
alerts: 0,
|
||||
cases: 0,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
elastic_total: {
|
||||
enabled: 0,
|
||||
disabled: 0,
|
||||
alerts: 0,
|
||||
cases: 0,
|
||||
},
|
||||
legacy_notifications: {
|
||||
total: 0,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
custom_total: {
|
||||
enabled: 0,
|
||||
disabled: 0,
|
||||
alerts: 0,
|
||||
cases: 0,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -112,6 +140,16 @@ export const updateDetectionRuleUsage = (
|
|||
): DetectionRulesTypeUsage => {
|
||||
let updatedUsage = usage;
|
||||
|
||||
const legacyNotificationEnabled =
|
||||
detectionRuleMetric.has_legacy_notification && detectionRuleMetric.enabled;
|
||||
|
||||
const legacyNotificationDisabled =
|
||||
detectionRuleMetric.has_legacy_notification && !detectionRuleMetric.enabled;
|
||||
|
||||
const notificationEnabled = detectionRuleMetric.has_notification && detectionRuleMetric.enabled;
|
||||
|
||||
const notificationDisabled = detectionRuleMetric.has_notification && !detectionRuleMetric.enabled;
|
||||
|
||||
if (detectionRuleMetric.rule_type === 'query') {
|
||||
updatedUsage = {
|
||||
...usage,
|
||||
|
@ -121,6 +159,18 @@ export const updateDetectionRuleUsage = (
|
|||
disabled: !detectionRuleMetric.enabled ? usage.query.disabled + 1 : usage.query.disabled,
|
||||
alerts: usage.query.alerts + detectionRuleMetric.alert_count_daily,
|
||||
cases: usage.query.cases + detectionRuleMetric.cases_count_total,
|
||||
legacy_notifications_enabled: legacyNotificationEnabled
|
||||
? usage.query.legacy_notifications_enabled + 1
|
||||
: usage.query.legacy_notifications_enabled,
|
||||
legacy_notifications_disabled: legacyNotificationDisabled
|
||||
? usage.query.legacy_notifications_disabled + 1
|
||||
: usage.query.legacy_notifications_disabled,
|
||||
notifications_enabled: notificationEnabled
|
||||
? usage.query.notifications_enabled + 1
|
||||
: usage.query.notifications_enabled,
|
||||
notifications_disabled: notificationDisabled
|
||||
? usage.query.notifications_disabled + 1
|
||||
: usage.query.notifications_disabled,
|
||||
},
|
||||
};
|
||||
} else if (detectionRuleMetric.rule_type === 'threshold') {
|
||||
|
@ -136,6 +186,18 @@ export const updateDetectionRuleUsage = (
|
|||
: usage.threshold.disabled,
|
||||
alerts: usage.threshold.alerts + detectionRuleMetric.alert_count_daily,
|
||||
cases: usage.threshold.cases + detectionRuleMetric.cases_count_total,
|
||||
legacy_notifications_enabled: legacyNotificationEnabled
|
||||
? usage.threshold.legacy_notifications_enabled + 1
|
||||
: usage.threshold.legacy_notifications_enabled,
|
||||
legacy_notifications_disabled: legacyNotificationDisabled
|
||||
? usage.threshold.legacy_notifications_disabled + 1
|
||||
: usage.threshold.legacy_notifications_disabled,
|
||||
notifications_enabled: notificationEnabled
|
||||
? usage.threshold.notifications_enabled + 1
|
||||
: usage.threshold.notifications_enabled,
|
||||
notifications_disabled: notificationDisabled
|
||||
? usage.threshold.notifications_disabled + 1
|
||||
: usage.threshold.notifications_disabled,
|
||||
},
|
||||
};
|
||||
} else if (detectionRuleMetric.rule_type === 'eql') {
|
||||
|
@ -147,6 +209,18 @@ export const updateDetectionRuleUsage = (
|
|||
disabled: !detectionRuleMetric.enabled ? usage.eql.disabled + 1 : usage.eql.disabled,
|
||||
alerts: usage.eql.alerts + detectionRuleMetric.alert_count_daily,
|
||||
cases: usage.eql.cases + detectionRuleMetric.cases_count_total,
|
||||
legacy_notifications_enabled: legacyNotificationEnabled
|
||||
? usage.eql.legacy_notifications_enabled + 1
|
||||
: usage.eql.legacy_notifications_enabled,
|
||||
legacy_notifications_disabled: legacyNotificationDisabled
|
||||
? usage.eql.legacy_notifications_disabled + 1
|
||||
: usage.eql.legacy_notifications_disabled,
|
||||
notifications_enabled: notificationEnabled
|
||||
? usage.eql.notifications_enabled + 1
|
||||
: usage.eql.notifications_enabled,
|
||||
notifications_disabled: notificationDisabled
|
||||
? usage.eql.notifications_disabled + 1
|
||||
: usage.eql.notifications_disabled,
|
||||
},
|
||||
};
|
||||
} else if (detectionRuleMetric.rule_type === 'machine_learning') {
|
||||
|
@ -162,6 +236,18 @@ export const updateDetectionRuleUsage = (
|
|||
: usage.machine_learning.disabled,
|
||||
alerts: usage.machine_learning.alerts + detectionRuleMetric.alert_count_daily,
|
||||
cases: usage.machine_learning.cases + detectionRuleMetric.cases_count_total,
|
||||
legacy_notifications_enabled: legacyNotificationEnabled
|
||||
? usage.machine_learning.legacy_notifications_enabled + 1
|
||||
: usage.machine_learning.legacy_notifications_enabled,
|
||||
legacy_notifications_disabled: legacyNotificationDisabled
|
||||
? usage.machine_learning.legacy_notifications_disabled + 1
|
||||
: usage.machine_learning.legacy_notifications_disabled,
|
||||
notifications_enabled: notificationEnabled
|
||||
? usage.machine_learning.notifications_enabled + 1
|
||||
: usage.machine_learning.notifications_enabled,
|
||||
notifications_disabled: notificationDisabled
|
||||
? usage.machine_learning.notifications_disabled + 1
|
||||
: usage.machine_learning.notifications_disabled,
|
||||
},
|
||||
};
|
||||
} else if (detectionRuleMetric.rule_type === 'threat_match') {
|
||||
|
@ -177,6 +263,18 @@ export const updateDetectionRuleUsage = (
|
|||
: usage.threat_match.disabled,
|
||||
alerts: usage.threat_match.alerts + detectionRuleMetric.alert_count_daily,
|
||||
cases: usage.threat_match.cases + detectionRuleMetric.cases_count_total,
|
||||
legacy_notifications_enabled: legacyNotificationEnabled
|
||||
? usage.threat_match.legacy_notifications_enabled + 1
|
||||
: usage.threat_match.legacy_notifications_enabled,
|
||||
legacy_notifications_disabled: legacyNotificationDisabled
|
||||
? usage.threat_match.legacy_notifications_disabled + 1
|
||||
: usage.threat_match.legacy_notifications_disabled,
|
||||
notifications_enabled: notificationEnabled
|
||||
? usage.threat_match.notifications_enabled + 1
|
||||
: usage.threat_match.notifications_enabled,
|
||||
notifications_disabled: notificationDisabled
|
||||
? usage.threat_match.notifications_disabled + 1
|
||||
: usage.threat_match.notifications_disabled,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -194,6 +292,18 @@ export const updateDetectionRuleUsage = (
|
|||
: updatedUsage.elastic_total.disabled,
|
||||
alerts: updatedUsage.elastic_total.alerts + detectionRuleMetric.alert_count_daily,
|
||||
cases: updatedUsage.elastic_total.cases + detectionRuleMetric.cases_count_total,
|
||||
legacy_notifications_enabled: legacyNotificationEnabled
|
||||
? updatedUsage.elastic_total.legacy_notifications_enabled + 1
|
||||
: updatedUsage.elastic_total.legacy_notifications_enabled,
|
||||
legacy_notifications_disabled: legacyNotificationDisabled
|
||||
? updatedUsage.elastic_total.legacy_notifications_disabled + 1
|
||||
: updatedUsage.elastic_total.legacy_notifications_disabled,
|
||||
notifications_enabled: notificationEnabled
|
||||
? updatedUsage.elastic_total.notifications_enabled + 1
|
||||
: updatedUsage.elastic_total.notifications_enabled,
|
||||
notifications_disabled: notificationDisabled
|
||||
? updatedUsage.elastic_total.notifications_disabled + 1
|
||||
: updatedUsage.elastic_total.notifications_disabled,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
|
@ -209,6 +319,18 @@ export const updateDetectionRuleUsage = (
|
|||
: updatedUsage.custom_total.disabled,
|
||||
alerts: updatedUsage.custom_total.alerts + detectionRuleMetric.alert_count_daily,
|
||||
cases: updatedUsage.custom_total.cases + detectionRuleMetric.cases_count_total,
|
||||
legacy_notifications_enabled: legacyNotificationEnabled
|
||||
? updatedUsage.custom_total.legacy_notifications_enabled + 1
|
||||
: updatedUsage.custom_total.legacy_notifications_enabled,
|
||||
legacy_notifications_disabled: legacyNotificationDisabled
|
||||
? updatedUsage.custom_total.legacy_notifications_disabled + 1
|
||||
: updatedUsage.custom_total.legacy_notifications_disabled,
|
||||
notifications_enabled: notificationEnabled
|
||||
? updatedUsage.custom_total.notifications_enabled + 1
|
||||
: updatedUsage.custom_total.notifications_enabled,
|
||||
notifications_disabled: notificationDisabled
|
||||
? updatedUsage.custom_total.notifications_disabled + 1
|
||||
: updatedUsage.custom_total.notifications_disabled,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -287,18 +409,28 @@ export const getDetectionRuleMetrics = async (
|
|||
filter: `${CASE_COMMENT_SAVED_OBJECT}.attributes.type: alert`,
|
||||
});
|
||||
|
||||
// We get just 1 per a single page so we can get the total count to add to the rulesUsage.
|
||||
// Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function.
|
||||
const legacyNotificationsCount = (
|
||||
await savedObjectClient.find({
|
||||
type: 'alert',
|
||||
const legacyRuleActions =
|
||||
await savedObjectClient.find<LegacyIRuleActionsAttributesSavedObjectAttributes>({
|
||||
type: legacyRuleActionsSavedObjectType,
|
||||
page: 1,
|
||||
perPage: MAX_RESULTS_WINDOW,
|
||||
namespaces: ['*'],
|
||||
perPage: 1,
|
||||
filter: `alert.attributes.alertTypeId: ${LEGACY_NOTIFICATIONS_ID}`,
|
||||
})
|
||||
).total;
|
||||
rulesUsage = { ...rulesUsage, legacy_notifications: { total: legacyNotificationsCount } };
|
||||
});
|
||||
|
||||
const legacyNotificationRuleIds = legacyRuleActions.saved_objects.reduce(
|
||||
(cache, legacyNotificationsObject) => {
|
||||
const ruleRef = legacyNotificationsObject.references.find(
|
||||
(reference) => reference.name === 'alert_0' && reference.type === 'alert'
|
||||
);
|
||||
if (ruleRef != null) {
|
||||
const enabled = legacyNotificationsObject.attributes.ruleThrottle !== 'no_actions';
|
||||
cache.set(ruleRef.id, { enabled });
|
||||
}
|
||||
return cache;
|
||||
},
|
||||
new Map<string, { enabled: boolean }>()
|
||||
);
|
||||
|
||||
const casesCache = cases.saved_objects.reduce((cache, { attributes: casesObject }) => {
|
||||
const ruleId = casesObject.rule.id;
|
||||
|
@ -320,6 +452,17 @@ export const getDetectionRuleMetrics = async (
|
|||
const ruleObjects = ruleResults.hits.hits.map((hit) => {
|
||||
const ruleId = hit._id.split(':')[1];
|
||||
const isElastic = isElasticRule(hit._source?.alert.tags);
|
||||
|
||||
// Even if the legacy notification is set to "no_actions" we still count the rule as having a legacy notification that is not migrated yet.
|
||||
const hasLegacyNotification = legacyNotificationRuleIds.get(ruleId) != null;
|
||||
|
||||
// We only count a rule as having a notification and being "enabled" if it is _not_ set to "no_actions"/"muteAll" and it has at least one action within its array.
|
||||
const hasNotification =
|
||||
!hasLegacyNotification &&
|
||||
hit._source?.alert.actions != null &&
|
||||
hit._source?.alert.actions.length > 0 &&
|
||||
hit._source?.alert.muteAll !== true;
|
||||
|
||||
return {
|
||||
rule_name: hit._source?.alert.name,
|
||||
rule_id: hit._source?.alert.params.ruleId,
|
||||
|
@ -331,6 +474,8 @@ export const getDetectionRuleMetrics = async (
|
|||
updated_on: hit._source?.alert.updatedAt,
|
||||
alert_count_daily: alertsCache.get(ruleId) || 0,
|
||||
cases_count_total: casesCache.get(ruleId) || 0,
|
||||
has_legacy_notification: hasLegacyNotification,
|
||||
has_notification: hasNotification,
|
||||
} as DetectionRuleMetric;
|
||||
});
|
||||
|
||||
|
|
|
@ -70,6 +70,8 @@ describe('Detections Usage and Metrics', () => {
|
|||
rule_type: 'query',
|
||||
rule_version: 4,
|
||||
updated_on: '2021-03-23T17:15:59.634Z',
|
||||
has_legacy_notification: false,
|
||||
has_notification: false,
|
||||
},
|
||||
],
|
||||
detection_rule_usage: {
|
||||
|
@ -79,15 +81,20 @@ describe('Detections Usage and Metrics', () => {
|
|||
disabled: 1,
|
||||
alerts: 3400,
|
||||
cases: 1,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
elastic_total: {
|
||||
alerts: 3400,
|
||||
cases: 1,
|
||||
disabled: 1,
|
||||
enabled: 0,
|
||||
},
|
||||
legacy_notifications: {
|
||||
total: 4,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -118,15 +125,20 @@ describe('Detections Usage and Metrics', () => {
|
|||
cases: 1,
|
||||
disabled: 1,
|
||||
enabled: 0,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
query: {
|
||||
alerts: 800,
|
||||
cases: 1,
|
||||
disabled: 1,
|
||||
enabled: 0,
|
||||
},
|
||||
legacy_notifications: {
|
||||
total: 4,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -144,7 +156,7 @@ describe('Detections Usage and Metrics', () => {
|
|||
savedObjectsClient.find.mockResolvedValue(getMockAlertCasesResponse());
|
||||
const result = await fetchDetectionsMetrics('', '', esClientMock, savedObjectsClient, mlMock);
|
||||
|
||||
expect(result).toEqual({
|
||||
expect(result).toEqual<DetectionMetrics>({
|
||||
...getInitialDetectionMetrics(),
|
||||
detection_rules: {
|
||||
detection_rule_detail: [
|
||||
|
@ -159,6 +171,8 @@ describe('Detections Usage and Metrics', () => {
|
|||
rule_type: 'query',
|
||||
rule_version: 4,
|
||||
updated_on: '2021-03-23T17:15:59.634Z',
|
||||
has_legacy_notification: false,
|
||||
has_notification: false,
|
||||
},
|
||||
],
|
||||
detection_rule_usage: {
|
||||
|
@ -168,15 +182,20 @@ describe('Detections Usage and Metrics', () => {
|
|||
cases: 1,
|
||||
disabled: 1,
|
||||
enabled: 0,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
query: {
|
||||
alerts: 0,
|
||||
cases: 1,
|
||||
disabled: 1,
|
||||
enabled: 0,
|
||||
},
|
||||
legacy_notifications: {
|
||||
total: 4,
|
||||
legacy_notifications_enabled: 0,
|
||||
legacy_notifications_disabled: 0,
|
||||
notifications_enabled: 0,
|
||||
notifications_disabled: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -30,7 +30,9 @@ export interface RuleSearchResult {
|
|||
tags: string[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
muteAll: boolean | undefined | null;
|
||||
params: DetectionRuleParms;
|
||||
actions: unknown[];
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -55,8 +57,11 @@ interface FeatureTypeUsage {
|
|||
disabled: number;
|
||||
alerts: number;
|
||||
cases: number;
|
||||
legacy_notifications_enabled: number;
|
||||
legacy_notifications_disabled: number;
|
||||
notifications_enabled: number;
|
||||
notifications_disabled: number;
|
||||
}
|
||||
|
||||
export interface DetectionRulesTypeUsage {
|
||||
query: FeatureTypeUsage;
|
||||
threshold: FeatureTypeUsage;
|
||||
|
@ -65,7 +70,6 @@ export interface DetectionRulesTypeUsage {
|
|||
threat_match: FeatureTypeUsage;
|
||||
elastic_total: FeatureTypeUsage;
|
||||
custom_total: FeatureTypeUsage;
|
||||
legacy_notifications: LegacyNotifications;
|
||||
}
|
||||
|
||||
export interface MlJobsUsage {
|
||||
|
@ -129,6 +133,8 @@ export interface DetectionRuleMetric {
|
|||
updated_on: string;
|
||||
alert_count_daily: number;
|
||||
cases_count_total: number;
|
||||
has_legacy_notification: boolean;
|
||||
has_notification: boolean;
|
||||
}
|
||||
|
||||
export interface AlertsAggregationResponse {
|
||||
|
@ -162,11 +168,3 @@ export interface DetectionRuleAdoption {
|
|||
detection_rule_detail: DetectionRuleMetric[];
|
||||
detection_rule_usage: DetectionRulesTypeUsage;
|
||||
}
|
||||
|
||||
/**
|
||||
* The legacy notifications that are still in use.
|
||||
* @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function
|
||||
*/
|
||||
export interface LegacyNotifications {
|
||||
total: number;
|
||||
}
|
||||
|
|
|
@ -7214,6 +7214,30 @@
|
|||
"_meta": {
|
||||
"description": "Number of cases attached to query detection rule alerts"
|
||||
}
|
||||
},
|
||||
"legacy_notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications enabled"
|
||||
}
|
||||
},
|
||||
"legacy_notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications disabled"
|
||||
}
|
||||
},
|
||||
"notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
},
|
||||
"notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -7242,6 +7266,30 @@
|
|||
"_meta": {
|
||||
"description": "Number of cases attached to threshold detection rule alerts"
|
||||
}
|
||||
},
|
||||
"legacy_notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications enabled"
|
||||
}
|
||||
},
|
||||
"legacy_notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications disabled"
|
||||
}
|
||||
},
|
||||
"notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
},
|
||||
"notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -7270,6 +7318,30 @@
|
|||
"_meta": {
|
||||
"description": "Number of cases attached to eql detection rule alerts"
|
||||
}
|
||||
},
|
||||
"legacy_notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications enabled"
|
||||
}
|
||||
},
|
||||
"legacy_notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications disabled"
|
||||
}
|
||||
},
|
||||
"notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
},
|
||||
"notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -7298,6 +7370,30 @@
|
|||
"_meta": {
|
||||
"description": "Number of cases attached to machine_learning detection rule alerts"
|
||||
}
|
||||
},
|
||||
"legacy_notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications enabled"
|
||||
}
|
||||
},
|
||||
"legacy_notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications disabled"
|
||||
}
|
||||
},
|
||||
"notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
},
|
||||
"notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -7326,15 +7422,29 @@
|
|||
"_meta": {
|
||||
"description": "Number of cases attached to threat_match detection rule alerts"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"legacy_notifications": {
|
||||
"properties": {
|
||||
"total": {
|
||||
},
|
||||
"legacy_notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications still in use"
|
||||
"description": "Number of legacy notifications enabled"
|
||||
}
|
||||
},
|
||||
"legacy_notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications disabled"
|
||||
}
|
||||
},
|
||||
"notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
},
|
||||
"notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7364,6 +7474,30 @@
|
|||
"_meta": {
|
||||
"description": "Number of cases attached to elastic detection rule alerts"
|
||||
}
|
||||
},
|
||||
"legacy_notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications enabled"
|
||||
}
|
||||
},
|
||||
"legacy_notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications disabled"
|
||||
}
|
||||
},
|
||||
"notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
},
|
||||
"notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -7392,6 +7526,30 @@
|
|||
"_meta": {
|
||||
"description": "Number of cases attached to custom detection rule alerts"
|
||||
}
|
||||
},
|
||||
"legacy_notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications enabled"
|
||||
}
|
||||
},
|
||||
"legacy_notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of legacy notifications disabled"
|
||||
}
|
||||
},
|
||||
"notifications_enabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
},
|
||||
"notifications_disabled": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of notifications enabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7460,6 +7618,18 @@
|
|||
"_meta": {
|
||||
"description": "The number of total cases generated by a rule"
|
||||
}
|
||||
},
|
||||
"has_legacy_notification": {
|
||||
"type": "boolean",
|
||||
"_meta": {
|
||||
"description": "True if this rule has a legacy notification"
|
||||
}
|
||||
},
|
||||
"has_notification": {
|
||||
"type": "boolean",
|
||||
"_meta": {
|
||||
"description": "True if this rule has a notification"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
These are tests for the telemetry rules within "security_solution/server/usage"
|
||||
* detection_rules
|
||||
* legacy_notifications
|
||||
|
||||
Detection rules are tests around each of the rule types to affirm they work such as query, eql, etc...
|
||||
Legacy notifications are tests around the legacy notification telemetry. Once legacy notifications are removed,
|
||||
these tests can be removed too.
|
||||
Detection rules are tests around each of the rule types to affirm they work such as query, eql, etc... This includes
|
||||
legacy notifications. Once legacy notifications are moved, those tests can be removed too.
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,7 +13,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => {
|
|||
describe('', function () {
|
||||
this.tags('ciGroup11');
|
||||
loadTestFile(require.resolve('./detection_rules'));
|
||||
loadTestFile(require.resolve('./legacy_notifications'));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../../common/ftr_provider_context';
|
||||
import {
|
||||
createRule,
|
||||
createSignalsIndex,
|
||||
deleteAllAlerts,
|
||||
deleteSignalsIndex,
|
||||
getSimpleRule,
|
||||
getStats,
|
||||
getWebHookAction,
|
||||
} from '../../../utils';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default ({ getService }: FtrProviderContext) => {
|
||||
const supertest = getService('supertest');
|
||||
const log = getService('log');
|
||||
const retry = getService('retry');
|
||||
|
||||
describe('legacy notification telemetry', async () => {
|
||||
beforeEach(async () => {
|
||||
await createSignalsIndex(supertest, log);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await deleteSignalsIndex(supertest, log);
|
||||
await deleteAllAlerts(supertest, log);
|
||||
});
|
||||
|
||||
it('should have 1 legacy notification when there is a rule on the default', async () => {
|
||||
// create an connector/action
|
||||
const { body: hookAction } = await supertest
|
||||
.post('/api/actions/action')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(getWebHookAction())
|
||||
.expect(200);
|
||||
|
||||
// create a rule without actions
|
||||
const createRuleBody = await createRule(supertest, log, getSimpleRule('rule-1'));
|
||||
|
||||
// attach the legacy notification
|
||||
await supertest
|
||||
.post(`/internal/api/detection/legacy/notifications?alert_id=${createRuleBody.id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
name: 'Legacy notification with one action',
|
||||
interval: '1h',
|
||||
actions: [
|
||||
{
|
||||
id: hookAction.id,
|
||||
group: 'default',
|
||||
params: {
|
||||
message:
|
||||
'Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts',
|
||||
},
|
||||
actionTypeId: hookAction.actionTypeId,
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await retry.try(async () => {
|
||||
const stats = await getStats(supertest, log);
|
||||
// NOTE: We have to do "above 0" until this bug is fixed: https://github.com/elastic/kibana/issues/122456 because other tests are accumulating non-cleaned up legacy actions/notifications and this number isn't reliable at the moment
|
||||
expect(stats.detection_rules.detection_rule_usage.legacy_notifications.total).to.above(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue