Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security Solution] Resolver retrieve entity id of documents without field mapped #76562

Merged
merged 10 commits into from
Sep 4, 2020

Conversation

jonathan-buttner
Copy link
Contributor

@jonathan-buttner jonathan-buttner commented Sep 2, 2020

This PR fixes a bug in resolver and refactors a couple things:

  • Relaxes the query to ES in the entity route so that the document doesn't have to have entity_id field mapped
    • Instead of having the ES query do the check that entity_id exists and is not empty, we use a runtime check to avoid the mapping issue
  • Refactors how timeline passes the indices to resolver
    • Now timeline passes resolver all the indices (the ones the user has defined in the settings and the .siem-signals index)

screenshots

image

@jonathan-buttner jonathan-buttner added v8.0.0 release_note:skip Skip the PR/issue when compiling release notes Team:Endpoint Data Visibility Team managing the endpoint resolver Feature:Resolver Security Solution Resolver feature v7.9.2 labels Sep 2, 2020
@jonathan-buttner jonathan-buttner requested review from a team as code owners September 2, 2020 20:09
@elasticmachine
Copy link
Contributor

Pinging @elastic/endpoint-app-team (Feature:Resolver)

@elasticmachine
Copy link
Contributor

Pinging @elastic/endpoint-data-visibility-team (Team:Endpoint Data Visibility)

import _ from 'lodash';
import { DatabaseParameters } from '../types';

export function equal(param1: DatabaseParameters, param2?: DatabaseParameters) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why add this extra abstraction layer? For the type checking?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think since timeline now sends resolver the ID and the indices we figured it'd be a good idea to combine them in a single object. Since indices is a string array we need some way to compare all the strings easily so Rob and I came up with this method. We might switch out the lodash equal though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was specifically talking about the abstraction of equal over isEqual. I understand the combined type, that makes sense. It's really more, if this equality check is going to be focused solely on checking the equality of DatabaseParameters, we know the shape, so might as well explicitly check the equality of the individual fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh you mean like, why not just use _.isEqual instead of our equal function? Or are you suggesting doing the comparisons directly in the places we're calling equal? I think @oatkiller was considering removing the lodash use so we'd have to implement an array comparison in that case. We'd probably want the array comparison at a minimum to be in a helper function because we do the DatabaseParameters check in like 3 different places I think.

I guess another option is we make DatabaseParameters into a class and move equal as a method of that class?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, that was my thought, but since it's going to be something different from isEqual, then I would just leave it. Depending on what it is, it could still be more generalized into a util, but no need to do that here anyways

oatkiller and others added 3 commits September 3, 2020 13:04
* 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
* 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
@@ -38,13 +37,6 @@ export function dataAccessLayerFactory(
});
},

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indices to use are now passed in to Resolver via props from the Security Solution app.

@@ -115,7 +115,7 @@ interface AppReceivedNewExternalProperties {
/**
* the `_id` of an ES document. This defines the origin of the Resolver graph.
*/
databaseDocumentID?: string;
databaseDocumentID: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is required by ResolverProps now should it will always be present and can always be passed to this event.

*/
databaseDocumentID: string;
parameters: TreeFetcherParameters;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of keeping track of just the databaseDocumentID used in the request, we now also keep track of the indices.


const initialState: DataState = {
relatedEvents: new Map(),
relatedEventsReady: new Map(),
resolverComponentInstanceID: undefined,
tree: {},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The data related to fetching the resolver tree is now namespaced under tree.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll likely try to move this logic into a separate nested selector in the future.

} else if (action.type === 'appAbortedResolverDataRequest') {
if (action.payload === state.pendingRequestDatabaseDocumentID) {
if (treeFetcherParameters.equal(action.payload, state.tree.pendingRequestParameters)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before we strictly compared the databaseDocumentIDs but now we use the equal method to compare the parameters.

}) {
const dispatch = useResolverDispatch();
const locationSearch = useLocation().search;
useLayoutEffect(() => {
dispatch({
type: 'appReceivedNewExternalProperties',
payload: { databaseDocumentID, resolverComponentInstanceID, locationSearch },
payload: { databaseDocumentID, resolverComponentInstanceID, locationSearch, indices },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now keep the redux store in sync with the Resolver indices prop.

@@ -137,6 +139,17 @@ const GraphOverlayComponent = ({
globalFullScreen,
]);

const { signalIndexName } = useSignalIndex();
const [siemDefaultIndices] = useUiSetting$<string[]>(DEFAULT_INDEX_KEY);
const indices: string[] = useMemo(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concat the signal indices and the SIEM default indices and pass that to Resolver.

databaseDocumentID={graphEventId}
resolverComponentInstanceID={currentTimeline.id}
/>
{graphEventId !== undefined && (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolver cannot work without a databaseDocumentID so we hold off rendering it unless we have one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is <Suspense> still not ready yet?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot that even existed.

<StyledResolver
databaseDocumentID={graphEventId}
resolverComponentInstanceID={currentTimeline.id}
indices={indices}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will render resolver with the SIEM default indices then once the signals index is fetched, it will rerender Resolver. This causes Resolver to start a request with just the default indices then cancel that request and re-request with the full set of indices.

@jonathan-buttner @XavierM Should we hold off rendering Resolver until the signals index has been fetched?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrew-goldstein Also worked on this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it probably makes sense to wait for the response from the signals index api request 🤷

@@ -64,19 +59,6 @@ export function handleEntities(): RequestHandler<unknown, TypeOf<typeof validate
values: _id,
},
},
{
exists: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By removing these checks, Resolver should work even if the new 7.9 index mappings aren't present. @jonathan-buttner Is that the right description?

Also, how should we mark this PR in release notes? Enhancement? or bug fix?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By removing these checks, Resolver should work even if the new 7.9 index mappings aren't present. @jonathan-buttner Is that the right description?

That's correct.

Also, how should we mark this PR in release notes? Enhancement? or bug fix?

@benskelker @spong This PR addresses the issue where resolver wouldn't render without the steps documented by Ben. Now resolver should render if the user upgrades their stack to 7.9.2 even if they don't perform the .siem-signals index mapping migration. Do we need to update release notes for this bug fix? If so how do I go about doing that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also to answer the original question I think it's probably a bug fix.

if (first.length !== second.length) {
return false;
}
const firstSet = new Set(first);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ It could be a WeakSet! It's your big chance WeakSet get in there! 🤣

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha I think to use a WeakSet the values would have to be objects though right? first is a string[] behind the scenes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right 😢 next time, WeakSet

*/
export function resolverComponentInstanceID(state: DataState): string {
return state.resolverComponentInstanceID ? state.resolverComponentInstanceID : '';
export function hadErrorLoadingTree(state: DataState): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❔ Suggest hadErrorLoadingLastTree to be more precise?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not opposed to it. That being said, this code will only try once. If you get an error, you'll have it for good.

Copy link
Contributor

@bkimmel bkimmel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Build metrics

@kbn/optimizer bundle module count

id value diff baseline
securitySolution 1940 +1 1939

async chunks size

id value diff baseline
securitySolution 9.8MB +8.5KB 9.8MB

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@jonathan-buttner jonathan-buttner merged commit ae093e5 into elastic:master Sep 4, 2020
@jonathan-buttner jonathan-buttner deleted the entity-upgrade-fix branch September 4, 2020 13:24
jonathan-buttner added a commit to jonathan-buttner/kibana that referenced this pull request Sep 4, 2020
…field mapped (elastic#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 <[email protected]>
jonathan-buttner added a commit that referenced this pull request Sep 4, 2020
…field mapped (#76562) (#76772)

* 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 <[email protected]>

Co-authored-by: oatkiller <[email protected]>
gmmorris added a commit to gmmorris/kibana that referenced this pull request Sep 4, 2020
* master: (47 commits)
  Do not require id & description when creating a logstash pipeline (elastic#76616)
  Remove commented src/core/tsconfig file (elastic#76792)
  Replaced whitelistedHosts with allowedHosts in actions ascii docs (elastic#76731)
  [Dashboard First] Genericize Attribute Service (elastic#76057)
  [ci-metrics] unify distributable file count metrics (elastic#76448)
  [Security Solution][Detections] Handle conflicts on alert status update (elastic#75492)
  [eslint] convert to @typescript-eslint/no-unused-expressions (elastic#76471)
  [DOCS] Add default time range filter to advanced settings (elastic#76414)
  [Security Solution] Refactor NetworkTopNFlow to use Search Strategy (elastic#76249)
  [Dashboard] Update Index Patterns when Child Index Patterns Change (elastic#76356)
  [ML] Add option to Advanced Settings to set default time range filter for AD jobs (elastic#76347)
  Add CSM app to CODEOWNERS (elastic#76793)
  [Security Solution][Exceptions] - Updates exception item find sort field (elastic#76685)
  [Security Solution][Detections][Tech Debt] - Move to using common io-ts types (elastic#75009)
  [Lens] Drag dimension to replace (elastic#75895)
  URI encode the index names we fetch in the fetchIndices lib function. (elastic#76584)
  [Security Solution] Resolver retrieve entity id of documents without field mapped (elastic#76562)
  [Ingest Manager] validate agent route using AJV instead kbn-config-schema (elastic#76546)
  Updated non-dev usages of node-forge (elastic#76699)
  [Ingest Pipelines] Processor forms for processors K-S (elastic#75638)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:Resolver Security Solution Resolver feature release_note:skip Skip the PR/issue when compiling release notes Team:Endpoint Data Visibility Team managing the endpoint resolver v7.10.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants