From 7824d32dc9e3c77716cc41b7537b610ff3302ca4 Mon Sep 17 00:00:00 2001 From: Patrick Mueller Date: Tue, 22 Jun 2021 15:18:35 -0400 Subject: [PATCH] [actions] add rule saved object reference to action execution event log doc (#101526) resolves https://github.com/elastic/kibana/issues/99225 Prior to this PR, when an alerting connection action was executed, the event log document generated did not contain a reference to the originating rule. This makes it difficult to diagnose problems with connector errors, since the error is often in the parameters specified in the actions in the alert. In this PR, a reference to the alerting rule is added to the saved_objects field in the event document for these events. --- .../actions/server/actions_client.test.ts | 64 ++++++++++++++ .../plugins/actions/server/actions_client.ts | 9 +- .../server/create_execute_function.test.ts | 56 ++++++++++++ .../actions/server/create_execute_function.ts | 5 +- .../actions/server/lib/action_executor.ts | 13 +++ .../server/lib/related_saved_objects.test.ts | 86 +++++++++++++++++++ .../server/lib/related_saved_objects.ts | 31 +++++++ .../server/lib/task_runner_factory.test.ts | 76 ++++++++++++++++ .../actions/server/lib/task_runner_factory.ts | 4 +- .../actions/server/routes/execute.test.ts | 2 + .../plugins/actions/server/routes/execute.ts | 1 + .../server/routes/legacy/execute.test.ts | 2 + .../actions/server/routes/legacy/execute.ts | 1 + .../server/saved_objects/mappings.json | 4 + .../create_execution_handler.test.ts | 32 +++++++ .../task_runner/create_execution_handler.ts | 12 ++- .../server/task_runner/task_runner.test.ts | 32 +++++++ x-pack/plugins/event_log/README.md | 29 ++++--- 18 files changed, 442 insertions(+), 17 deletions(-) create mode 100644 x-pack/plugins/actions/server/lib/related_saved_objects.test.ts create mode 100644 x-pack/plugins/actions/server/lib/related_saved_objects.ts diff --git a/x-pack/plugins/actions/server/actions_client.test.ts b/x-pack/plugins/actions/server/actions_client.test.ts index 3b91b07eb30f4e..16388b2faf52e1 100644 --- a/x-pack/plugins/actions/server/actions_client.test.ts +++ b/x-pack/plugins/actions/server/actions_client.test.ts @@ -1676,6 +1676,70 @@ describe('execute()', () => { name: 'my name', }, }); + + await expect( + actionsClient.execute({ + actionId, + params: { + name: 'my name', + }, + relatedSavedObjects: [ + { + id: 'some-id', + typeId: 'some-type-id', + type: 'some-type', + }, + ], + }) + ).resolves.toMatchObject({ status: 'ok', actionId }); + + expect(actionExecutor.execute).toHaveBeenCalledWith({ + actionId, + request, + params: { + name: 'my name', + }, + relatedSavedObjects: [ + { + id: 'some-id', + typeId: 'some-type-id', + type: 'some-type', + }, + ], + }); + + await expect( + actionsClient.execute({ + actionId, + params: { + name: 'my name', + }, + relatedSavedObjects: [ + { + id: 'some-id', + typeId: 'some-type-id', + type: 'some-type', + namespace: 'some-namespace', + }, + ], + }) + ).resolves.toMatchObject({ status: 'ok', actionId }); + + expect(actionExecutor.execute).toHaveBeenCalledWith({ + actionId, + request, + params: { + name: 'my name', + }, + relatedSavedObjects: [ + { + id: 'some-id', + typeId: 'some-type-id', + type: 'some-type', + namespace: 'some-namespace', + }, + ], + }); }); }); diff --git a/x-pack/plugins/actions/server/actions_client.ts b/x-pack/plugins/actions/server/actions_client.ts index 449d218ed5ae04..f8d13cdafa7557 100644 --- a/x-pack/plugins/actions/server/actions_client.ts +++ b/x-pack/plugins/actions/server/actions_client.ts @@ -469,6 +469,7 @@ export class ActionsClient { actionId, params, source, + relatedSavedObjects, }: Omit): Promise> { if ( (await getAuthorizationModeBySource(this.unsecuredSavedObjectsClient, source)) === @@ -476,7 +477,13 @@ export class ActionsClient { ) { await this.authorization.ensureAuthorized('execute'); } - return this.actionExecutor.execute({ actionId, params, source, request: this.request }); + return this.actionExecutor.execute({ + actionId, + params, + source, + request: this.request, + relatedSavedObjects, + }); } public async enqueueExecution(options: EnqueueExecutionOptions): Promise { diff --git a/x-pack/plugins/actions/server/create_execute_function.test.ts b/x-pack/plugins/actions/server/create_execute_function.test.ts index 4cacba6dc880ab..ee8064d2aadc53 100644 --- a/x-pack/plugins/actions/server/create_execute_function.test.ts +++ b/x-pack/plugins/actions/server/create_execute_function.test.ts @@ -83,6 +83,62 @@ describe('execute()', () => { }); }); + test('schedules the action with all given parameters and relatedSavedObjects', async () => { + const actionTypeRegistry = actionTypeRegistryMock.create(); + const executeFn = createExecutionEnqueuerFunction({ + taskManager: mockTaskManager, + actionTypeRegistry, + isESOCanEncrypt: true, + preconfiguredActions: [], + }); + savedObjectsClient.get.mockResolvedValueOnce({ + id: '123', + type: 'action', + attributes: { + actionTypeId: 'mock-action', + }, + references: [], + }); + savedObjectsClient.create.mockResolvedValueOnce({ + id: '234', + type: 'action_task_params', + attributes: {}, + references: [], + }); + await executeFn(savedObjectsClient, { + id: '123', + params: { baz: false }, + spaceId: 'default', + apiKey: Buffer.from('123:abc').toString('base64'), + source: asHttpRequestExecutionSource(request), + relatedSavedObjects: [ + { + id: 'some-id', + namespace: 'some-namespace', + type: 'some-type', + typeId: 'some-typeId', + }, + ], + }); + expect(savedObjectsClient.create).toHaveBeenCalledWith( + 'action_task_params', + { + actionId: '123', + params: { baz: false }, + apiKey: Buffer.from('123:abc').toString('base64'), + relatedSavedObjects: [ + { + id: 'some-id', + namespace: 'some-namespace', + type: 'some-type', + typeId: 'some-typeId', + }, + ], + }, + {} + ); + }); + test('schedules the action with all given parameters with a preconfigured action', async () => { const executeFn = createExecutionEnqueuerFunction({ taskManager: mockTaskManager, diff --git a/x-pack/plugins/actions/server/create_execute_function.ts b/x-pack/plugins/actions/server/create_execute_function.ts index 4f3ffbef36c6e2..7dcd66c711bdde 100644 --- a/x-pack/plugins/actions/server/create_execute_function.ts +++ b/x-pack/plugins/actions/server/create_execute_function.ts @@ -11,6 +11,7 @@ import { RawAction, ActionTypeRegistryContract, PreConfiguredAction } from './ty import { ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE } from './constants/saved_objects'; import { ExecuteOptions as ActionExecutorOptions } from './lib/action_executor'; import { isSavedObjectExecutionSource } from './lib'; +import { RelatedSavedObjects } from './lib/related_saved_objects'; interface CreateExecuteFunctionOptions { taskManager: TaskManagerStartContract; @@ -23,6 +24,7 @@ export interface ExecuteOptions extends Pick { request: KibanaRequest; params: Record; source?: ActionExecutionSource; + relatedSavedObjects?: RelatedSavedObjects; } export type ActionExecutorContract = PublicMethodsOf; @@ -68,6 +70,7 @@ export class ActionExecutor { params, request, source, + relatedSavedObjects, }: ExecuteOptions): Promise> { if (!this.isInitialized) { throw new Error('ActionExecutor not initialized'); @@ -154,6 +157,16 @@ export class ActionExecutor { }, }; + for (const relatedSavedObject of relatedSavedObjects || []) { + event.kibana?.saved_objects?.push({ + rel: SAVED_OBJECT_REL_PRIMARY, + type: relatedSavedObject.type, + id: relatedSavedObject.id, + type_id: relatedSavedObject.typeId, + namespace: relatedSavedObject.namespace, + }); + } + eventLogger.startTiming(event); let rawResult: ActionTypeExecutorResult; try { diff --git a/x-pack/plugins/actions/server/lib/related_saved_objects.test.ts b/x-pack/plugins/actions/server/lib/related_saved_objects.test.ts new file mode 100644 index 00000000000000..8fd13d13756977 --- /dev/null +++ b/x-pack/plugins/actions/server/lib/related_saved_objects.test.ts @@ -0,0 +1,86 @@ +/* + * 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 { validatedRelatedSavedObjects } from './related_saved_objects'; +import { loggingSystemMock } from '../../../../../src/core/server/mocks'; +import { Logger } from '../../../../../src/core/server'; + +const loggerMock = loggingSystemMock.createLogger(); + +describe('related_saved_objects', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('validates valid objects', () => { + ensureValid(loggerMock, undefined); + ensureValid(loggerMock, []); + ensureValid(loggerMock, [ + { + id: 'some-id', + type: 'some-type', + }, + ]); + ensureValid(loggerMock, [ + { + id: 'some-id', + type: 'some-type', + typeId: 'some-type-id', + }, + ]); + ensureValid(loggerMock, [ + { + id: 'some-id', + type: 'some-type', + namespace: 'some-namespace', + }, + ]); + ensureValid(loggerMock, [ + { + id: 'some-id', + type: 'some-type', + typeId: 'some-type-id', + namespace: 'some-namespace', + }, + ]); + ensureValid(loggerMock, [ + { + id: 'some-id', + type: 'some-type', + }, + { + id: 'some-id-2', + type: 'some-type-2', + }, + ]); + }); +}); + +it('handles invalid objects', () => { + ensureInvalid(loggerMock, 42); + ensureInvalid(loggerMock, {}); + ensureInvalid(loggerMock, [{}]); + ensureInvalid(loggerMock, [{ id: 'some-id' }]); + ensureInvalid(loggerMock, [{ id: 42 }]); + ensureInvalid(loggerMock, [{ id: 'some-id', type: 'some-type', x: 42 }]); +}); + +function ensureValid(logger: Logger, savedObjects: unknown) { + const result = validatedRelatedSavedObjects(logger, savedObjects); + expect(result).toEqual(savedObjects === undefined ? [] : savedObjects); + expect(loggerMock.warn).not.toHaveBeenCalled(); +} + +function ensureInvalid(logger: Logger, savedObjects: unknown) { + const result = validatedRelatedSavedObjects(logger, savedObjects); + expect(result).toEqual([]); + + const message = loggerMock.warn.mock.calls[0][0]; + expect(message).toMatch( + /ignoring invalid related saved objects: expected value of type \[array\] but got/ + ); +} diff --git a/x-pack/plugins/actions/server/lib/related_saved_objects.ts b/x-pack/plugins/actions/server/lib/related_saved_objects.ts new file mode 100644 index 00000000000000..160587a3a9a8be --- /dev/null +++ b/x-pack/plugins/actions/server/lib/related_saved_objects.ts @@ -0,0 +1,31 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import { Logger } from '../../../../../src/core/server'; + +export type RelatedSavedObjects = TypeOf; + +const RelatedSavedObjectsSchema = schema.arrayOf( + schema.object({ + namespace: schema.maybe(schema.string({ minLength: 1 })), + id: schema.string({ minLength: 1 }), + type: schema.string({ minLength: 1 }), + // optional; for SO types like action/alert that have type id's + typeId: schema.maybe(schema.string({ minLength: 1 })), + }), + { defaultValue: [] } +); + +export function validatedRelatedSavedObjects(logger: Logger, data: unknown): RelatedSavedObjects { + try { + return RelatedSavedObjectsSchema.validate(data); + } catch (err) { + logger.warn(`ignoring invalid related saved objects: ${err.message}`); + return []; + } +} diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts index 229324c1f0df38..2292994e3ccfde 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts @@ -126,6 +126,7 @@ test('executes the task by calling the executor with proper parameters', async ( expect(mockedActionExecutor.execute).toHaveBeenCalledWith({ actionId: '2', params: { baz: true }, + relatedSavedObjects: [], request: expect.objectContaining({ headers: { // base64 encoded "123:abc" @@ -247,6 +248,7 @@ test('uses API key when provided', async () => { expect(mockedActionExecutor.execute).toHaveBeenCalledWith({ actionId: '2', params: { baz: true }, + relatedSavedObjects: [], request: expect.objectContaining({ headers: { // base64 encoded "123:abc" @@ -262,6 +264,79 @@ test('uses API key when provided', async () => { ); }); +test('uses relatedSavedObjects when provided', async () => { + const taskRunner = taskRunnerFactory.create({ + taskInstance: mockedTaskInstance, + }); + + mockedActionExecutor.execute.mockResolvedValueOnce({ status: 'ok', actionId: '2' }); + spaceIdToNamespace.mockReturnValueOnce('namespace-test'); + mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({ + id: '3', + type: 'action_task_params', + attributes: { + actionId: '2', + params: { baz: true }, + apiKey: Buffer.from('123:abc').toString('base64'), + relatedSavedObjects: [{ id: 'some-id', type: 'some-type' }], + }, + references: [], + }); + + await taskRunner.run(); + + expect(mockedActionExecutor.execute).toHaveBeenCalledWith({ + actionId: '2', + params: { baz: true }, + relatedSavedObjects: [ + { + id: 'some-id', + type: 'some-type', + }, + ], + request: expect.objectContaining({ + headers: { + // base64 encoded "123:abc" + authorization: 'ApiKey MTIzOmFiYw==', + }, + }), + }); +}); + +test('sanitizes invalid relatedSavedObjects when provided', async () => { + const taskRunner = taskRunnerFactory.create({ + taskInstance: mockedTaskInstance, + }); + + mockedActionExecutor.execute.mockResolvedValueOnce({ status: 'ok', actionId: '2' }); + spaceIdToNamespace.mockReturnValueOnce('namespace-test'); + mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({ + id: '3', + type: 'action_task_params', + attributes: { + actionId: '2', + params: { baz: true }, + apiKey: Buffer.from('123:abc').toString('base64'), + relatedSavedObjects: [{ Xid: 'some-id', type: 'some-type' }], + }, + references: [], + }); + + await taskRunner.run(); + + expect(mockedActionExecutor.execute).toHaveBeenCalledWith({ + actionId: '2', + params: { baz: true }, + relatedSavedObjects: [], + request: expect.objectContaining({ + headers: { + // base64 encoded "123:abc" + authorization: 'ApiKey MTIzOmFiYw==', + }, + }), + }); +}); + test(`doesn't use API key when not provided`, async () => { const factory = new TaskRunnerFactory(mockedActionExecutor); factory.initialize(taskRunnerFactoryInitializerParams); @@ -284,6 +359,7 @@ test(`doesn't use API key when not provided`, async () => { expect(mockedActionExecutor.execute).toHaveBeenCalledWith({ actionId: '2', params: { baz: true }, + relatedSavedObjects: [], request: expect.objectContaining({ headers: {}, }), diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.ts index cf4b1576f27786..0515963ab82f4e 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.ts @@ -30,6 +30,7 @@ import { } from '../types'; import { ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE } from '../constants/saved_objects'; import { asSavedObjectExecutionSource } from './action_execution_source'; +import { validatedRelatedSavedObjects } from './related_saved_objects'; export interface TaskRunnerContext { logger: Logger; @@ -77,7 +78,7 @@ export class TaskRunnerFactory { const namespace = spaceIdToNamespace(spaceId); const { - attributes: { actionId, params, apiKey }, + attributes: { actionId, params, apiKey, relatedSavedObjects }, references, } = await encryptedSavedObjectsClient.getDecryptedAsInternalUser( ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, @@ -117,6 +118,7 @@ export class TaskRunnerFactory { actionId, request: fakeRequest, ...getSourceFromReferences(references), + relatedSavedObjects: validatedRelatedSavedObjects(logger, relatedSavedObjects), }); } catch (e) { if (e instanceof ActionTypeDisabledError) { diff --git a/x-pack/plugins/actions/server/routes/execute.test.ts b/x-pack/plugins/actions/server/routes/execute.test.ts index 4b12bf3111c1f5..54e10698e5af96 100644 --- a/x-pack/plugins/actions/server/routes/execute.test.ts +++ b/x-pack/plugins/actions/server/routes/execute.test.ts @@ -65,6 +65,7 @@ describe('executeActionRoute', () => { someData: 'data', }, source: asHttpRequestExecutionSource(req), + relatedSavedObjects: [], }); expect(res.ok).toHaveBeenCalled(); @@ -101,6 +102,7 @@ describe('executeActionRoute', () => { expect(actionsClient.execute).toHaveBeenCalledWith({ actionId: '1', params: {}, + relatedSavedObjects: [], source: asHttpRequestExecutionSource(req), }); diff --git a/x-pack/plugins/actions/server/routes/execute.ts b/x-pack/plugins/actions/server/routes/execute.ts index 377fe1215b3fb0..7e8110365e87a2 100644 --- a/x-pack/plugins/actions/server/routes/execute.ts +++ b/x-pack/plugins/actions/server/routes/execute.ts @@ -53,6 +53,7 @@ export const executeActionRoute = ( params, actionId: id, source: asHttpRequestExecutionSource(req), + relatedSavedObjects: [], }); return body ? res.ok({ diff --git a/x-pack/plugins/actions/server/routes/legacy/execute.test.ts b/x-pack/plugins/actions/server/routes/legacy/execute.test.ts index 2ac53ddaaedf64..05b71819911a3d 100644 --- a/x-pack/plugins/actions/server/routes/legacy/execute.test.ts +++ b/x-pack/plugins/actions/server/routes/legacy/execute.test.ts @@ -63,6 +63,7 @@ describe('executeActionRoute', () => { someData: 'data', }, source: asHttpRequestExecutionSource(req), + relatedSavedObjects: [], }); expect(res.ok).toHaveBeenCalled(); @@ -100,6 +101,7 @@ describe('executeActionRoute', () => { actionId: '1', params: {}, source: asHttpRequestExecutionSource(req), + relatedSavedObjects: [], }); expect(res.ok).not.toHaveBeenCalled(); diff --git a/x-pack/plugins/actions/server/routes/legacy/execute.ts b/x-pack/plugins/actions/server/routes/legacy/execute.ts index f6ddec1d01c200..d7ed8d2e156041 100644 --- a/x-pack/plugins/actions/server/routes/legacy/execute.ts +++ b/x-pack/plugins/actions/server/routes/legacy/execute.ts @@ -48,6 +48,7 @@ export const executeActionRoute = ( params, actionId: id, source: asHttpRequestExecutionSource(req), + relatedSavedObjects: [], }); return body ? res.ok({ diff --git a/x-pack/plugins/actions/server/saved_objects/mappings.json b/x-pack/plugins/actions/server/saved_objects/mappings.json index c598b96ba24513..57f801ae9a0758 100644 --- a/x-pack/plugins/actions/server/saved_objects/mappings.json +++ b/x-pack/plugins/actions/server/saved_objects/mappings.json @@ -35,6 +35,10 @@ }, "apiKey": { "type": "binary" + }, + "relatedSavedObjects": { + "enabled": false, + "type": "object" } } } diff --git a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts index 25f0656163f5d3..033ffcceb6a0ae 100644 --- a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts @@ -135,6 +135,14 @@ test('enqueues execution per selected action', async () => { "foo": true, "stateVal": "My goes here", }, + "relatedSavedObjects": Array [ + Object { + "id": "1", + "namespace": "test1", + "type": "alert", + "typeId": "test", + }, + ], "source": Object { "source": Object { "id": "1", @@ -247,6 +255,14 @@ test(`doesn't call actionsPlugin.execute for disabled actionTypes`, async () => id: '1', type: 'alert', }), + relatedSavedObjects: [ + { + id: '1', + namespace: 'test1', + type: 'alert', + typeId: 'test', + }, + ], spaceId: 'test1', apiKey: createExecutionHandlerParams.apiKey, }); @@ -327,6 +343,14 @@ test('context attribute gets parameterized', async () => { "foo": true, "stateVal": "My goes here", }, + "relatedSavedObjects": Array [ + Object { + "id": "1", + "namespace": "test1", + "type": "alert", + "typeId": "test", + }, + ], "source": Object { "source": Object { "id": "1", @@ -360,6 +384,14 @@ test('state attribute gets parameterized', async () => { "foo": true, "stateVal": "My state-val goes here", }, + "relatedSavedObjects": Array [ + Object { + "id": "1", + "namespace": "test1", + "type": "alert", + "typeId": "test", + }, + ], "source": Object { "source": Object { "id": "1", diff --git a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts index c3a36297c217ac..968fff540dc030 100644 --- a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts +++ b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts @@ -157,6 +157,8 @@ export function createExecutionHandler< continue; } + const namespace = spaceId === 'default' ? {} : { namespace: spaceId }; + // TODO would be nice to add the action name here, but it's not available const actionLabel = `${action.actionTypeId}:${action.id}`; const actionsClient = await actionsPlugin.getActionsClientWithRequest(request); @@ -169,10 +171,16 @@ export function createExecutionHandler< id: alertId, type: 'alert', }), + relatedSavedObjects: [ + { + id: alertId, + type: 'alert', + namespace: namespace.namespace, + typeId: alertType.id, + }, + ], }); - const namespace = spaceId === 'default' ? {} : { namespace: spaceId }; - const event: IEvent = { event: { action: EVENT_LOG_ACTIONS.executeAction, diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index 39a45584631d23..8ab267a5610d3b 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -352,6 +352,14 @@ describe('Task Runner', () => { "params": Object { "foo": true, }, + "relatedSavedObjects": Array [ + Object { + "id": "1", + "namespace": undefined, + "type": "alert", + "typeId": "test", + }, + ], "source": Object { "source": Object { "id": "1", @@ -1098,6 +1106,14 @@ describe('Task Runner', () => { "params": Object { "foo": true, }, + "relatedSavedObjects": Array [ + Object { + "id": "1", + "namespace": undefined, + "type": "alert", + "typeId": "test", + }, + ], "source": Object { "source": Object { "id": "1", @@ -1634,6 +1650,14 @@ describe('Task Runner', () => { "params": Object { "isResolved": true, }, + "relatedSavedObjects": Array [ + Object { + "id": "1", + "namespace": undefined, + "type": "alert", + "typeId": "test", + }, + ], "source": Object { "source": Object { "id": "1", @@ -1826,6 +1850,14 @@ describe('Task Runner', () => { "params": Object { "isResolved": true, }, + "relatedSavedObjects": Array [ + Object { + "id": "1", + "namespace": undefined, + "type": "alert", + "typeId": "test", + }, + ], "source": Object { "source": Object { "id": "1", diff --git a/x-pack/plugins/event_log/README.md b/x-pack/plugins/event_log/README.md index 032f77543acb97..ffbd20dd6f2bec 100644 --- a/x-pack/plugins/event_log/README.md +++ b/x-pack/plugins/event_log/README.md @@ -131,7 +131,7 @@ Below is a document in the expected structure, with descriptions of the fields: instance_id: "alert instance id, for relevant documents", action_group_id: "alert action group, for relevant documents", action_subgroup: "alert action subgroup, for relevant documents", - status: "overall alert status, after alert execution", + status: "overall alert status, after rule execution", }, saved_objects: [ { @@ -160,21 +160,26 @@ plugins: - `action: execute-via-http` - generated when an action is executed via HTTP request - `provider: alerting` - - `action: execute` - generated when an alert executor runs - - `action: execute-action` - generated when an alert schedules an action to run - - `action: new-instance` - generated when an alert has a new instance id that is active - - `action: recovered-instance` - generated when an alert has a previously active instance id that is no longer active - - `action: active-instance` - generated when an alert determines an instance id is active + - `action: execute` - generated when a rule executor runs + - `action: execute-action` - generated when a rule schedules an action to run + - `action: new-instance` - generated when a rule has a new instance id that is active + - `action: recovered-instance` - generated when a rule has a previously active instance id that is no longer active + - `action: active-instance` - generated when a rule determines an instance id is active For the `saved_objects` array elements, these are references to saved objects -associated with the event. For the `alerting` provider, those are alert saved -ojects and for the `actions` provider those are action saved objects. The -`alerts:execute-action` event includes both the alert and action saved object -references. For that event, only the alert reference has the optional `rel` +associated with the event. For the `alerting` provider, those are rule saved +ojects and for the `actions` provider those are connector saved objects. The +`alerts:execute-action` event includes both the rule and connector saved object +references. For that event, only the rule reference has the optional `rel` property with a `primary` value. This property is used when searching the event log to indicate which saved objects should be directly searchable via -saved object references. For the `alerts:execute-action` event, searching -only via the alert saved object reference will return the event. +saved object references. For the `alerts:execute-action` event, only searching +via the rule saved object reference will return the event; searching via the +connector save object reference will **NOT** return the event. The +`actions:execute` event also includes both the rule and connector saved object +references, and both of them have the `rel` property with a `primary` value, +allowing those events to be returned in searches of either the rule or +connector. ## Event Log index - associated resources