Skip to content

Commit

Permalink
Execution type field (elastic#195884)
Browse files Browse the repository at this point in the history
## Added new field - execution type for alerts

Added new field only for security type alerts:

`kibana.alert.rule.execution.type` - can be `manual` or `scheduled`

Also, move intended timestamp settings from
`create_persistence_rule_type_wrapper` to `build_alert`

Also added those new field to Alert schema and types.



https://github.com/user-attachments/assets/c5b021a6-4763-47ae-b46c-814a138be65a



For tests:

- tests all rule types with and without suppression:
`kibana.alert.rule.execution.type` - should be `scheduled`,
`kibana.alert.intended_timestamp` - should equal alert timestamp

- tests all rules with and without suppression with manual run -
`kibana.alert.rule.execution.type` - should be `manual`,
`kibana.alert.intended_timestamp` - should equal date inside you manual
rule run date range

---------

Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
nkhristinin and elasticmachine authored Oct 14, 2024
1 parent e89c9d5 commit 3d466a7
Show file tree
Hide file tree
Showing 48 changed files with 551 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
ALERT_RULE_CATEGORY,
ALERT_RULE_CONSUMER,
ALERT_RULE_EXECUTION_TIMESTAMP,
ALERT_RULE_EXECUTION_TYPE,
ALERT_RULE_EXECUTION_UUID,
ALERT_RULE_NAME,
ALERT_RULE_PARAMETERS,
Expand Down Expand Up @@ -134,6 +135,11 @@ export const alertFieldMap = {
array: false,
required: false,
},
[ALERT_RULE_EXECUTION_TYPE]: {
type: 'keyword',
array: false,
required: false,
},
[ALERT_INTENDED_TIMESTAMP]: {
type: 'date',
array: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const AlertOptional = rt.partial({
'kibana.alert.previous_action_group': schemaString,
'kibana.alert.reason': schemaString,
'kibana.alert.rule.execution.timestamp': schemaDate,
'kibana.alert.rule.execution.type': schemaString,
'kibana.alert.rule.execution.uuid': schemaString,
'kibana.alert.rule.parameters': schemaUnknown,
'kibana.alert.rule.tags': schemaStringArray,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ const SecurityAlertOptional = rt.partial({
'kibana.alert.rule.description': schemaString,
'kibana.alert.rule.enabled': schemaString,
'kibana.alert.rule.execution.timestamp': schemaDate,
'kibana.alert.rule.execution.type': schemaString,
'kibana.alert.rule.execution.uuid': schemaString,
'kibana.alert.rule.from': schemaString,
'kibana.alert.rule.immutable': schemaStringArray,
Expand Down
5 changes: 5 additions & 0 deletions packages/kbn-rule-data-utils/src/default_alerts_as_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ const ALERT_URL = `${ALERT_NAMESPACE}.url` as const;
// kibana.alert.rule.uuid - rule ID for rule that generated this alert
const ALERT_RULE_UUID = `${ALERT_RULE_NAMESPACE}.uuid` as const;

// kibana.alert.rule.execution.type - rule execution type for rule that generated this alert (manual /scheduled)
const ALERT_RULE_EXECUTION_TYPE = `${ALERT_RULE_NAMESPACE}.execution.type` as const;

const namespaces = {
KIBANA_NAMESPACE,
ALERT_NAMESPACE,
Expand All @@ -144,6 +147,7 @@ const fields = {
ALERT_RULE_CATEGORY,
ALERT_RULE_CONSUMER,
ALERT_RULE_EXECUTION_TIMESTAMP,
ALERT_RULE_EXECUTION_TYPE,
ALERT_INTENDED_TIMESTAMP,
ALERT_RULE_EXECUTION_UUID,
ALERT_RULE_NAME,
Expand Down Expand Up @@ -189,6 +193,7 @@ export {
ALERT_RULE_CATEGORY,
ALERT_RULE_CONSUMER,
ALERT_RULE_EXECUTION_TIMESTAMP,
ALERT_RULE_EXECUTION_TYPE,
ALERT_INTENDED_TIMESTAMP,
ALERT_RULE_EXECUTION_UUID,
ALERT_RULE_NAME,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ describe('mappingFromFieldMap', () => {
timestamp: {
type: 'date',
},
type: {
type: 'keyword',
},
uuid: {
type: 'keyword',
},
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ it('matches snapshot', () => {
"required": false,
"type": "date",
},
"kibana.alert.rule.execution.type": Object {
"array": false,
"required": false,
"type": "keyword",
},
"kibana.alert.rule.execution.uuid": Object {
"array": false,
"required": false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
TIMESTAMP,
VERSION,
ALERT_RULE_EXECUTION_TIMESTAMP,
ALERT_INTENDED_TIMESTAMP,
} from '@kbn/rule-data-utils';
import { mapKeys, snakeCase } from 'lodash/fp';
import type { IRuleDataClient } from '..';
Expand Down Expand Up @@ -56,13 +55,11 @@ const augmentAlerts = async <T>({
options,
kibanaVersion,
currentTimeOverride,
intendedTimestamp,
}: {
alerts: Array<{ _id: string; _source: T }>;
options: RuleExecutorOptions<any, any, any, any, any>;
kibanaVersion: string;
currentTimeOverride: Date | undefined;
intendedTimestamp: Date | undefined;
}) => {
const commonRuleFields = getCommonAlertFields(options);
const maintenanceWindowIds: string[] =
Expand All @@ -77,9 +74,6 @@ const augmentAlerts = async <T>({
[ALERT_RULE_EXECUTION_TIMESTAMP]: currentDate,
[ALERT_START]: timestampOverrideOrCurrent,
[ALERT_LAST_DETECTED]: timestampOverrideOrCurrent,
[ALERT_INTENDED_TIMESTAMP]: intendedTimestamp
? intendedTimestamp
: timestampOverrideOrCurrent,
[VERSION]: kibanaVersion,
...(maintenanceWindowIds.length
? { [ALERT_MAINTENANCE_WINDOW_IDS]: maintenanceWindowIds }
Expand Down Expand Up @@ -309,17 +303,11 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper
alertsWereTruncated = true;
}

let intendedTimestamp;
if (options.startedAtOverridden) {
intendedTimestamp = options.startedAt;
}

const augmentedAlerts = await augmentAlerts({
alerts: enrichedAlerts,
options,
kibanaVersion: ruleDataClient.kibanaVersion,
currentTimeOverride: undefined,
intendedTimestamp,
});

const response = await ruleDataClientWriter.bulk({
Expand Down Expand Up @@ -399,11 +387,6 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper

let alertsWereTruncated = false;

let intendedTimestamp;
if (options.startedAtOverridden) {
intendedTimestamp = options.startedAt;
}

if (writeAlerts && alerts.length > 0) {
const suppressionWindowStart = dateMath.parse(suppressionWindow, {
forceNow: currentTimeOverride,
Expand Down Expand Up @@ -583,7 +566,6 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper
options,
kibanaVersion: ruleDataClient.kibanaVersion,
currentTimeOverride,
intendedTimestamp,
});

const bulkResponse = await ruleDataClientWriter.bulk({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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 type { ALERT_RULE_EXECUTION_TYPE, ALERT_INTENDED_TIMESTAMP } from '@kbn/rule-data-utils';
import type { AlertWithCommonFields800 } from '@kbn/rule-registry-plugin/common/schemas/8.0.0';
import type {
Ancestor8130,
BaseFields8130,
EqlBuildingBlockFields8130,
EqlShellFields8130,
NewTermsFields8130,
} from '../8.13.0';

/* DO NOT MODIFY THIS SCHEMA TO ADD NEW FIELDS. These types represent the alerts that shipped in 8.12.0.
Any changes to these types should be bug fixes so the types more accurately represent the alerts from 8.12.0.
If you are adding new fields for a new release of Kibana, create a new sibling folder to this one
for the version to be released and add the field(s) to the schema in that folder.
Then, update `../index.ts` to import from the new folder that has the latest schemas, add the
new schemas to the union of all alert schemas, and re-export the new schemas as the `*Latest` schemas.
*/

export type { Ancestor8130 as Ancestor8160 };

export interface BaseFields8160 extends BaseFields8130 {
[ALERT_RULE_EXECUTION_TYPE]: string;
[ALERT_INTENDED_TIMESTAMP]: string;
}

export interface WrappedFields8160<T extends BaseFields8160> {
_id: string;
_index: string;
_source: T;
}

export type GenericAlert8160 = AlertWithCommonFields800<BaseFields8160>;

export type EqlShellFields8160 = EqlShellFields8130 & BaseFields8160;

export type EqlBuildingBlockFields8160 = EqlBuildingBlockFields8130 & BaseFields8160;

export type NewTermsFields8160 = NewTermsFields8130 & BaseFields8160;

export type NewTermsAlert8160 = NewTermsFields8130 & BaseFields8160;

export type EqlBuildingBlockAlert8160 = AlertWithCommonFields800<EqlBuildingBlockFields8130>;

export type EqlShellAlert8160 = AlertWithCommonFields800<EqlShellFields8160>;

export type DetectionAlert8160 =
| GenericAlert8160
| EqlShellAlert8160
| EqlBuildingBlockAlert8160
| NewTermsAlert8160;
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@ import type { DetectionAlert870 } from './8.7.0';
import type { DetectionAlert880 } from './8.8.0';
import type { DetectionAlert890 } from './8.9.0';
import type { DetectionAlert8120 } from './8.12.0';
import type { DetectionAlert8130 } from './8.13.0';

import type {
Ancestor8130,
BaseFields8130,
DetectionAlert8130,
EqlBuildingBlockFields8130,
EqlShellFields8130,
NewTermsFields8130,
WrappedFields8130,
} from './8.13.0';
Ancestor8160,
BaseFields8160,
DetectionAlert8160,
EqlBuildingBlockFields8160,
EqlShellFields8160,
NewTermsFields8160,
WrappedFields8160,
} from './8.16.0';

// When new Alert schemas are created for new Kibana versions, add the DetectionAlert type from the new version
// here, e.g. `export type DetectionAlert = DetectionAlert800 | DetectionAlert820` if a new schema is created in 8.2.0
Expand All @@ -33,14 +35,15 @@ export type DetectionAlert =
| DetectionAlert880
| DetectionAlert890
| DetectionAlert8120
| DetectionAlert8130;
| DetectionAlert8130
| DetectionAlert8160;

export type {
Ancestor8130 as AncestorLatest,
BaseFields8130 as BaseFieldsLatest,
DetectionAlert8130 as DetectionAlertLatest,
WrappedFields8130 as WrappedFieldsLatest,
EqlBuildingBlockFields8130 as EqlBuildingBlockFieldsLatest,
EqlShellFields8130 as EqlShellFieldsLatest,
NewTermsFields8130 as NewTermsFieldsLatest,
Ancestor8160 as AncestorLatest,
BaseFields8160 as BaseFieldsLatest,
DetectionAlert8160 as DetectionAlertLatest,
WrappedFields8160 as WrappedFieldsLatest,
EqlBuildingBlockFields8160 as EqlBuildingBlockFieldsLatest,
EqlShellFields8160 as EqlShellFieldsLatest,
NewTermsFields8160 as NewTermsFieldsLatest,
};
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
params,
previousStartedAt,
startedAt,
startedAtOverridden,
services,
spaceId,
state,
Expand Down Expand Up @@ -363,6 +364,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
ignoreFieldsStandard.forEach((field) => {
ignoreFieldsObject[field] = true;
});
const intendedTimestamp = startedAtOverridden ? startedAt : undefined;
const wrapHits = wrapHitsFactory({
ignoreFields: ignoreFieldsObject,
ignoreFieldsRegexes,
Expand All @@ -373,6 +375,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
alertTimestampOverride,
publicBaseUrl,
ruleExecutionLogger,
intendedTimestamp,
});

const wrapSequences = wrapSequencesFactory({
Expand All @@ -384,6 +387,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
publicBaseUrl,
indicesToQuery: inputIndex,
alertTimestampOverride,
intendedTimestamp,
});

const { filter: exceptionFilter, unprocessedExceptions } = await buildExceptionFilter({
Expand Down Expand Up @@ -427,6 +431,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
refreshOnIndexingAlerts: refresh,
publicBaseUrl,
experimentalFeatures,
intendedTimestamp,
},
});

Expand Down
Loading

0 comments on commit 3d466a7

Please sign in to comment.