From 591585df173073b7fb7e64009b542b84ff43fd68 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com> Date: Mon, 12 Oct 2020 13:22:33 -0400 Subject: [PATCH] [Security Solution] [Resolver] Remove related events api (#79036) * Removing old related events route * Removing outer describe block Co-authored-by: Elastic Machine --- .../common/endpoint/schema/resolver.ts | 17 - .../common/endpoint/types/index.ts | 10 - .../server/endpoint/routes/resolver.ts | 13 - .../resolver/queries/related_events.test.ts | 35 -- .../routes/resolver/queries/related_events.ts | 92 ---- .../routes/resolver/related_events.ts | 44 -- .../resolver/utils/events_query_handler.ts | 96 ---- .../endpoint/routes/resolver/utils/fetch.ts | 37 -- .../endpoint/routes/resolver/utils/node.ts | 20 - .../routes/resolver/utils/tree.test.ts | 21 +- .../endpoint/routes/resolver/utils/tree.ts | 17 - .../apis/resolver/events.ts | 422 +++++------------- .../apis/resolver/tree.ts | 5 - 13 files changed, 124 insertions(+), 705 deletions(-) delete mode 100644 x-pack/plugins/security_solution/server/endpoint/routes/resolver/queries/related_events.test.ts delete mode 100644 x-pack/plugins/security_solution/server/endpoint/routes/resolver/queries/related_events.ts delete mode 100644 x-pack/plugins/security_solution/server/endpoint/routes/resolver/related_events.ts delete mode 100644 x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/events_query_handler.ts diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/resolver.ts b/x-pack/plugins/security_solution/common/endpoint/schema/resolver.ts index a6d59615794a6..1dd5668b3177a 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/resolver.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/resolver.ts @@ -23,23 +23,6 @@ export const validateTree = { }), }; -/** - * Used to validate GET requests for non process events for a specific event. - */ -export const validateRelatedEvents = { - params: schema.object({ id: schema.string({ minLength: 1 }) }), - query: schema.object({ - events: schema.number({ defaultValue: 1000, min: 1, max: 10000 }), - afterEvent: schema.maybe(schema.string()), - legacyEndpointID: schema.maybe(schema.string({ minLength: 1 })), - }), - body: schema.nullable( - schema.object({ - filter: schema.maybe(schema.string()), - }) - ), -}; - /** * Used to validate POST requests for `/resolver/events` api. */ diff --git a/x-pack/plugins/security_solution/common/endpoint/types/index.ts b/x-pack/plugins/security_solution/common/endpoint/types/index.ts index 0054c1f1abdd5..510f1833b793b 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/index.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/index.ts @@ -197,7 +197,6 @@ export interface SafeResolverTree { */ entityID: string; children: SafeResolverChildren; - relatedEvents: Omit; relatedAlerts: Omit; ancestry: SafeResolverAncestry; lifecycle: SafeResolverEvent[]; @@ -267,15 +266,6 @@ export interface ResolverRelatedEvents { nextEvent: string | null; } -/** - * Safe version of `ResolverRelatedEvents` - */ -export interface SafeResolverRelatedEvents { - entityID: string; - events: SafeResolverEvent[]; - nextEvent: string | null; -} - /** * Response structure for the events route. * `nextEvent` will be set to null when at the time of querying there were no more results to retrieve from ES. diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver.ts index c9159032a7917..b5d657fe55a1f 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver.ts @@ -8,14 +8,12 @@ import { IRouter } from 'kibana/server'; import { EndpointAppContext } from '../types'; import { validateTree, - validateRelatedEvents, validateEvents, validateChildren, validateAncestry, validateAlerts, validateEntities, } from '../../../common/endpoint/schema/resolver'; -import { handleRelatedEvents } from './resolver/related_events'; import { handleChildren } from './resolver/children'; import { handleAncestry } from './resolver/ancestry'; import { handleTree } from './resolver/tree'; @@ -26,17 +24,6 @@ import { handleEvents } from './resolver/events'; export function registerResolverRoutes(router: IRouter, endpointAppContext: EndpointAppContext) { const log = endpointAppContext.logFactory.get('resolver'); - // this route will be removed in favor of the one below - router.post( - { - // @deprecated use `/resolver/events` instead - path: '/api/endpoint/resolver/{id}/events', - validate: validateRelatedEvents, - options: { authRequired: true }, - }, - handleRelatedEvents(log, endpointAppContext) - ); - router.post( { path: '/api/endpoint/resolver/events', diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/queries/related_events.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/queries/related_events.test.ts deleted file mode 100644 index 3ddf8fa4090d6..0000000000000 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/queries/related_events.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -/** - * @deprecated use the `events.ts` file's query instead - */ -import { EventsQuery } from './related_events'; -import { PaginationBuilder } from '../utils/pagination'; -import { legacyEventIndexPattern } from './legacy_event_index_pattern'; - -describe('Events query', () => { - it('constructs a legacy multi search query', () => { - const query = new EventsQuery(new PaginationBuilder(1), 'index-pattern', 'endpointID'); - // using any here because otherwise ts complains that it doesn't know what bool and filter are - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const msearch: any = query.buildMSearch('1234'); - expect(msearch[0].index).toBe(legacyEventIndexPattern); - expect(msearch[1].query.bool.filter[0]).toStrictEqual({ - terms: { 'endgame.unique_pid': ['1234'] }, - }); - }); - - it('constructs a non-legacy multi search query', () => { - const query = new EventsQuery(new PaginationBuilder(1), 'index-pattern'); - // using any here because otherwise ts complains that it doesn't know what bool and filter are - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const msearch: any = query.buildMSearch(['1234', '5678']); - expect(msearch[0].index).toBe('index-pattern'); - expect(msearch[1].query.bool.filter[0]).toStrictEqual({ - terms: { 'process.entity_id': ['1234', '5678'] }, - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/queries/related_events.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/queries/related_events.ts deleted file mode 100644 index f419c1fb6e1d5..0000000000000 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/queries/related_events.ts +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -/** - * @deprecated use the `events.ts` file's query instead - */ -import { SearchResponse } from 'elasticsearch'; -import { esKuery } from '../../../../../../../../src/plugins/data/server'; -import { SafeResolverEvent } from '../../../../../common/endpoint/types'; -import { ResolverQuery } from './base'; -import { PaginationBuilder } from '../utils/pagination'; -import { JsonObject } from '../../../../../../../../src/plugins/kibana_utils/common'; - -/** - * Builds a query for retrieving related events for a node. - */ -export class EventsQuery extends ResolverQuery { - private readonly kqlQuery: JsonObject[] = []; - - constructor( - private readonly pagination: PaginationBuilder, - indexPattern: string | string[], - endpointID?: string, - kql?: string - ) { - super(indexPattern, endpointID); - if (kql) { - this.kqlQuery.push(esKuery.toElasticsearchQuery(esKuery.fromKueryExpression(kql))); - } - } - - protected legacyQuery(endpointID: string, uniquePIDs: string[]): JsonObject { - return { - query: { - bool: { - filter: [ - ...this.kqlQuery, - { - terms: { 'endgame.unique_pid': uniquePIDs }, - }, - { - term: { 'agent.id': endpointID }, - }, - { - term: { 'event.kind': 'event' }, - }, - { - bool: { - must_not: { - term: { 'event.category': 'process' }, - }, - }, - }, - ], - }, - }, - ...this.pagination.buildQueryFields('endgame.serial_event_id', 'desc'), - }; - } - - protected query(entityIDs: string[]): JsonObject { - return { - query: { - bool: { - filter: [ - ...this.kqlQuery, - { - terms: { 'process.entity_id': entityIDs }, - }, - { - term: { 'event.kind': 'event' }, - }, - { - bool: { - must_not: { - term: { 'event.category': 'process' }, - }, - }, - }, - ], - }, - }, - ...this.pagination.buildQueryFields('event.id', 'desc'), - }; - } - - formatResponse(response: SearchResponse): SafeResolverEvent[] { - return this.getResults(response); - } -} diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/related_events.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/related_events.ts deleted file mode 100644 index 8fd9ab9a5ccd3..0000000000000 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/related_events.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -/** - * @deprecated use the `resolver/events` route and handler instead - */ -import { TypeOf } from '@kbn/config-schema'; -import { RequestHandler, Logger } from 'kibana/server'; -import { eventsIndexPattern, alertsIndexPattern } from '../../../../common/endpoint/constants'; -import { validateRelatedEvents } from '../../../../common/endpoint/schema/resolver'; -import { Fetcher } from './utils/fetch'; -import { EndpointAppContext } from '../../types'; - -export function handleRelatedEvents( - log: Logger, - endpointAppContext: EndpointAppContext -): RequestHandler< - TypeOf, - TypeOf, - TypeOf -> { - return async (context, req, res) => { - const { - params: { id }, - query: { events, afterEvent, legacyEndpointID: endpointID }, - body, - } = req; - try { - const client = context.core.elasticsearch.legacy.client; - - const fetcher = new Fetcher(client, id, eventsIndexPattern, alertsIndexPattern, endpointID); - - return res.ok({ - body: await fetcher.events(events, afterEvent, body?.filter), - }); - } catch (err) { - log.warn(err); - return res.internalError({ body: err }); - } - }; -} diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/events_query_handler.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/events_query_handler.ts deleted file mode 100644 index a5aa9b6c288c8..0000000000000 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/events_query_handler.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -/** - * @deprecated msearch functionality for querying events will be removed shortly - */ -import { SearchResponse } from 'elasticsearch'; -import { ILegacyScopedClusterClient } from 'kibana/server'; -import { SafeResolverRelatedEvents, SafeResolverEvent } from '../../../../../common/endpoint/types'; -import { createRelatedEvents } from './node'; -import { EventsQuery } from '../queries/related_events'; -import { PaginationBuilder } from './pagination'; -import { QueryInfo } from '../queries/multi_searcher'; -import { SingleQueryHandler } from './fetch'; - -/** - * Parameters for the RelatedEventsQueryHandler - */ -export interface RelatedEventsParams { - limit: number; - entityID: string; - indexPattern: string; - after?: string; - legacyEndpointID?: string; - filter?: string; -} - -/** - * This retrieves the related events for the origin node of a resolver tree. - */ -export class RelatedEventsQueryHandler implements SingleQueryHandler { - private relatedEvents: SafeResolverRelatedEvents | undefined; - private readonly query: EventsQuery; - private readonly limit: number; - private readonly entityID: string; - - constructor(options: RelatedEventsParams) { - this.limit = options.limit; - this.entityID = options.entityID; - - this.query = new EventsQuery( - PaginationBuilder.createBuilder(this.limit, options.after), - options.indexPattern, - options.legacyEndpointID, - options.filter - ); - } - - private handleResponse = (response: SearchResponse) => { - const results = this.query.formatResponse(response); - this.relatedEvents = createRelatedEvents( - this.entityID, - results, - PaginationBuilder.buildCursorRequestLimit(this.limit, results) - ); - }; - - /** - * Get a query to use in a msearch. - */ - nextQuery(): QueryInfo | undefined { - if (this.getResults()) { - return; - } - - return { - query: this.query, - ids: this.entityID, - handler: this.handleResponse, - }; - } - - /** - * Get the results after an msearch. - */ - getResults() { - return this.relatedEvents; - } - - /** - * Perform a normal search and return the related events results. - * - * @param client the elasticsearch client - */ - async search(client: ILegacyScopedClusterClient) { - const results = this.getResults(); - if (results) { - return results; - } - - this.handleResponse(await this.query.search(client, this.entityID)); - return this.getResults() ?? createRelatedEvents(this.entityID); - } -} diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/fetch.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/fetch.ts index 15a9639872f2a..8f17a20e182ad 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/fetch.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/fetch.ts @@ -7,7 +7,6 @@ import { ILegacyScopedClusterClient } from 'kibana/server'; import { SafeResolverChildren, - SafeResolverRelatedEvents, SafeResolverAncestry, ResolverRelatedAlerts, SafeResolverLifecycleNode, @@ -18,7 +17,6 @@ import { StatsQuery } from '../queries/stats'; import { createLifecycle } from './node'; import { MultiSearcher, QueryInfo } from '../queries/multi_searcher'; import { AncestryQueryHandler } from './ancestry_query_handler'; -import { RelatedEventsQueryHandler } from './events_query_handler'; import { RelatedAlertsQueryHandler } from './alerts_query_handler'; import { ChildrenStartQueryHandler } from './children_start_query_handler'; import { ChildrenLifecycleQueryHandler } from './children_lifecycle_query_handler'; @@ -110,14 +108,6 @@ export class Fetcher { this.endpointID ); - const eventsHandler = new RelatedEventsQueryHandler({ - limit: options.events, - entityID: this.id, - after: options.afterEvent, - indexPattern: this.eventsIndexPattern, - legacyEndpointID: this.endpointID, - }); - const alertsHandler = new RelatedAlertsQueryHandler({ limit: options.alerts, entityID: this.id, @@ -139,7 +129,6 @@ export class Fetcher { const msearch = new MultiSearcher(this.client); let queries: QueryInfo[] = []; - addQueryToList(eventsHandler, queries); addQueryToList(alertsHandler, queries); addQueryToList(childrenHandler, queries); addQueryToList(originHandler, queries); @@ -176,7 +165,6 @@ export class Fetcher { const tree = new Tree(this.id, { ancestry: ancestryHandler.getResults(), - relatedEvents: eventsHandler.getResults(), relatedAlerts: alertsHandler.getResults(), children: childrenLifecycleHandler.getResults(), }); @@ -225,31 +213,6 @@ export class Fetcher { return childrenLifecycleHandler.search(this.client); } - /** - * Retrieves the related events for the origin node. - * - * @param limit the upper bound number of related events to return. The limit is applied after the cursor is used to - * skip the previous results. - * @param after a cursor to use as the starting point for retrieving related events - * @param filter a kql query for filtering the results - */ - public async events( - limit: number, - after?: string, - filter?: string - ): Promise { - const eventsHandler = new RelatedEventsQueryHandler({ - limit, - entityID: this.id, - after, - indexPattern: this.eventsIndexPattern, - legacyEndpointID: this.endpointID, - filter, - }); - - return eventsHandler.search(this.client); - } - /** * Retrieves the alerts for the origin node. * diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/node.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/node.ts index cecdc8a478958..286564d9302c1 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/node.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/node.ts @@ -12,25 +12,9 @@ import { SafeResolverLifecycleNode, SafeResolverEvent, SafeResolverChildNode, - SafeResolverRelatedEvents, ResolverPaginatedEvents, } from '../../../../../common/endpoint/types'; -/** - * Creates a related event object that the related events handler would return - * - * @param entityID the entity_id for these related events - * @param events array of related events - * @param nextEvent the cursor to retrieve the next related event - */ -export function createRelatedEvents( - entityID: string, - events: SafeResolverEvent[] = [], - nextEvent: string | null = null -): SafeResolverRelatedEvents { - return { entityID, events, nextEvent }; -} - /** * Creates an object that the events handler would return * @@ -116,10 +100,6 @@ export function createTree(entityID: string): SafeResolverTree { childNodes: [], nextChild: null, }, - relatedEvents: { - events: [], - nextEvent: null, - }, relatedAlerts: { alerts: [], nextAlert: null, diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/tree.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/tree.test.ts index 290af87a61b1d..ce933380e9f34 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/tree.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/tree.test.ts @@ -6,11 +6,7 @@ import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; import { Tree } from './tree'; -import { - SafeResolverAncestry, - SafeResolverEvent, - SafeResolverRelatedEvents, -} from '../../../../../common/endpoint/types'; +import { SafeResolverAncestry, SafeResolverEvent } from '../../../../../common/endpoint/types'; import { entityIDSafeVersion } from '../../../../../common/endpoint/models/event'; describe('Tree', () => { @@ -46,19 +42,4 @@ describe('Tree', () => { expect(tree.render().ancestry.nextAncestor).toEqual('hello'); }); }); - - describe('related events', () => { - it('adds related events to the tree', () => { - const root = generator.generateEvent(); - const events: SafeResolverRelatedEvents = { - entityID: entityIDSafeVersion(root) ?? '', - events: Array.from(generator.relatedEventsGenerator(root)), - nextEvent: null, - }; - const tree = new Tree(entityIDSafeVersion(root) ?? '', { relatedEvents: events }); - const rendered = tree.render(); - expect(rendered.relatedEvents.nextEvent).toBeNull(); - expect(rendered.relatedEvents.events).toStrictEqual(events.events); - }); - }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/tree.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/tree.ts index dd493d70ffcd3..26ac15e73759a 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/tree.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/tree.ts @@ -8,7 +8,6 @@ import _ from 'lodash'; import { SafeResolverEvent, ResolverNodeStats, - SafeResolverRelatedEvents, SafeResolverAncestry, SafeResolverTree, SafeResolverChildren, @@ -23,7 +22,6 @@ interface Node { } export interface Options { - relatedEvents?: SafeResolverRelatedEvents; ancestry?: SafeResolverAncestry; children?: SafeResolverChildren; relatedAlerts?: ResolverRelatedAlerts; @@ -44,7 +42,6 @@ export class Tree { this.tree = tree; this.cache.set(id, tree); - this.addRelatedEvents(options.relatedEvents); this.addAncestors(options.ancestry); this.addChildren(options.children); this.addRelatedAlerts(options.relatedAlerts); @@ -68,20 +65,6 @@ export class Tree { return [...this.cache.keys()]; } - /** - * Add related events for the tree's origin node. Related events cannot be added for other nodes. - * - * @param relatedEventsInfo is the related events and pagination information to add to the tree. - */ - private addRelatedEvents(relatedEventsInfo: SafeResolverRelatedEvents | undefined) { - if (!relatedEventsInfo) { - return; - } - - this.tree.relatedEvents.events = relatedEventsInfo.events; - this.tree.relatedEvents.nextEvent = relatedEventsInfo.nextEvent; - } - /** * Add alerts for the tree's origin node. Alerts cannot be added for other nodes. * diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/resolver/events.ts b/x-pack/test/security_solution_endpoint_api_int/apis/resolver/events.ts index b57486ee55ca4..0878c09cff500 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/resolver/events.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/resolver/events.ts @@ -5,10 +5,7 @@ */ import expect from '@kbn/expect'; import { eventIDSafeVersion } from '../../../../plugins/security_solution/common/endpoint/models/event'; -import { - ResolverPaginatedEvents, - SafeResolverRelatedEvents, -} from '../../../../plugins/security_solution/common/endpoint/types'; +import { ResolverPaginatedEvents } from '../../../../plugins/security_solution/common/endpoint/types'; import { FtrProviderContext } from '../../ftr_provider_context'; import { Tree, @@ -20,7 +17,6 @@ import { compareArrays } from './common'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const resolver = getService('resolverGenerator'); - const esArchiver = getService('esArchiver'); const relatedEventsToGen = [ { category: RelatedEventCategory.Driver, count: 2 }, @@ -44,308 +40,136 @@ export default function ({ getService }: FtrProviderContext) { ancestryArraySize: 2, }; - describe('event routes', () => { - describe('related events route', () => { - before(async () => { - await esArchiver.load('endpoint/resolver/api_feature'); - resolverTrees = await resolver.createTrees(treeOptions); - // we only requested a single alert so there's only 1 tree - tree = resolverTrees.trees[0]; - }); - after(async () => { - await resolver.deleteData(resolverTrees); - await esArchiver.unload('endpoint/resolver/api_feature'); - }); - - describe('legacy events', () => { - const endpointID = '5a0c957f-b8e7-4538-965e-57e8bb86ad3a'; - const entityID = '94042'; - const cursor = 'eyJ0aW1lc3RhbXAiOjE1ODE0NTYyNTUwMDAsImV2ZW50SUQiOiI5NDA0MyJ9'; - - it('should return details for the root node', async () => { - const { body }: { body: SafeResolverRelatedEvents } = await supertest - .post(`/api/endpoint/resolver/${entityID}/events?legacyEndpointID=${endpointID}`) - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(body.events.length).to.eql(1); - expect(body.entityID).to.eql(entityID); - expect(body.nextEvent).to.eql(null); - }); - - it('returns no values when there is no more data', async () => { - const { body }: { body: SafeResolverRelatedEvents } = await supertest - // after is set to the document id of the last event so there shouldn't be any more after it - .post( - `/api/endpoint/resolver/${entityID}/events?legacyEndpointID=${endpointID}&afterEvent=${cursor}` - ) - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(body.events).be.empty(); - expect(body.entityID).to.eql(entityID); - expect(body.nextEvent).to.eql(null); - }); - - it('should return the first page of information when the cursor is invalid', async () => { - const { body }: { body: SafeResolverRelatedEvents } = await supertest - .post( - `/api/endpoint/resolver/${entityID}/events?legacyEndpointID=${endpointID}&afterEvent=blah` - ) - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(body.entityID).to.eql(entityID); - expect(body.nextEvent).to.eql(null); - }); - - it('should return no results for an invalid endpoint ID', async () => { - const { body }: { body: SafeResolverRelatedEvents } = await supertest - .post(`/api/endpoint/resolver/${entityID}/events?legacyEndpointID=foo`) - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(body.nextEvent).to.eql(null); - expect(body.entityID).to.eql(entityID); - expect(body.events).to.be.empty(); - }); - - it('should error on invalid pagination values', async () => { - await supertest - .post(`/api/endpoint/resolver/${entityID}/events?events=0`) - .set('kbn-xsrf', 'xxx') - .expect(400); - await supertest - .post(`/api/endpoint/resolver/${entityID}/events?events=20000`) - .set('kbn-xsrf', 'xxx') - .expect(400); - await supertest - .post(`/api/endpoint/resolver/${entityID}/events?events=-1`) - .set('kbn-xsrf', 'xxx') - .expect(400); - }); - }); - - describe('endpoint events', () => { - it('should not find any events', async () => { - const { body }: { body: SafeResolverRelatedEvents } = await supertest - .post(`/api/endpoint/resolver/5555/events`) - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(body.nextEvent).to.eql(null); - expect(body.events).to.be.empty(); - }); - - it('should return details for the root node', async () => { - const { body }: { body: SafeResolverRelatedEvents } = await supertest - .post(`/api/endpoint/resolver/${tree.origin.id}/events`) - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(body.events.length).to.eql(4); - compareArrays(tree.origin.relatedEvents, body.events, true); - expect(body.nextEvent).to.eql(null); - }); - - it('should allow for the events to be filtered', async () => { - const filter = `event.category:"${RelatedEventCategory.Driver}"`; - const { body }: { body: SafeResolverRelatedEvents } = await supertest - .post(`/api/endpoint/resolver/${tree.origin.id}/events`) - .set('kbn-xsrf', 'xxx') - .send({ - filter, - }) - .expect(200); - expect(body.events.length).to.eql(2); - compareArrays(tree.origin.relatedEvents, body.events); - expect(body.nextEvent).to.eql(null); - for (const event of body.events) { - expect(event.event?.category).to.be(RelatedEventCategory.Driver); - } - }); - - it('should return paginated results for the root node', async () => { - let { body }: { body: SafeResolverRelatedEvents } = await supertest - .post(`/api/endpoint/resolver/${tree.origin.id}/events?events=2`) - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(body.events.length).to.eql(2); - compareArrays(tree.origin.relatedEvents, body.events); - expect(body.nextEvent).not.to.eql(null); - - ({ body } = await supertest - .post( - `/api/endpoint/resolver/${tree.origin.id}/events?events=2&afterEvent=${body.nextEvent}` - ) - .set('kbn-xsrf', 'xxx') - .expect(200)); - expect(body.events.length).to.eql(2); - compareArrays(tree.origin.relatedEvents, body.events); - expect(body.nextEvent).to.not.eql(null); - - ({ body } = await supertest - .post( - `/api/endpoint/resolver/${tree.origin.id}/events?events=2&afterEvent=${body.nextEvent}` - ) - .set('kbn-xsrf', 'xxx') - .expect(200)); - expect(body.events).to.be.empty(); - expect(body.nextEvent).to.eql(null); - }); - - it('should return the first page of information when the cursor is invalid', async () => { - const { body }: { body: SafeResolverRelatedEvents } = await supertest - .post(`/api/endpoint/resolver/${tree.origin.id}/events?afterEvent=blah`) - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(body.events.length).to.eql(4); - compareArrays(tree.origin.relatedEvents, body.events, true); - expect(body.nextEvent).to.eql(null); - }); - - it('should sort the events in descending order', async () => { - const { body }: { body: SafeResolverRelatedEvents } = await supertest - .post(`/api/endpoint/resolver/${tree.origin.id}/events`) - .set('kbn-xsrf', 'xxx') - .expect(200); - expect(body.events.length).to.eql(4); - // these events are created in the order they are defined in the array so the newest one is - // the last element in the array so let's reverse it - const relatedEvents = tree.origin.relatedEvents.reverse(); - for (let i = 0; i < body.events.length; i++) { - expect(body.events[i].event?.category).to.equal(relatedEvents[i].event?.category); - expect(eventIDSafeVersion(body.events[i])).to.equal(relatedEvents[i].event?.id); - } - }); - }); + describe('event route', () => { + let entityIDFilter: string | undefined; + before(async () => { + resolverTrees = await resolver.createTrees(treeOptions); + // we only requested a single alert so there's only 1 tree + tree = resolverTrees.trees[0]; + entityIDFilter = `process.entity_id:"${tree.origin.id}" and not event.category:"process"`; + }); + after(async () => { + await resolver.deleteData(resolverTrees); }); - describe('kql events route', () => { - let entityIDFilter: string | undefined; - before(async () => { - resolverTrees = await resolver.createTrees(treeOptions); - // we only requested a single alert so there's only 1 tree - tree = resolverTrees.trees[0]; - entityIDFilter = `process.entity_id:"${tree.origin.id}" and not event.category:"process"`; - }); - after(async () => { - await resolver.deleteData(resolverTrees); - }); - - it('should filter events by event.id', async () => { - const { body }: { body: ResolverPaginatedEvents } = await supertest - .post(`/api/endpoint/resolver/events`) - .set('kbn-xsrf', 'xxx') - .send({ - filter: `event.id:"${tree.origin.relatedEvents[0]?.event?.id}"`, - }) - .expect(200); - expect(body.events.length).to.eql(1); - expect(tree.origin.relatedEvents[0]?.event?.id).to.eql(body.events[0].event?.id); - expect(body.nextEvent).to.eql(null); - }); - - it('should not find any events when given an invalid entity id', async () => { - const { body }: { body: ResolverPaginatedEvents } = await supertest - .post(`/api/endpoint/resolver/events`) - .set('kbn-xsrf', 'xxx') - .send({ - filter: 'process.entity_id:"5555"', - }) - .expect(200); - expect(body.nextEvent).to.eql(null); - expect(body.events).to.be.empty(); - }); - - it('should return related events for the root node', async () => { - const { body }: { body: ResolverPaginatedEvents } = await supertest - .post(`/api/endpoint/resolver/events`) - .set('kbn-xsrf', 'xxx') - .send({ - filter: entityIDFilter, - }) - .expect(200); - expect(body.events.length).to.eql(4); - compareArrays(tree.origin.relatedEvents, body.events, true); - expect(body.nextEvent).to.eql(null); - }); + it('should filter events by event.id', async () => { + const { body }: { body: ResolverPaginatedEvents } = await supertest + .post(`/api/endpoint/resolver/events`) + .set('kbn-xsrf', 'xxx') + .send({ + filter: `event.id:"${tree.origin.relatedEvents[0]?.event?.id}"`, + }) + .expect(200); + expect(body.events.length).to.eql(1); + expect(tree.origin.relatedEvents[0]?.event?.id).to.eql(body.events[0].event?.id); + expect(body.nextEvent).to.eql(null); + }); - it('should allow for the events to be filtered', async () => { - const filter = `event.category:"${RelatedEventCategory.Driver}" and ${entityIDFilter}`; - const { body }: { body: ResolverPaginatedEvents } = await supertest - .post(`/api/endpoint/resolver/events`) - .set('kbn-xsrf', 'xxx') - .send({ - filter, - }) - .expect(200); - expect(body.events.length).to.eql(2); - compareArrays(tree.origin.relatedEvents, body.events); - expect(body.nextEvent).to.eql(null); - for (const event of body.events) { - expect(event.event?.category).to.be(RelatedEventCategory.Driver); - } - }); + it('should not find any events when given an invalid entity id', async () => { + const { body }: { body: ResolverPaginatedEvents } = await supertest + .post(`/api/endpoint/resolver/events`) + .set('kbn-xsrf', 'xxx') + .send({ + filter: 'process.entity_id:"5555"', + }) + .expect(200); + expect(body.nextEvent).to.eql(null); + expect(body.events).to.be.empty(); + }); - it('should return paginated results for the root node', async () => { - let { body }: { body: ResolverPaginatedEvents } = await supertest - .post(`/api/endpoint/resolver/events?limit=2`) - .set('kbn-xsrf', 'xxx') - .send({ - filter: entityIDFilter, - }) - .expect(200); - expect(body.events.length).to.eql(2); - compareArrays(tree.origin.relatedEvents, body.events); - expect(body.nextEvent).not.to.eql(null); + it('should return related events for the root node', async () => { + const { body }: { body: ResolverPaginatedEvents } = await supertest + .post(`/api/endpoint/resolver/events`) + .set('kbn-xsrf', 'xxx') + .send({ + filter: entityIDFilter, + }) + .expect(200); + expect(body.events.length).to.eql(4); + compareArrays(tree.origin.relatedEvents, body.events, true); + expect(body.nextEvent).to.eql(null); + }); - ({ body } = await supertest - .post(`/api/endpoint/resolver/events?limit=2&afterEvent=${body.nextEvent}`) - .set('kbn-xsrf', 'xxx') - .send({ - filter: entityIDFilter, - }) - .expect(200)); - expect(body.events.length).to.eql(2); - compareArrays(tree.origin.relatedEvents, body.events); - expect(body.nextEvent).to.not.eql(null); + it('should allow for the events to be filtered', async () => { + const filter = `event.category:"${RelatedEventCategory.Driver}" and ${entityIDFilter}`; + const { body }: { body: ResolverPaginatedEvents } = await supertest + .post(`/api/endpoint/resolver/events`) + .set('kbn-xsrf', 'xxx') + .send({ + filter, + }) + .expect(200); + expect(body.events.length).to.eql(2); + compareArrays(tree.origin.relatedEvents, body.events); + expect(body.nextEvent).to.eql(null); + for (const event of body.events) { + expect(event.event?.category).to.be(RelatedEventCategory.Driver); + } + }); - ({ body } = await supertest - .post(`/api/endpoint/resolver/events?limit=2&afterEvent=${body.nextEvent}`) - .set('kbn-xsrf', 'xxx') - .send({ - filter: entityIDFilter, - }) - .expect(200)); - expect(body.events).to.be.empty(); - expect(body.nextEvent).to.eql(null); - }); + it('should return paginated results for the root node', async () => { + let { body }: { body: ResolverPaginatedEvents } = await supertest + .post(`/api/endpoint/resolver/events?limit=2`) + .set('kbn-xsrf', 'xxx') + .send({ + filter: entityIDFilter, + }) + .expect(200); + expect(body.events.length).to.eql(2); + compareArrays(tree.origin.relatedEvents, body.events); + expect(body.nextEvent).not.to.eql(null); + + ({ body } = await supertest + .post(`/api/endpoint/resolver/events?limit=2&afterEvent=${body.nextEvent}`) + .set('kbn-xsrf', 'xxx') + .send({ + filter: entityIDFilter, + }) + .expect(200)); + expect(body.events.length).to.eql(2); + compareArrays(tree.origin.relatedEvents, body.events); + expect(body.nextEvent).to.not.eql(null); + + ({ body } = await supertest + .post(`/api/endpoint/resolver/events?limit=2&afterEvent=${body.nextEvent}`) + .set('kbn-xsrf', 'xxx') + .send({ + filter: entityIDFilter, + }) + .expect(200)); + expect(body.events).to.be.empty(); + expect(body.nextEvent).to.eql(null); + }); - it('should return the first page of information when the cursor is invalid', async () => { - const { body }: { body: ResolverPaginatedEvents } = await supertest - .post(`/api/endpoint/resolver/events?afterEvent=blah`) - .set('kbn-xsrf', 'xxx') - .send({ - filter: entityIDFilter, - }) - .expect(200); - expect(body.events.length).to.eql(4); - compareArrays(tree.origin.relatedEvents, body.events, true); - expect(body.nextEvent).to.eql(null); - }); + it('should return the first page of information when the cursor is invalid', async () => { + const { body }: { body: ResolverPaginatedEvents } = await supertest + .post(`/api/endpoint/resolver/events?afterEvent=blah`) + .set('kbn-xsrf', 'xxx') + .send({ + filter: entityIDFilter, + }) + .expect(200); + expect(body.events.length).to.eql(4); + compareArrays(tree.origin.relatedEvents, body.events, true); + expect(body.nextEvent).to.eql(null); + }); - it('should sort the events in descending order', async () => { - const { body }: { body: ResolverPaginatedEvents } = await supertest - .post(`/api/endpoint/resolver/events`) - .set('kbn-xsrf', 'xxx') - .send({ - filter: entityIDFilter, - }) - .expect(200); - expect(body.events.length).to.eql(4); - // these events are created in the order they are defined in the array so the newest one is - // the last element in the array so let's reverse it - const relatedEvents = tree.origin.relatedEvents.reverse(); - for (let i = 0; i < body.events.length; i++) { - expect(body.events[i].event?.category).to.equal(relatedEvents[i].event?.category); - expect(eventIDSafeVersion(body.events[i])).to.equal(relatedEvents[i].event?.id); - } - }); + it('should sort the events in descending order', async () => { + const { body }: { body: ResolverPaginatedEvents } = await supertest + .post(`/api/endpoint/resolver/events`) + .set('kbn-xsrf', 'xxx') + .send({ + filter: entityIDFilter, + }) + .expect(200); + expect(body.events.length).to.eql(4); + // these events are created in the order they are defined in the array so the newest one is + // the last element in the array so let's reverse it + const relatedEvents = tree.origin.relatedEvents.reverse(); + for (let i = 0; i < body.events.length; i++) { + expect(body.events[i].event?.category).to.equal(relatedEvents[i].event?.category); + expect(eventIDSafeVersion(body.events[i])).to.equal(relatedEvents[i].event?.id); + } }); }); } diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/resolver/tree.ts b/x-pack/test/security_solution_endpoint_api_int/apis/resolver/tree.ts index 837af6a940f5c..7a95bf7bab883 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/resolver/tree.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/resolver/tree.ts @@ -340,10 +340,8 @@ export default function ({ getService }: FtrProviderContext) { .get(`/api/endpoint/resolver/93933?legacyEndpointID=${endpointID}`) .expect(200); expect(body.ancestry.nextAncestor).to.equal(null); - expect(body.relatedEvents.nextEvent).to.equal(null); expect(body.children.nextChild).to.equal(null); expect(body.children.childNodes.length).to.equal(0); - expect(body.relatedEvents.events.length).to.equal(0); expect(body.lifecycle.length).to.equal(2); }); }); @@ -365,9 +363,6 @@ export default function ({ getService }: FtrProviderContext) { verifyAncestry(body.ancestry.ancestors, tree, true); verifyLifecycleStats(body.ancestry.ancestors, relatedEventsToGen, relatedAlerts); - expect(body.relatedEvents.nextEvent).to.equal(null); - compareArrays(tree.origin.relatedEvents, body.relatedEvents.events, true); - expect(body.relatedAlerts.nextAlert).to.equal(null); compareArrays(tree.origin.relatedAlerts, body.relatedAlerts.alerts, true);