Skip to content

Commit ae093e5

Browse files
jonathan-buttneroatkiller
andauthored
[Security Solution] Resolver retrieve entity id of documents without field mapped (#76562)
* More comments * Adding tests for mapping without entity_id * Removing unnecessary comments * Fixing type errors * Removing unnecessary import * Fixups and style * change 'data' state shape, nesting the tree fetcher data * rename 'TreeFetcherParameters' from 'DatabaseParameters' to make it more specific to the API it works on * fix bug in 'equal' method of 'TreeFetcherParameters'` * use mockTreeFetcherParameters method in tests that need to specify a TreeFetcherParameters but when the value isn't relevant to the test * Hide Resolver if there is no databaseDocumentID * add doc comments * Fixing test name and adding comments * Pulling in roberts test name changes * [Resolver] Only render resolver once we have a signals index Co-authored-by: oatkiller <robert.austin@elastic.co>
1 parent f7ad02d commit ae093e5

File tree

37 files changed

+3886
-261
lines changed

37 files changed

+3886
-261
lines changed

x-pack/plugins/security_solution/public/resolver/data_access_layer/factory.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
ResolverTree,
1313
ResolverEntityIndex,
1414
} from '../../../common/endpoint/types';
15-
import { DEFAULT_INDEX_KEY as defaultIndexKey } from '../../../common/constants';
1615

1716
/**
1817
* The data access layer for resolver. All communication with the Kibana server is done through this object. This object is provided to Resolver. In tests, a mock data access layer can be used instead.
@@ -38,13 +37,6 @@ export function dataAccessLayerFactory(
3837
});
3938
},
4039

41-
/**
42-
* Used to get the default index pattern from the SIEM application.
43-
*/
44-
indexPatterns(): string[] {
45-
return context.services.uiSettings.get(defaultIndexKey);
46-
},
47-
4840
/**
4941
* Used to get the entity_id for an _id.
5042
*/

x-pack/plugins/security_solution/public/resolver/data_access_layer/mocks/emptify_mock.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { mockTreeWithNoProcessEvents } from '../../mocks/resolver_tree';
1313
import { DataAccessLayer } from '../../types';
1414

15-
type EmptiableRequests = 'relatedEvents' | 'resolverTree' | 'entities' | 'indexPatterns';
15+
type EmptiableRequests = 'relatedEvents' | 'resolverTree' | 'entities';
1616

1717
interface Metadata<T> {
1818
/**
@@ -66,15 +66,6 @@ export function emptifyMock<T>(
6666
: dataAccessLayer.resolverTree(...args);
6767
},
6868

69-
/**
70-
* Get an array of index patterns that contain events.
71-
*/
72-
indexPatterns(...args): string[] {
73-
return dataShouldBeEmpty.includes('indexPatterns')
74-
? []
75-
: dataAccessLayer.indexPatterns(...args);
76-
},
77-
7869
/**
7970
* Get entities matching a document.
8071
*/

x-pack/plugins/security_solution/public/resolver/data_access_layer/mocks/no_ancestors_two_children.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,6 @@ export function noAncestorsTwoChildren(): { dataAccessLayer: DataAccessLayer; me
7878
);
7979
},
8080

81-
/**
82-
* Get an array of index patterns that contain events.
83-
*/
84-
indexPatterns(): string[] {
85-
return ['index pattern'];
86-
},
87-
8881
/**
8982
* Get entities matching a document.
9083
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import {
8+
ResolverRelatedEvents,
9+
ResolverTree,
10+
ResolverEntityIndex,
11+
} from '../../../../common/endpoint/types';
12+
import { mockEndpointEvent } from '../../mocks/endpoint_event';
13+
import { mockTreeWithNoAncestorsAnd2Children } from '../../mocks/resolver_tree';
14+
import { DataAccessLayer } from '../../types';
15+
16+
interface Metadata {
17+
/**
18+
* The `_id` of the document being analyzed.
19+
*/
20+
databaseDocumentID: string;
21+
/**
22+
* A record of entityIDs to be used in tests assertions.
23+
*/
24+
entityIDs: {
25+
/**
26+
* The entityID of the node related to the document being analyzed.
27+
*/
28+
origin: 'origin';
29+
/**
30+
* The entityID of the first child of the origin.
31+
*/
32+
firstChild: 'firstChild';
33+
/**
34+
* The entityID of the second child of the origin.
35+
*/
36+
secondChild: 'secondChild';
37+
};
38+
}
39+
40+
/**
41+
* A mock DataAccessLayer that will return an origin in two children. The `entity` response will be empty unless
42+
* `awesome_index` is passed in the indices array.
43+
*/
44+
export function noAncestorsTwoChildenInIndexCalledAwesomeIndex(): {
45+
dataAccessLayer: DataAccessLayer;
46+
metadata: Metadata;
47+
} {
48+
const metadata: Metadata = {
49+
databaseDocumentID: '_id',
50+
entityIDs: { origin: 'origin', firstChild: 'firstChild', secondChild: 'secondChild' },
51+
};
52+
return {
53+
metadata,
54+
dataAccessLayer: {
55+
/**
56+
* Fetch related events for an entity ID
57+
*/
58+
relatedEvents(entityID: string): Promise<ResolverRelatedEvents> {
59+
return Promise.resolve({
60+
entityID,
61+
events: [
62+
mockEndpointEvent({
63+
entityID,
64+
name: 'event',
65+
timestamp: 0,
66+
}),
67+
],
68+
nextEvent: null,
69+
});
70+
},
71+
72+
/**
73+
* Fetch a ResolverTree for a entityID
74+
*/
75+
resolverTree(): Promise<ResolverTree> {
76+
return Promise.resolve(
77+
mockTreeWithNoAncestorsAnd2Children({
78+
originID: metadata.entityIDs.origin,
79+
firstChildID: metadata.entityIDs.firstChild,
80+
secondChildID: metadata.entityIDs.secondChild,
81+
})
82+
);
83+
},
84+
85+
/**
86+
* Get entities matching a document.
87+
*/
88+
entities({ indices }): Promise<ResolverEntityIndex> {
89+
// Only return values if the `indices` array contains exactly `'awesome_index'`
90+
if (indices.length === 1 && indices[0] === 'awesome_index') {
91+
return Promise.resolve([{ entity_id: metadata.entityIDs.origin }]);
92+
}
93+
return Promise.resolve([]);
94+
},
95+
},
96+
};
97+
}

x-pack/plugins/security_solution/public/resolver/data_access_layer/mocks/no_ancestors_two_children_with_related_events_on_origin.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,6 @@ export function noAncestorsTwoChildrenWithRelatedEventsOnOrigin(): {
7676
return Promise.resolve(tree);
7777
},
7878

79-
/**
80-
* Get an array of index patterns that contain events.
81-
*/
82-
indexPatterns(): string[] {
83-
return ['index pattern'];
84-
},
85-
8679
/**
8780
* Get entities matching a document.
8881
*/

x-pack/plugins/security_solution/public/resolver/data_access_layer/mocks/pausify_mock.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,6 @@ export function pausifyMock<T>({
105105
return dataAccessLayer.resolverTree(...args);
106106
},
107107

108-
/**
109-
* Get an array of index patterns that contain events.
110-
*/
111-
indexPatterns(...args): string[] {
112-
return dataAccessLayer.indexPatterns(...args);
113-
},
114-
115108
/**
116109
* Get entities matching a document.
117110
*/
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { TreeFetcherParameters } from '../types';
8+
9+
/**
10+
* A factory for the most basic `TreeFetcherParameters`. Many tests need to provide this even when the values aren't relevant to the test.
11+
*/
12+
export function mockTreeFetcherParameters(): TreeFetcherParameters {
13+
return {
14+
databaseDocumentID: '',
15+
indices: [],
16+
};
17+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { TreeFetcherParameters } from '../types';
8+
9+
import { equal } from './tree_fetcher_parameters';
10+
describe('TreeFetcherParameters#equal:', () => {
11+
const cases: Array<[TreeFetcherParameters, TreeFetcherParameters, boolean]> = [
12+
// different databaseDocumentID
13+
[{ databaseDocumentID: 'a', indices: [] }, { databaseDocumentID: 'b', indices: [] }, false],
14+
// different indices length
15+
[{ databaseDocumentID: 'a', indices: [''] }, { databaseDocumentID: 'a', indices: [] }, false],
16+
// same indices length, different databaseDocumentID
17+
[{ databaseDocumentID: 'a', indices: [''] }, { databaseDocumentID: 'b', indices: [''] }, false],
18+
// 1 item in `indices`
19+
[{ databaseDocumentID: 'b', indices: [''] }, { databaseDocumentID: 'b', indices: [''] }, true],
20+
// 2 item in `indices`
21+
[
22+
{ databaseDocumentID: 'b', indices: ['1', '2'] },
23+
{ databaseDocumentID: 'b', indices: ['1', '2'] },
24+
true,
25+
],
26+
// 2 item in `indices`, but order inversed
27+
[
28+
{ databaseDocumentID: 'b', indices: ['2', '1'] },
29+
{ databaseDocumentID: 'b', indices: ['1', '2'] },
30+
true,
31+
],
32+
];
33+
describe.each(cases)('%p when compared to %p', (first, second, expected) => {
34+
it(`should ${expected ? '' : 'not'}be equal`, () => {
35+
expect(equal(first, second)).toBe(expected);
36+
});
37+
});
38+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { TreeFetcherParameters } from '../types';
8+
9+
/**
10+
* Determine if two instances of `TreeFetcherParameters` are equivalent. Use this to determine if
11+
* a change to a `TreeFetcherParameters` warrants invaliding a request or response.
12+
*/
13+
export function equal(param1: TreeFetcherParameters, param2?: TreeFetcherParameters): boolean {
14+
if (!param2) {
15+
return false;
16+
}
17+
if (param1 === param2) {
18+
return true;
19+
}
20+
if (param1.databaseDocumentID !== param2.databaseDocumentID) {
21+
return false;
22+
}
23+
return arraysContainTheSameElements(param1.indices, param2.indices);
24+
}
25+
26+
function arraysContainTheSameElements(first: unknown[], second: unknown[]): boolean {
27+
if (first === second) {
28+
return true;
29+
}
30+
if (first.length !== second.length) {
31+
return false;
32+
}
33+
const firstSet = new Set(first);
34+
for (let index = 0; index < second.length; index++) {
35+
if (!firstSet.has(second[index])) {
36+
return false;
37+
}
38+
}
39+
return true;
40+
}

x-pack/plugins/security_solution/public/resolver/store/actions.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ interface AppReceivedNewExternalProperties {
115115
/**
116116
* the `_id` of an ES document. This defines the origin of the Resolver graph.
117117
*/
118-
databaseDocumentID?: string;
118+
databaseDocumentID: string;
119119
/**
120120
* An ID that uniquely identifies this Resolver instance from other concurrent Resolvers.
121121
*/
@@ -125,6 +125,11 @@ interface AppReceivedNewExternalProperties {
125125
* The `search` part of the URL of this page.
126126
*/
127127
locationSearch: string;
128+
129+
/**
130+
* Indices that the backend will use to find the document.
131+
*/
132+
indices: string[];
128133
};
129134
}
130135

0 commit comments

Comments
 (0)