diff --git a/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts index fbc82719bd381..474aab15b2c1e 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts @@ -57,7 +57,7 @@ describe('checking migration metadata changes on all registered SO types', () => Object { "action": "6cfc277ed3211639e37546ac625f4a68f2494215", "action_task_params": "5f419caba96dd8c77d0f94013e71d43890e3d5d6", - "alert": "785240e3137f5eb1a0f8986e5b8eff99780fc04f", + "alert": "1e4cd6941f1eb39c729c646e91fbfb9700de84b9", "api_key_pending_invalidation": "16e7bcf8e78764102d7f525542d5b616809a21ee", "apm-indices": "d19dd7fb51f2d2cbc1f8769481721e0953f9a6d2", "apm-server-schema": "1d42f17eff9ec6c16d3a9324d9539e2d123d0a9a", diff --git a/x-pack/examples/triggers_actions_ui_example/public/components/rules_list_notify_badge_sandbox.tsx b/x-pack/examples/triggers_actions_ui_example/public/components/rules_list_notify_badge_sandbox.tsx index 47b08acd88e31..6ff26f7725f64 100644 --- a/x-pack/examples/triggers_actions_ui_example/public/components/rules_list_notify_badge_sandbox.tsx +++ b/x-pack/examples/triggers_actions_ui_example/public/components/rules_list_notify_badge_sandbox.tsx @@ -45,6 +45,7 @@ const mockRule: RuleTableItem = { ruleType: 'Test Rule Type', isEditable: true, enabledInLicense: true, + revision: 0, }; export const RulesListNotifyBadgeSandbox = ({ triggersActionsUi }: SandboxProps) => { diff --git a/x-pack/plugins/alerting/common/rule.ts b/x-pack/plugins/alerting/common/rule.ts index 3ff66f68c5417..b886f6af83705 100644 --- a/x-pack/plugins/alerting/common/rule.ts +++ b/x-pack/plugins/alerting/common/rule.ts @@ -161,6 +161,7 @@ export interface Rule { isSnoozedUntil?: Date | null; lastRun?: RuleLastRun | null; nextRun?: Date | null; + revision: number; running?: boolean | null; viewInAppRelativeUrl?: string; } diff --git a/x-pack/plugins/alerting/public/alert_api.test.ts b/x-pack/plugins/alerting/public/alert_api.test.ts index abbaa6a5049eb..7bd910f5deff3 100644 --- a/x-pack/plugins/alerting/public/alert_api.test.ts +++ b/x-pack/plugins/alerting/public/alert_api.test.ts @@ -132,6 +132,7 @@ describe('loadRule', () => { "params": Object { "x": 42, }, + "revision": 0, "schedule": Object { "interval": "1s", }, @@ -268,6 +269,7 @@ function getApiRule() { updated_by: '2889684073', mute_all: false, muted_alert_ids: [], + revision: 0, schedule: { interval: '1s', }, @@ -333,5 +335,6 @@ function getRule(): Rule<{ x: number }> { lastExecutionDate: RuleExecuteDate, lastDuration: 1194, }, + revision: 0, }; } diff --git a/x-pack/plugins/alerting/public/lib/common_transformations.test.ts b/x-pack/plugins/alerting/public/lib/common_transformations.test.ts index ac57340f109b2..0a3cdcb336386 100644 --- a/x-pack/plugins/alerting/public/lib/common_transformations.test.ts +++ b/x-pack/plugins/alerting/public/lib/common_transformations.test.ts @@ -46,6 +46,7 @@ describe('common_transformations', () => { notify_when: 'onActiveAlert', mute_all: false, muted_alert_ids: ['bob', 'jim'], + revision: 0, execution_status: { last_execution_date: dateExecuted.toISOString(), last_duration: 42, @@ -185,6 +186,7 @@ describe('common_transformations', () => { ], }, }, + "revision": 0, "schedule": Object { "interval": "1s", }, @@ -229,6 +231,7 @@ describe('common_transformations', () => { notify_when: 'onActiveAlert', mute_all: false, muted_alert_ids: ['bob', 'jim'], + revision: 0, execution_status: { last_execution_date: dateExecuted.toISOString(), status: 'error', @@ -344,6 +347,7 @@ describe('common_transformations', () => { "nextRun": 2021-12-15T12:34:55.789Z, "notifyWhen": "onActiveAlert", "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1s", }, diff --git a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts index 3bf01caaead1a..fc6518a5d0960 100644 --- a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts +++ b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts @@ -784,4 +784,5 @@ const BaseRule: SanitizedRule<{ bar: boolean }> = { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }; diff --git a/x-pack/plugins/alerting/server/routes/bulk_edit_rules.test.ts b/x-pack/plugins/alerting/server/routes/bulk_edit_rules.test.ts index 944b2db172c91..b2819fda6f60f 100644 --- a/x-pack/plugins/alerting/server/routes/bulk_edit_rules.test.ts +++ b/x-pack/plugins/alerting/server/routes/bulk_edit_rules.test.ts @@ -59,6 +59,7 @@ describe('bulkEditInternalRulesRoute', () => { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }; const mockedAlerts: Array> = [mockedAlert]; diff --git a/x-pack/plugins/alerting/server/routes/clone_rule.test.ts b/x-pack/plugins/alerting/server/routes/clone_rule.test.ts index 6c79ca7680940..035e5fa5885b8 100644 --- a/x-pack/plugins/alerting/server/routes/clone_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/clone_rule.test.ts @@ -65,6 +65,7 @@ describe('cloneRuleRoute', () => { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }; const ruleToClone: AsApiContract['data']> = { @@ -90,6 +91,7 @@ describe('cloneRuleRoute', () => { created_at: mockedRule.createdAt, updated_at: mockedRule.updatedAt, id: mockedRule.id, + revision: 0, execution_status: { status: mockedRule.executionStatus.status, last_execution_date: mockedRule.executionStatus.lastExecutionDate, diff --git a/x-pack/plugins/alerting/server/routes/create_rule.test.ts b/x-pack/plugins/alerting/server/routes/create_rule.test.ts index 0d8caff92202a..5563c886b24b0 100644 --- a/x-pack/plugins/alerting/server/routes/create_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/create_rule.test.ts @@ -68,6 +68,7 @@ describe('createRuleRoute', () => { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }; const ruleToCreate: AsApiContract['data']> = { @@ -93,6 +94,7 @@ describe('createRuleRoute', () => { created_at: mockedAlert.createdAt, updated_at: mockedAlert.updatedAt, id: mockedAlert.id, + revision: mockedAlert.revision, execution_status: { status: mockedAlert.executionStatus.status, last_execution_date: mockedAlert.executionStatus.lastExecutionDate, diff --git a/x-pack/plugins/alerting/server/routes/get_rule.test.ts b/x-pack/plugins/alerting/server/routes/get_rule.test.ts index 81b0ed5a6032a..9ae211eed0bcc 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule.test.ts @@ -62,6 +62,7 @@ describe('getRuleRoute', () => { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }; const getResult: AsApiContract> = { @@ -76,6 +77,7 @@ describe('getRuleRoute', () => { created_at: mockedAlert.createdAt, updated_at: mockedAlert.updatedAt, id: mockedAlert.id, + revision: mockedAlert.revision, execution_status: { status: mockedAlert.executionStatus.status, last_execution_date: mockedAlert.executionStatus.lastExecutionDate, diff --git a/x-pack/plugins/alerting/server/routes/legacy/create.test.ts b/x-pack/plugins/alerting/server/routes/legacy/create.test.ts index 60b299be6db97..548015ef55f03 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/create.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/create.test.ts @@ -80,6 +80,7 @@ describe('createAlertRoute', () => { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }; it('creates an alert with proper parameters', async () => { diff --git a/x-pack/plugins/alerting/server/routes/legacy/get.test.ts b/x-pack/plugins/alerting/server/routes/legacy/get.test.ts index 6860140ce2540..403f7a5b42ac8 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get.test.ts @@ -66,6 +66,7 @@ describe('getAlertRoute', () => { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }; it('gets an alert with proper parameters', async () => { diff --git a/x-pack/plugins/alerting/server/routes/lib/rewrite_rule.test.ts b/x-pack/plugins/alerting/server/routes/lib/rewrite_rule.test.ts index b4d1962931218..64326075b495a 100644 --- a/x-pack/plugins/alerting/server/routes/lib/rewrite_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/lib/rewrite_rule.test.ts @@ -60,6 +60,7 @@ const sampleRule: SanitizedRule & { activeSnoozes?: string[] } = }, }, nextRun: DATE_2020, + revision: 0, }; describe('rewriteRule', () => { diff --git a/x-pack/plugins/alerting/server/routes/resolve_rule.test.ts b/x-pack/plugins/alerting/server/routes/resolve_rule.test.ts index dfac49fc04a67..273a7ea7fb8aa 100644 --- a/x-pack/plugins/alerting/server/routes/resolve_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/resolve_rule.test.ts @@ -64,6 +64,7 @@ describe('resolveRuleRoute', () => { }, outcome: 'aliasMatch', alias_target_id: '2', + revision: 0, }; const resolveResult: AsApiContract> = { @@ -88,6 +89,7 @@ describe('resolveRuleRoute', () => { created_at: mockedRule.createdAt, updated_at: mockedRule.updatedAt, id: mockedRule.id, + revision: mockedRule.revision, execution_status: { status: mockedRule.executionStatus.status, last_execution_date: mockedRule.executionStatus.lastExecutionDate, diff --git a/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.test.ts b/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.test.ts new file mode 100644 index 0000000000000..aed29b5996003 --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.test.ts @@ -0,0 +1,100 @@ +/* + * 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 { UpdateOptions } from '..'; +import { mockedDateString } from '../tests/lib'; +import { incrementRevision } from './increment_revision'; +import { SavedObject } from '@kbn/core/server'; +import { RawRule, RuleTypeParams } from '../../types'; + +describe('incrementRevision', () => { + const currentRule: SavedObject = { + id: '1', + type: 'alert', + attributes: { + enabled: true, + name: 'rule-name', + tags: ['tag-1', 'tag-2'], + alertTypeId: '123', + consumer: 'rule-consumer', + legacyId: null, + schedule: { interval: '1s' }, + actions: [], + params: {}, + createdBy: null, + updatedBy: null, + createdAt: mockedDateString, + updatedAt: mockedDateString, + apiKey: null, + apiKeyOwner: null, + throttle: null, + notifyWhen: null, + muteAll: false, + mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: '2020-08-20T19:23:38Z', + error: null, + warning: null, + }, + revision: 0, + }, + references: [], + }; + + const updateOptions: UpdateOptions = { + id: '1', + data: { + schedule: { + interval: '1m', + }, + name: 'abc', + tags: ['foo'], + params: { + bar: true, + risk_score: 40, + severity: 'low', + }, + throttle: null, + notifyWhen: 'onActiveAlert', + actions: [], + }, + }; + const updatedParams: RuleTypeParams = { bar: true, risk_score: 40, severity: 'low' }; + + it('should return the current revision if no attrs or params are updated', () => { + // @ts-expect-error + expect(incrementRevision(currentRule, { data: {} }, {})).toBe(0); + }); + + it('should increment the revision if a root level attr is updated', () => { + expect(incrementRevision(currentRule, updateOptions, {})).toBe(1); + }); + + it('should increment the revision if a rule param is updated', () => { + // @ts-expect-error + expect(incrementRevision(currentRule, { data: {} }, updatedParams)).toBe(1); + }); + + it('should not increment the revision if an excluded attr is updated', () => { + // @ts-expect-error + expect(incrementRevision(currentRule, { data: { activeSnoozes: 'excludedValue' } }, {})).toBe( + 0 + ); + }); + + it('should not increment the revision if an excluded param is updated', () => { + expect( + incrementRevision( + currentRule, + // @ts-expect-error + { data: {} }, + { isSnoozedUntil: '1970-01-02T00:00:00.000Z' } + ) + ).toBe(0); + }); +}); diff --git a/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.ts b/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.ts new file mode 100644 index 0000000000000..5bf3ae02cedc8 --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/lib/increment_revision.ts @@ -0,0 +1,38 @@ +/* + * 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 { SavedObject } from '@kbn/core/server'; +import { get, isEqual } from 'lodash'; +import { RawRule, RuleTypeParams } from '../../types'; +import { fieldsToExcludeFromRevisionUpdates, UpdateOptions } from '..'; + +export function incrementRevision( + currentRule: SavedObject, + { data }: UpdateOptions, + updatedParams: RuleTypeParams +): number { + // Diff root level attrs + for (const [field, value] of Object.entries(data).filter(([key]) => key !== 'params')) { + if ( + !fieldsToExcludeFromRevisionUpdates.has(field) && + !isEqual(value, get(currentRule.attributes, field)) + ) { + return currentRule.attributes.revision + 1; + } + } + + // Diff rule params + for (const [field, value] of Object.entries(updatedParams)) { + if ( + !fieldsToExcludeFromRevisionUpdates.has(field) && + !isEqual(value, get(currentRule.attributes.params, field)) + ) { + return currentRule.attributes.revision + 1; + } + } + return currentRule.attributes.revision; +} diff --git a/x-pack/plugins/alerting/server/rules_client/lib/index.ts b/x-pack/plugins/alerting/server/rules_client/lib/index.ts index 26cf359d14f15..09024474020e1 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/index.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/index.ts @@ -16,3 +16,4 @@ export { scheduleTask } from './schedule_task'; export { createNewAPIKeySet } from './create_new_api_key_set'; export { recoverRuleAlerts } from './recover_rule_alerts'; export { addUuid } from './add_uuid'; +export { incrementRevision } from './increment_revision'; diff --git a/x-pack/plugins/alerting/server/rules_client/methods/bulk_edit.ts b/x-pack/plugins/alerting/server/rules_client/methods/bulk_edit.ts index 9bf0280e4314b..4bbe493d93c6b 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/bulk_edit.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/bulk_edit.ts @@ -69,6 +69,9 @@ export type BulkEditFields = keyof Pick< 'actions' | 'tags' | 'schedule' | 'throttle' | 'notifyWhen' | 'snoozeSchedule' | 'apiKey' >; +export const bulkEditFieldsToExcludeFromRevisionUpdates: ReadonlySet = + new Set(['snoozeSchedule', 'apiKey']); + export type BulkEditOperation = | { operation: 'add' | 'delete' | 'set'; @@ -126,16 +129,22 @@ export type RuleParamsModifier = ( params: Params ) => Promise>; +export type ShouldIncrementRevision = ( + params?: RuleTypeParams +) => boolean; + export interface BulkEditOptionsFilter { filter?: string | KueryNode; operations: BulkEditOperation[]; paramsModifier?: RuleParamsModifier; + shouldIncrementRevision?: ShouldIncrementRevision; } export interface BulkEditOptionsIds { ids: string[]; operations: BulkEditOperation[]; paramsModifier?: RuleParamsModifier; + shouldIncrementRevision?: ShouldIncrementRevision; } export type BulkEditOptions = @@ -244,12 +253,13 @@ export async function bulkEdit( context.logger, `rulesClient.update('operations=${JSON.stringify(options.operations)}, paramsModifier=${ options.paramsModifier ? '[Function]' : undefined - }')`, + }', shouldIncrementRevision=${options.shouldIncrementRevision ? '[Function]' : undefined}')`, (filterKueryNode: KueryNode | null) => bulkEditOcc(context, { filter: filterKueryNode, operations: options.operations, paramsModifier: options.paramsModifier, + shouldIncrementRevision: options.shouldIncrementRevision, }), qNodeFilterWithAuth ); @@ -284,10 +294,12 @@ async function bulkEditOcc( filter, operations, paramsModifier, + shouldIncrementRevision, }: { filter: KueryNode | null; operations: BulkEditOptions['operations']; paramsModifier: BulkEditOptions['paramsModifier']; + shouldIncrementRevision?: BulkEditOptions['shouldIncrementRevision']; } ): Promise<{ apiKeysToInvalidate: string[]; @@ -326,6 +338,7 @@ async function bulkEditOcc( skipped, errors, username, + shouldIncrementRevision, }), { concurrency: API_KEY_GENERATE_CONCURRENCY } ); @@ -395,6 +408,7 @@ async function updateRuleAttributesAndParamsInMemory true, }: { context: RulesClientContext; rule: SavedObjectsFindResult; @@ -405,6 +419,7 @@ async function updateRuleAttributesAndParamsInMemory['shouldIncrementRevision']; }): Promise { try { if (rule.attributes.apiKey) { @@ -427,6 +442,15 @@ async function updateRuleAttributesAndParamsInMemory( mutedInstanceIds: [], executionStatus: getRuleExecutionStatusPending(lastRunTimestamp.toISOString()), monitoring: getDefaultMonitoring(lastRunTimestamp.toISOString()), + revision: 0, scheduledTaskId: null, running: false, }; diff --git a/x-pack/plugins/alerting/server/rules_client/methods/create.ts b/x-pack/plugins/alerting/server/rules_client/methods/create.ts index 48735c0327d04..960cd8a7c43f7 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/create.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/create.ts @@ -43,6 +43,7 @@ export interface CreateOptions { | 'isSnoozedUntil' | 'lastRun' | 'nextRun' + | 'revision' > & { actions: NormalizedAlertAction[] }; options?: SavedObjectOptions; allowMissingConnectorSecrets?: boolean; @@ -153,6 +154,7 @@ export async function create( throttle, executionStatus: getRuleExecutionStatusPending(lastRunTimestamp.toISOString()), monitoring: getDefaultMonitoring(lastRunTimestamp.toISOString()), + revision: 0, running: false, }; diff --git a/x-pack/plugins/alerting/server/rules_client/methods/update.ts b/x-pack/plugins/alerting/server/rules_client/methods/update.ts index 673f300a722c6..0e1ecd40da43c 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/update.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/update.ts @@ -9,6 +9,7 @@ import Boom from '@hapi/boom'; import { isEqual, omit } from 'lodash'; import { SavedObject } from '@kbn/core/server'; import { AlertConsumers } from '@kbn/rule-data-utils'; +import type { ShouldIncrementRevision } from './bulk_edit'; import { PartialRule, RawRule, @@ -30,6 +31,7 @@ import { updateMeta, getPartialRuleFromRaw, addUuid, + incrementRevision, } from '../lib'; import { generateAPIKeyName, apiKeyAsAlertAttributes } from '../common'; @@ -45,22 +47,29 @@ export interface UpdateOptions { notifyWhen?: RuleNotifyWhenType | null; }; allowMissingConnectorSecrets?: boolean; + shouldIncrementRevision?: ShouldIncrementRevision; } export async function update( context: RulesClientContext, - { id, data, allowMissingConnectorSecrets }: UpdateOptions + { id, data, allowMissingConnectorSecrets, shouldIncrementRevision }: UpdateOptions ): Promise> { return await retryIfConflicts( context.logger, `rulesClient.update('${id}')`, - async () => await updateWithOCC(context, { id, data, allowMissingConnectorSecrets }) + async () => + await updateWithOCC(context, { + id, + data, + allowMissingConnectorSecrets, + shouldIncrementRevision, + }) ); } async function updateWithOCC( context: RulesClientContext, - { id, data, allowMissingConnectorSecrets }: UpdateOptions + { id, data, allowMissingConnectorSecrets, shouldIncrementRevision }: UpdateOptions ): Promise> { let alertSavedObject: SavedObject; @@ -108,7 +117,7 @@ async function updateWithOCC( const updateResult = await updateAlert( context, - { id, data, allowMissingConnectorSecrets }, + { id, data, allowMissingConnectorSecrets, shouldIncrementRevision }, alertSavedObject ); @@ -149,9 +158,15 @@ async function updateWithOCC( async function updateAlert( context: RulesClientContext, - { id, data: initialData, allowMissingConnectorSecrets }: UpdateOptions, - { attributes, version }: SavedObject + { + id, + data: initialData, + allowMissingConnectorSecrets, + shouldIncrementRevision = () => true, + }: UpdateOptions, + currentRule: SavedObject ): Promise> { + const { attributes, version } = currentRule; const data = { ...initialData, actions: addUuid(initialData.actions) }; const ruleType = context.ruleTypeRegistry.get(attributes.alertTypeId); @@ -203,6 +218,15 @@ async function updateAlert( const apiKeyAttributes = apiKeyAsAlertAttributes(createdAPIKey, username); const notifyWhen = getRuleNotifyWhenType(data.notifyWhen ?? null, data.throttle ?? null); + // Increment revision if applicable field has changed + const revision = shouldIncrementRevision(updatedParams) + ? incrementRevision( + currentRule, + { id, data, allowMissingConnectorSecrets }, + updatedParams + ) + : currentRule.attributes.revision; + let updatedObject: SavedObject; const createAttributes = updateMeta(context, { ...attributes, @@ -211,6 +235,7 @@ async function updateAlert( params: updatedParams as RawRule['params'], actions, notifyWhen, + revision, updatedBy: username, updatedAt: new Date().toISOString(), }); diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index 75e563d2011da..ec720335c94e6 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -66,6 +66,30 @@ const fieldsToExcludeFromPublicApi: Array = [ 'activeSnoozes', ]; +export const fieldsToExcludeFromRevisionUpdates: ReadonlySet = new Set([ + 'activeSnoozes', + 'alertTypeId', + 'apiKey', + 'apiKeyOwner', + 'consumer', + 'createdAt', + 'createdBy', + 'enabled', + 'executionStatus', + 'id', + 'isSnoozedUntil', + 'lastRun', + 'monitoring', + 'muteAll', + 'mutedInstanceIds', + 'nextRun', + 'revision', + 'running', + 'snoozeSchedule', + 'updatedBy', + 'updatedAt', +]); + export class RulesClient { private readonly context: RulesClientContext; diff --git a/x-pack/plugins/alerting/server/rules_client/tests/bulk_edit.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/bulk_edit.test.ts index 9bcf957a467a6..7ae9d4fcf041b 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/bulk_edit.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/bulk_edit.test.ts @@ -94,6 +94,7 @@ describe('bulkEdit()', () => { notifyWhen: null, actions: [], name: 'my rule name', + revision: 0, }, references: [], version: '123', @@ -220,6 +221,7 @@ describe('bulkEdit()', () => { throttle: null, notifyWhen: null, actions: [], + revision: 0, }, references: [], version: '123', @@ -251,6 +253,7 @@ describe('bulkEdit()', () => { type: 'alert', attributes: expect.objectContaining({ tags: ['foo', 'test-1'], + revision: 1, }), }), ], @@ -275,6 +278,7 @@ describe('bulkEdit()', () => { throttle: null, notifyWhen: null, actions: [], + revision: 0, }, references: [], version: '123', @@ -302,6 +306,7 @@ describe('bulkEdit()', () => { type: 'alert', attributes: expect.objectContaining({ tags: [], + revision: 1, }), }), ], @@ -326,6 +331,7 @@ describe('bulkEdit()', () => { throttle: null, notifyWhen: null, actions: [], + revision: 0, }, references: [], version: '123', @@ -354,6 +360,7 @@ describe('bulkEdit()', () => { type: 'alert', attributes: expect.objectContaining({ tags: ['test-1', 'test-2'], + revision: 1, }), }), ], @@ -579,6 +586,7 @@ describe('bulkEdit()', () => { updatedAt: '2019-02-12T21:01:22.479Z', updatedBy: 'elastic', tags: ['foo'], + revision: 1, }, references: [{ id: '1', name: 'action_0', type: 'action' }], }, @@ -592,6 +600,50 @@ describe('bulkEdit()', () => { snoozeSchedule: [], }); }); + + test('should only increment revision once for multiple operations', async () => { + unsecuredSavedObjectsClient.bulkCreate.mockResolvedValue({ + saved_objects: [ + { + ...existingRule, + attributes: { + ...existingRule.attributes, + revision: 1, + }, + }, + ], + }); + const result = await rulesClient.bulkEdit({ + filter: '', + operations: [ + { + field: 'actions', + operation: 'add', + value: [ + { + id: '687300e0-b882-11ed-ad70-c74a8cf8f386', + group: 'default', + params: { + message: 'Rule {{context.rule.name}} generated {{state.signals_count}} alerts', + }, + }, + ], + }, + { + field: 'throttle', + operation: 'set', + value: null, + }, + { + field: 'notifyWhen', + operation: 'set', + value: 'onActiveAlert', + }, + ], + }); + + expect(result.rules[0]).toHaveProperty('revision', 1); + }); }); describe('index pattern operations', () => { @@ -628,6 +680,7 @@ describe('bulkEdit()', () => { throttle: null, notifyWhen: null, actions: [], + revision: 0, }, references: [], version: '123', @@ -665,6 +718,7 @@ describe('bulkEdit()', () => { params: expect.objectContaining({ index: ['test-1', 'test-2', 'test-4', 'test-5'], }), + revision: 1, }), }), ], @@ -691,6 +745,7 @@ describe('bulkEdit()', () => { throttle: null, notifyWhen: null, actions: [], + revision: 0, }, references: [], version: '123', @@ -723,6 +778,7 @@ describe('bulkEdit()', () => { params: expect.objectContaining({ index: ['test-1'], }), + revision: 1, }), }), ], @@ -819,6 +875,7 @@ describe('bulkEdit()', () => { type: 'alert', attributes: expect.objectContaining({ snoozeSchedule: [snoozePayload], + revision: 0, }), }), ], @@ -848,6 +905,7 @@ describe('bulkEdit()', () => { id: '1', type: 'alert', attributes: expect.objectContaining({ + revision: 0, snoozeSchedule: [snoozePayload], }), }), @@ -893,6 +951,7 @@ describe('bulkEdit()', () => { id: '1', type: 'alert', attributes: expect.objectContaining({ + revision: 0, snoozeSchedule: [...existingSnooze, snoozePayload], }), }), @@ -938,6 +997,7 @@ describe('bulkEdit()', () => { type: 'alert', attributes: expect.objectContaining({ muteAll: true, + revision: 0, snoozeSchedule: [snoozePayload], }), }), @@ -981,6 +1041,7 @@ describe('bulkEdit()', () => { id: '1', type: 'alert', attributes: expect.objectContaining({ + revision: 0, snoozeSchedule: [existingSnooze[1], existingSnooze[2]], }), }), @@ -1025,6 +1086,7 @@ describe('bulkEdit()', () => { id: '1', type: 'alert', attributes: expect.objectContaining({ + revision: 0, snoozeSchedule: [], }), }), @@ -1069,6 +1131,7 @@ describe('bulkEdit()', () => { id: '1', type: 'alert', attributes: expect.objectContaining({ + revision: 0, snoozeSchedule: [existingSnooze[0]], }), }), @@ -1181,7 +1244,7 @@ describe('bulkEdit()', () => { expect(createAPIKeyMock).not.toHaveBeenCalled(); // Explicitly bulk editing the apiKey will set the api key, even if the rule is disabled - await rulesClient.bulkEdit({ + const result = await rulesClient.bulkEdit({ filter: 'alert.attributes.tags: "APM"', operations: [ { @@ -1192,6 +1255,9 @@ describe('bulkEdit()', () => { }); expect(createAPIKeyMock).toHaveBeenCalled(); + + // Just API key updates do not result in an increment to revision + expect(result.rules[0]).toHaveProperty('revision', 0); }); }); @@ -1211,7 +1277,7 @@ describe('bulkEdit()', () => { }); }); - it('should succesfully update tags and index patterns and return updated rule', async () => { + it('should successfully update tags and index patterns and return updated rule', async () => { unsecuredSavedObjectsClient.bulkCreate.mockResolvedValue({ saved_objects: [ { @@ -1230,6 +1296,7 @@ describe('bulkEdit()', () => { throttle: null, notifyWhen: null, actions: [], + revision: 0, }, references: [], version: '123', @@ -1270,6 +1337,7 @@ describe('bulkEdit()', () => { params: { index: ['index-1', 'index-2', 'index-3'], }, + revision: 1, }), }), ], @@ -1277,7 +1345,7 @@ describe('bulkEdit()', () => { ); }); - it('should succesfully update rule if tags are updated but index patterns are not', async () => { + it('should successfully update rule if tags are updated but index patterns are not', async () => { unsecuredSavedObjectsClient.bulkCreate.mockResolvedValue({ saved_objects: [ { @@ -1296,6 +1364,7 @@ describe('bulkEdit()', () => { throttle: null, notifyWhen: null, actions: [], + revision: 0, }, references: [], version: '123', @@ -1337,6 +1406,7 @@ describe('bulkEdit()', () => { params: { index: ['index-1', 'index-2'], }, + revision: 1, }), }), ], @@ -1344,7 +1414,7 @@ describe('bulkEdit()', () => { ); }); - it('should succesfully update rule if index patterns are updated but tags are not', async () => { + it('should successfully update rule if index patterns are updated but tags are not', async () => { unsecuredSavedObjectsClient.bulkCreate.mockResolvedValue({ saved_objects: [ { @@ -1363,6 +1433,7 @@ describe('bulkEdit()', () => { throttle: null, notifyWhen: null, actions: [], + revision: 0, }, references: [], version: '123', @@ -1404,6 +1475,7 @@ describe('bulkEdit()', () => { params: { index: ['index-1', 'index-2', 'index-3'], }, + revision: 1, }), }), ], diff --git a/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts index 8d5d681845f8a..61d204b6024b5 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts @@ -457,6 +457,7 @@ describe('create()', () => { "params": Object { "bar": true, }, + "revision": 0, "running": false, "schedule": Object { "interval": "1m", @@ -677,6 +678,7 @@ describe('create()', () => { "params": Object { "bar": true, }, + "revision": 0, "running": false, "schedule": Object { "interval": "1m", @@ -1105,6 +1107,7 @@ describe('create()', () => { name: 'abc', notifyWhen: null, params: { bar: true }, + revision: 0, running: false, schedule: { interval: '1m' }, tags: ['foo'], @@ -1314,6 +1317,7 @@ describe('create()', () => { name: 'abc', notifyWhen: null, params: { bar: true, parameterThatIsSavedObjectRef: 'soRef_0' }, + revision: 0, running: false, schedule: { interval: '1m' }, tags: ['foo'], @@ -1493,6 +1497,7 @@ describe('create()', () => { name: 'abc', notifyWhen: null, params: { bar: true, parameterThatIsSavedObjectRef: 'action_0' }, + revision: 0, running: false, schedule: { interval: '1m' }, tags: ['foo'], @@ -1668,6 +1673,7 @@ describe('create()', () => { warning: null, }, monitoring: getDefaultMonitoring('2019-02-12T21:01:22.479Z'), + revision: 0, running: false, }, { @@ -1804,6 +1810,7 @@ describe('create()', () => { warning: null, }, monitoring: getDefaultMonitoring('2019-02-12T21:01:22.479Z'), + revision: 0, running: false, }, { @@ -1940,6 +1947,7 @@ describe('create()', () => { warning: null, }, monitoring: getDefaultMonitoring('2019-02-12T21:01:22.479Z'), + revision: 0, running: false, }, { @@ -2116,6 +2124,7 @@ describe('create()', () => { meta: { versionApiKeyLastmodified: 'v8.0.0', }, + revision: 0, running: false, }, { @@ -2470,6 +2479,7 @@ describe('create()', () => { warning: null, }, monitoring: getDefaultMonitoring('2019-02-12T21:01:22.479Z'), + revision: 0, running: false, }, { @@ -2575,6 +2585,7 @@ describe('create()', () => { warning: null, }, monitoring: getDefaultMonitoring('2019-02-12T21:01:22.479Z'), + revision: 0, running: false, }, { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts index 672281469d18b..90d68301f97aa 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts @@ -90,6 +90,7 @@ const BaseRuleSavedObject: SavedObject = { error: null, warning: null, }, + revision: 0, }, references: [], }; diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts index cbf766bd482d5..c7e2c65980afb 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts @@ -94,6 +94,7 @@ const BaseRuleSavedObject: SavedObject = { error: null, warning: null, }, + revision: 0, }, references: [], }; diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts index ffc40cd705abd..3f8dfd92ee894 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts @@ -91,6 +91,7 @@ const BaseRuleSavedObject: SavedObject = { error: null, warning: null, }, + revision: 0, }, references: [], }; diff --git a/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts index 2e1be7076004a..074bbfa3552b1 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts @@ -90,6 +90,7 @@ describe('update()', () => { alertTypeId: 'myType', schedule: { interval: '1m' }, consumer: 'myApp', + revision: 0, scheduledTaskId: 'task-123', params: {}, actions: [ @@ -235,6 +236,7 @@ describe('update()', () => { }, ], notifyWhen: 'onActiveAlert', + revision: 1, scheduledTaskId: 'task-123', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), @@ -330,6 +332,7 @@ describe('update()', () => { "params": Object { "bar": true, }, + "revision": 1, "schedule": Object { "interval": "1m", }, @@ -395,6 +398,7 @@ describe('update()', () => { "risk_score": 40, "severity": "low", }, + "revision": 1, "schedule": Object { "interval": "1m", }, @@ -527,6 +531,7 @@ describe('update()', () => { }, ], notifyWhen: 'onActiveAlert', + revision: 1, scheduledTaskId: 'task-123', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), @@ -623,6 +628,7 @@ describe('update()', () => { name: 'abc', notifyWhen: 'onActiveAlert', params: { bar: true }, + revision: 1, schedule: { interval: '1m' }, scheduledTaskId: 'task-123', tags: ['foo'], @@ -673,6 +679,7 @@ describe('update()', () => { "params": Object { "bar": true, }, + "revision": 1, "schedule": Object { "interval": "1m", }, @@ -747,6 +754,7 @@ describe('update()', () => { }, ], notifyWhen: 'onActiveAlert', + revision: 1, scheduledTaskId: 'task-123', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), @@ -807,6 +815,7 @@ describe('update()', () => { name: 'abc', notifyWhen: 'onActiveAlert', params: { bar: true, parameterThatIsSavedObjectRef: 'soRef_0' }, + revision: 1, schedule: { interval: '1m' }, scheduledTaskId: 'task-123', tags: ['foo'], @@ -852,6 +861,7 @@ describe('update()', () => { "bar": true, "parameterThatIsSavedObjectId": "9", }, + "revision": 1, "schedule": Object { "interval": "1m", }, @@ -889,6 +899,7 @@ describe('update()', () => { }, ], apiKey: Buffer.from('123:abc').toString('base64'), + revision: 1, scheduledTaskId: 'task-123', }, updated_at: new Date().toISOString(), @@ -942,6 +953,7 @@ describe('update()', () => { "params": Object { "bar": true, }, + "revision": 1, "schedule": Object { "interval": "1m", }, @@ -986,6 +998,7 @@ describe('update()', () => { "params": Object { "bar": true, }, + "revision": 1, "schedule": Object { "interval": "1m", }, @@ -1044,6 +1057,7 @@ describe('update()', () => { }, }, ], + revision: 1, scheduledTaskId: 'task-123', apiKey: null, }, @@ -1099,6 +1113,7 @@ describe('update()', () => { "params": Object { "bar": true, }, + "revision": 1, "schedule": Object { "interval": "1m", }, @@ -1135,6 +1150,7 @@ describe('update()', () => { "params": Object { "bar": true, }, + "revision": 1, "schedule": Object { "interval": "1m", }, @@ -2079,6 +2095,7 @@ describe('update()', () => { }, ], notifyWhen: 'onActiveAlert', + revision: 1, scheduledTaskId: 'task-123', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), @@ -2144,6 +2161,7 @@ describe('update()', () => { name: 'abc', notifyWhen: 'onActiveAlert', params: { bar: true }, + revision: 1, schedule: { interval: '1m' }, scheduledTaskId: 'task-123', tags: ['foo'], @@ -2178,6 +2196,7 @@ describe('update()', () => { "params": Object { "bar": true, }, + "revision": 1, "schedule": Object { "interval": "1m", }, @@ -2690,6 +2709,7 @@ describe('update()', () => { name: 'abc', notifyWhen: null, params: { bar: true, risk_score: 40, severity: 'low' }, + revision: 1, schedule: { interval: '1m' }, scheduledTaskId: 'task-123', tags: ['foo'], diff --git a/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts index e2841ba4927c6..3051a39f238c1 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts @@ -64,6 +64,7 @@ describe('updateApiKey()', () => { id: '1', type: 'alert', attributes: { + revision: 0, schedule: { interval: '10s' }, alertTypeId: 'myType', consumer: 'myApp', @@ -117,6 +118,7 @@ describe('updateApiKey()', () => { enabled: true, apiKey: Buffer.from('234:abc').toString('base64'), apiKeyOwner: 'elastic', + revision: 0, updatedBy: 'elastic', updatedAt: '2019-02-12T21:01:22.479Z', actions: [ @@ -177,6 +179,7 @@ describe('updateApiKey()', () => { enabled: true, apiKey: Buffer.from('234:abc').toString('base64'), apiKeyOwner: 'elastic', + revision: 0, updatedAt: '2019-02-12T21:01:22.479Z', updatedBy: 'elastic', actions: [ diff --git a/x-pack/plugins/alerting/server/saved_objects/index.ts b/x-pack/plugins/alerting/server/saved_objects/index.ts index cd69efaf3e875..2d8fe52469386 100644 --- a/x-pack/plugins/alerting/server/saved_objects/index.ts +++ b/x-pack/plugins/alerting/server/saved_objects/index.ts @@ -40,6 +40,7 @@ export const AlertAttributesExcludedFromAAD = [ 'isSnoozedUntil', 'lastRun', 'nextRun', + 'revision', 'running', ]; @@ -60,6 +61,7 @@ export type AlertAttributesExcludedFromAADType = | 'isSnoozedUntil' | 'lastRun' | 'nextRun' + | 'revision' | 'running'; export function setupSavedObjects( diff --git a/x-pack/plugins/alerting/server/saved_objects/mappings.ts b/x-pack/plugins/alerting/server/saved_objects/mappings.ts index f065c5e069ce1..9e3bc06e7ca39 100644 --- a/x-pack/plugins/alerting/server/saved_objects/mappings.ts +++ b/x-pack/plugins/alerting/server/saved_objects/mappings.ts @@ -198,6 +198,10 @@ export const alertMappings: SavedObjectsTypeMappingDefinition = { }, }, }, + revision: { + index: true, // Explicitly setting to `true` as there is need to query for a rule by a specific revision + type: 'long', + }, snoozeSchedule: { type: 'nested', properties: { diff --git a/x-pack/plugins/alerting/server/saved_objects/migrations/8.8/index.ts b/x-pack/plugins/alerting/server/saved_objects/migrations/8.8/index.ts index 48c58fad0c2c6..fb90230f64f6f 100644 --- a/x-pack/plugins/alerting/server/saved_objects/migrations/8.8/index.ts +++ b/x-pack/plugins/alerting/server/saved_objects/migrations/8.8/index.ts @@ -11,6 +11,16 @@ import { v4 as uuidv4 } from 'uuid'; import { createEsoMigration, pipeMigrations } from '../utils'; import { RawRule } from '../../../types'; +function addRevision(doc: SavedObjectUnsanitizedDoc): SavedObjectUnsanitizedDoc { + return { + ...doc, + attributes: { + ...doc.attributes, + revision: 0, + }, + }; +} + function addActionUuid( doc: SavedObjectUnsanitizedDoc ): SavedObjectUnsanitizedDoc { @@ -36,5 +46,5 @@ export const getMigrations880 = (encryptedSavedObjects: EncryptedSavedObjectsPlu createEsoMigration( encryptedSavedObjects, (doc: SavedObjectUnsanitizedDoc): doc is SavedObjectUnsanitizedDoc => true, - pipeMigrations(addActionUuid) + pipeMigrations(addActionUuid, addRevision) ); diff --git a/x-pack/plugins/alerting/server/saved_objects/migrations/index.test.ts b/x-pack/plugins/alerting/server/saved_objects/migrations/index.test.ts index de03eec71d4e1..aba9b085f70dc 100644 --- a/x-pack/plugins/alerting/server/saved_objects/migrations/index.test.ts +++ b/x-pack/plugins/alerting/server/saved_objects/migrations/index.test.ts @@ -2652,6 +2652,14 @@ describe('successful migrations', () => { }, ]); }); + + test('migrates rule to include revision and defaults revision to 0', () => { + const migration880 = getMigrations(encryptedSavedObjectsSetup, {}, isPreconfigured)['8.8.0']; + + const rule = getMockData(); + const migratedAlert880 = migration880(rule, migrationContext); + expect(migratedAlert880.attributes.revision).toEqual(0); + }); }); describe('Metrics Inventory Threshold rule', () => { diff --git a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts index b78c06eaff7b6..916d9c27a7831 100644 --- a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts @@ -37,6 +37,7 @@ const alert: SanitizedRule<{ status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }; describe('Alert Task Instance', () => { diff --git a/x-pack/plugins/alerting/server/task_runner/fixtures.ts b/x-pack/plugins/alerting/server/task_runner/fixtures.ts index 8558cd6cbd70f..af5576f041c89 100644 --- a/x-pack/plugins/alerting/server/task_runner/fixtures.ts +++ b/x-pack/plugins/alerting/server/task_runner/fixtures.ts @@ -210,6 +210,7 @@ export const mockedRuleTypeSavedObject: Rule = { lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, monitoring: getDefaultMonitoring('2020-08-20T19:23:38Z'), + revision: 0, }; export const mockTaskInstance = () => ({ diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index 8a463e7ec1aa1..ebe0f98a5b150 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -350,6 +350,7 @@ export interface RawRule extends SavedObjectAttributes { isSnoozedUntil?: string | null; lastRun?: RawRuleLastRun | null; nextRun?: string | null; + revision: number; running?: boolean | null; } diff --git a/x-pack/plugins/monitoring/public/alerts/lib/__snapshots__/get_alert_panels_by_category.test.tsx.snap b/x-pack/plugins/monitoring/public/alerts/lib/__snapshots__/get_alert_panels_by_category.test.tsx.snap index c2d9d0df2d4d1..1ed3850227b76 100644 --- a/x-pack/plugins/monitoring/public/alerts/lib/__snapshots__/get_alert_panels_by_category.test.tsx.snap +++ b/x-pack/plugins/monitoring/public/alerts/lib/__snapshots__/get_alert_panels_by_category.test.tsx.snap @@ -87,6 +87,7 @@ Array [ "name": "monitoring_alert_cpu_usage_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -250,6 +251,7 @@ Array [ "name": "monitoring_alert_jvm_memory_usage_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -310,6 +312,7 @@ Array [ "name": "monitoring_alert_jvm_memory_usage_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -602,6 +605,7 @@ Array [ "name": "monitoring_alert_nodes_changed_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -662,6 +666,7 @@ Array [ "name": "monitoring_alert_nodes_changed_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -722,6 +727,7 @@ Array [ "name": "monitoring_alert_disk_usage_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -782,6 +788,7 @@ Array [ "name": "monitoring_alert_license_expiration_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -842,6 +849,7 @@ Array [ "name": "monitoring_alert_license_expiration_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -931,6 +939,7 @@ Array [ "name": "monitoring_alert_jvm_memory_usage_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -1032,6 +1041,7 @@ Array [ "name": "monitoring_alert_nodes_changed_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -1068,6 +1078,7 @@ Array [ "name": "monitoring_alert_disk_usage_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -1104,6 +1115,7 @@ Array [ "name": "monitoring_alert_license_expiration_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -1205,6 +1217,7 @@ Array [ "name": "monitoring_alert_logstash_version_mismatch_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -1241,6 +1254,7 @@ Array [ "name": "monitoring_alert_cpu_usage_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -1277,6 +1291,7 @@ Array [ "name": "monitoring_alert_thread_pool_write_rejections_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, diff --git a/x-pack/plugins/monitoring/public/alerts/lib/__snapshots__/get_alert_panels_by_node.test.tsx.snap b/x-pack/plugins/monitoring/public/alerts/lib/__snapshots__/get_alert_panels_by_node.test.tsx.snap index 9bb6d1c979571..b576b029f1a70 100644 --- a/x-pack/plugins/monitoring/public/alerts/lib/__snapshots__/get_alert_panels_by_node.test.tsx.snap +++ b/x-pack/plugins/monitoring/public/alerts/lib/__snapshots__/get_alert_panels_by_node.test.tsx.snap @@ -114,6 +114,7 @@ Array [ "name": "monitoring_alert_jvm_memory_usage_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -174,6 +175,7 @@ Array [ "name": "monitoring_alert_jvm_memory_usage_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -407,6 +409,7 @@ Array [ "name": "monitoring_alert_nodes_changed_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -467,6 +470,7 @@ Array [ "name": "monitoring_alert_disk_usage_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -527,6 +531,7 @@ Array [ "name": "monitoring_alert_license_expiration_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -587,6 +592,7 @@ Array [ "name": "monitoring_alert_nodes_changed_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -647,6 +653,7 @@ Array [ "name": "monitoring_alert_license_expiration_label", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, @@ -707,6 +714,7 @@ Array [ "name": "monitoring_alert_nodes_changed_label_2", "notifyWhen": null, "params": Object {}, + "revision": 0, "schedule": Object { "interval": "1m", }, diff --git a/x-pack/plugins/monitoring/public/alerts/lib/get_alert_panels_by_category.test.tsx b/x-pack/plugins/monitoring/public/alerts/lib/get_alert_panels_by_category.test.tsx index 445006ecf715e..367b48f5a6786 100644 --- a/x-pack/plugins/monitoring/public/alerts/lib/get_alert_panels_by_category.test.tsx +++ b/x-pack/plugins/monitoring/public/alerts/lib/get_alert_panels_by_category.test.tsx @@ -58,6 +58,7 @@ const mockAlert = { lastExecutionDate: new Date('2020-12-08'), }, notifyWhen: null, + revision: 0, }; describe('getAlertPanelsByCategory', () => { diff --git a/x-pack/plugins/monitoring/public/alerts/lib/get_alert_panels_by_node.test.tsx b/x-pack/plugins/monitoring/public/alerts/lib/get_alert_panels_by_node.test.tsx index 7e7cd96f75aba..9103eaa0c3207 100644 --- a/x-pack/plugins/monitoring/public/alerts/lib/get_alert_panels_by_node.test.tsx +++ b/x-pack/plugins/monitoring/public/alerts/lib/get_alert_panels_by_node.test.tsx @@ -57,6 +57,7 @@ const mockAlert = { lastExecutionDate: new Date('2020-12-08'), }, notifyWhen: null, + revision: 0, }; describe('getAlertPanelsByNode', () => { diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import.ts index b40bed8ce65c5..8d9cee09a9f7b 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_management/model/import/rule_to_import.ts @@ -17,7 +17,7 @@ import { BaseCreateProps, TypeSpecificCreateProps, } from '../../../rule_schema'; -import { created_at, updated_at, created_by, updated_by } from '../../../schemas/common'; +import { created_at, updated_at, created_by, updated_by, revision } from '../../../schemas/common'; /** * Differences from this and the createRulesSchema are @@ -44,6 +44,7 @@ export const RuleToImport = t.intersection([ created_by, related_integrations: RelatedIntegrationArray, required_fields: RequiredFieldArray, + revision, setup: SetupGuide, }) ), diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_response_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_response_schema.mock.ts index 86018ff1a7b88..7ccdd03b1355c 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_response_schema.mock.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_response_schema.mock.ts @@ -31,6 +31,7 @@ const getResponseBaseParams = (anchorDate: string = ANCHOR_DATE): SharedResponse immutable: false, name: 'Query with a rule id', references: ['test 1', 'test 2'], + revision: 0, severity: 'high' as const, severity_mapping: [], updated_by: 'elastic_kibana', diff --git a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_schemas.ts index 636c5ee5f6fa8..e0b427cdcefbc 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/rule_schema/model/rule_schemas.ts @@ -36,6 +36,7 @@ import { updated_by, created_at, created_by, + revision, } from '../../schemas/common'; import { @@ -154,6 +155,7 @@ const responseRequiredFields = { updated_by, created_at, created_by, + revision, // NOTE: For now, Related Integrations, Required Fields and Setup Guide are supported for prebuilt // rules only. We don't want to allow users to edit these 3 fields via the API. If we added them diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts index 52ba9e06622d4..b6f90f4cf7025 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts @@ -59,6 +59,7 @@ export const status_code = PositiveInteger; export const message = t.string; export const perPage = PositiveInteger; export const total = PositiveInteger; +export const revision = PositiveInteger; export const success = t.boolean; export const success_count = PositiveInteger; diff --git a/x-pack/plugins/security_solution/cypress/objects/rule.ts b/x-pack/plugins/security_solution/cypress/objects/rule.ts index 5506fa091f478..cdcdc99b7ae8a 100644 --- a/x-pack/plugins/security_solution/cypress/objects/rule.ts +++ b/x-pack/plugins/security_solution/cypress/objects/rule.ts @@ -499,6 +499,7 @@ export const expectedExportedRule = (ruleResponse: Cypress.Response(params: T): SanitizedRule = status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }); export const resolveRuleMock = (params: T): ResolvedSanitizedRule => ({ @@ -552,6 +553,7 @@ export const legacyGetNotificationResult = ({ status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }); /** @@ -600,6 +602,7 @@ export const legacyGetHourlyNotificationResult = ( status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }); /** @@ -648,6 +651,7 @@ export const legacyGetDailyNotificationResult = ( status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }); /** @@ -696,6 +700,7 @@ export const legacyGetWeeklyNotificationResult = ( status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }); /** diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/utils.ts index edb7c2c699882..7df109deb6f3b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/utils.ts @@ -86,6 +86,7 @@ export const getOutputRuleAlertForRest = (): RuleResponse => ({ type: 'query', note: '# Investigative notes', version: 1, + revision: 0, execution_summary: undefined, related_integrations: [], required_fields: [], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts index e3fabc5366980..8779c19e71988 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts @@ -544,6 +544,7 @@ export const performBulkActionRoute = ( exceptionsList: exceptions, }, }, + shouldIncrementRevision: () => false, }); // TODO: figureout why types can't return just updatedRule diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.test.ts index ecc646d11c8da..b441d071c21c1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.test.ts @@ -76,6 +76,7 @@ describe('duplicateRule', () => { mutedInstanceIds: [], updatedAt: new Date(2021, 0), createdAt: new Date(2021, 0), + revision: 0, scheduledTaskId: undefined, executionStatus: { lastExecutionDate: new Date(2021, 0), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/patch_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/patch_rules.ts index 45d1a21325abd..3ce61fcc9800b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/patch_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/patch_rules.ts @@ -17,6 +17,8 @@ export interface PatchRulesOptions { nextParams: PatchRuleRequestBody; existingRule: RuleAlertType | null | undefined; allowMissingConnectorSecrets?: boolean; + + shouldIncrementRevision?: boolean; } export const patchRules = async ({ @@ -24,6 +26,7 @@ export const patchRules = async ({ existingRule, nextParams, allowMissingConnectorSecrets, + shouldIncrementRevision = true, }: PatchRulesOptions): Promise | null> => { if (existingRule == null) { return null; @@ -35,6 +38,7 @@ export const patchRules = async ({ id: existingRule.id, data: patchedRule, allowMissingConnectorSecrets, + shouldIncrementRevision: () => shouldIncrementRevision, }); if (nextParams.throttle !== undefined) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.test.ts index d5511ccf7b1cc..b38329bdab3da 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_all.test.ts @@ -93,6 +93,7 @@ describe('getExportAll', () => { references: ['http://example.com', 'https://example.com'], related_integrations: [], required_fields: [], + revision: 0, setup: '', timeline_id: 'some-timeline-id', timeline_title: 'some-timeline-title', @@ -287,6 +288,7 @@ describe('getExportAll', () => { throttle: 'rule', note: '# Investigative notes', version: 1, + revision: 0, exceptions_list: getListArrayMock(), }); expect(detailsJson).toEqual({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.test.ts index 570954ba9c8b0..40a1435b2d64f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.test.ts @@ -91,6 +91,7 @@ describe('get_export_by_object_ids', () => { references: ['http://example.com', 'https://example.com'], related_integrations: [], required_fields: [], + revision: 0, setup: '', timeline_id: 'some-timeline-id', timeline_title: 'some-timeline-title', @@ -297,6 +298,7 @@ describe('get_export_by_object_ids', () => { throttle: 'rule', note: '# Investigative notes', version: 1, + revision: 0, exceptions_list: getListArrayMock(), }); expect(detailsJson).toEqual({ @@ -399,6 +401,7 @@ describe('get_export_by_object_ids', () => { throttle: 'no_actions', note: '# Investigative notes', version: 1, + revision: 0, exceptions_list: getListArrayMock(), execution_summary: undefined, outcome: undefined, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts index 5a8d6f9a34e87..89ec68ff79bb1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/import_rules_utils.ts @@ -141,6 +141,7 @@ export const importRules = async ({ exceptions_list: [...exceptions], }, allowMissingConnectorSecrets, + shouldIncrementRevision: false, }); resolve({ rule_id: parsedRule.rule_id, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.ts index 0eec37b2c83db..b2554e4f957da 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.ts @@ -692,6 +692,7 @@ export const internalRuleToAPIResponse = ( tags: rule.tags, interval: rule.schedule.interval, enabled: rule.enabled, + revision: rule.revision, // Security solution shared rule params ...commonParamsCamelToSnake(rule.params), // Type specific security solution rule params diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts index 40ced9baaf28f..71ccb07d03cb3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts @@ -46,6 +46,7 @@ export const ruleOutput = (): RuleResponse => ({ throttle: 'no_actions', threat: getThreatMock(), version: 1, + revision: 0, filters: [ { query: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/es_results.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/es_results.ts index 5bf47929cffa5..9593dd5624c22 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/es_results.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/es_results.ts @@ -497,6 +497,7 @@ export const sampleSignalHit = (): SignalHit => ({ related_integrations: [], required_fields: [], response_actions: undefined, + revision: 0, setup: '', throttle: 'no_actions', actions: [], diff --git a/x-pack/plugins/synthetics/e2e/journeys/synthetics/index.ts b/x-pack/plugins/synthetics/e2e/journeys/synthetics/index.ts index bf4ecd526e911..1e182d06fefdc 100644 --- a/x-pack/plugins/synthetics/e2e/journeys/synthetics/index.ts +++ b/x-pack/plugins/synthetics/e2e/journeys/synthetics/index.ts @@ -20,7 +20,8 @@ export * from './detail_flyout'; export * from './alert_rules/default_status_alert.journey'; export * from './test_now_mode.journey'; export * from './data_retention.journey'; -export * from './monitor_details_page/monitor_summary.journey'; +// Additional flake skip along with https://github.com/elastic/kibana/pull/151936 +// export * from './monitor_details_page/monitor_summary.journey'; export * from './test_run_details.journey'; export * from './step_details.journey'; export * from './project_monitor_read_only.journey'; diff --git a/x-pack/plugins/synthetics/public/legacy_uptime/state/api/alerts.ts b/x-pack/plugins/synthetics/public/legacy_uptime/state/api/alerts.ts index 33cbac6468306..db335a1ef458b 100644 --- a/x-pack/plugins/synthetics/public/legacy_uptime/state/api/alerts.ts +++ b/x-pack/plugins/synthetics/public/legacy_uptime/state/api/alerts.ts @@ -63,6 +63,7 @@ type NewMonitorStatusAlert = Omit< | 'muteAll' | 'mutedInstanceIds' | 'executionStatus' + | 'revision' | 'ruleTypeId' | 'notifyWhen' | 'actions' diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/create.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/create.test.ts index 484bff68d92b3..b2e5ecd01a63a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/create.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/create.test.ts @@ -95,6 +95,7 @@ describe('createRule', () => { createdAt: new Date('2021-04-01T21:33:13.247Z'), updatedAt: new Date('2021-04-01T21:33:13.247Z'), apiKeyOwner: '', + revision: 0, }; http.post.mockResolvedValueOnce(resolvedValue); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/update.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/update.test.ts index 6b65e6cc64818..8b3ebc3f96e52 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/update.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/update.test.ts @@ -26,6 +26,7 @@ describe('updateRule', () => { updatedAt: new Date('1970-01-01T00:00:00.000Z'), apiKey: null, apiKeyOwner: null, + revision: 0, }; const resolvedValue: Rule = { ...ruleToUpdate, @@ -40,6 +41,7 @@ describe('updateRule', () => { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 1, }; http.put.mockResolvedValueOnce(resolvedValue); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/value_validators.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/value_validators.test.ts index a0069bcdc328d..4fdd9fe0893ab 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/value_validators.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/value_validators.test.ts @@ -275,6 +275,7 @@ describe('getRuleWithInvalidatedFields', () => { throttle: '', updatedAt: new Date(), updatedBy: '', + revision: 0, }; const baseAlertErrors = {}; const actionsErrors: IErrorObject[] = []; @@ -313,6 +314,7 @@ describe('getRuleWithInvalidatedFields', () => { throttle: '', updatedAt: new Date(), updatedBy: '', + revision: 0, }; const baseAlertErrors = {}; const actionsErrors: IErrorObject[] = []; @@ -363,6 +365,7 @@ describe('getRuleWithInvalidatedFields', () => { throttle: '', updatedAt: new Date(), updatedBy: '', + revision: 0, }; const baseAlertErrors = {}; const actionsErrors = [{ 'incident.field.name': ['Name is required.'] }]; @@ -422,6 +425,7 @@ describe('getRuleWithInvalidatedFields', () => { throttle: '', updatedAt: new Date(), updatedBy: '', + revision: 0, }; const baseAlertErrors = {}; const actionsErrors = [ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_rule_api_operations.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_rule_api_operations.test.tsx index 753b3c8497fe9..4fba7e7027d8c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_rule_api_operations.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_rule_api_operations.test.tsx @@ -385,6 +385,7 @@ function mockRule(overloads: Partial = {}): Rule { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_actions_popover.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_actions_popover.test.tsx index 6fa62883e3aff..f981fd07a1b54 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_actions_popover.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_actions_popover.test.tsx @@ -40,6 +40,7 @@ describe('rule_actions_popover', () => { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_definition.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_definition.test.tsx index 6f215e139adf0..148d0994fc497 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_definition.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_definition.test.tsx @@ -215,6 +215,7 @@ function mockRule(overwrite = {}): Rule { updatedAt: new Date(), consumer: 'alerts', notifyWhen: 'onActiveAlert', + revision: 0, executionStatus: { status: 'active', lastDuration: 500, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.test.tsx index a57b896a95902..d07ee7460217c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.test.tsx @@ -818,6 +818,7 @@ describe('rule_details', () => { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details_route.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details_route.test.tsx index 1d0be2b9ae834..a04e0b2e14df7 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details_route.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details_route.test.tsx @@ -494,6 +494,7 @@ function mockRule(overloads: Partial = {}): Rule { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.test.tsx index 20114096699d1..c586aba931682 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.test.tsx @@ -117,6 +117,7 @@ const mockRule: Rule = { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, }; const loadActionErrorLogMock = jest.fn(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.test.tsx index ab8d28d4a0c0e..117bca134f0f9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.test.tsx @@ -125,6 +125,7 @@ function mockRule(overloads: Partial = {}): Rule { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/test_helpers.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/test_helpers.ts index 6cc06dbd80d40..4146ac8006325 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/test_helpers.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/test_helpers.ts @@ -54,6 +54,7 @@ export function mockRule(overloads: Partial = {}): Rule { notifyWhen: null, muteAll: false, mutedInstanceIds: [], + revision: 0, executionStatus: { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/view_in_app.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/view_in_app.test.tsx index 7744846863bec..6b6e467a96359 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/view_in_app.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/view_in_app.test.tsx @@ -93,6 +93,7 @@ function mockRule(overloads: Partial = {}): Rule { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx index d3e989bd135a0..92a1329b0e67a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx @@ -397,6 +397,7 @@ function mockRule(overloads: Partial = {}): Rule { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.test.tsx index 57ba467c79762..50f8049fc4299 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.test.tsx @@ -174,6 +174,7 @@ describe('rule_edit', () => { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, ...initialRuleFields, }; actionTypeRegistry.get.mockReturnValueOnce(actionTypeModel); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_errors.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_errors.test.tsx index babd4ce594b8c..0e4bd4108c271 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_errors.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_errors.test.tsx @@ -266,6 +266,7 @@ function mockRule(overloads: Partial = {}): Rule { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + revision: 0, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/collapsed_item_actions.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/collapsed_item_actions.test.tsx index 30b871104b393..8d5b7952b5f00 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/collapsed_item_actions.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/collapsed_item_actions.test.tsx @@ -83,6 +83,7 @@ describe('CollapsedItemActions', () => { ruleType: 'Test Rule Type', isEditable: true, enabledInLicense: true, + revision: 0, ...overrides, }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/notify_badge/notify_badge.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/notify_badge/notify_badge.test.tsx index 84c39f38136e9..35cddf249d8e7 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/notify_badge/notify_badge.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/notify_badge/notify_badge.test.tsx @@ -53,6 +53,7 @@ const getRule = (overrides = {}): RuleTableItem => ({ ruleType: 'Test Rule Type', isEditable: true, enabledInLicense: true, + revision: 0, ...overrides, }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_enabled_switch.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_enabled_switch.test.tsx index 418b6931ca1a3..6796b741fc0c1 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_enabled_switch.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_enabled_switch.test.tsx @@ -42,6 +42,7 @@ describe('RuleEnabledSwitch', () => { notifyWhen: null, index: 0, updatedAt: new Date('2020-08-20T19:23:38Z'), + revision: 0, }, onRuleChanged: jest.fn(), }; @@ -86,6 +87,7 @@ describe('RuleEnabledSwitch', () => { notifyWhen: null, index: 0, updatedAt: new Date('2020-08-20T19:23:38Z'), + revision: 0, }, }} /> diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts index 6fa2b71176788..5ff6a1cf55175 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts @@ -126,6 +126,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { mute_all: false, muted_alert_ids: [], execution_status: response.body.execution_status, + revision: 0, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts index be950eedb8c18..2c7a55134c711 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts @@ -123,6 +123,7 @@ const findTestUtils = ( api_key_owner: 'elastic', mute_all: false, muted_alert_ids: [], + revision: 0, execution_status: match.execution_status, ...(match.next_run ? { next_run: match.next_run } : {}), ...(match.last_run ? { last_run: match.last_run } : {}), @@ -335,6 +336,7 @@ const findTestUtils = ( created_at: match.created_at, updated_at: match.updated_at, execution_status: match.execution_status, + revision: 0, ...(match.next_run ? { next_run: match.next_run } : {}), ...(match.last_run ? { last_run: match.last_run } : {}), ...(describeType === 'internal' diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/get.ts index d6de374d2524b..d0d93c0154745 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/get.ts @@ -82,6 +82,7 @@ const getTestUtils = ( mute_all: false, muted_alert_ids: [], execution_status: response.body.execution_status, + revision: 0, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), ...(describeType === 'internal' diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update.ts index a5254c6032109..ba3963a00ddd1 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update.ts @@ -134,6 +134,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { created_at: response.body.created_at, updated_at: response.body.updated_at, execution_status: response.body.execution_status, + revision: 1, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), }); @@ -224,6 +225,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { created_at: response.body.created_at, updated_at: response.body.updated_at, execution_status: response.body.execution_status, + revision: 1, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), }); @@ -325,6 +327,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { created_at: response.body.created_at, updated_at: response.body.updated_at, execution_status: response.body.execution_status, + revision: 1, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), }); @@ -426,6 +429,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { created_at: response.body.created_at, updated_at: response.body.updated_at, execution_status: response.body.execution_status, + revision: 1, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), }); @@ -525,6 +529,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { created_at: response.body.created_at, updated_at: response.body.updated_at, execution_status: response.body.execution_status, + revision: 1, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update_api_key.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update_api_key.ts index a0d1eb4dd0756..6a594316796d4 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update_api_key.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update_api_key.ts @@ -98,6 +98,8 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte .auth(user.username, user.password) .expect(200); expect(updatedAlert.api_key_owner).to.eql(user.username); + // Ensure revision is not incremented when API key is updated + expect(updatedAlert.revision).to.eql(0); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -152,6 +154,8 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte .auth(user.username, user.password) .expect(200); expect(updatedAlert.api_key_owner).to.eql(user.username); + // Ensure revision is not incremented when API key is updated + expect(updatedAlert.revision).to.eql(0); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -217,6 +221,8 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte .auth(user.username, user.password) .expect(200); expect(updatedAlert.api_key_owner).to.eql(user.username); + // Ensure revision is not incremented when API key is updated + expect(updatedAlert.revision).to.eql(0); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -282,6 +288,8 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte .auth(user.username, user.password) .expect(200); expect(updatedAlert.api_key_owner).to.eql(user.username); + // Ensure revision is not incremented when API key is updated + expect(updatedAlert.revision).to.eql(0); // Ensure AAD isn't broken await checkAAD({ supertest, @@ -346,6 +354,8 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte .auth(user.username, user.password) .expect(200); expect(updatedAlert.api_key_owner).to.eql(user.username); + // Ensure revision is not incremented when API key is updated + expect(updatedAlert.revision).to.eql(0); // Ensure AAD isn't broken await checkAAD({ supertest, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_delete.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_delete.ts index cb5cc4b1d5687..3073fc077b5e8 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_delete.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_delete.ts @@ -35,6 +35,7 @@ const getDefaultRules = (response: any) => ({ scheduledTaskId: response.body.rules[0].scheduledTaskId, executionStatus: response.body.rules[0].executionStatus, monitoring: response.body.rules[0].monitoring, + revision: 0, ...(response.body.rules[0].nextRun ? { nextRun: response.body.rules[0].nextRun } : {}), ...(response.body.rules[0].lastRun ? { lastRun: response.body.rules[0].lastRun } : {}), }); @@ -67,6 +68,7 @@ const getThreeRules = (response: any) => { scheduledTaskId: response.body.rules[i].scheduledTaskId, executionStatus: response.body.rules[i].executionStatus, monitoring: response.body.rules[i].monitoring, + revision: 0, ...(response.body.rules[i].nextRun ? { nextRun: response.body.rules[i].nextRun } : {}), ...(response.body.rules[i].lastRun ? { lastRun: response.body.rules[i].lastRun } : {}), }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_disable.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_disable.ts index ee2e6c27b58a4..86f468534318e 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_disable.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_disable.ts @@ -34,6 +34,7 @@ const getDefaultRules = (response: any) => ({ scheduledTaskId: response.body.rules[0].scheduledTaskId, executionStatus: response.body.rules[0].executionStatus, monitoring: response.body.rules[0].monitoring, + revision: 0, ...(response.body.rules[0].nextRun ? { nextRun: response.body.rules[0].nextRun } : {}), ...(response.body.rules[0].lastRun ? { lastRun: response.body.rules[0].lastRun } : {}), }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_enable.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_enable.ts index d16cfe0a77720..7469773cc5705 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_enable.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_enable.ts @@ -95,6 +95,7 @@ export default ({ getService }: FtrProviderContext) => { snoozeSchedule: [], updatedAt: response.body.rules[0].updatedAt, createdAt: response.body.rules[0].createdAt, + revision: 0, scheduledTaskId: response.body.rules[0].scheduledTaskId, executionStatus: { lastDuration: 0, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/clone.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/clone.ts index 8bb9d14572725..d9fc773d5d12a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/clone.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/clone.ts @@ -165,6 +165,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { mute_all: false, muted_alert_ids: [], execution_status: response.body.execution_status, + revision: 0, last_run: { alerts_count: { active: 0, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts index ccf6d89cc602e..fe71eca901745 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts @@ -81,6 +81,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { ], enabled: true, rule_type_id: 'test.noop', + revision: 0, running: false, consumer: 'alertsFixture', params: {}, @@ -184,6 +185,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { ], enabled: true, rule_type_id: 'test.noop', + revision: 0, running: false, consumer: 'alertsFixture', params: {}, @@ -503,6 +505,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, executionStatus: response.body.executionStatus, + revision: 0, running: false, ...(response.body.next_run ? { next_run: response.body.next_run } : {}), ...(response.body.last_run ? { last_run: response.body.last_run } : {}), diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/disable.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/disable.ts index 1ff7aab8f4ca6..c4620416f4bd6 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/disable.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/disable.ts @@ -63,6 +63,14 @@ export default function createDisableRuleTests({ getService }: FtrProviderContex expect(taskRecord.task.enabled).to.eql(false); }); + const { body: disabledRule } = await supertestWithoutAuth + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdRule.id}`) + .set('kbn-xsrf', 'foo') + .expect(200); + + // Ensure revision was not updated + expect(disabledRule.revision).to.eql(0); + // Ensure AAD isn't broken await checkAAD({ supertest: supertestWithoutAuth, @@ -173,6 +181,14 @@ export default function createDisableRuleTests({ getService }: FtrProviderContex }); await ruleUtils.disable(createdRule.id); + const { body: disabledRule } = await supertestWithoutAuth + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdRule.id}`) + .set('kbn-xsrf', 'foo') + .expect(200); + + // Ensure revision was not updated + expect(disabledRule.revision).to.eql(0); + // Ensure AAD isn't broken await checkAAD({ supertest: supertestWithoutAuth, @@ -209,6 +225,14 @@ export default function createDisableRuleTests({ getService }: FtrProviderContex expect(taskRecord.task.enabled).to.eql(false); }); + const { body: disabledRule } = await supertestWithoutAuth + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createdRule.id}`) + .set('kbn-xsrf', 'foo') + .expect(200); + + // Ensure revision was not updated + expect(disabledRule.revision).to.eql(0); + // Ensure AAD isn't broken await checkAAD({ supertest: supertestWithoutAuth, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/enable.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/enable.ts index f4ad874d3357e..b9538c786a496 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/enable.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/enable.ts @@ -61,6 +61,9 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex }); expect(taskRecord.task.enabled).to.eql(true); + // Ensure revision was not updated + expect(updatedAlert.revision).to.eql(0); + // Ensure AAD isn't broken await checkAAD({ supertest: supertestWithoutAuth, @@ -114,6 +117,9 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex }); expect(taskRecord.task.enabled).to.eql(true); + // Ensure revision was not updated + expect(updatedAlert.revision).to.eql(0); + // Ensure AAD isn't broken await checkAAD({ supertest: supertestWithoutAuth, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find.ts index d730c2819596c..2d85f6249db5e 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find.ts @@ -87,6 +87,7 @@ const findTestUtils = ( name: 'abc', tags: ['foo'], rule_type_id: 'test.noop', + revision: 0, running: false, consumer: 'alertsFixture', schedule: { interval: '1m' }, @@ -369,6 +370,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { createdAt: match.createdAt, updatedAt: match.updatedAt, executionStatus: match.executionStatus, + revision: 0, running: false, ...(match.nextRun ? { nextRun: match.nextRun } : {}), ...(match.lastRun ? { lastRun: match.lastRun } : {}), diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/get.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/get.ts index dd6b7b9327d27..43f93cccfe470 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/get.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/get.ts @@ -38,6 +38,7 @@ const getTestUtils = ( name: 'abc', tags: ['foo'], rule_type_id: 'test.noop', + revision: 0, running: false, consumer: 'alertsFixture', schedule: { interval: '1m' }, @@ -155,6 +156,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, executionStatus: response.body.executionStatus, + revision: 0, running: false, ...(response.body.nextRun ? { nextRun: response.body.nextRun } : {}), ...(response.body.lastRun ? { lastRun: response.body.lastRun } : {}), diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update.ts index 20239f94cfef3..d3ef53d5d4bd8 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update.ts @@ -60,6 +60,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { mute_all: false, muted_alert_ids: [], notify_when: 'onThrottleInterval', + revision: 1, scheduled_task_id: createdAlert.scheduled_task_id, created_at: response.body.created_at, updated_at: response.body.updated_at, @@ -169,6 +170,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, executionStatus: response.body.executionStatus, + revision: 1, running: false, ...(response.body.nextRun ? { nextRun: response.body.nextRun } : {}), ...(response.body.lastRun ? { lastRun: response.body.lastRun } : {}), diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update_api_key.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update_api_key.ts index a57d9dc90fd6d..bd3a12d9afdb6 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update_api_key.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update_api_key.ts @@ -46,6 +46,9 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte .expect(200); expect(updatedAlert.api_key_owner).to.eql(null); + // Ensure revision is not incremented when API key is updated + expect(updatedAlert.revision).to.eql(0); + // Ensure AAD isn't broken await checkAAD({ supertest: supertestWithoutAuth, @@ -92,6 +95,9 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte .expect(200); expect(updatedAlert.api_key_owner).to.eql(null); + // Ensure revision is not incremented when API key is updated + expect(updatedAlert.revision).to.eql(0); + // Ensure AAD isn't broken await checkAAD({ supertest: supertestWithoutAuth, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/bulk_edit.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/bulk_edit.ts index fa039cc3f0533..cfd8be8d5b181 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/bulk_edit.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/bulk_edit.ts @@ -76,6 +76,9 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(updatedRule.tags).to.eql(['default', 'tag-1']); + // Ensure revision is updated + expect(updatedRule.revision).to.eql(1); + // Ensure AAD isn't broken await checkAAD({ supertest, @@ -137,6 +140,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { updatedRules.forEach((rule) => { expect(rule.tags).to.eql([`rewritten`]); + expect(rule.revision).to.eql(1); }); }); @@ -174,6 +178,9 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(updatedRule.schedule).to.eql({ interval: '1h' }); + // Ensure revision is updated + expect(updatedRule.revision).to.eql(1); + // Ensure AAD isn't broken await checkAAD({ supertest, @@ -217,6 +224,9 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(updatedRule).property('throttle', '1h'); + // Ensure revision is updated + expect(updatedRule.revision).to.eql(1); + // Ensure AAD isn't broken await checkAAD({ supertest, @@ -260,6 +270,9 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(updatedRule).property('notify_when', 'onActionGroupChange'); + // Ensure revision is updated + expect(updatedRule.revision).to.eql(1); + // Ensure AAD isn't broken await checkAAD({ supertest, @@ -305,6 +318,9 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(bulkSnoozeResponse.body.rules[0].snooze_schedule.length).to.eql(1); expect(bulkSnoozeResponse.body.rules[0].snooze_schedule[0].duration).to.eql(28800000); + // Ensure revision is NOT updated + expect(bulkSnoozeResponse.body.rules[0].revision).to.eql(0); + const bulkUnsnoozeResponse = await supertest .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/_bulk_edit`) .set('kbn-xsrf', 'foo') @@ -378,6 +394,8 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(bulkSnoozeResponse.body.errors).to.have.length(0); expect(bulkSnoozeResponse.body.rules).to.have.length(1); expect(bulkSnoozeResponse.body.rules[0].snooze_schedule.length).to.eql(5); + // Ensure revision is NOT updated + expect(bulkSnoozeResponse.body.rules[0].revision).to.eql(0); // Try adding more than 5 schedules const bulkSnoozeError = await supertest @@ -433,6 +451,8 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(bulkSnoozeResponse.body.errors).to.have.length(0); expect(bulkSnoozeResponse.body.rules).to.have.length(1); expect(bulkSnoozeResponse.body.rules[0].snooze_schedule).empty(); + // Ensure revision is NOT updated + expect(bulkSnoozeResponse.body.rules[0].revision).to.eql(0); // Ensure AAD isn't broken await checkAAD({ @@ -473,6 +493,8 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(bulkApiKeyResponse.body.errors).to.have.length(0); expect(bulkApiKeyResponse.body.rules).to.have.length(1); expect(bulkApiKeyResponse.body.rules[0].api_key_owner).to.eql(null); + // Ensure revision is updated + expect(bulkApiKeyResponse.body.rules[0].revision).to.eql(1); }); it(`shouldn't bulk edit rule from another space`, async () => { diff --git a/x-pack/test/api_integration/apis/synthetics/enable_default_alerting.ts b/x-pack/test/api_integration/apis/synthetics/enable_default_alerting.ts index ad47a031f0628..b1e587eedb5ea 100644 --- a/x-pack/test/api_integration/apis/synthetics/enable_default_alerting.ts +++ b/x-pack/test/api_integration/apis/synthetics/enable_default_alerting.ts @@ -81,6 +81,7 @@ export default function ({ getService }: FtrProviderContext) { executionStatus: { status: 'pending', lastExecutionDate: '2022-12-20T09:10:15.500Z' }, ruleTypeId: 'xpack.synthetics.alerts.monitorStatus', running: false, + revision: 0, }, omitFields ) diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/create_rules.ts b/x-pack/test/detection_engine_api_integration/basic/tests/create_rules.ts index da25991d1d25b..62fa4d3786db6 100644 --- a/x-pack/test/detection_engine_api_integration/basic/tests/create_rules.ts +++ b/x-pack/test/detection_engine_api_integration/basic/tests/create_rules.ts @@ -102,6 +102,7 @@ export default ({ getService }: FtrProviderContext) => { throttle: 'no_actions', exceptions_list: [], version: 1, + revision: 0, }; const { body } = await supertest diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/import_rules.ts b/x-pack/test/detection_engine_api_integration/basic/tests/import_rules.ts index 774c0f8607058..5b8508ffe480d 100644 --- a/x-pack/test/detection_engine_api_integration/basic/tests/import_rules.ts +++ b/x-pack/test/detection_engine_api_integration/basic/tests/import_rules.ts @@ -361,6 +361,7 @@ export default ({ getService }: FtrProviderContext): void => { }; ruleOutput.name = 'some other name'; ruleOutput.version = 2; + ruleOutput.revision = 0; expect(bodyToCompare).to.eql(ruleOutput); }); diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/patch_rules.ts b/x-pack/test/detection_engine_api_integration/basic/tests/patch_rules.ts index 21de2d8e3e432..31dd7b0dbc99c 100644 --- a/x-pack/test/detection_engine_api_integration/basic/tests/patch_rules.ts +++ b/x-pack/test/detection_engine_api_integration/basic/tests/patch_rules.ts @@ -50,6 +50,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -86,6 +87,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutputWithoutRuleId(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedPropertiesIncludingRuleId(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -103,6 +105,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -138,6 +141,7 @@ export default ({ getService }: FtrProviderContext) => { outputRule.enabled = false; outputRule.severity = 'low'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); @@ -165,6 +169,7 @@ export default ({ getService }: FtrProviderContext) => { outputRule.timeline_title = 'some title'; outputRule.timeline_id = 'some id'; outputRule.version = 3; + outputRule.revision = 2; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/patch_rules_bulk.ts b/x-pack/test/detection_engine_api_integration/basic/tests/patch_rules_bulk.ts index 54fb2948e9c61..21715fb7901bb 100644 --- a/x-pack/test/detection_engine_api_integration/basic/tests/patch_rules_bulk.ts +++ b/x-pack/test/detection_engine_api_integration/basic/tests/patch_rules_bulk.ts @@ -50,6 +50,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); }); @@ -71,10 +72,12 @@ export default ({ getService }: FtrProviderContext) => { const outputRule1 = getSimpleRuleOutput(); outputRule1.name = 'some other name'; outputRule1.version = 2; + outputRule1.revision = 1; const outputRule2 = getSimpleRuleOutput('rule-2'); outputRule2.name = 'some other name'; outputRule2.version = 2; + outputRule2.revision = 1; const bodyToCompare1 = removeServerGeneratedProperties(body[0]); const bodyToCompare2 = removeServerGeneratedProperties(body[1]); @@ -95,6 +98,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); }); @@ -116,10 +120,12 @@ export default ({ getService }: FtrProviderContext) => { const outputRule1 = getSimpleRuleOutputWithoutRuleId('rule-1'); outputRule1.name = 'some other name'; outputRule1.version = 2; + outputRule1.revision = 1; const outputRule2 = getSimpleRuleOutputWithoutRuleId('rule-2'); outputRule2.name = 'some other name'; outputRule2.version = 2; + outputRule2.revision = 1; const bodyToCompare1 = removeServerGeneratedPropertiesIncludingRuleId(body[0]); const bodyToCompare2 = removeServerGeneratedPropertiesIncludingRuleId(body[1]); @@ -140,6 +146,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); }); @@ -175,6 +182,7 @@ export default ({ getService }: FtrProviderContext) => { outputRule.enabled = false; outputRule.severity = 'low'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); @@ -202,6 +210,7 @@ export default ({ getService }: FtrProviderContext) => { outputRule.timeline_title = 'some title'; outputRule.timeline_id = 'some id'; outputRule.version = 3; + outputRule.revision = 2; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); @@ -256,6 +265,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect([bodyToCompare, body[1]]).to.eql([ @@ -286,6 +296,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect([bodyToCompare, body[1]]).to.eql([ diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/update_rules.ts b/x-pack/test/detection_engine_api_integration/basic/tests/update_rules.ts index 0f9e7276b8798..4270e70d68f0e 100644 --- a/x-pack/test/detection_engine_api_integration/basic/tests/update_rules.ts +++ b/x-pack/test/detection_engine_api_integration/basic/tests/update_rules.ts @@ -57,6 +57,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -102,6 +103,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutputWithoutRuleId(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedPropertiesIncludingRuleId(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -124,6 +126,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -146,6 +149,7 @@ export default ({ getService }: FtrProviderContext) => { outputRule.enabled = false; outputRule.severity = 'low'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); @@ -178,6 +182,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 3; + outputRule.revision = 2; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/update_rules_bulk.ts b/x-pack/test/detection_engine_api_integration/basic/tests/update_rules_bulk.ts index 03a0fa5b3963a..0cc2cee2066bb 100644 --- a/x-pack/test/detection_engine_api_integration/basic/tests/update_rules_bulk.ts +++ b/x-pack/test/detection_engine_api_integration/basic/tests/update_rules_bulk.ts @@ -57,6 +57,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); }); @@ -87,10 +88,12 @@ export default ({ getService }: FtrProviderContext) => { const outputRule1 = getSimpleRuleOutput(); outputRule1.name = 'some other name'; outputRule1.version = 2; + outputRule1.revision = 1; const outputRule2 = getSimpleRuleOutput('rule-2'); outputRule2.name = 'some other name'; outputRule2.version = 2; + outputRule2.revision = 1; const bodyToCompare1 = removeServerGeneratedProperties(body[0]); const bodyToCompare2 = removeServerGeneratedProperties(body[1]); @@ -116,6 +119,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); }); @@ -144,10 +148,12 @@ export default ({ getService }: FtrProviderContext) => { const outputRule1 = getSimpleRuleOutputWithoutRuleId('rule-1'); outputRule1.name = 'some other name'; outputRule1.version = 2; + outputRule1.revision = 1; const outputRule2 = getSimpleRuleOutputWithoutRuleId('rule-2'); outputRule2.name = 'some other name'; outputRule2.version = 2; + outputRule2.revision = 1; const bodyToCompare1 = removeServerGeneratedPropertiesIncludingRuleId(body[0]); const bodyToCompare2 = removeServerGeneratedPropertiesIncludingRuleId(body[1]); @@ -173,6 +179,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); }); @@ -195,6 +202,7 @@ export default ({ getService }: FtrProviderContext) => { outputRule.enabled = false; outputRule.severity = 'low'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); @@ -227,6 +235,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 3; + outputRule.revision = 2; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); @@ -294,6 +303,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect([bodyToCompare, body[1]]).to.eql([ @@ -331,6 +341,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect([bodyToCompare, body[1]]).to.eql([ diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules.ts index 1975e8b5133e0..dbb8210cfd962 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules.ts @@ -192,6 +192,7 @@ export default ({ getService }: FtrProviderContext) => { references: [], related_integrations: [], required_fields: [], + revision: 0, setup: '', severity: 'high', severity_mapping: [], diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/export_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/export_rules.ts index 0946852e6a117..3340c700ed95a 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/export_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/export_rules.ts @@ -606,6 +606,7 @@ function expectToMatchRuleSchema(obj: unknown): void { false_positives: expect.arrayContaining([]), from: expect.any(String), max_signals: expect.any(Number), + revision: expect.any(Number), risk_score_mapping: expect.arrayContaining([]), severity_mapping: expect.arrayContaining([]), threat: expect.arrayContaining([]), diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/update_actions.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/update_actions.ts index 858ea3722b2de..61e25772c1d44 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/update_actions.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/update_actions.ts @@ -75,6 +75,7 @@ export default ({ getService }: FtrProviderContext) => { `${bodyToCompare.actions?.[0].id}`, `${bodyToCompare.actions?.[0].uuid}` ), + revision: 1, // version bump is required since this is an updated rule and this is part of the testing that we do bump the version number on update version: 2, // version bump is required since this is an updated rule and this is part of the testing that we do bump the version number on update }; expect(bodyToCompare).to.eql(expected); @@ -90,6 +91,7 @@ export default ({ getService }: FtrProviderContext) => { const bodyToCompare = removeServerGeneratedProperties(ruleAfterActionRemoved); const expected = { ...getSimpleRuleOutput(), + revision: 2, // version bump is required since this is an updated rule and this is part of the testing that we do bump the version number on update version: 3, // version bump is required since this is an updated rule and this is part of the testing that we do bump the version number on update }; expect(bodyToCompare).to.eql(expected); @@ -130,10 +132,10 @@ export default ({ getService }: FtrProviderContext) => { const updatedRule = await updateRule(supertest, log, ruleToUpdate); const expected = omit(removeServerGeneratedProperties(updatedRule), actionsProps); - const immutableRuleToAssert = omit( - removeServerGeneratedProperties(immutableRule), - actionsProps - ); + const immutableRuleToAssert = { + ...omit(removeServerGeneratedProperties(immutableRule), actionsProps), + revision: 1, // Unlike `version` which is static for immutable rules, `revision` will increment when an action/exception is added + }; expect(immutableRuleToAssert).to.eql(expected); expect(expected.immutable).to.be(true); // It should stay immutable true when returning diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_rules.ts index a15b6d799adea..849c2a9858aaf 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_rules.ts @@ -715,6 +715,7 @@ export default ({ getService }: FtrProviderContext): void => { }; ruleOutput.name = 'some other name'; ruleOutput.version = 2; + ruleOutput.revision = 0; expect(bodyToCompare).to.eql(ruleOutput); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules.ts index 71c778789a8c3..e8df71ca61a4c 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules.ts @@ -54,6 +54,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -70,6 +71,9 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleMlRuleOutput(); outputRule.version = 2; + // TODO: Followup to #147398 + // NOTE: Once we remove `version` increment, revision will not be updated as `machine_learning_job_id` value doesn't actually change + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -87,6 +91,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleMlRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -106,6 +111,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutputWithoutRuleId(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedPropertiesIncludingRuleId(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -123,6 +129,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -158,6 +165,7 @@ export default ({ getService }: FtrProviderContext) => { outputRule.enabled = false; outputRule.severity = 'low'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); @@ -185,6 +193,7 @@ export default ({ getService }: FtrProviderContext) => { outputRule.timeline_title = 'some title'; outputRule.timeline_id = 'some id'; outputRule.version = 3; + outputRule.revision = 2; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); @@ -374,7 +383,7 @@ export default ({ getService }: FtrProviderContext) => { }, ]; outputRule.throttle = '1h'; - + outputRule.revision = 2; // Expected revision is 2 as call to `createLegacyRuleAction()` does two separate rules updates for `notifyWhen` & `actions` field expect(bodyToCompare).to.eql(outputRule); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules_bulk.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules_bulk.ts index 03156e53e978b..48ea361536585 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules_bulk.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules_bulk.ts @@ -73,6 +73,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); }); @@ -94,10 +95,12 @@ export default ({ getService }: FtrProviderContext) => { const outputRule1 = getSimpleRuleOutput(); outputRule1.name = 'some other name'; outputRule1.version = 2; + outputRule1.revision = 1; const outputRule2 = getSimpleRuleOutput('rule-2'); outputRule2.name = 'some other name'; outputRule2.version = 2; + outputRule2.revision = 1; const bodyToCompare1 = removeServerGeneratedProperties(body[0]); const bodyToCompare2 = removeServerGeneratedProperties(body[1]); @@ -118,6 +121,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); }); @@ -139,10 +143,12 @@ export default ({ getService }: FtrProviderContext) => { const outputRule1 = getSimpleRuleOutputWithoutRuleId('rule-1'); outputRule1.name = 'some other name'; outputRule1.version = 2; + outputRule1.revision = 1; const outputRule2 = getSimpleRuleOutputWithoutRuleId('rule-2'); outputRule2.name = 'some other name'; outputRule2.version = 2; + outputRule2.revision = 1; const bodyToCompare1 = removeServerGeneratedPropertiesIncludingRuleId(body[0]); const bodyToCompare2 = removeServerGeneratedPropertiesIncludingRuleId(body[1]); @@ -196,6 +202,7 @@ export default ({ getService }: FtrProviderContext) => { }, ]; outputRule.throttle = '1h'; + outputRule.revision = 2; // Expected revision is 2 as call to `createLegacyRuleAction()` does two separate rules updates for `notifyWhen` & `actions` field expect(bodyToCompare).to.eql(outputRule); }); }); @@ -213,6 +220,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); }); @@ -248,6 +256,7 @@ export default ({ getService }: FtrProviderContext) => { outputRule.enabled = false; outputRule.severity = 'low'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); @@ -275,6 +284,7 @@ export default ({ getService }: FtrProviderContext) => { outputRule.timeline_title = 'some title'; outputRule.timeline_id = 'some id'; outputRule.version = 3; + outputRule.revision = 2; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); @@ -329,6 +339,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect([bodyToCompare, body[1]]).to.eql([ @@ -359,6 +370,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect([bodyToCompare, body[1]]).to.eql([ diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts index 9a454f8f4acd4..52f6613100e2a 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts @@ -63,6 +63,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -86,6 +87,7 @@ export default ({ getService }: FtrProviderContext) => { // @ts-expect-error type narrowing is lost due to Omit<> outputRule.machine_learning_job_id = ['legacy_job_id']; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -108,6 +110,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleMlRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -132,6 +135,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutputWithoutRuleId(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedPropertiesIncludingRuleId(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -181,6 +185,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutputWithoutRuleId(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; // Expect an empty array outputRule.actions = []; // Expect "no_actions" @@ -234,6 +239,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutputWithoutRuleId(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 2; // Migration of action results in additional revision increment (change to `notifyWhen`), so expected revision is 2 outputRule.actions = [ { action_type_id: '.slack', @@ -269,6 +275,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); }); @@ -291,6 +298,7 @@ export default ({ getService }: FtrProviderContext) => { outputRule.enabled = false; outputRule.severity = 'low'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); @@ -323,6 +331,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 3; + outputRule.revision = 2; const bodyToCompare = removeServerGeneratedProperties(body); expect(bodyToCompare).to.eql(outputRule); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts index 326a7a3693be8..2148b9b13d797 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts @@ -79,6 +79,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); }); @@ -109,10 +110,12 @@ export default ({ getService }: FtrProviderContext) => { const outputRule1 = getSimpleRuleOutput(); outputRule1.name = 'some other name'; outputRule1.version = 2; + outputRule1.revision = 1; const outputRule2 = getSimpleRuleOutput('rule-2'); outputRule2.name = 'some other name'; outputRule2.version = 2; + outputRule2.revision = 1; const bodyToCompare1 = removeServerGeneratedProperties(body[0]); const bodyToCompare2 = removeServerGeneratedProperties(body[1]); @@ -170,6 +173,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(response.rule_id); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 2; outputRule.actions = [ { action_type_id: '.slack', @@ -233,6 +237,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(response.rule_id); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 2; outputRule.actions = []; outputRule.throttle = 'no_actions'; const bodyToCompare = removeServerGeneratedProperties(response); @@ -258,6 +263,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); }); @@ -286,10 +292,12 @@ export default ({ getService }: FtrProviderContext) => { const outputRule1 = getSimpleRuleOutput('rule-1'); outputRule1.name = 'some other name'; outputRule1.version = 2; + outputRule1.revision = 1; const outputRule2 = getSimpleRuleOutput('rule-2'); outputRule2.name = 'some other name'; outputRule2.version = 2; + outputRule2.revision = 1; const bodyToCompare1 = removeServerGeneratedProperties(body[0]); const bodyToCompare2 = removeServerGeneratedProperties(body[1]); @@ -315,6 +323,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); }); @@ -337,6 +346,7 @@ export default ({ getService }: FtrProviderContext) => { outputRule.enabled = false; outputRule.severity = 'low'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); @@ -369,6 +379,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 3; + outputRule.revision = 2; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect(bodyToCompare).to.eql(outputRule); @@ -436,6 +447,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect([bodyToCompare, body[1]]).to.eql([ @@ -473,6 +485,7 @@ export default ({ getService }: FtrProviderContext) => { const outputRule = getSimpleRuleOutput(); outputRule.name = 'some other name'; outputRule.version = 2; + outputRule.revision = 1; const bodyToCompare = removeServerGeneratedProperties(body[0]); expect([bodyToCompare, body[1]]).to.eql([ diff --git a/x-pack/test/detection_engine_api_integration/utils/get_complex_rule_output.ts b/x-pack/test/detection_engine_api_integration/utils/get_complex_rule_output.ts index a8f5916c3598d..af66123014383 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_complex_rule_output.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_complex_rule_output.ts @@ -51,6 +51,7 @@ export const getComplexRuleOutput = (ruleId = 'rule-1'): Partial = tags: ['tag 1', 'tag 2', 'any tag you want'], to: 'now', from: 'now-6m', + revision: 0, severity: 'high', severity_mapping: [], language: 'kuery', diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_output.ts b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_output.ts index 39b8d2acf088e..9826d9a2b98b4 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_output.ts +++ b/x-pack/test/detection_engine_api_integration/utils/get_simple_rule_output.ts @@ -43,6 +43,7 @@ export const getMockSharedResponseSchema = ( throttle: 'no_actions', exceptions_list: [], version: 1, + revision: 0, id: 'id', updated_at: '2020-07-08T16:36:32.377Z', created_at: '2020-07-08T16:36:32.377Z', diff --git a/x-pack/test/detection_engine_api_integration/utils/rule_to_update_schema.ts b/x-pack/test/detection_engine_api_integration/utils/rule_to_update_schema.ts index 7c10c98c105d6..b4d2759ccf67d 100644 --- a/x-pack/test/detection_engine_api_integration/utils/rule_to_update_schema.ts +++ b/x-pack/test/detection_engine_api_integration/utils/rule_to_update_schema.ts @@ -20,6 +20,7 @@ const propertiesToRemove = [ 'created_by', 'related_integrations', 'required_fields', + 'revision', 'setup', 'execution_summary', ]; diff --git a/x-pack/test/functional/es_archives/security_solution/legacy_actions/data.json b/x-pack/test/functional/es_archives/security_solution/legacy_actions/data.json index f0c883c6b3756..8dbc0fbe883e8 100644 --- a/x-pack/test/functional/es_archives/security_solution/legacy_actions/data.json +++ b/x-pack/test/functional/es_archives/security_solution/legacy_actions/data.json @@ -74,6 +74,7 @@ ], "alertTypeId" : "siem.queryRule", "consumer" : "siem", + "revision": 0, "params" : { "author" : [ ], "description" : "a", @@ -168,6 +169,7 @@ ], "alertTypeId" : "siem.queryRule", "consumer" : "siem", + "revision": 0, "params" : { "author" : [ ], "description" : "a", @@ -281,6 +283,7 @@ ], "alertTypeId" : "siem.queryRule", "consumer" : "siem", + "revision": 0, "params" : { "author" : [ ], "description" : "a", @@ -375,6 +378,7 @@ ], "alertTypeId" : "siem.queryRule", "consumer" : "siem", + "revision": 0, "params" : { "author" : [ ], "description" : "a", @@ -469,6 +473,7 @@ ], "alertTypeId" : "siem.queryRule", "consumer" : "siem", + "revision": 0, "params" : { "author" : [ ], "description" : "a", @@ -561,6 +566,7 @@ ], "alertTypeId" : "siem.notifications", "consumer" : "siem", + "revision": 0, "params" : { "ruleAlertId" : "61ec7a40-b076-11ec-bb3f-1f063f8e06cf" }, @@ -641,6 +647,7 @@ ], "alertTypeId" : "siem.notifications", "consumer" : "siem", + "revision": 0, "params" : { "ruleAlertId" : "064e3160-b076-11ec-bb3f-1f063f8e06cf" }, @@ -733,6 +740,7 @@ ], "alertTypeId" : "siem.notifications", "consumer" : "siem", + "revision": 0, "params" : { "ruleAlertId" : "27639570-b076-11ec-bb3f-1f063f8e06cf" },