diff --git a/docs/user/troubleshooting/trace-query.asciidoc b/docs/user/troubleshooting/trace-query.asciidoc index 70c7853d3a3f3..f037b26ade630 100644 --- a/docs/user/troubleshooting/trace-query.asciidoc +++ b/docs/user/troubleshooting/trace-query.asciidoc @@ -3,7 +3,7 @@ Sometimes the {es} server might be slowed down by the execution of an expensive query. Such queries are logged to {es}'s {ref}/index-modules-slowlog.html#search-slow-log[search slow log] file. But there is a problem: it's impossible to say what triggered a slow search request—a {kib} instance or a user accessing an {es} endpoint directly. To simplify the investigation of such cases, the search slow log file includes the `x-opaque-id` header, which might provide additional information about a request if it originated from {kib}. -WARNING: At the moment, {kib} can only highlight cases where a slow query originated from a {kib} visualization, *Lens*, *Discover*, or *Alerting*. +WARNING: At the moment, {kib} can only highlight cases where a slow query originated from a {kib} visualization, *Lens*, *Discover*, *Maps*, or *Alerting*. For example, if a request to {es} was initiated by a Vega visualization on a dashboard, you will see the following in the slow logs: [source,json] diff --git a/test/common/fixtures/plugins/newsfeed/server/index.ts b/test/common/fixtures/plugins/newsfeed/server/index.ts index 17ac12bcd7284..8077c979014d9 100644 --- a/test/common/fixtures/plugins/newsfeed/server/index.ts +++ b/test/common/fixtures/plugins/newsfeed/server/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { PluginInitializerContext } from 'kibana/public'; +import type { PluginInitializerContext } from 'kibana/server'; import { NewsFeedSimulatorPlugin } from './plugin'; export function plugin(initializerContext: PluginInitializerContext) { diff --git a/test/common/fixtures/plugins/newsfeed/server/plugin.ts b/test/common/fixtures/plugins/newsfeed/server/plugin.ts index 49ffa464efac9..a592a832532ce 100644 --- a/test/common/fixtures/plugins/newsfeed/server/plugin.ts +++ b/test/common/fixtures/plugins/newsfeed/server/plugin.ts @@ -6,8 +6,7 @@ * Side Public License, v 1. */ -import { CoreSetup, Plugin } from 'kibana/server'; -import { PluginInitializerContext } from 'kibana/public'; +import type { CoreSetup, Plugin, PluginInitializerContext } from 'kibana/server'; export class NewsFeedSimulatorPlugin implements Plugin { constructor(private readonly initializerContext: PluginInitializerContext) {} diff --git a/x-pack/plugins/actions/server/actions_client.test.ts b/x-pack/plugins/actions/server/actions_client.test.ts index 868b8be7a041c..3565a978b5f07 100644 --- a/x-pack/plugins/actions/server/actions_client.test.ts +++ b/x-pack/plugins/actions/server/actions_client.test.ts @@ -1888,6 +1888,7 @@ describe('enqueueExecution()', () => { id: uuid.v4(), params: {}, spaceId: 'default', + executionId: '123abc', apiKey: null, }); expect(authorization.ensureAuthorized).toHaveBeenCalledWith('execute'); @@ -1906,6 +1907,7 @@ describe('enqueueExecution()', () => { id: uuid.v4(), params: {}, spaceId: 'default', + executionId: '123abc', apiKey: null, }) ).rejects.toMatchInlineSnapshot(`[Error: Unauthorized to execute all actions]`); @@ -1922,6 +1924,7 @@ describe('enqueueExecution()', () => { id: uuid.v4(), params: {}, spaceId: 'default', + executionId: '123abc', apiKey: null, }); @@ -1937,6 +1940,7 @@ describe('enqueueExecution()', () => { id: uuid.v4(), params: { baz: false }, spaceId: 'default', + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }; await expect(actionsClient.enqueueExecution(opts)).resolves.toMatchInlineSnapshot(`undefined`); 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 f31916458e59c..916dd9ed02b9f 100644 --- a/x-pack/plugins/actions/server/create_execute_function.test.ts +++ b/x-pack/plugins/actions/server/create_execute_function.test.ts @@ -49,6 +49,7 @@ describe('execute()', () => { id: '123', params: { baz: false }, spaceId: 'default', + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), source: asHttpRequestExecutionSource(request), }); @@ -74,6 +75,7 @@ describe('execute()', () => { { actionId: '123', params: { baz: false }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }, { @@ -119,6 +121,7 @@ describe('execute()', () => { spaceId: 'default', apiKey: Buffer.from('123:abc').toString('base64'), source: asHttpRequestExecutionSource(request), + executionId: '123abc', relatedSavedObjects: [ { id: 'some-id', @@ -134,6 +137,7 @@ describe('execute()', () => { actionId: '123', params: { baz: false }, apiKey: Buffer.from('123:abc').toString('base64'), + executionId: '123abc', relatedSavedObjects: [ { id: 'related_some-type_0', @@ -196,6 +200,7 @@ describe('execute()', () => { id: '123', params: { baz: false }, spaceId: 'default', + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), source: asSavedObjectExecutionSource(source), }); @@ -221,6 +226,7 @@ describe('execute()', () => { { actionId: '123', params: { baz: false }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }, { @@ -273,6 +279,7 @@ describe('execute()', () => { spaceId: 'default', apiKey: Buffer.from('123:abc').toString('base64'), source: asSavedObjectExecutionSource(source), + executionId: '123abc', relatedSavedObjects: [ { id: 'some-id', @@ -305,6 +312,7 @@ describe('execute()', () => { actionId: '123', params: { baz: false }, apiKey: Buffer.from('123:abc').toString('base64'), + executionId: '123abc', relatedSavedObjects: [ { id: 'related_some-type_0', @@ -343,6 +351,7 @@ describe('execute()', () => { id: '123', params: { baz: false }, spaceId: 'default', + executionId: '123abc', apiKey: null, }) ).rejects.toThrowErrorMatchingInlineSnapshot( @@ -372,6 +381,7 @@ describe('execute()', () => { id: '123', params: { baz: false }, spaceId: 'default', + executionId: '123abc', apiKey: null, }) ).rejects.toThrowErrorMatchingInlineSnapshot( @@ -404,6 +414,7 @@ describe('execute()', () => { id: '123', params: { baz: false }, spaceId: 'default', + executionId: '123abc', apiKey: null, }) ).rejects.toThrowErrorMatchingInlineSnapshot(`"Fail"`); @@ -446,6 +457,7 @@ describe('execute()', () => { id: '123', params: { baz: false }, spaceId: 'default', + executionId: '123abc', apiKey: null, }); diff --git a/x-pack/plugins/actions/server/create_execute_function.ts b/x-pack/plugins/actions/server/create_execute_function.ts index de15a1e0ca446..c071be4759de4 100644 --- a/x-pack/plugins/actions/server/create_execute_function.ts +++ b/x-pack/plugins/actions/server/create_execute_function.ts @@ -29,6 +29,7 @@ export interface ExecuteOptions extends Pick { return async function execute( unsecuredSavedObjectsClient: SavedObjectsClientContract, - { id, params, spaceId, source, apiKey, relatedSavedObjects }: ExecuteOptions + { id, params, spaceId, source, apiKey, executionId, relatedSavedObjects }: ExecuteOptions ) { if (!isESOCanEncrypt) { throw new Error( @@ -87,6 +88,7 @@ export function createExecutionEnqueuerFunction({ actionId: id, params, apiKey, + executionId, relatedSavedObjects: relatedSavedObjectWithRefs, }, { @@ -113,7 +115,7 @@ export function createEphemeralExecutionEnqueuerFunction({ }: CreateExecuteFunctionOptions): ExecutionEnqueuer { return async function execute( unsecuredSavedObjectsClient: SavedObjectsClientContract, - { id, params, spaceId, source, apiKey }: ExecuteOptions + { id, params, spaceId, source, apiKey, executionId }: ExecuteOptions ): Promise { const { action } = await getAction(unsecuredSavedObjectsClient, preconfiguredActions, id); validateCanActionBeUsed(action); @@ -131,6 +133,7 @@ export function createEphemeralExecutionEnqueuerFunction({ // eslint-disable-next-line @typescript-eslint/no-explicit-any params: params as Record, ...(apiKey ? { apiKey } : {}), + ...(executionId ? { executionId } : {}), }, ...executionSourceAsSavedObjectReferences(source), }; diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index 1d678c244c1b0..9b7f9a97e58ec 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -30,6 +30,7 @@ const executeParams = { params: { foo: true, }, + executionId: '123abc', request: {} as KibanaRequest, }; @@ -118,6 +119,13 @@ test('successfully executes', async () => { "kind": "action", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "123abc", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -139,6 +147,13 @@ test('successfully executes', async () => { "outcome": "success", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "123abc", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -518,15 +533,24 @@ test('writes to event log for execute timeout', async () => { await actionExecutor.logCancellation({ actionId: 'action1', + executionId: '123abc', relatedSavedObjects: [], request: {} as KibanaRequest, }); expect(eventLogger.logEvent).toHaveBeenCalledTimes(1); - expect(eventLogger.logEvent.mock.calls[0][0]).toMatchObject({ + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { event: { action: 'execute-timeout', + kind: 'action', }, kibana: { + alert: { + rule: { + execution: { + uuid: '123abc', + }, + }, + }, saved_objects: [ { rel: 'primary', @@ -549,11 +573,19 @@ test('writes to event log for execute and execute start', async () => { }); await actionExecutor.execute(executeParams); expect(eventLogger.logEvent).toHaveBeenCalledTimes(2); - expect(eventLogger.logEvent.mock.calls[0][0]).toMatchObject({ + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { event: { action: 'execute-start', + kind: 'action', }, kibana: { + alert: { + rule: { + execution: { + uuid: '123abc', + }, + }, + }, saved_objects: [ { rel: 'primary', @@ -566,11 +598,20 @@ test('writes to event log for execute and execute start', async () => { }, message: 'action started: test:1: action-1', }); - expect(eventLogger.logEvent.mock.calls[1][0]).toMatchObject({ + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(2, { event: { action: 'execute', + kind: 'action', + outcome: 'success', }, kibana: { + alert: { + rule: { + execution: { + uuid: '123abc', + }, + }, + }, saved_objects: [ { rel: 'primary', diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index 9737630628823..0efdc4f8f082f 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -60,6 +60,7 @@ export interface ExecuteOptions { params: Record; source?: ActionExecutionSource; taskInfo?: TaskInfo; + executionId?: string; relatedSavedObjects?: RelatedSavedObjects; } @@ -90,6 +91,7 @@ export class ActionExecutor { source, isEphemeral, taskInfo, + executionId, relatedSavedObjects, }: ExecuteOptions): Promise> { if (!this.isInitialized) { @@ -187,6 +189,7 @@ export class ActionExecutor { action: EVENT_LOG_ACTIONS.execute, ...namespace, ...task, + executionId, savedObjects: [ { type: 'action', @@ -283,11 +286,13 @@ export class ActionExecutor { request, relatedSavedObjects, source, + executionId, taskInfo, }: { actionId: string; request: KibanaRequest; taskInfo?: TaskInfo; + executionId?: string; relatedSavedObjects: RelatedSavedObjects; source?: ActionExecutionSource; }) { @@ -327,6 +332,7 @@ export class ActionExecutor { }' execution cancelled due to timeout - exceeded default timeout of "5m"`, ...namespace, ...task, + executionId, savedObjects: [ { type: 'action', diff --git a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts index ee58f8a01488c..bea2a2680bb83 100644 --- a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts +++ b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts @@ -18,6 +18,7 @@ describe('createActionEventLogRecordObject', () => { scheduled: '1970-01-01T00:00:00.000Z', scheduleDelay: 0, }, + executionId: '123abc', savedObjects: [ { id: '1', @@ -34,6 +35,13 @@ describe('createActionEventLogRecordObject', () => { kind: 'action', }, kibana: { + alert: { + rule: { + execution: { + uuid: '123abc', + }, + }, + }, saved_objects: [ { id: '1', @@ -58,6 +66,7 @@ describe('createActionEventLogRecordObject', () => { action: 'execute', message: 'action execution start', namespace: 'default', + executionId: '123abc', savedObjects: [ { id: '2', @@ -73,6 +82,13 @@ describe('createActionEventLogRecordObject', () => { kind: 'action', }, kibana: { + alert: { + rule: { + execution: { + uuid: '123abc', + }, + }, + }, saved_objects: [ { id: '2', @@ -95,6 +111,7 @@ describe('createActionEventLogRecordObject', () => { task: { scheduled: '1970-01-01T00:00:00.000Z', }, + executionId: '123abc', savedObjects: [ { id: '1', @@ -110,6 +127,13 @@ describe('createActionEventLogRecordObject', () => { kind: 'action', }, kibana: { + alert: { + rule: { + execution: { + uuid: '123abc', + }, + }, + }, saved_objects: [ { id: '1', diff --git a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts index 1a1c5e9e6b3aa..5555fe8ada325 100644 --- a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts +++ b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts @@ -20,6 +20,7 @@ interface CreateActionEventLogRecordParams { scheduled?: string; scheduleDelay?: number; }; + executionId?: string; savedObjects: Array<{ type: string; id: string; @@ -29,7 +30,7 @@ interface CreateActionEventLogRecordParams { } export function createActionEventLogRecordObject(params: CreateActionEventLogRecordParams): Event { - const { action, message, task, namespace } = params; + const { action, message, task, namespace, executionId } = params; const event: Event = { ...(params.timestamp ? { '@timestamp': params.timestamp } : {}), @@ -38,6 +39,17 @@ export function createActionEventLogRecordObject(params: CreateActionEventLogRec kind: 'action', }, kibana: { + ...(executionId + ? { + alert: { + rule: { + execution: { + uuid: executionId, + }, + }, + }, + } + : {}), saved_objects: params.savedObjects.map((so) => ({ ...(so.relation ? { rel: so.relation } : {}), type: so.type, 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 0ea6b5316fb82..ab4d50338684b 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 @@ -111,6 +111,7 @@ test('executes the task by calling the executor with proper parameters, using gi attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }, references: [], @@ -131,6 +132,7 @@ test('executes the task by calling the executor with proper parameters, using gi isEphemeral: false, params: { baz: true }, relatedSavedObjects: [], + executionId: '123abc', request: expect.objectContaining({ headers: { // base64 encoded "123:abc" @@ -163,6 +165,7 @@ test('executes the task by calling the executor with proper parameters, using st attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }, references: [ @@ -188,6 +191,7 @@ test('executes the task by calling the executor with proper parameters, using st actionId: '9', isEphemeral: false, params: { baz: true }, + executionId: '123abc', relatedSavedObjects: [], request: expect.objectContaining({ headers: { @@ -221,6 +225,7 @@ test('cleans up action_task_params object', async () => { attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }, references: [ @@ -244,6 +249,7 @@ test('task runner should implement CancellableTask cancel method with logging wa attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }, references: [ @@ -281,6 +287,7 @@ test('runs successfully when cleanup fails and logs the error', async () => { attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }, references: [ @@ -312,6 +319,7 @@ test('throws an error with suggested retry logic when return status is error', a attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }, references: [ @@ -353,6 +361,7 @@ test('uses API key when provided', async () => { attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }, references: [ @@ -370,6 +379,7 @@ test('uses API key when provided', async () => { actionId: '2', isEphemeral: false, params: { baz: true }, + executionId: '123abc', relatedSavedObjects: [], request: expect.objectContaining({ headers: { @@ -403,6 +413,7 @@ test('uses relatedSavedObjects merged with references when provided', async () = attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), relatedSavedObjects: [{ id: 'related_some-type_0', type: 'some-type' }], }, @@ -426,6 +437,7 @@ test('uses relatedSavedObjects merged with references when provided', async () = actionId: '2', isEphemeral: false, params: { baz: true }, + executionId: '123abc', relatedSavedObjects: [ { id: 'some-id', @@ -458,6 +470,7 @@ test('uses relatedSavedObjects as is when references are empty', async () => { attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), relatedSavedObjects: [{ id: 'abc', type: 'some-type', namespace: 'yo' }], }, @@ -476,6 +489,7 @@ test('uses relatedSavedObjects as is when references are empty', async () => { actionId: '2', isEphemeral: false, params: { baz: true }, + executionId: '123abc', relatedSavedObjects: [ { id: 'abc', @@ -509,6 +523,7 @@ test('sanitizes invalid relatedSavedObjects when provided', async () => { attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), relatedSavedObjects: [{ Xid: 'related_some-type_0', type: 'some-type' }], }, @@ -537,6 +552,7 @@ test('sanitizes invalid relatedSavedObjects when provided', async () => { authorization: 'ApiKey MTIzOmFiYw==', }, }), + executionId: '123abc', relatedSavedObjects: [], taskInfo: { scheduled: new Date(), @@ -558,6 +574,7 @@ test(`doesn't use API key when not provided`, async () => { attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', }, references: [ { @@ -574,6 +591,7 @@ test(`doesn't use API key when not provided`, async () => { actionId: '2', isEphemeral: false, params: { baz: true }, + executionId: '123abc', relatedSavedObjects: [], request: expect.objectContaining({ headers: {}, @@ -608,6 +626,7 @@ test(`throws an error when license doesn't support the action type`, async () => attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }, references: [ @@ -646,6 +665,7 @@ test(`treats errors as errors if the task is retryable`, async () => { attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }, references: [ @@ -693,6 +713,7 @@ test(`treats errors as successes if the task is not retryable`, async () => { attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }, references: [ @@ -737,6 +758,7 @@ test('treats errors as errors if the error is thrown instead of returned', async attributes: { actionId: '2', params: { baz: true }, + executionId: '123abc', apiKey: Buffer.from('123:abc').toString('base64'), }, references: [ 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 f3fdf627e08ff..99aead5a73a40 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.ts @@ -86,7 +86,7 @@ export class TaskRunnerFactory { const { spaceId } = actionTaskExecutorParams; const { - attributes: { actionId, params, apiKey, relatedSavedObjects }, + attributes: { actionId, params, apiKey, executionId, relatedSavedObjects }, references, } = await getActionTaskParams( actionTaskExecutorParams, @@ -114,6 +114,7 @@ export class TaskRunnerFactory { request, ...getSourceFromReferences(references), taskInfo, + executionId, relatedSavedObjects: validatedRelatedSavedObjects(logger, relatedSavedObjects), }); } catch (e) { @@ -178,7 +179,7 @@ export class TaskRunnerFactory { const { spaceId } = actionTaskExecutorParams; const { - attributes: { actionId, apiKey, relatedSavedObjects }, + attributes: { actionId, apiKey, executionId, relatedSavedObjects }, references, } = await getActionTaskParams( actionTaskExecutorParams, @@ -193,6 +194,7 @@ export class TaskRunnerFactory { await actionExecutor.logCancellation({ actionId, request, + executionId, relatedSavedObjects: (relatedSavedObjects || []) as RelatedSavedObjects, ...getSourceFromReferences(references), }); diff --git a/x-pack/plugins/actions/server/saved_objects/mappings.json b/x-pack/plugins/actions/server/saved_objects/mappings.json index a357d095d85c6..deb80c4c9798f 100644 --- a/x-pack/plugins/actions/server/saved_objects/mappings.json +++ b/x-pack/plugins/actions/server/saved_objects/mappings.json @@ -36,6 +36,9 @@ "apiKey": { "type": "binary" }, + "executionId": { + "type": "keyword" + }, "relatedSavedObjects": { "enabled": false, "type": "object" diff --git a/x-pack/plugins/actions/server/types.ts b/x-pack/plugins/actions/server/types.ts index 04159ec7b8963..1e58627cefbcc 100644 --- a/x-pack/plugins/actions/server/types.ts +++ b/x-pack/plugins/actions/server/types.ts @@ -138,6 +138,7 @@ export interface ActionTaskParams extends SavedObjectAttributes { // eslint-disable-next-line @typescript-eslint/no-explicit-any params: Record; apiKey?: string; + executionId?: string; } interface PersistedActionTaskExecutorParams { 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 71ec12e29a9dd..3442216a2f1fd 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 @@ -134,6 +134,7 @@ test('enqueues execution per selected action', async () => { Array [ Object { "apiKey": "MTIzOmFiYw==", + "executionId": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", "id": "1", "params": Object { "alertVal": "My 1 name-of-alert test1 tag-A,tag-B 2 goes here", @@ -276,6 +277,7 @@ test(`doesn't call actionsPlugin.execute for disabled actionTypes`, async () => ], spaceId: 'test1', apiKey: createExecutionHandlerParams.apiKey, + executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', }); }); @@ -347,6 +349,7 @@ test('context attribute gets parameterized', async () => { Array [ Object { "apiKey": "MTIzOmFiYw==", + "executionId": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", "id": "1", "params": Object { "alertVal": "My 1 name-of-alert test1 tag-A,tag-B 2 goes here", @@ -388,6 +391,7 @@ test('state attribute gets parameterized', async () => { Array [ Object { "apiKey": "MTIzOmFiYw==", + "executionId": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", "id": "1", "params": Object { "alertVal": "My 1 name-of-alert test1 tag-A,tag-B 2 goes here", 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 58f8089890c87..84f044f4041ba 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 @@ -181,6 +181,7 @@ export function createExecutionHandler< id: ruleId, type: 'alert', }), + executionId, relatedSavedObjects: [ { id: ruleId, 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 30336a7d5fc48..c4fc6b0171be0 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 @@ -455,6 +455,7 @@ describe('Task Runner', () => { Array [ Object { "apiKey": "MTIzOmFiYw==", + "executionId": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", "id": "1", "params": Object { "foo": true, @@ -1370,6 +1371,7 @@ describe('Task Runner', () => { Array [ Object { "apiKey": "MTIzOmFiYw==", + "executionId": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", "id": "1", "params": Object { "foo": true, @@ -2003,6 +2005,7 @@ describe('Task Runner', () => { Array [ Object { "apiKey": "MTIzOmFiYw==", + "executionId": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", "id": "2", "params": Object { "isResolved": true, @@ -2238,6 +2241,7 @@ describe('Task Runner', () => { Array [ Object { "apiKey": "MTIzOmFiYw==", + "executionId": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", "id": "2", "params": Object { "isResolved": true, diff --git a/x-pack/plugins/cases/public/components/all_cases/columns.tsx b/x-pack/plugins/cases/public/components/all_cases/columns.tsx index 701a2ec24a3ee..d08f788c85311 100644 --- a/x-pack/plugins/cases/public/components/all_cases/columns.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/columns.tsx @@ -305,7 +305,7 @@ export const useCasesColumns = ({ if (createdAt != null) { return ( - + ); } diff --git a/x-pack/plugins/cases/public/components/case_view/metrics/status.tsx b/x-pack/plugins/cases/public/components/case_view/metrics/status.tsx index 1451e5409ff63..f3bfcee1ab947 100644 --- a/x-pack/plugins/cases/public/components/case_view/metrics/status.tsx +++ b/x-pack/plugins/cases/public/components/case_view/metrics/status.tsx @@ -18,7 +18,7 @@ import { CASE_REOPENED_ON, } from './translations'; import { getMaybeDate } from '../../formatted_date/maybe_date'; -import { FormattedDate, FormattedRelativePreferenceDate } from '../../formatted_date'; +import { FormattedRelativePreferenceDate } from '../../formatted_date'; import { getEmptyTagValue } from '../../empty_value'; import { euiStyled } from '../../../../../../../src/plugins/kibana_react/common'; import { CaseViewMetricsProps } from './types'; @@ -118,6 +118,7 @@ const CreationDate: React.FC<{ date: string }> = React.memo(({ date }) => { ); }); @@ -210,9 +211,10 @@ const ValueWithExplanationIcon: React.FC<{ {explanationValues.map((explanationValue, index) => { return ( - {isNotLastItem(index, explanationValues.length) ? : null} diff --git a/x-pack/plugins/cases/public/components/case_view/metrics/translations.ts b/x-pack/plugins/cases/public/components/case_view/metrics/translations.ts index 7964bc7ac98e2..0ca0ec7ae7380 100644 --- a/x-pack/plugins/cases/public/components/case_view/metrics/translations.ts +++ b/x-pack/plugins/cases/public/components/case_view/metrics/translations.ts @@ -66,5 +66,5 @@ export const CASE_REOPENED = i18n.translate('xpack.cases.caseView.metrics.lifesp }); export const CASE_REOPENED_ON = i18n.translate('xpack.cases.caseView.metrics.lifespan.reopenedOn', { - defaultMessage: 'Reopened on ', + defaultMessage: 'Reopened ', }); diff --git a/x-pack/plugins/cases/public/components/formatted_date/index.test.tsx b/x-pack/plugins/cases/public/components/formatted_date/index.test.tsx index d54430b9f27da..3a61928e9f4c7 100644 --- a/x-pack/plugins/cases/public/components/formatted_date/index.test.tsx +++ b/x-pack/plugins/cases/public/components/formatted_date/index.test.tsx @@ -63,6 +63,23 @@ describe('formatted_date', () => { expect(wrapper.text()).toEqual('Feb-25-2019'); }); + + test('it strips down milliseconds when stripMs is passed', () => { + const date = new Date('2022-01-27T10:30:00.000Z'); + + const wrapper = mount(); + + expect(wrapper.text()).toEqual('Jan 27, 2022 @ 10:30:00'); + }); + + test('it strips down milliseconds when stripMs is passed and user-defined format is used', () => { + const date = new Date('2022-01-27T10:30:00.000Z'); + mockUseDateFormat.mockImplementation(() => 'HH:mm:ss.SSS'); + + const wrapper = mount(); + + expect(wrapper.text()).toEqual('10:30:00'); + }); }); describe('FormattedDate', () => { @@ -166,5 +183,16 @@ describe('formatted_date', () => { expect(wrapper.text()).toBe(getEmptyValue()); }); + + test('strips down the time milliseconds when stripMs is passed', () => { + const date = new Date('2022-01-27T10:30:00.000Z'); + const wrapper = mount( + + + + ); + + expect(wrapper.text()).toBe('Jan 27, 2022 @ 10:30:00'); + }); }); }); diff --git a/x-pack/plugins/cases/public/components/formatted_date/index.tsx b/x-pack/plugins/cases/public/components/formatted_date/index.tsx index 8e00ddf80e045..567cf9e95636d 100644 --- a/x-pack/plugins/cases/public/components/formatted_date/index.tsx +++ b/x-pack/plugins/cases/public/components/formatted_date/index.tsx @@ -14,12 +14,17 @@ import { getOrEmptyTagFromValue } from '../empty_value'; import { LocalizedDateTooltip } from '../localized_date_tooltip'; import { getMaybeDate } from './maybe_date'; -export const PreferenceFormattedDate = React.memo<{ dateFormat?: string; value: Date }>( - /* eslint-disable-next-line react-hooks/rules-of-hooks */ - ({ value, dateFormat = useDateFormat() }) => ( - <>{moment.tz(value, useTimeZone()).format(dateFormat)} - ) -); +export const PreferenceFormattedDate = React.memo<{ + dateFormat?: string; + value: Date; + stripMs?: boolean; +}>(({ value, dateFormat, stripMs = false }) => { + const systemDateFormat = useDateFormat(); + const toUseDateFormat = dateFormat ? dateFormat : systemDateFormat; + const strippedDateFormat = + toUseDateFormat && stripMs ? toUseDateFormat.replace(/\.?SSS/, '') : toUseDateFormat; + return <>{moment.tz(value, useTimeZone()).format(strippedDateFormat)}; +}); PreferenceFormattedDate.displayName = 'PreferenceFormattedDate'; @@ -121,9 +126,16 @@ FormattedDate.displayName = 'FormattedDate'; * - a humanized relative date (e.g. 16 minutes ago) * - a long representation of the date that includes the day of the week (e.g. Thursday, March 21, 2019 6:47pm) * - the raw date value (e.g. 2019-03-22T00:47:46Z) + * @param value - raw date + * @param stripMs - strip milliseconds when formatting time (remove ".SSS" from the date format) */ - -export const FormattedRelativePreferenceDate = ({ value }: { value?: string | number | null }) => { +export const FormattedRelativePreferenceDate = ({ + value, + stripMs = false, +}: { + value?: string | number | null; + stripMs?: boolean; +}) => { if (value == null) { return getOrEmptyTagFromValue(value); } @@ -135,7 +147,7 @@ export const FormattedRelativePreferenceDate = ({ value }: { value?: string | nu return ( {moment(date).add(1, 'hours').isBefore(new Date()) ? ( - + ) : ( )} diff --git a/x-pack/plugins/cases/public/components/localized_date_tooltip/index.test.tsx b/x-pack/plugins/cases/public/components/localized_date_tooltip/index.test.tsx index 83fba7a041ca5..901afd55dd38a 100644 --- a/x-pack/plugins/cases/public/components/localized_date_tooltip/index.test.tsx +++ b/x-pack/plugins/cases/public/components/localized_date_tooltip/index.test.tsx @@ -10,6 +10,7 @@ import moment from 'moment-timezone'; import React from 'react'; import { LocalizedDateTooltip } from '.'; +import { TestProviders } from '../../common/mock'; describe('LocalizedDateTooltip', () => { beforeEach(() => { @@ -29,9 +30,11 @@ describe('LocalizedDateTooltip', () => { test('it renders the child content', () => { const wrapper = mount( - - - + + + + + ); expect(wrapper.find('[data-test-subj="sample-content"]').exists()).toEqual(true); @@ -39,9 +42,11 @@ describe('LocalizedDateTooltip', () => { test('it renders', () => { const wrapper = mount( - - - + + + + + ); expect(wrapper.find('[data-test-subj="localized-date-tool-tip"]').exists()).toEqual(true); diff --git a/x-pack/plugins/cases/public/components/localized_date_tooltip/index.tsx b/x-pack/plugins/cases/public/components/localized_date_tooltip/index.tsx index 34825dfa5ae9d..108f94a636d3b 100644 --- a/x-pack/plugins/cases/public/components/localized_date_tooltip/index.tsx +++ b/x-pack/plugins/cases/public/components/localized_date_tooltip/index.tsx @@ -6,9 +6,9 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; -import { FormattedRelative } from '@kbn/i18n-react'; -import moment from 'moment'; +import moment from 'moment-timezone'; import React from 'react'; +import { useTimeZone } from '../../common/lib/kibana'; export const LocalizedDateTooltip = React.memo<{ children: React.ReactNode; @@ -26,17 +26,8 @@ export const LocalizedDateTooltip = React.memo<{ {fieldName} ) : null} - - - - {moment.utc(date).local().format('llll')} - - - {moment(date).format()} + {moment.tz(date, useTimeZone()).format('llll')} } diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx index f1a23ea759def..b1cc6ad81ec5f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx @@ -9,7 +9,7 @@ import React, { useState, useEffect, useMemo } from 'react'; import { fromKueryExpression } from '@kbn/es-query'; -import type { IFieldType } from '../../../../../../../src/plugins/data/public'; +import type { FieldSpec } from '../../../../../../../src/plugins/data/common'; import { QueryStringInput } from '../../../../../../../src/plugins/data/public'; import { useStartServices } from '../hooks'; import { INDEX_NAME, AGENTS_PREFIX } from '../constants'; @@ -32,7 +32,7 @@ export const SearchBar: React.FunctionComponent = ({ indexPattern = INDEX_NAME, }) => { const { data } = useStartServices(); - const [indexPatternFields, setIndexPatternFields] = useState(); + const [indexPatternFields, setIndexPatternFields] = useState(); const isQueryValid = useMemo(() => { if (!value || value === '') { @@ -50,7 +50,7 @@ export const SearchBar: React.FunctionComponent = ({ useEffect(() => { const fetchFields = async () => { try { - const _fields: IFieldType[] = await data.indexPatterns.getFieldsForWildcard({ + const _fields: FieldSpec[] = await data.dataViews.getFieldsForWildcard({ pattern: indexPattern, }); const fields = (_fields || []).filter((field) => { @@ -69,7 +69,7 @@ export const SearchBar: React.FunctionComponent = ({ } }; fetchFields(); - }, [data.indexPatterns, fieldPrefix, indexPattern]); + }, [data.dataViews, fieldPrefix, indexPattern]); return ( void; }> = memo(({ query, isQueryValid, onUpdateQuery }) => { const { data } = useStartServices(); - const [indexPatternFields, setIndexPatternFields] = useState(); + const [indexPatternFields, setIndexPatternFields] = useState(); useEffect(() => { const fetchFields = async () => { try { const fields = ( - ((await data.indexPatterns.getFieldsForWildcard({ + (await data.dataViews.getFieldsForWildcard({ pattern: AGENT_LOG_INDEX_PATTERN, - })) as IFieldType[]) || [] + })) || [] ).filter((field) => { return !EXCLUDED_FIELDS.includes(field.name); }); @@ -45,7 +45,7 @@ export const LogQueryBar: React.FunctionComponent<{ } }; fetchFields(); - }, [data.indexPatterns]); + }, [data.dataViews]); return ( ; +function getSupertestWithAdminUser(root: Root, method: HttpMethod, path: string) { + const testUserCredentials = Buffer.from(`${adminTestUser.username}:${adminTestUser.password}`); + return kbnTestServer + .getSupertest(root, method, path) + .set('Authorization', `Basic ${testUserCredentials.toString('base64')}`); +} + const waitForFleetSetup = async (root: Root) => { const isFleetSetupRunning = async () => { - const statusApi = kbnTestServer.getSupertest(root, 'get', '/api/status'); + const statusApi = getSupertestWithAdminUser(root, 'get', '/api/status'); const resp = await statusApi.send(); const fleetStatus = resp.body?.status?.plugins?.fleet; if (fleetStatus?.meta?.error) { @@ -181,12 +191,12 @@ describe('Fleet preconfiguration rest', () => { describe('Reset all policy', () => { it('Works and reset all preconfigured policies', async () => { - const resetAPI = kbnTestServer.getSupertest( + const resetAPI = getSupertestWithAdminUser( kbnServer.root, 'post', '/internal/fleet/reset_preconfigured_agent_policies' ); - await resetAPI.set('kbn-sxrf', 'xx').send(); + await resetAPI.set('kbn-sxrf', 'xx').expect(200).send(); const agentPolicies = await kbnServer.coreStart.savedObjects .createInternalRepository() @@ -208,8 +218,7 @@ describe('Fleet preconfiguration rest', () => { }); }); - // SKIP: https://github.com/elastic/kibana/issues/123528 - describe.skip('Reset one preconfigured policy', () => { + describe('Reset one preconfigured policy', () => { const POLICY_ID = 'test-12345'; it('Works and reset one preconfigured policies if the policy is already deleted (with a ghost package policy)', async () => { @@ -224,12 +233,12 @@ describe('Fleet preconfiguration rest', () => { const secondAgentPoliciesUpdatedAt = oldAgentPolicies.saved_objects[0].updated_at; - const resetAPI = kbnTestServer.getSupertest( + const resetAPI = getSupertestWithAdminUser( kbnServer.root, 'post', '/internal/fleet/reset_preconfigured_agent_policies/test-12345' ); - await resetAPI.set('kbn-sxrf', 'xx').send(); + await resetAPI.set('kbn-sxrf', 'xx').expect(200).send(); const agentPolicies = await kbnServer.coreStart.savedObjects .createInternalRepository() @@ -260,12 +269,12 @@ describe('Fleet preconfiguration rest', () => { package_policies: [], }); - const resetAPI = kbnTestServer.getSupertest( + const resetAPI = getSupertestWithAdminUser( kbnServer.root, 'post', '/internal/fleet/reset_preconfigured_agent_policies/test-12345' ); - await resetAPI.set('kbn-sxrf', 'xx').send(); + await resetAPI.set('kbn-sxrf', 'xx').expect(200).send(); const agentPolicies = await soClient.find({ type: 'ingest-agent-policies', diff --git a/x-pack/plugins/fleet/server/services/package_policy.test.ts b/x-pack/plugins/fleet/server/services/package_policy.test.ts index 72f6ff49e608d..a44355522dd42 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.test.ts @@ -1993,6 +1993,10 @@ describe('Package policy service', () => { type: 'text', value: ['/var/log/logfile.log'], }, + is_value_enabled: { + type: 'bool', + value: false, + }, }, streams: [], }, @@ -2023,6 +2027,10 @@ describe('Package policy service', () => { name: 'path', type: 'text', }, + { + name: 'is_value_enabled', + type: 'bool', + }, ], }, ], @@ -2042,6 +2050,10 @@ describe('Package policy service', () => { type: 'text', value: '/var/log/new-logfile.log', }, + is_value_enabled: { + type: 'bool', + value: 'true', + }, }, }, ]; @@ -2055,6 +2067,7 @@ describe('Package policy service', () => { false ); expect(result.inputs[0]?.vars?.path.value).toEqual(['/var/log/logfile.log']); + expect(result.inputs[0]?.vars?.is_value_enabled.value).toEqual(false); }); }); diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 1ad4ff1adbdd0..b0ef179834ebb 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -1369,7 +1369,7 @@ function deepMergeVars(original: any, override: any, keepOriginalValue = false): // Ensure that any value from the original object is persisted on the newly merged resulting object, // even if we merge other data about the given variable - if (keepOriginalValue && originalVar?.value) { + if (keepOriginalValue && originalVar?.value !== undefined) { result.vars[name].value = originalVar.value; } } diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.test.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.test.ts index 255aa587666c7..3b6f2cb6ae4f2 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.test.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.test.ts @@ -12,6 +12,7 @@ import { createExtensionPointStorageMock, } from '../extension_points/extension_point_storage.mock'; import type { ExtensionPointCallbackDataArgument } from '../extension_points'; +import { httpServerMock } from '../../../../../../src/core/server/mocks'; import { getCreateExceptionListItemOptionsMock, @@ -49,13 +50,16 @@ describe('exception_list_client', () => { describe('server extension points execution', () => { let extensionPointStorageContext: ExtensionPointStorageContextMock; let exceptionListClient: ExceptionListClient; + let kibanaRequest: ReturnType; beforeEach(() => { extensionPointStorageContext = createExtensionPointStorageMock(); + kibanaRequest = httpServerMock.createKibanaRequest(); }); it('should initialize class instance with `enableServerExtensionPoints` enabled by default', async () => { exceptionListClient = new ExceptionListClient({ + request: kibanaRequest, savedObjectsClient: getExceptionListSavedObjectClientMock(), serverExtensionsClient: extensionPointStorageContext.extensionPointStorage.getClient(), user: 'elastic', @@ -98,6 +102,7 @@ describe('exception_list_client', () => { describe('and server extension points are enabled', () => { beforeEach(() => { exceptionListClient = new ExceptionListClient({ + request: kibanaRequest, savedObjectsClient: getExceptionListSavedObjectClientMock(), serverExtensionsClient: extensionPointStorageContext.extensionPointStorage.getClient(), @@ -111,6 +116,15 @@ describe('exception_list_client', () => { expect(getExtensionPointCallback()).toHaveBeenCalled(); }); + it('should provide `context` object to extension point callbacks', async () => { + await callExceptionListClientMethod(); + + expect(getExtensionPointCallback().mock.calls[0][0].context).toEqual({ + exceptionListClient: expect.any(ExceptionListClient), + request: kibanaRequest, + }); + }); + it('should error if extension point callback throws an error', async () => { const error = new Error('foo'); const extensionCallback = getExtensionPointCallback(); @@ -157,6 +171,7 @@ describe('exception_list_client', () => { beforeEach(() => { exceptionListClient = new ExceptionListClient({ enableServerExtensionPoints: false, + request: kibanaRequest, savedObjectsClient: getExceptionListSavedObjectClientMock(), serverExtensionsClient: extensionPointStorageContext.extensionPointStorage.getClient(), @@ -305,6 +320,7 @@ describe('exception_list_client', () => { (methodName, callExceptionListClientMethod, getExtensionPointCallback) => { beforeEach(() => { exceptionListClient = new ExceptionListClient({ + request: kibanaRequest, savedObjectsClient: getExceptionListSavedObjectClientMock(), serverExtensionsClient: extensionPointStorageContext.extensionPointStorage.getClient(), user: 'elastic', @@ -317,6 +333,15 @@ describe('exception_list_client', () => { expect(getExtensionPointCallback()).toHaveBeenCalled(); }); + it('should provide `context` object to extension point callbacks', async () => { + await callExceptionListClientMethod(); + + expect(getExtensionPointCallback().mock.calls[0][0].context).toEqual({ + exceptionListClient: expect.any(ExceptionListClient), + request: kibanaRequest, + }); + }); + it('should error if extension point callback throws an error', async () => { const error = new Error('foo'); const extensionCallback = getExtensionPointCallback(); @@ -332,6 +357,7 @@ describe('exception_list_client', () => { beforeEach(() => { exceptionListClient = new ExceptionListClient({ enableServerExtensionPoints: false, + request: kibanaRequest, savedObjectsClient: getExceptionListSavedObjectClientMock(), serverExtensionsClient: extensionPointStorageContext.extensionPointStorage.getClient(), diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts index 62fa8524cd466..93f5077f021d5 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts @@ -103,7 +103,24 @@ export class ExceptionListClient { } private getServerExtensionCallbackContext(): ServerExtensionCallbackContext { + const { user, serverExtensionsClient, savedObjectsClient, request } = this; + let exceptionListClient: undefined | ExceptionListClient; + return { + // Lazy getter so that we only initialize a new instance of the class if needed + get exceptionListClient(): ExceptionListClient { + if (!exceptionListClient) { + exceptionListClient = new ExceptionListClient({ + enableServerExtensionPoints: false, + request, + savedObjectsClient, + serverExtensionsClient, + user, + }); + } + + return exceptionListClient; + }, request: this.request, }; } diff --git a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage.mock.ts b/x-pack/plugins/lists/server/services/extension_points/extension_point_storage.mock.ts index 2a63da494dc3b..47eeee057e072 100644 --- a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage.mock.ts +++ b/x-pack/plugins/lists/server/services/extension_points/extension_point_storage.mock.ts @@ -8,6 +8,7 @@ import { MockedLogger, loggerMock } from '@kbn/logging/mocks'; import { httpServerMock } from '../../../../../../src/core/server/mocks'; +import { ExceptionListClient } from '../exception_lists/exception_list_client'; import { ExtensionPointStorage } from './extension_point_storage'; import { @@ -122,6 +123,7 @@ export const createExtensionPointStorageMock = ( return { callbackContext: { + exceptionListClient: {} as unknown as ExceptionListClient, request: httpServerMock.createKibanaRequest(), }, exceptionPreCreate, diff --git a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.test.ts b/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.test.ts index 1e094f7258f86..567a83fd2eb35 100644 --- a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.test.ts +++ b/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.test.ts @@ -138,9 +138,7 @@ describe('When using the ExtensionPointStorageClient', () => { if (extensionPointsMock.type === 'exceptionsListPreCreateItem') { expect(extensionPointsMock.callback).toHaveBeenCalledWith( expect.objectContaining({ - context: { - request: expect.any(Object), - }, + context: callbackContext, }) ); } diff --git a/x-pack/plugins/lists/server/services/extension_points/types.ts b/x-pack/plugins/lists/server/services/extension_points/types.ts index c8fdddc4b0969..dd94612a60295 100644 --- a/x-pack/plugins/lists/server/services/extension_points/types.ts +++ b/x-pack/plugins/lists/server/services/extension_points/types.ts @@ -19,6 +19,7 @@ import { UpdateExceptionListItemOptions, } from '../exception_lists/exception_list_client_types'; import { PromiseFromStreams } from '../exception_lists/import_exception_list_and_items'; +import type { ExceptionListClient } from '../exception_lists/exception_list_client'; /** * The `this` context provided to extension point's callback function @@ -30,6 +31,13 @@ export interface ServerExtensionCallbackContext { * is not triggered via one of the HTTP handlers */ request?: KibanaRequest; + + /** + * An `ExceptionListClient` instance that **DOES NOT** execute server extension point callbacks. + * This client should be used when needing to access Exception List content from within an Extension + * Point to avoid circular infinite loops + */ + exceptionListClient: ExceptionListClient; } export type ServerExtensionCallback = (args: { diff --git a/x-pack/plugins/maps/common/execution_context.ts b/x-pack/plugins/maps/common/execution_context.ts new file mode 100644 index 0000000000000..23de29cfa8cd7 --- /dev/null +++ b/x-pack/plugins/maps/common/execution_context.ts @@ -0,0 +1,18 @@ +/* + * 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 { APP_ID } from './constants'; + +export function makeExecutionContext(id: string, url: string, description?: string) { + return { + name: APP_ID, + type: 'application', + id, + description: description || '', + url, + }; +} diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx index 9b90f5f35827e..95f0204320fd0 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx @@ -44,6 +44,7 @@ import { ISearchSource } from '../../../../../../../src/plugins/data/common/sear import { IndexPattern } from '../../../../../../../src/plugins/data/common'; import { Adapters } from '../../../../../../../src/plugins/inspector/common/adapters'; import { isValidStringConfig } from '../../util/valid_string_config'; +import { makePublicExecutionContext } from '../../../util'; type ESGeoGridSourceSyncMeta = Pick; @@ -287,6 +288,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo } ), searchSessionId, + executionContext: makePublicExecutionContext('es_geo_grid_source:cluster_composite'), }); features.push(...convertCompositeRespToGeoJson(esResponse, this._descriptor.requestType)); @@ -360,6 +362,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo defaultMessage: 'Elasticsearch geo grid aggregation request', }), searchSessionId, + executionContext: makePublicExecutionContext('es_geo_grid_source:cluster'), }); return convertRegularRespToGeoJson(esResponse, this._descriptor.requestType); diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_line_source/es_geo_line_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_line_source/es_geo_line_source.tsx index 7c165d076e35e..e98b45e407087 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_line_source/es_geo_line_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_line_source/es_geo_line_source.tsx @@ -39,6 +39,7 @@ import { ITooltipProperty, TooltipProperty } from '../../tooltips/tooltip_proper import { esFilters } from '../../../../../../../src/plugins/data/public'; import { getIsGoldPlus } from '../../../licensed_features'; import { LICENSED_FEATURES } from '../../../licensed_features'; +import { makePublicExecutionContext } from '../../../util'; type ESGeoLineSourceSyncMeta = Pick; @@ -225,6 +226,7 @@ export class ESGeoLineSource extends AbstractESAggSource { defaultMessage: 'Elasticsearch terms request to fetch entities within map buffer.', }), searchSessionId: searchFilters.searchSessionId, + executionContext: makePublicExecutionContext('es_geo_line:entities'), }); const entityBuckets: Array<{ key: string; doc_count: number }> = _.get( entityResp, @@ -296,6 +298,7 @@ export class ESGeoLineSource extends AbstractESAggSource { 'Elasticsearch geo_line request to fetch tracks for entities. Tracks are not filtered by map buffer.', }), searchSessionId: searchFilters.searchSessionId, + executionContext: makePublicExecutionContext('es_geo_line:tracks'), }); const { featureCollection, numTrimmedTracks } = convertToGeoJson( tracksResp, diff --git a/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.js b/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.js index 8a916192cfe16..b3d2074c91667 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.js +++ b/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.js @@ -18,6 +18,7 @@ import { AbstractESAggSource } from '../es_agg_source'; import { registerSource } from '../source_registry'; import { turfBboxToBounds } from '../../../../common/elasticsearch_util'; import { DataRequestAbortError } from '../../util/data_request'; +import { makePublicExecutionContext } from '../../../util'; const MAX_GEOTILE_LEVEL = 29; @@ -163,6 +164,7 @@ export class ESPewPewSource extends AbstractESAggSource { defaultMessage: 'Source-destination connections request', }), searchSessionId: searchFilters.searchSessionId, + executionContext: makePublicExecutionContext('es_pew_pew_source:connections'), }); const { featureCollection } = convertToLines(esResponse); @@ -202,6 +204,7 @@ export class ESPewPewSource extends AbstractESAggSource { const esResp = await searchSource.fetch({ abortSignal: abortController.signal, legacyHitsTotal: false, + executionContext: makePublicExecutionContext('es_pew_pew_source:bounds'), }); if (esResp.aggregations.destFitToBounds.bounds) { corners.push([ diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx index 1b7c9e1cd6aa0..a9fdc7458bfd0 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx @@ -72,6 +72,7 @@ import { getIsDrawLayer, getMatchingIndexes, } from './util/feature_edit'; +import { makePublicExecutionContext } from '../../../util'; type ESSearchSourceSyncMeta = Pick< ESSearchSourceDescriptor, @@ -357,6 +358,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource registerCancelCallback, requestDescription: 'Elasticsearch document top hits request', searchSessionId: searchFilters.searchSessionId, + executionContext: makePublicExecutionContext('es_search_source:top_hits'), }); const allHits: any[] = []; @@ -438,6 +440,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource registerCancelCallback, requestDescription: 'Elasticsearch document request', searchSessionId: searchFilters.searchSessionId, + executionContext: makePublicExecutionContext('es_search_source:doc_search'), }); const isTimeExtentForTimeslice = @@ -599,7 +602,10 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource searchSource.setField('query', query); searchSource.setField('fieldsFromSource', this._getTooltipPropertyNames()); - const resp = await searchSource.fetch({ legacyHitsTotal: false }); + const resp = await searchSource.fetch({ + legacyHitsTotal: false, + executionContext: makePublicExecutionContext('es_search_source:load_tooltip_properties'), + }); const hit = _.get(resp, 'hits.hits[0]'); if (!hit) { @@ -905,6 +911,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource abortSignal: abortController.signal, sessionId: searchFilters.searchSessionId, legacyHitsTotal: false, + executionContext: makePublicExecutionContext('es_search_source:all_doc_counts'), }); return !isTotalHitsGreaterThan(resp.hits.total as unknown as TotalHits, maxResultWindow); } diff --git a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts index 71e58c0174fd3..54746773b6317 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts @@ -10,6 +10,7 @@ import uuid from 'uuid/v4'; import { Filter } from '@kbn/es-query'; import { IndexPatternField, IndexPattern, ISearchSource } from 'src/plugins/data/public'; import type { Query } from 'src/plugins/data/common'; +import type { KibanaExecutionContext } from 'kibana/public'; import { AbstractVectorSource, BoundsRequestMeta } from '../vector_source'; import { getAutocompleteService, @@ -38,6 +39,7 @@ import { IField } from '../../fields/field'; import { FieldFormatter } from '../../../../common/constants'; import { Adapters } from '../../../../../../../src/plugins/inspector/common/adapters'; import { isValidStringConfig } from '../../util/valid_string_config'; +import { makePublicExecutionContext } from '../../../util'; export function isSearchSourceAbortError(error: Error) { return error.name === 'AbortError'; @@ -160,6 +162,7 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource requestName, searchSessionId, searchSource, + executionContext, }: { registerCancelCallback: (callback: () => void) => void; requestDescription: string; @@ -167,6 +170,7 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource requestName: string; searchSessionId?: string; searchSource: ISearchSource; + executionContext: KibanaExecutionContext; }): Promise { const abortController = new AbortController(); registerCancelCallback(() => abortController.abort()); @@ -183,6 +187,7 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource title: requestName, description: requestDescription, }, + executionContext, }) .toPromise(); return resp; @@ -277,6 +282,7 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource const esResp = await searchSource.fetch({ abortSignal: abortController.signal, legacyHitsTotal: false, + executionContext: makePublicExecutionContext('es_source:bounds'), }); if (!esResp.aggregations) { @@ -469,6 +475,7 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource } ), searchSessionId, + executionContext: makePublicExecutionContext('es_source:style_meta'), }); return resp.aggregations; diff --git a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.ts b/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.ts index f7fc863eabb4a..b583dc7b281d0 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.ts @@ -32,6 +32,7 @@ import { PropertiesMap } from '../../../../common/elasticsearch_util'; import { isValidStringConfig } from '../../util/valid_string_config'; import { ITermJoinSource } from '../term_join_source'; import { IField } from '../../fields/field'; +import { makePublicExecutionContext } from '../../../util'; const TERMS_AGG_NAME = 'join'; const TERMS_BUCKET_KEYS_TO_IGNORE = ['key', 'doc_count']; @@ -153,6 +154,7 @@ export class ESTermSource extends AbstractESAggSource implements ITermJoinSource }, }), searchSessionId: searchFilters.searchSessionId, + executionContext: makePublicExecutionContext('es_term_source:terms'), }); const countPropertyName = this.getAggKey(AGG_TYPE.COUNT); diff --git a/x-pack/plugins/maps/public/util.ts b/x-pack/plugins/maps/public/util.ts index 18b9cd87850b4..a1118c3e3cec6 100644 --- a/x-pack/plugins/maps/public/util.ts +++ b/x-pack/plugins/maps/public/util.ts @@ -6,9 +6,11 @@ */ import { EMSClient, FileLayer, TMSService } from '@elastic/ems-client'; +import type { KibanaExecutionContext } from 'kibana/public'; import { FONTS_API_PATH } from '../common/constants'; import { getHttp, getTilemap, getEMSSettings, getMapsEmsStart } from './kibana_services'; import { getLicenseId } from './licensed_features'; +import { makeExecutionContext } from '../common/execution_context'; export function getKibanaTileMap(): unknown { return getTilemap(); @@ -56,3 +58,10 @@ export function getGlyphUrl(): string { export function isRetina(): boolean { return window.devicePixelRatio === 2; } + +export function makePublicExecutionContext( + id: string, + description?: string +): KibanaExecutionContext { + return makeExecutionContext(id, window.location.pathname, description); +} diff --git a/x-pack/plugins/maps/server/mvt/get_grid_tile.ts b/x-pack/plugins/maps/server/mvt/get_grid_tile.ts index cfaabef12b432..2eb55056692d6 100644 --- a/x-pack/plugins/maps/server/mvt/get_grid_tile.ts +++ b/x-pack/plugins/maps/server/mvt/get_grid_tile.ts @@ -5,13 +5,16 @@ * 2.0. */ -import { Logger } from 'src/core/server'; +import { CoreStart, Logger } from 'src/core/server'; import type { DataRequestHandlerContext } from 'src/plugins/data/server'; import { Stream } from 'stream'; import { RENDER_AS } from '../../common/constants'; import { isAbortError } from './util'; +import { makeExecutionContext } from '../../common/execution_context'; export async function getEsGridTile({ + url, + core, logger, context, index, @@ -24,6 +27,8 @@ export async function getEsGridTile({ gridPrecision, abortController, }: { + url: string; + core: CoreStart; x: number; y: number; z: number; @@ -49,20 +54,27 @@ export async function getEsGridTile({ fields: requestBody.fields, runtime_mappings: requestBody.runtime_mappings, }; - const tile = await context.core.elasticsearch.client.asCurrentUser.transport.request( - { - method: 'GET', - path, - body, - }, - { - signal: abortController.signal, - headers: { - 'Accept-Encoding': 'gzip', - }, - asStream: true, + + const tile = await core.executionContext.withContext( + makeExecutionContext('mvt:get_grid_tile', url), + async () => { + return await context.core.elasticsearch.client.asCurrentUser.transport.request( + { + method: 'GET', + path, + body, + }, + { + signal: abortController.signal, + headers: { + 'Accept-Encoding': 'gzip', + }, + asStream: true, + } + ); } ); + return tile.body as Stream; } catch (e) { if (!isAbortError(e)) { diff --git a/x-pack/plugins/maps/server/mvt/get_tile.ts b/x-pack/plugins/maps/server/mvt/get_tile.ts index 33a8ee291116a..35c3ad044216c 100644 --- a/x-pack/plugins/maps/server/mvt/get_tile.ts +++ b/x-pack/plugins/maps/server/mvt/get_tile.ts @@ -6,12 +6,15 @@ */ import _ from 'lodash'; -import { Logger } from 'src/core/server'; +import { CoreStart, Logger } from 'src/core/server'; import type { DataRequestHandlerContext } from 'src/plugins/data/server'; import { Stream } from 'stream'; import { isAbortError } from './util'; +import { makeExecutionContext } from '../../common/execution_context'; export async function getEsTile({ + url, + core, logger, context, index, @@ -22,6 +25,8 @@ export async function getEsTile({ requestBody = {}, abortController, }: { + url: string; + core: CoreStart; x: number; y: number; z: number; @@ -45,18 +50,24 @@ export async function getEsTile({ runtime_mappings: requestBody.runtime_mappings, track_total_hits: requestBody.size + 1, }; - const tile = await context.core.elasticsearch.client.asCurrentUser.transport.request( - { - method: 'GET', - path, - body, - }, - { - signal: abortController.signal, - headers: { - 'Accept-Encoding': 'gzip', - }, - asStream: true, + + const tile = await core.executionContext.withContext( + makeExecutionContext('mvt:get_tile', url), + async () => { + return await context.core.elasticsearch.client.asCurrentUser.transport.request( + { + method: 'GET', + path, + body, + }, + { + signal: abortController.signal, + headers: { + 'Accept-Encoding': 'gzip', + }, + asStream: true, + } + ); } ); diff --git a/x-pack/plugins/maps/server/mvt/mvt_routes.ts b/x-pack/plugins/maps/server/mvt/mvt_routes.ts index 6d3b531c466bf..ad6b3f8eb1235 100644 --- a/x-pack/plugins/maps/server/mvt/mvt_routes.ts +++ b/x-pack/plugins/maps/server/mvt/mvt_routes.ts @@ -8,7 +8,7 @@ import rison from 'rison-node'; import { Stream } from 'stream'; import { schema } from '@kbn/config-schema'; -import { KibanaRequest, KibanaResponseFactory, Logger } from 'src/core/server'; +import { CoreStart, KibanaRequest, KibanaResponseFactory, Logger } from 'src/core/server'; import { IRouter } from 'src/core/server'; import type { DataRequestHandlerContext } from 'src/plugins/data/server'; import { @@ -25,9 +25,11 @@ const CACHE_TIMEOUT_SECONDS = 60 * 60; export function initMVTRoutes({ router, logger, + core, }: { router: IRouter; logger: Logger; + core: CoreStart; }) { router.get( { @@ -58,6 +60,8 @@ export function initMVTRoutes({ const requestBodyDSL = rison.decode(query.requestBody as string); const gzippedTile = await getEsTile({ + url: `${API_ROOT_PATH}/${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`, + core, logger, context, geometryFieldName: query.geometryFieldName as string, @@ -104,6 +108,8 @@ export function initMVTRoutes({ const requestBodyDSL = rison.decode(query.requestBody as string); const gzipTileStream = await getEsGridTile({ + url: `${API_ROOT_PATH}/${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf`, + core, logger, context, geometryFieldName: query.geometryFieldName as string, diff --git a/x-pack/plugins/maps/server/routes.ts b/x-pack/plugins/maps/server/routes.ts index ec1519f20bb54..56e178741b21d 100644 --- a/x-pack/plugins/maps/server/routes.ts +++ b/x-pack/plugins/maps/server/routes.ts @@ -8,18 +8,18 @@ import { schema } from '@kbn/config-schema'; import fs from 'fs'; import path from 'path'; -import { CoreSetup, IRouter, Logger } from 'kibana/server'; +import { CoreSetup, CoreStart, IRouter, Logger } from 'kibana/server'; import { INDEX_SETTINGS_API_PATH, FONTS_API_PATH } from '../common/constants'; import { getIndexPatternSettings } from './lib/get_index_pattern_settings'; import { initMVTRoutes } from './mvt/mvt_routes'; import { initIndexingRoutes } from './data_indexing/indexing_routes'; -import { StartDeps, SetupDeps } from './types'; +import { StartDeps } from './types'; import { DataRequestHandlerContext } from '../../../../src/plugins/data/server'; -export async function initRoutes(core: CoreSetup, logger: Logger): Promise { - const router: IRouter = core.http.createRouter(); - const [, { data: dataPlugin }]: [SetupDeps, StartDeps] = - (await core.getStartServices()) as unknown as [SetupDeps, StartDeps]; +export async function initRoutes(coreSetup: CoreSetup, logger: Logger): Promise { + const router: IRouter = coreSetup.http.createRouter(); + const [coreStart, { data: dataPlugin }]: [CoreStart, StartDeps] = + (await coreSetup.getStartServices()) as unknown as [CoreStart, StartDeps]; router.get( { @@ -94,6 +94,6 @@ export async function initRoutes(core: CoreSetup, logger: Logger): Promise } ); - initMVTRoutes({ router, logger }); + initMVTRoutes({ router, logger, core: coreStart }); initIndexingRoutes({ router, logger, dataPlugin }); } diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/policy.ts b/x-pack/plugins/security_solution/common/endpoint/schema/policy.ts index dab0845dd252d..9b02ab073c9ce 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/policy.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/policy.ts @@ -19,21 +19,3 @@ export const GetAgentPolicySummaryRequestSchema = { policy_id: schema.nullable(schema.string()), }), }; - -const ListWithKuerySchema = schema.object({ - page: schema.maybe(schema.number({ defaultValue: 1 })), - pageSize: schema.maybe(schema.number({ defaultValue: 20 })), - sort: schema.maybe(schema.string()), - sortOrder: schema.maybe(schema.oneOf([schema.literal('desc'), schema.literal('asc')])), - showUpgradeable: schema.maybe(schema.boolean()), - kuery: schema.maybe( - schema.oneOf([ - schema.string(), - schema.any(), // KueryNode - ]) - ), -}); - -export const GetEndpointPackagePolicyRequestSchema = { - query: ListWithKuerySchema, -}; diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx index e0d511b23f4f8..2c09eed85b191 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx @@ -151,7 +151,7 @@ describe('When event filters delete modal is shown', () => { }); expect(coreStart.notifications.toasts.addSuccess).toHaveBeenCalledWith( - '"tic-tac-toe" has been removed from the Event Filters list.' + '"tic-tac-toe" has been removed from the event filters list.' ); }); @@ -170,7 +170,7 @@ describe('When event filters delete modal is shown', () => { }); expect(coreStart.notifications.toasts.addDanger).toHaveBeenCalledWith( - 'Unable to remove "tic-tac-toe" from the Event Filters list. Reason: oh oh' + 'Unable to remove "tic-tac-toe" from the event filters list. Reason: oh oh' ); expect(showDeleteModal(getCurrentState())).toBe(true); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.tsx index 544fa60d29b0a..75e49bf270bab 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.tsx @@ -58,7 +58,7 @@ export const EventFilterDeleteModal = memo<{}>(() => { if (wasDeleted) { toasts.addSuccess( i18n.translate('xpack.securitySolution.eventFilters.deletionDialog.deleteSuccess', { - defaultMessage: '"{name}" has been removed from the Event Filters list.', + defaultMessage: '"{name}" has been removed from the event filters list.', values: { name: eventFilter?.name }, }) ); @@ -73,7 +73,7 @@ export const EventFilterDeleteModal = memo<{}>(() => { toasts.addDanger( i18n.translate('xpack.securitySolution.eventFilters.deletionDialog.deleteFailure', { defaultMessage: - 'Unable to remove "{name}" from the Event Filters list. Reason: {message}', + 'Unable to remove "{name}" from the event filters list. Reason: {message}', values: { name: eventFilter?.name, message: deleteError.message }, }) ); diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/flyout/index.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/flyout/index.tsx index 9bffd2fc41871..95e08753b9b87 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/flyout/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/flyout/index.tsx @@ -257,7 +257,7 @@ export const EventFiltersFlyout: React.FC = memo( diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.test.tsx index e64ab09367ca8..0477e8fa5055d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.test.tsx @@ -119,7 +119,7 @@ describe('When on the host isolation exceptions delete modal', () => { await waitFor(expect(deleteOneHostIsolationExceptionItemMock).toHaveBeenCalled); expect(coreStart.notifications.toasts.addSuccess).toHaveBeenCalledWith( - '"some name" has been removed from the Host isolation exceptions list.' + '"some name" has been removed from the host isolation exceptions list.' ); expect(onCancel).toHaveBeenCalledWith(true); }); @@ -140,7 +140,7 @@ describe('When on the host isolation exceptions delete modal', () => { await waitFor(expect(deleteOneHostIsolationExceptionItemMock).toHaveBeenCalled); expect(coreStart.notifications.toasts.addDanger).toHaveBeenCalledWith( - 'Unable to remove "some name" from the Host isolation exceptions list. Reason: That\'s not true. That\'s impossible' + 'Unable to remove "some name" from the host isolation exceptions list. Reason: That\'s not true. That\'s impossible' ); expect(onCancel).toHaveBeenCalledWith(true); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.tsx index 259313f5c7ee1..c101f4884825b 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/delete_modal.tsx @@ -50,7 +50,7 @@ export const HostIsolationExceptionDeleteModal = memo( 'xpack.securitySolution.hostIsolationExceptions.deletionDialog.deleteFailure', { defaultMessage: - 'Unable to remove "{name}" from the Host isolation exceptions list. Reason: {message}', + 'Unable to remove "{name}" from the host isolation exceptions list. Reason: {message}', values: { name: item?.name, message: error.message }, } ) @@ -63,7 +63,7 @@ export const HostIsolationExceptionDeleteModal = memo( 'xpack.securitySolution.hostIsolationExceptions.deletionDialog.deleteSuccess', { defaultMessage: - '"{name}" has been removed from the Host isolation exceptions list.', + '"{name}" has been removed from the host isolation exceptions list.', values: { name: item?.name }, } ) @@ -87,7 +87,7 @@ export const HostIsolationExceptionDeleteModal = memo( diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/empty.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/empty.tsx index f4b4388086012..605229dc04c53 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/empty.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/empty.tsx @@ -30,14 +30,14 @@ export const HostIsolationExceptionsEmptyState = memo<{

} body={ } actions={[ @@ -48,7 +48,7 @@ export const HostIsolationExceptionsEmptyState = memo<{ > , diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/translations.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/translations.ts index 9504aa0673e54..2690a0e68d78d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/translations.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/translations.ts @@ -60,7 +60,7 @@ export const IP_LABEL = i18n.translate( export const IP_ERROR = i18n.translate( 'xpack.securitySolution.hostIsolationExceptions.form.ip.error', { - defaultMessage: 'The ip is invalid. Only IPv4 with optional CIDR is supported', + defaultMessage: 'The IP is invalid. Only IPv4 with optional CIDR is supported', } ); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx index b206dd708329e..097fbe97fd908 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx @@ -123,7 +123,7 @@ describe('When on the host isolation exceptions page', () => { await waitForApiCall(); expect(renderResult.getByTestId('searchExceptions')).toBeTruthy(); expect(renderResult.getByTestId('hostIsolationExceptions-totalCount').textContent).toBe( - 'Showing 1 exception' + 'Showing 1 host isolation exception' ); expect(renderResult.getByTestId('policiesSelectorButton')).toBeTruthy(); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx index 96b095826cbe2..083c7bb58e340 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx @@ -214,7 +214,7 @@ export const HostIsolationExceptionsList = () => { subtitle={ } actions={ @@ -228,7 +228,7 @@ export const HostIsolationExceptionsList = () => { > ) : ( @@ -256,7 +256,7 @@ export const HostIsolationExceptionsList = () => { placeholder={i18n.translate( 'xpack.securitySolution.hostIsolationExceptions.search.placeholder', { - defaultMessage: 'Search on the fields below: name, description, ip', + defaultMessage: 'Search on the fields below: name, description, IP', } )} /> @@ -264,7 +264,7 @@ export const HostIsolationExceptionsList = () => { diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts b/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts index 2a69d6ba4a3ab..c7ba1a5c30c22 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts @@ -820,4 +820,24 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [ } ), }, + { + key: 'windows.advanced.events.etw', + first_supported_version: '8.1', + documentation: i18n.translate( + 'xpack.securitySolution.endpoint.policy.advanced.windows.advanced.events.etw', + { + defaultMessage: 'Enable collection of ETW events. Default: true', + } + ), + }, + { + key: 'windows.advanced.diagnostic.rollback_telemetry_enabled', + first_supported_version: '8.1', + documentation: i18n.translate( + 'xpack.securitySolution.endpoint.policy.advanced.windows.advanced.diagnostic.rollback_telemetry_enabled', + { + defaultMessage: 'Enable diagnostic rollback telemetry. Default: true', + } + ), + }, ]; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/components/list.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/components/list.test.tsx index 52af3343972d4..55667a79d66a4 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/components/list.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/components/list.test.tsx @@ -63,7 +63,7 @@ describe('Policy details host isolation exceptions tab', () => { render(emptyList); expect( renderResult.getByTestId('policyDetailsHostIsolationExceptionsSearchCount') - ).toHaveTextContent('Showing 0 exceptions'); + ).toHaveTextContent('Showing 0 host isolation exceptions'); expect(renderResult.getByTestId('searchField')).toBeTruthy(); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/components/list.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/components/list.tsx index 80c35783fd99b..f8f18a2292c5d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/components/list.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/components/list.tsx @@ -160,7 +160,8 @@ export const PolicyHostIsolationExceptionsList = ({ return i18n.translate( 'xpack.securitySolution.endpoint.policy.hostIsolationExceptions.list.totalItemCount', { - defaultMessage: 'Showing {totalItemsCount, plural, one {# exception} other {# exceptions}}', + defaultMessage: + 'Showing {totalItemsCount, plural, one {# host isolation exception} other {# host isolation exceptions}}', values: { totalItemsCount: pagination.totalItemCount }, } ); @@ -179,7 +180,7 @@ export const PolicyHostIsolationExceptionsList = ({ placeholder={i18n.translate( 'xpack.securitySolution.endpoint.policy.hostIsolationExceptions.list.search.placeholder', { - defaultMessage: 'Search on the fields below: name, description, ip', + defaultMessage: 'Search on the fields below: name, description, IP', } )} defaultValue={urlParams.filter} diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/host_isolation_exceptions_tab.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/host_isolation_exceptions_tab.test.tsx index e36849796b879..e76433d670f63 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/host_isolation_exceptions_tab.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/host_isolation_exceptions_tab.test.tsx @@ -109,7 +109,7 @@ describe('Policy details host isolation exceptions tab', () => { render(); expect( await renderResult.findByTestId('policyHostIsolationExceptionsTabSubtitle') - ).toHaveTextContent('There are 4 exceptions associated with this policy'); + ).toHaveTextContent('There are 4 host isolation exceptions associated with this policy'); }); it('should apply a filter when requested from location search params', async () => { diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/host_isolation_exceptions_tab.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/host_isolation_exceptions_tab.tsx index c5281fd0407fd..e55038d6a11f2 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/host_isolation_exceptions_tab.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/host_isolation_exceptions/host_isolation_exceptions_tab.tsx @@ -89,7 +89,7 @@ export const PolicyHostIsolationExceptionsTab = ({ policy }: { policy: PolicyDat return policySearchedExceptionsListRequest.data ? ( { }); expect(notifications.toasts.addSuccess).toBeCalledWith({ - text: '"trusted app 3" has been removed from the Trusted Applications list.', + text: '"trusted app 3" has been removed from the trusted applications list.', title: 'Successfully removed', }); expect(notifications.toasts.addDanger).not.toBeCalled(); @@ -91,7 +91,7 @@ describe('TrustedAppsNotifications', () => { expect(notifications.toasts.addSuccess).not.toBeCalled(); expect(notifications.toasts.addDanger).toBeCalledWith({ - text: 'Unable to remove "trusted app 3" from the Trusted Applications list. Reason: Not Found', + text: 'Unable to remove "trusted app 3" from the trusted applications list. Reason: Not Found', title: 'Removal failure', }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_notifications.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_notifications.tsx index a86a08a894ed9..dd03636d7cc66 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_notifications.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_notifications.tsx @@ -29,7 +29,7 @@ const getDeletionErrorMessage = (error: ServerApiError, entry: Immutable) => { defaultMessage: 'Successfully removed', }), text: i18n.translate('xpack.securitySolution.trustedapps.deletionSuccess.text', { - defaultMessage: '"{name}" has been removed from the Trusted Applications list.', + defaultMessage: '"{name}" has been removed from the trusted applications list.', values: { name: entry?.name }, }), }; @@ -55,7 +55,7 @@ const getCreationSuccessMessage = (entry: Immutable) => { text: i18n.translate( 'xpack.securitySolution.trustedapps.createTrustedAppFlyout.successToastTitle', { - defaultMessage: '"{name}" has been added to the Trusted Applications list.', + defaultMessage: '"{name}" has been added to the trusted applications list.', values: { name: entry.name }, } ), diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx index 31b259c73b540..73d85077e9579 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx @@ -595,7 +595,7 @@ describe('When on the Trusted Apps Page', () => { it('should show success toast notification', () => { expect(coreStart.notifications.toasts.addSuccess.mock.calls[0][0]).toEqual({ - text: '"Generated Exception (3xnng)" has been added to the Trusted Applications list.', + text: '"Generated Exception (3xnng)" has been added to the trusted applications list.', title: 'Success!', }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.test.ts index 9ad26443cf0d5..b8efa2636d8c7 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.test.ts @@ -12,12 +12,7 @@ import { createRouteHandlerContext, } from '../../mocks'; import { createMockAgentClient, createMockAgentService } from '../../../../../fleet/server/mocks'; -import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../../fleet/common'; -import { - getHostPolicyResponseHandler, - getAgentPolicySummaryHandler, - getPolicyListHandler, -} from './handlers'; +import { getHostPolicyResponseHandler, getAgentPolicySummaryHandler } from './handlers'; import { KibanaResponseFactory, SavedObjectsClientContract, @@ -38,7 +33,6 @@ import { AgentClient, AgentService } from '../../../../../fleet/server/services' import { get } from 'lodash'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { ScopedClusterClientMock } from '../../../../../../../src/core/server/elasticsearch/client/mocks'; -import { PackagePolicyServiceInterface } from '../../../../../fleet/server'; describe('test policy response handler', () => { let endpointAppContextService: EndpointAppContextService; @@ -242,88 +236,6 @@ describe('test policy response handler', () => { }); }); }); - describe('test GET policy list handler', () => { - let mockPackagePolicyService: jest.Mocked; - let policyHandler: ReturnType; - - beforeEach(() => { - const endpointAppContextServiceStartContract = - createMockEndpointAppContextServiceStartContract(); - - mockScopedClient = elasticsearchServiceMock.createScopedClusterClient(); - mockSavedObjectClient = savedObjectsClientMock.create(); - mockResponse = httpServerMock.createResponseFactory(); - - if (endpointAppContextServiceStartContract.packagePolicyService) { - mockPackagePolicyService = - endpointAppContextServiceStartContract.packagePolicyService as jest.Mocked; - } else { - expect(endpointAppContextServiceStartContract.packagePolicyService).toBeTruthy(); - } - - mockPackagePolicyService.list.mockImplementation(() => { - return Promise.resolve({ - items: [], - total: 0, - page: 1, - perPage: 10, - }); - }); - endpointAppContextService = new EndpointAppContextService(); - endpointAppContextService.setup(createMockEndpointAppContextServiceSetupContract()); - endpointAppContextService.start(endpointAppContextServiceStartContract); - policyHandler = getPolicyListHandler({ - logFactory: loggingSystemMock.create(), - service: endpointAppContextService, - config: () => Promise.resolve(createMockConfig()), - experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), - }); - }); - - afterEach(() => endpointAppContextService.stop()); - - it('should return a list of endpoint package policies', async () => { - const mockRequest = httpServerMock.createKibanaRequest({ - query: {}, - }); - - await policyHandler( - createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), - mockRequest, - mockResponse - ); - expect(mockPackagePolicyService.list).toHaveBeenCalled(); - expect(mockPackagePolicyService.list.mock.calls[0][1]).toEqual({ - kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: endpoint`, - perPage: undefined, - sortField: undefined, - }); - expect(mockResponse.ok).toBeCalled(); - expect(mockResponse.ok.mock.calls[0][0]?.body).toEqual({ - items: [], - total: 0, - page: 1, - perPage: 10, - }); - }); - - it('should add endpoint-specific kuery to the requests kuery', async () => { - const mockRequest = httpServerMock.createKibanaRequest({ - query: { kuery: 'some query' }, - }); - - await policyHandler( - createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), - mockRequest, - mockResponse - ); - expect(mockPackagePolicyService.list.mock.calls[0][1]).toEqual({ - kuery: `(some query) and ${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: endpoint`, - perPage: undefined, - sortField: undefined, - }); - }); - }); }); /** diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.ts index beb197ec5d5f7..d02e0402a922e 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.ts @@ -11,13 +11,10 @@ import { policyIndexPattern } from '../../../../common/endpoint/constants'; import { GetPolicyResponseSchema, GetAgentPolicySummaryRequestSchema, - GetEndpointPackagePolicyRequestSchema, } from '../../../../common/endpoint/schema/policy'; import { EndpointAppContext } from '../../types'; import { getAgentPolicySummary, getPolicyResponseByAgentId } from './service'; import { GetAgentSummaryResponse } from '../../../../common/endpoint/types'; -import { wrapErrorIfNeeded } from '../../utils'; -import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../../fleet/common'; export const getHostPolicyResponseHandler = function (): RequestHandler< undefined, @@ -65,33 +62,3 @@ export const getAgentPolicySummaryHandler = function ( }); }; }; - -export const getPolicyListHandler = function ( - endpointAppContext: EndpointAppContext -): RequestHandler< - undefined, - TypeOf, - undefined -> { - return async (context, request, response) => { - const soClient = context.core.savedObjects.client; - const fleetServices = endpointAppContext.service.getScopedFleetServices(request); - const endpointFilteredKuery = `${ - request?.query?.kuery ? `(${request.query.kuery}) and ` : '' - }${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: endpoint`; - try { - const listResponse = await fleetServices.packagePolicy.list(soClient, { - ...request.query, - perPage: request.query.pageSize, - sortField: request.query.sort, - kuery: endpointFilteredKuery, - }); - - return response.ok({ - body: listResponse, - }); - } catch (error) { - throw wrapErrorIfNeeded(error); - } - }; -}; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/policy/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/policy/index.ts index 53afaadc23142..8991dfa9a6bcc 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/policy/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/policy/index.ts @@ -10,16 +10,10 @@ import { EndpointAppContext } from '../../types'; import { GetPolicyResponseSchema, GetAgentPolicySummaryRequestSchema, - GetEndpointPackagePolicyRequestSchema, } from '../../../../common/endpoint/schema/policy'; -import { - getHostPolicyResponseHandler, - getAgentPolicySummaryHandler, - getPolicyListHandler, -} from './handlers'; +import { getHostPolicyResponseHandler, getAgentPolicySummaryHandler } from './handlers'; import { AGENT_POLICY_SUMMARY_ROUTE, - BASE_POLICY_ROUTE, BASE_POLICY_RESPONSE_ROUTE, } from '../../../../common/endpoint/constants'; import { withEndpointAuthz } from '../with_endpoint_authz'; @@ -54,17 +48,4 @@ export function registerPolicyRoutes(router: IRouter, endpointAppContext: Endpoi getAgentPolicySummaryHandler(endpointAppContext) ) ); - - router.get( - { - path: BASE_POLICY_ROUTE, - validate: GetEndpointPackagePolicyRequestSchema, - options: { authRequired: true }, - }, - withEndpointAuthz( - { all: ['canAccessEndpointManagement'] }, - logger, - getPolicyListHandler(endpointAppContext) - ) - ); } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx index d3a6e94c786a4..3187021518c9c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx @@ -47,11 +47,6 @@ const actionTypeRegistry = actionTypeRegistryMock.create(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); const useKibanaMock = useKibana as jest.Mocked; -const delay = (wait: number = 1000) => - new Promise((resolve) => { - setTimeout(resolve, wait); - }); - export const TestExpression: FunctionComponent = () => { return ( @@ -64,8 +59,7 @@ export const TestExpression: FunctionComponent = () => { ); }; -// FLAKY: https://github.com/elastic/kibana/issues/g -describe.skip('alert_add', () => { +describe('alert_add', () => { let wrapper: ReactWrapper; async function setup( @@ -179,7 +173,6 @@ describe.skip('alert_add', () => { it('renders alert add flyout', async () => { const onClose = jest.fn(); await setup({}, onClose); - await delay(1000); expect(wrapper.find('[data-test-subj="addAlertFlyoutTitle"]').exists()).toBeTruthy(); expect(wrapper.find('[data-test-subj="saveAlertButton"]').exists()).toBeTruthy(); @@ -209,8 +202,6 @@ describe.skip('alert_add', () => { onClose ); - await delay(1000); - expect(wrapper.find('input#alertName').props().value).toBe('Simple status alert'); expect(wrapper.find('[data-test-subj="tagsComboBox"]').first().text()).toBe('uptimelogs'); @@ -249,7 +240,6 @@ describe.skip('alert_add', () => { it('should enforce any default inteval', async () => { await setup({ alertTypeId: 'my-alert-type' }, jest.fn(), '3h'); - await delay(1000); // Wait for handlers to fire await act(async () => { diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/routes.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/routes.ts index 111ee7739a80f..ae55eff23c579 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/routes.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/routes.ts @@ -306,6 +306,7 @@ export function defineRoutes(core: CoreSetup, { logger }: { lo await actionsClient.enqueueExecution({ id: req.params.id, spaceId: spaces ? spaces.spacesService.getSpaceId(req) : 'default', + executionId: uuid.v4(), apiKey: createAPIKeyResult ? Buffer.from(`${createAPIKeyResult.id}:${createAPIKeyResult.api_key}`).toString( 'base64' diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/event_log.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/event_log.ts index 0a4a6c76f7196..1d35595cf055d 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/event_log.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/event_log.ts @@ -124,10 +124,14 @@ export default function eventLogTests({ getService }: FtrProviderContext) { // validate each event let executeCount = 0; + let currentExecutionId; + const executionIds = []; const executeStatuses = ['ok', 'active', 'active']; for (const event of events) { switch (event?.event?.action) { case 'execute-start': + currentExecutionId = event?.kibana?.alert?.rule?.execution?.uuid; + executionIds.push(currentExecutionId); validateEvent(event, { spaceId: space.id, savedObjects: [ @@ -135,6 +139,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) { ], message: `rule execution start: "${alertId}"`, shouldHaveTask: true, + executionId: currentExecutionId, rule: { id: alertId, category: response.body.rule_type_id, @@ -153,6 +158,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) { message: `rule executed: test.patternFiring:${alertId}: 'abc'`, status: executeStatuses[executeCount++], shouldHaveTask: true, + executionId: currentExecutionId, rule: { id: alertId, category: response.body.rule_type_id, @@ -172,6 +178,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) { message: `alert: test.patternFiring:${alertId}: 'abc' instanceId: 'instance' scheduled actionGroup: 'default' action: test.noop:${createdAction.id}`, instanceId: 'instance', actionGroupId: 'default', + executionId: currentExecutionId, rule: { id: alertId, category: response.body.rule_type_id, @@ -182,16 +189,27 @@ export default function eventLogTests({ getService }: FtrProviderContext) { }); break; case 'new-instance': - validateInstanceEvent(event, `created new alert: 'instance'`, false); + validateInstanceEvent( + event, + `created new alert: 'instance'`, + false, + currentExecutionId + ); break; case 'recovered-instance': - validateInstanceEvent(event, `alert 'instance' has recovered`, true); + validateInstanceEvent( + event, + `alert 'instance' has recovered`, + true, + currentExecutionId + ); break; case 'active-instance': validateInstanceEvent( event, `active alert: 'instance' in actionGroup: 'default'`, - false + false, + currentExecutionId ); break; // this will get triggered as we add new event actions @@ -214,6 +232,10 @@ export default function eventLogTests({ getService }: FtrProviderContext) { for (const event of actionEvents) { switch (event?.event?.action) { case 'execute': + expect(event?.kibana?.alert?.rule?.execution?.uuid).not.to.be(undefined); + expect( + executionIds.indexOf(event?.kibana?.alert?.rule?.execution?.uuid) + ).to.be.greaterThan(-1); validateEvent(event, { spaceId: space.id, savedObjects: [ @@ -231,7 +253,8 @@ export default function eventLogTests({ getService }: FtrProviderContext) { function validateInstanceEvent( event: IValidatedEvent, subMessage: string, - shouldHaveEventEnd: boolean + shouldHaveEventEnd: boolean, + executionId?: string ) { validateEvent(event, { spaceId: space.id, @@ -242,6 +265,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) { instanceId: 'instance', actionGroupId: 'default', shouldHaveEventEnd, + executionId, rule: { id: alertId, category: response.body.rule_type_id, @@ -335,10 +359,12 @@ export default function eventLogTests({ getService }: FtrProviderContext) { // validate each event let executeCount = 0; + let currentExecutionId; const executeStatuses = ['ok', 'active', 'active']; for (const event of events) { switch (event?.event?.action) { case 'execute-start': + currentExecutionId = event?.kibana?.alert?.rule?.execution?.uuid; validateEvent(event, { spaceId: space.id, savedObjects: [ @@ -346,6 +372,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) { ], message: `rule execution start: "${alertId}"`, shouldHaveTask: true, + executionId: currentExecutionId, rule: { id: alertId, category: response.body.rule_type_id, @@ -364,6 +391,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) { message: `rule executed: test.patternFiring:${alertId}: 'abc'`, status: executeStatuses[executeCount++], shouldHaveTask: true, + executionId: currentExecutionId, rule: { id: alertId, category: response.body.rule_type_id, @@ -388,6 +416,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) { message: `alert: test.patternFiring:${alertId}: 'abc' instanceId: 'instance' scheduled actionGroup(subgroup): 'default(${event?.kibana?.alerting?.action_subgroup})' action: test.noop:${createdAction.id}`, instanceId: 'instance', actionGroupId: 'default', + executionId: currentExecutionId, rule: { id: alertId, category: response.body.rule_type_id, @@ -398,10 +427,20 @@ export default function eventLogTests({ getService }: FtrProviderContext) { }); break; case 'new-instance': - validateInstanceEvent(event, `created new alert: 'instance'`, false); + validateInstanceEvent( + event, + `created new alert: 'instance'`, + false, + currentExecutionId + ); break; case 'recovered-instance': - validateInstanceEvent(event, `alert 'instance' has recovered`, true); + validateInstanceEvent( + event, + `alert 'instance' has recovered`, + true, + currentExecutionId + ); break; case 'active-instance': expect( @@ -412,7 +451,8 @@ export default function eventLogTests({ getService }: FtrProviderContext) { validateInstanceEvent( event, `active alert: 'instance' in actionGroup(subgroup): 'default(${event?.kibana?.alerting?.action_subgroup})'`, - false + false, + currentExecutionId ); break; // this will get triggered as we add new event actions @@ -424,7 +464,8 @@ export default function eventLogTests({ getService }: FtrProviderContext) { function validateInstanceEvent( event: IValidatedEvent, subMessage: string, - shouldHaveEventEnd: boolean + shouldHaveEventEnd: boolean, + executionId?: string ) { validateEvent(event, { spaceId: space.id, @@ -435,6 +476,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) { instanceId: 'instance', actionGroupId: 'default', shouldHaveEventEnd, + executionId, rule: { id: alertId, category: response.body.rule_type_id, @@ -541,6 +583,7 @@ interface ValidateEventLogParams { actionGroupId?: string; instanceId?: string; reason?: string; + executionId?: string; rule?: { id: string; name?: string; @@ -555,7 +598,16 @@ interface ValidateEventLogParams { } export function validateEvent(event: IValidatedEvent, params: ValidateEventLogParams): void { - const { spaceId, savedObjects, outcome, message, errorMessage, rule, shouldHaveTask } = params; + const { + spaceId, + savedObjects, + outcome, + message, + errorMessage, + rule, + shouldHaveTask, + executionId, + } = params; const { status, actionGroupId, instanceId, reason, shouldHaveEventEnd } = params; if (status) { @@ -574,6 +626,10 @@ export function validateEvent(event: IValidatedEvent, params: ValidateEventLogPa expect(event?.event?.reason).to.be(reason); } + if (executionId) { + expect(event?.kibana?.alert?.rule?.execution?.uuid).to.be(executionId); + } + const duration = event?.event?.duration; const timestamp = Date.parse(event?.['@timestamp'] || 'undefined'); const eventStart = Date.parse(event?.event?.start || 'undefined'); diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_authz.ts b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_authz.ts index a2b03198234a6..1b9ce8911c5bf 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_authz.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_authz.ts @@ -62,11 +62,6 @@ export default function ({ getService }: FtrProviderContext) { path: '/api/endpoint/policy_response?agentId=1', body: undefined, }, - { - method: 'get', - path: '/api/endpoint/policy', - body: undefined, - }, { method: 'post', path: '/api/endpoint/isolate',