[Endpoint] add resolver middleware#58288
Conversation
x-pack/plugins/endpoint/public/embeddables/resolver/store/middleware.ts
Outdated
Show resolved
Hide resolved
|
Pinging @elastic/endpoint-app-team (Feature:Resolver) |
|
|
||
| export interface EndpointEvent { | ||
| '@timestamp': Date; | ||
| '@timestamp': string; |
There was a problem hiding this comment.
❔ Give the vagaries of dealing with time that you are especially familiar with, it might benefit the reader to have some comment describing what format is expected here.
There was a problem hiding this comment.
TBH I'm not sure "string" is right. Does anyone know how dates get serialized into JSON by default through hapi? The underlying value is a date equivalent in Elasticsearch, which according to the docs is stored as a 64-bit integer, so I would imagine that what we're more likely to see is that this is a number unless the elasticsearch node client/hapi combo is doing some number-->Date-->string conversion under the hood.
Then again, on second thought, this could be a string | number if we're working with the source document and just shoving it back to the client...
| type: string; | ||
| }; | ||
| endgame: { | ||
| pid: number; |
There was a problem hiding this comment.
❔ Since we're bringing these things in, it might brook a short explanation in comments (Like why is a pid not the same as a unique_pid? - things we know, but maybe are not obvious to someone who hasn't worked with us before that might be expected to read and understand this.)
| <Link | ||
| data-testid="alertTypeCellLink" | ||
| to={urlFromQueryParams({ ...queryParams, selected_alert: 'TODO' })} | ||
| to={urlFromQueryParams({ ...queryParams, selected_alert: row.event.id })} |
There was a problem hiding this comment.
❔ row could resolve to alertListData[NaN] (Div by 0) and throw if the selector ever returned 0 for pageSize. Unlikely? Or maybe use the new chaining syntax?
| height: 100%; | ||
| width: 100%; | ||
| display: flex; | ||
| flex-grow: 1; |
There was a problem hiding this comment.
❔ just flex: 1 in case it also needed a shrink?
| coreStart, | ||
| }: { | ||
| className?: string; | ||
| selectedEvent: object; |
There was a problem hiding this comment.
❔ 2 question: is selectedEvent being used (or will it)? can it be a ResolverEvent type?
| import { uniquePidForProcess, uniqueParentPidForProcess } from './process_event'; | ||
| import { IndexedProcessTree, ProcessEvent } from '../types'; | ||
| import { IndexedProcessTree } from '../types'; | ||
| import { EndpointEvent } from '../../../../common/types'; |
There was a problem hiding this comment.
❔ per @andrewstucki we will end up with two types
There was a problem hiding this comment.
Yep, looks like this interface is currently describing legacy endgame events, while our focus should be on the ECS-specified elastic-native events. Ideally we can do both to support both the legacy platform and new endpoint product through resolver, and just union their types together--but yeah, separate PR for that sometime in the future is most welcome.
There was a problem hiding this comment.
Yeah maybe eventually importing ResolverEvent and doing some type guard to narrow the type to either a LegacyEndpointEvent or EndpointEvent.
| } | ||
|
|
||
| export type ResolverAction = CameraAction | DataAction | UserBroughtProcessIntoView; | ||
| interface UserChangedSelectedEvent { |
There was a problem hiding this comment.
🔴 Follow the pattern in the file of describing actions with comments
| } = coreStart; | ||
| //const uniquePid = action.payload.selectedEvent?.value?.source.endgame.data.pid; | ||
| const uniquePid = '3096'; | ||
| const { lifecycle } = await http.get(`/api/endpoint/resolver/${uniquePid}`, { |
There was a problem hiding this comment.
❔ Looks like you could cut a little time out by doing these requests in parallel rather than in a series of awaits since they don't seem to depend on the previous one. (Or maybe that will change?)
| <StyledPanel /> | ||
| <StyledGraphControls /> | ||
| {isLoading ? ( | ||
| <div className="loading-container"> |
There was a problem hiding this comment.
❔ May want to check with a11y re: putting a live role on this.
bkimmel
left a comment
There was a problem hiding this comment.
👍 Call for a thumb when you do the revisions. I had one 🔴 about putting better comments in actions, everything else is ❔
| interface RouterProps { | ||
| basename: string; | ||
| store: Store; | ||
| coreStart: CoreStart; |
There was a problem hiding this comment.
@kqualters-elastic - maybe not for this PR, but we should consider using the kibana-react components for sharing coreStart in the app. I think the use of hooks rather than to force coreStart down to each route's View would be better DX. If we did not want to use the kibana-react components, we could just create our own react Context and set of hooks.
There was a problem hiding this comment.
agreed, updated to do just that.
| agent: { | ||
| type: string; | ||
| }; | ||
| endgame: { |
There was a problem hiding this comment.
This interface is for the new elastic endpoint events which will not have any references to endgame. I think these belong in LegacyEndpointEvent.
| import { uniquePidForProcess, uniqueParentPidForProcess } from './process_event'; | ||
| import { IndexedProcessTree, ProcessEvent } from '../types'; | ||
| import { IndexedProcessTree } from '../types'; | ||
| import { EndpointEvent } from '../../../../common/types'; |
There was a problem hiding this comment.
Yeah maybe eventually importing ResolverEvent and doing some type guard to narrow the type to either a LegacyEndpointEvent or EndpointEvent.
There was a problem hiding this comment.
We need to coordinate merging with this PR #58412, as there is overlapping code . We could base one on the other and make sure they play well together, then merge in sync.
| ({ selected_alert: selectedAlert }, alertList) => { | ||
| return (alertList.find( | ||
| alert => alert.event.id === selectedAlert | ||
| ) as unknown) as LegacyEndpointEvent; |
| } | ||
|
|
||
| public async create(initialInput: EmbeddableInput, parent?: IContainer) { | ||
| public async create(initialInput: EmbeddableInput, parent: IContainer) { |
| export type ResolverAction = CameraAction | DataAction | UserBroughtProcessIntoView; | ||
| interface UserChangedSelectedEvent { | ||
| readonly type: 'userChangedSelectedEvent'; | ||
| readonly payload: { |
There was a problem hiding this comment.
/**
* Used when the alert list selects an alert and the flyout shows resolver.
*/
| interface UserChangedSelectedEvent { | ||
| readonly type: 'userChangedSelectedEvent'; | ||
| readonly payload: { | ||
| selectedEvent?: LegacyEndpointEvent; |
There was a problem hiding this comment.
/**
* Optional because they could have unselected the event.
*/
| } | ||
|
|
||
| interface AppRequestedResolverData { | ||
| readonly type: 'appRequestedResolverData'; |
There was a problem hiding this comment.
/**
* Triggered by middleware when the data for resolver needs to be loaded. Used to set state in redux to 'loading'.
*/
| const { projectionMatrix, ref, onMouseDown } = useCamera(); | ||
| const isLoading = useSelector(selectors.isLoading); | ||
|
|
||
| useEffect(() => { |
There was a problem hiding this comment.
try useLayoutEffect. This way, if the resolver is rendered with a selected event initially, it'll dispatch the event and rerender before being flushed to the DOM. Otherwise you'll have a flash of uninitialized resolver DOM.
| // At this time, processes are provided via mock data. In the future, this test will have to provide those mocks. | ||
| const processes: ProcessEvent[] = [ | ||
| const serverResponseAction: ResolverAction = { | ||
| type: 'serverReturnedResolverData', |
There was a problem hiding this comment.
why not use the existing mock factory?
|
|
||
| export interface EndpointPluginStartDependencies {} // eslint-disable-line @typescript-eslint/no-empty-interface | ||
|
|
||
| export interface EndpointPluginServices extends Partial<CoreStart> { |
| describe('children events query', () => { | ||
| it('generates the correct legacy queries', () => { | ||
| const timestamp = new Date(); | ||
| const timestamp = new Date().getTime(); |
There was a problem hiding this comment.
consider reverting this file
There was a problem hiding this comment.
going to keep it as is, the ChildrenQuery function uses the PaginationParams interface, which has timestamp as a number https://github.com/elastic/kibana/pull/58288/files/0626d65f70f9164285fce3659c7643625a2ee085#diff-530e696bd60363b2b701f88bbb9bc6feR14
| describe('related events query', () => { | ||
| it('generates the correct legacy queries', () => { | ||
| const timestamp = new Date(); | ||
| const timestamp = new Date().getTime(); |
| <Link | ||
| data-testid="alertTypeCellLink" | ||
| to={urlFromQueryParams({ ...queryParams, selected_alert: 'TODO' })} | ||
| to={urlFromQueryParams({ ...queryParams, selected_alert: row.event.id })} |
There was a problem hiding this comment.
@kqualters-elastic We use row.id in the rest of the alert details flyout. We use row.id to fetch the details of the alert.
| uiQueryParams, | ||
| alertListData, | ||
| ({ selected_alert: selectedAlert }, alertList) => { | ||
| const found = alertList.find(alert => alert.event.id === selectedAlert); |
There was a problem hiding this comment.
These will never equal each other based on how the rest of the details flyout is implemented. We use row.id for selectedAlert.
💚 Build SucceededHistory
To update your PR or re-run it, just comment with: |
* master: (26 commits) [Endpoint] Alert Details Overview (elastic#58412) Service map language icons (elastic#58633) [SIEM] [Case] Comments to case view (elastic#58315) Remove appBasePath from docs + add mock for AppMountParameters (elastic#58775) [kbn/optimizer] fix ui/* url rewrites in dist (elastic#58627) Dashboard a11y tests (elastic#58122) Downgrade "setting up plugin" log to debug (elastic#58776) [CI] Pipeline refactoring (elastic#56447) [Advanced Settings] Fix a11y of unsaved indicator (elastic#58511) put params into short url instead of behind it (elastic#58846) show timepicker in timelion and tsvb (elastic#58857) improve graph missing workspace error message (elastic#58876) [Maps] direct Discover "visualize" to open Maps application (elastic#58549) Disallow duplicate percentiles (elastic#57444) (elastic#58299) removing references to visTypes uiExports (elastic#58337) [SIEM] Default the Timeline events filter to show All events (elastic#58953) [Remote clusters] Add indexManagement as required plugin (elastic#58915) [DOCS] Rework of main get started page (elastic#58260) [Endpoint] [Tests] fixes elastic#57946 flaky endpoint policy list test (elastic#58348) [Endpoint] add resolver middleware (elastic#58288) ...
|
Friendly reminder: Looks like this PR hasn’t been backported yet. |
* Add resolver middleware * Update types to match events, use sample events in useCamera tests * add predicate to convert alertdata to legacy endpoint event * Use mock event generator in tests * Guard against events not having agent or endpoint fields Co-authored-by: Robert Austin <robert.austin@elastic.co>
|
Looks like this PR has a backport PR but it still hasn't been merged. Please merge it ASAP to keep the branches relatively in sync. |
Summary
First pass at creating a middleware for resolver, that loads data from the recently added resolver apis. Context is passed to a new middleware for the separate resolver store that uses kibana http services to load events from the 3 recently added resolver apis.
Related issues:
https://github.com/elastic/endpoint-app-team/issues/25
https://github.com/elastic/endpoint-app-team/issues/202
Checklist
non goals
Delete any items that are not applicable to this PR.
For maintainers