[Security Solution][Resolver] New mock with cursor (#78863) (#79356)

* New mock with cursor

* include next cursor

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: Brent Kimmel <bkimmel@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Michael Olorunnisola 2020-10-05 11:30:18 -04:00 committed by GitHub
parent 45fad13396
commit a846cf7de3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 158 additions and 2 deletions

View file

@ -0,0 +1,147 @@
/*
* 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.
*/
import { DataAccessLayer } from '../../types';
import {
mockTreeWithNoAncestorsAndTwoChildrenAndRelatedEventsOnOrigin,
firstRelatedEventID,
secondRelatedEventID,
} from '../../mocks/resolver_tree';
import {
ResolverRelatedEvents,
ResolverTree,
ResolverEntityIndex,
SafeResolverEvent,
} from '../../../../common/endpoint/types';
import * as eventModel from '../../../../common/endpoint/models/event';
interface Metadata {
/**
* The `_id` of the document being analyzed.
*/
databaseDocumentID: string;
/**
* A record of entityIDs to be used in tests assertions.
*/
entityIDs: {
/**
* The entityID of the node related to the document being analyzed.
*/
origin: 'origin';
/**
* The entityID of the first child of the origin.
*/
firstChild: 'firstChild';
/**
* The entityID of the second child of the origin.
*/
secondChild: 'secondChild';
};
}
/**
* See the other mock `noAncestorsTwoChildrenWithRelatedEventsOnOrigin` but this one
* has one of the related events "after" the first (i.e. you have to call with `after` to
* get the second one).
*/
export function noAncestorsTwoChildrenWithRelatedEventsOnOriginWithOneAfterCursor(): {
dataAccessLayer: DataAccessLayer;
metadata: Metadata;
} {
const metadata: Metadata = {
databaseDocumentID: '_id',
entityIDs: { origin: 'origin', firstChild: 'firstChild', secondChild: 'secondChild' },
};
const tree = mockTreeWithNoAncestorsAndTwoChildrenAndRelatedEventsOnOrigin({
originID: metadata.entityIDs.origin,
firstChildID: metadata.entityIDs.firstChild,
secondChildID: metadata.entityIDs.secondChild,
});
return {
metadata,
dataAccessLayer: {
/**
* Fetch related events for an entity ID
*/
async relatedEvents(entityID: string): Promise<ResolverRelatedEvents> {
/**
* Respond with the mocked related events when the origin's related events are fetched.
**/
const events = entityID === metadata.entityIDs.origin ? tree.relatedEvents.events : [];
return {
entityID,
events,
nextEvent: null,
};
},
/**
* Any of the origin's related events by category.
* `entityID` must match the origin node's `process.entity_id`.
* These are split by the `after` cursor: Calling without the cursor will
* return the first event, calling with the cursor set to the id of the first event
* will return the second.
*/
async eventsWithEntityIDAndCategory(
entityID: string,
category: string,
after?: string
): Promise<{ events: SafeResolverEvent[]; nextEvent: string | null }> {
/**
* For testing: This 'fakes' the behavior of one related event being `after`
* a cursor for an earlier event.
* @param event A `SafeResolverEvent` to filter
*/
function splitOnCursor(event: SafeResolverEvent) {
if (typeof after === 'undefined') {
return eventModel.eventID(event) === firstRelatedEventID;
}
if (after === firstRelatedEventID) {
return eventModel.eventID(event) === secondRelatedEventID;
}
return false;
}
const events =
entityID === metadata.entityIDs.origin
? tree.relatedEvents.events.filter(
(event) =>
eventModel.eventCategory(event).includes(category) && splitOnCursor(event)
)
: [];
return {
events,
nextEvent: typeof after === 'undefined' ? firstRelatedEventID : null,
};
},
/**
* Any of the origin's related events by event.id
*/
async event(eventID: string): Promise<SafeResolverEvent | null> {
return (
tree.relatedEvents.events.find((event) => eventModel.eventID(event) === eventID) ?? null
);
},
/**
* Fetch a ResolverTree for a entityID
*/
async resolverTree(): Promise<ResolverTree> {
return tree;
},
/**
* Get entities matching a document.
*/
async entities(): Promise<ResolverEntityIndex> {
return [{ entity_id: metadata.entityIDs.origin }];
},
},
};
}

View file

@ -307,6 +307,15 @@ export function mockTreeWithNoProcessEvents(): ResolverTree {
};
}
/**
* first ID (to check in the mock data access layer)
*/
export const firstRelatedEventID = 'id of first related event';
/**
* second ID (to check in the mock data access layer)
*/
export const secondRelatedEventID = 'id of second related event';
export function mockTreeWithNoAncestorsAndTwoChildrenAndRelatedEventsOnOrigin({
originID,
firstChildID,
@ -326,14 +335,14 @@ export function mockTreeWithNoAncestorsAndTwoChildrenAndRelatedEventsOnOrigin({
mockEndpointEvent({
entityID: originID,
parentEntityID,
eventID: 'first related event',
eventID: firstRelatedEventID,
eventType: 'access',
eventCategory: 'registry',
}),
mockEndpointEvent({
entityID: originID,
parentEntityID,
eventID: 'second related event',
eventID: secondRelatedEventID,
eventType: 'access',
eventCategory: 'registry',
}),