diff --git a/x-pack/plugins/session_view/common/mocks/constants/session_view_process.mock.ts b/x-pack/plugins/session_view/common/mocks/constants/session_view_process.mock.ts new file mode 100644 index 0000000000000..f99f9f1bfabbc --- /dev/null +++ b/x-pack/plugins/session_view/common/mocks/constants/session_view_process.mock.ts @@ -0,0 +1,453 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Process, ProcessEvent, EventAction, EventKind } from '../../types/process_tree'; + +const mockEvents = [ + { + '@timestamp': new Date('2021-11-23T15:25:04.210Z'), + process: { + pid: 3535, + pgid: 2442, + user: { + name: '', + id: '-1', + }, + executable: '/usr/bin/bash', + interactive: false, + entity_id: '8e4daeb2-4a4e-56c4-980e-f0dcfdbc3726', + parent: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args: [], + args_count: 0, + working_directory: '/home/vagrant', + }, + session: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args: [], + args_count: 0, + working_directory: '/home/vagrant', + }, + entry: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args: [], + args_count: 0, + working_directory: '/home/vagrant', + }, + command_line: '', + name: '', + args_count: 0, + args: [], + working_directory: '/home/vagrant', + }, + event: { + action: EventAction.fork, + category: 'process', + kind: EventKind.event, + }, + }, + { + '@timestamp': new Date('2021-11-23T15:25:04.218Z'), + process: { + pid: 3535, + pgid: 3535, + user: { + name: 'vagrant', + id: '1000', + }, + executable: '/usr/bin/vi', + interactive: true, + entity_id: '8e4daeb2-4a4e-56c4-980e-f0dcfdbc3726', + parent: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args: [], + args_count: 0, + working_directory: '/home/vagrant', + }, + session: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args: [], + args_count: 0, + working_directory: '/home/vagrant', + }, + entry: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args: [], + args_count: 0, + working_directory: '/home/vagrant', + }, + command_line: '', + name: '', + args_count: 2, + args: ['vi', 'cmd/config.ini'], + working_directory: '/home/vagrant', + }, + event: { + action: EventAction.exec, + category: 'process', + kind: EventKind.event, + }, + }, + { + '@timestamp': new Date('2021-11-23T15:25:05.202Z'), + process: { + pid: 3535, + pgid: 3535, + user: { + name: 'vagrant', + id: '1000', + }, + executable: '/usr/bin/vi', + interactive: true, + entity_id: '8e4daeb2-4a4e-56c4-980e-f0dcfdbc3726', + parent: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args: [], + args_count: 0, + working_directory: '/home/vagrant', + }, + session: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args: [], + args_count: 0, + working_directory: '/home/vagrant', + }, + entry: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args: [], + args_count: 0, + working_directory: '/home/vagrant', + }, + command_line: '', + name: '', + args_count: 2, + args: ['vi', 'cmd/config.ini'], + working_directory: '/home/vagrant', + }, + event: { + action: EventAction.exit, + category: 'process', + kind: EventKind.event, + }, + }, +]; + +const mockAlerts = [ + { + kibana: { + alert: { + rule: { + category: 'Custom Query Rule', + consumer: 'siem', + name: 'cmd test alert', + uuid: '709d3890-4c71-11ec-8c67-01ccde9db9bf', + enabled: true, + description: 'cmd test alert', + risk_score: 21, + severity: 'low', + query: "process.executable: '/usr/bin/vi'", + }, + status: 'active', + workflow_status: 'open', + reason: 'process event created low alert cmd test alert.', + original_time: new Date('2021-11-23T15:25:04.218Z'), + original_event: { + action: 'exec', + }, + uuid: '6bb22512e0e588d1a2449b61f164b216e366fba2de39e65d002ae734d71a6c38', + }, + }, + '@timestamp': new Date('2021-11-23T15:26:34.859Z'), + process: { + pid: 3535, + pgid: 3535, + user: { + name: 'vagrant', + id: '1000', + }, + executable: '/usr/bin/vi', + interactive: true, + entity_id: '8e4daeb2-4a4e-56c4-980e-f0dcfdbc3726', + parent: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args: [], + args_count: 0, + working_directory: '/home/vagrant', + }, + session: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args: [], + args_count: 0, + working_directory: '/home/vagrant', + }, + entry: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args: [], + args_count: 0, + working_directory: '/home/vagrant', + }, + command_line: '', + name: '', + args_count: 2, + args: ['vi', 'cmd/config.ini'], + working_directory: '/home/vagrant', + }, + event: { + action: EventAction.exec, + category: 'process', + kind: EventKind.signal, + }, + }, + { + kibana: { + alert: { + rule: { + category: 'Custom Query Rule', + consumer: 'siem', + name: 'cmd test alert', + uuid: '709d3890-4c71-11ec-8c67-01ccde9db9bf', + enabled: true, + description: 'cmd test alert', + risk_score: 21, + severity: 'low', + query: "process.executable: '/usr/bin/vi'", + }, + status: 'active', + workflow_status: 'open', + reason: 'process event created low alert cmd test alert.', + original_time: new Date('2021-11-23T15:25:05.202Z'), + original_event: { + action: 'exit', + }, + uuid: '2873463965b70d37ab9b2b3a90ac5a03b88e76e94ad33568285cadcefc38ed75', + }, + }, + '@timestamp': new Date('2021-11-23T15:26:34.860Z'), + process: { + pid: 3535, + pgid: 3535, + user: { + name: 'vagrant', + id: '1000', + }, + executable: '/usr/bin/vi', + interactive: true, + entity_id: '8e4daeb2-4a4e-56c4-980e-f0dcfdbc3726', + parent: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args_count: 2, + args: ['vi', 'cmd/config.ini'], + working_directory: '/home/vagrant', + }, + session: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args_count: 2, + args: ['vi', 'cmd/config.ini'], + working_directory: '/home/vagrant', + }, + entry: { + pid: 2442, + pgid: 2442, + user: { + name: '', + id: '1000', + }, + executable: '/usr/bin/bash', + interactive: true, + entity_id: '3d0192c6-7c54-5ee6-a110-3539a7cf42bc', + command_line: '', + name: '', + args_count: 2, + args: ['vi', 'cmd/config.ini'], + working_directory: '/home/vagrant', + }, + command_line: '', + name: '', + args_count: 2, + args: ['vi', 'cmd/config.ini'], + working_directory: '/home/vagrant', + }, + event: { + action: EventAction.exit, + category: 'process', + kind: EventKind.signal, + }, + }, +]; + +const processMock: Process = { + id: '3f44d854-fe8d-5666-abc9-9efe7f970b4b', + events: [], + children: [], + autoExpand: false, + searchMatched: null, + parent: undefined, + hasOutput: () => false, + hasAlerts: () => false, + getAlerts: () => [], + hasExec: () => false, + getOutput: () => '', + getDetails: () => ({} as ProcessEvent), + isUserEntered: () => false, + getMaxAlertLevel: () => null, +}; + +export const sessionViewBasicProcessMock: Process = { + ...processMock, + events: mockEvents, + hasExec: () => true, + isUserEntered: () => true, +}; + +export const sessionViewAlertProcessMock: Process = { + ...processMock, + events: [...mockEvents, ...mockAlerts], + hasAlerts: () => true, + getAlerts: () => mockEvents, + hasExec: () => true, + isUserEntered: () => true, +}; diff --git a/x-pack/plugins/session_view/common/types/process_tree/index.ts b/x-pack/plugins/session_view/common/types/process_tree/index.ts new file mode 100644 index 0000000000000..18fc08feea18c --- /dev/null +++ b/x-pack/plugins/session_view/common/types/process_tree/index.ts @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export enum EventKind { + event = 'event', + signal = 'signal', +} + +export enum EventAction { + fork = 'fork', + exec = 'exec', + exit = 'exit', + output = 'output', +} + +export interface EventActionPartition { + fork: ProcessEvent[]; + exec: ProcessEvent[]; + exit: ProcessEvent[]; + output: ProcessEvent[]; +} + +export interface User { + id: string; + name: string; +} + +export interface ProcessFields { + args: string[]; + args_count: number; + command_line: string; + entity_id: string; + executable: string; + interactive: boolean; + name: string; + working_directory: string; + pid: number; + pgid: number; + user: User; + end?: string; + exit_code?: number; +} + +export interface ProcessSelf extends ProcessFields { + parent: ProcessFields; + session: ProcessFields; + entry: ProcessFields; + last_user_entered?: ProcessFields; +} + +export interface ProcessEventHost { + architecture: string; + hostname: string; + id: string; + ip: string; + mac: string; + name: string; + os: { + family: string; + full: string; + kernel: string; + name: string; + platform: string; + type: string; + version: string; + }; +} + +export interface ProcessEventAlertRule { + category: string; + consumer: string; + description: string; + enabled: boolean; + name: string; + query: string; + risk_score: number; + severity: string; + uuid: string; +} + +export interface ProcessEventAlert { + uuid: string; + reason: string; + workflow_status: string; + status: string; + original_time: Date; + original_event: { + action: string; + }; + rule: ProcessEventAlertRule; +} + +export interface ProcessEvent { + '@timestamp': Date; + event: { + kind: EventKind; + category: string; + action: EventAction; + }; + // optional host for now (raw agent output doesn't have server identity) + host?: ProcessEventHost; + process: ProcessSelf; + kibana?: { + alert: ProcessEventAlert; + }; +} + +export interface Process { + id: string; // the process entity_id + events: ProcessEvent[]; + children: Process[]; + parent: Process | undefined; + autoExpand: boolean; + searchMatched: string | null; // either false, or set to searchQuery + hasOutput(): boolean; + hasAlerts(): boolean; + getAlerts(): ProcessEvent[]; + hasExec(): boolean; + getOutput(): string; + getDetails(): ProcessEvent; + isUserEntered(): boolean; + getMaxAlertLevel(): number | null; +} diff --git a/x-pack/plugins/session_view/jest.config.js b/x-pack/plugins/session_view/jest.config.js index 768dea8ee0182..d35db0d369468 100644 --- a/x-pack/plugins/session_view/jest.config.js +++ b/x-pack/plugins/session_view/jest.config.js @@ -14,4 +14,5 @@ module.exports = { collectCoverageFrom: [ '/x-pack/plugins/session_view/{common,public,server}/**/*.{ts,tsx}', ], + setupFiles: ['jest-canvas-mock'], }; diff --git a/x-pack/plugins/session_view/public/components/ProcessTree/index.tsx b/x-pack/plugins/session_view/public/components/ProcessTree/index.tsx index 74406bd38bf32..382ecee2165aa 100644 --- a/x-pack/plugins/session_view/public/components/ProcessTree/index.tsx +++ b/x-pack/plugins/session_view/public/components/ProcessTree/index.tsx @@ -6,7 +6,8 @@ */ import React, { useRef, useLayoutEffect, useCallback } from 'react'; import { ProcessTreeNode } from '../ProcessTreeNode'; -import { useProcessTree, ProcessEvent, Process } from '../../hooks/use_process_tree'; +import { useProcessTree } from '../../hooks/use_process_tree'; +import { ProcessEvent, Process } from '../../../common/types/process_tree'; import { useScroll } from '../../hooks/use_scroll'; import { useStyles } from './styles'; diff --git a/x-pack/plugins/session_view/public/components/ProcessTreeAlerts/index.tsx b/x-pack/plugins/session_view/public/components/ProcessTreeAlerts/index.tsx index f3c71b1f4726f..31cdaa521bbe1 100644 --- a/x-pack/plugins/session_view/public/components/ProcessTreeAlerts/index.tsx +++ b/x-pack/plugins/session_view/public/components/ProcessTreeAlerts/index.tsx @@ -16,7 +16,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { useStyles } from './styles'; -import { ProcessEvent } from '../../hooks/use_process_tree'; +import { ProcessEvent } from '../../../common/types/process_tree'; import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; import { CoreStart } from '../../../../../../src/core/public'; diff --git a/x-pack/plugins/session_view/public/components/ProcessTreeNode/index.tsx b/x-pack/plugins/session_view/public/components/ProcessTreeNode/index.tsx index 33bc259d87a27..9db6d1d69d8ba 100644 --- a/x-pack/plugins/session_view/public/components/ProcessTreeNode/index.tsx +++ b/x-pack/plugins/session_view/public/components/ProcessTreeNode/index.tsx @@ -14,7 +14,7 @@ import React, { useMemo, useRef, useLayoutEffect, useState, useEffect, MouseEvent } from 'react'; import { EuiButton, EuiIcon } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Process } from '../../hooks/use_process_tree'; +import { Process } from '../../../common/types/process_tree'; import { useStyles, ButtonType } from './styles'; import { ProcessTreeAlerts } from '../ProcessTreeAlerts'; diff --git a/x-pack/plugins/session_view/public/components/SessionView/hooks.ts b/x-pack/plugins/session_view/public/components/SessionView/hooks.ts index e290670a76995..3ffbee15986f1 100644 --- a/x-pack/plugins/session_view/public/components/SessionView/hooks.ts +++ b/x-pack/plugins/session_view/public/components/SessionView/hooks.ts @@ -9,7 +9,7 @@ import { useQuery } from 'react-query'; import { EuiSearchBarOnChangeArgs } from '@elastic/eui'; import { CoreStart } from 'kibana/public'; import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; -import { ProcessEvent } from '../../hooks/use_process_tree'; +import { ProcessEvent } from '../../../common/types/process_tree'; import { PROCESS_EVENTS_ROUTE } from '../../../common/constants'; interface ProcessEventResults { diff --git a/x-pack/plugins/session_view/public/components/SessionView/SessionView.test.tsx b/x-pack/plugins/session_view/public/components/SessionView/index.test.tsx similarity index 100% rename from x-pack/plugins/session_view/public/components/SessionView/SessionView.test.tsx rename to x-pack/plugins/session_view/public/components/SessionView/index.test.tsx diff --git a/x-pack/plugins/session_view/public/components/SessionView/index.tsx b/x-pack/plugins/session_view/public/components/SessionView/index.tsx index 2e1834d37b6ee..db61b22111c99 100644 --- a/x-pack/plugins/session_view/public/components/SessionView/index.tsx +++ b/x-pack/plugins/session_view/public/components/SessionView/index.tsx @@ -16,7 +16,7 @@ import { import { FormattedMessage } from '@kbn/i18n/react'; import { SectionLoading } from '../../shared_imports'; import { ProcessTree } from '../ProcessTree'; -import { Process } from '../../hooks/use_process_tree'; +import { Process } from '../../../common/types/process_tree'; import { SessionViewDetailPanel } from '../SessionViewDetailPanel'; import { useStyles } from './styles'; import { diff --git a/x-pack/plugins/session_view/public/components/SessionViewDetailPanel/index.test.tsx b/x-pack/plugins/session_view/public/components/SessionViewDetailPanel/index.test.tsx new file mode 100644 index 0000000000000..aaeed3f8438c2 --- /dev/null +++ b/x-pack/plugins/session_view/public/components/SessionViewDetailPanel/index.test.tsx @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + sessionViewBasicProcessMock, + sessionViewAlertProcessMock, +} from '../../../common/mocks/constants/session_view_process.mock'; +import { AppContextTestRender, createAppRootMockRenderer } from '../../test'; +import { SessionViewDetailPanel } from './index'; + +describe('SessionView component', () => { + let render: () => ReturnType; + let renderResult: ReturnType; + let mockedContext: AppContextTestRender; + + beforeEach(() => { + mockedContext = createAppRootMockRenderer(); + }); + + describe('When SessionViewDetailPanel is mounted', () => { + it('should show session detail and server detail when no process is selected', async () => { + renderResult = mockedContext.render( + jest.fn()} + /> + ); + // see if loader is present + expect(renderResult.queryByTestId('sessionViewDetailPanelCommandDetail')).toBeNull(); + expect(renderResult.queryByTestId('sessionViewDetailPanelSessionDetail')).toBeTruthy(); + expect(renderResult.queryByTestId('sessionViewDetailPanelServerDetail')).toBeTruthy(); + expect(renderResult.queryByTestId('sessionViewDetailPanelAlertDetail')).toBeNull(); + }); + + it('should show command detail when selectedProcess is present', async () => { + renderResult = mockedContext.render( + jest.fn()} + /> + ); + expect(renderResult.queryByTestId('sessionViewDetailPanelCommandDetail')).toBeTruthy(); + expect(renderResult.queryByTestId('sessionViewDetailPanelSessionDetail')).toBeTruthy(); + expect(renderResult.queryByTestId('sessionViewDetailPanelServerDetail')).toBeTruthy(); + expect(renderResult.queryByTestId('sessionViewDetailPanelAlertDetail')).toBeNull(); + }); + + it('should show command and alerts detail if selectedProcess contains a signal event', async () => { + renderResult = mockedContext.render( + jest.fn()} + /> + ); + expect(renderResult.queryByTestId('sessionViewDetailPanelCommandDetail')).toBeTruthy(); + expect(renderResult.queryByTestId('sessionViewDetailPanelSessionDetail')).toBeTruthy(); + expect(renderResult.queryByTestId('sessionViewDetailPanelServerDetail')).toBeTruthy(); + expect(renderResult.queryByTestId('sessionViewDetailPanelAlertDetail')).toBeTruthy(); + }); + }); +}); diff --git a/x-pack/plugins/session_view/public/components/SessionViewDetailPanel/index.tsx b/x-pack/plugins/session_view/public/components/SessionViewDetailPanel/index.tsx index 746e6326a8379..098d5e21bc373 100644 --- a/x-pack/plugins/session_view/public/components/SessionViewDetailPanel/index.tsx +++ b/x-pack/plugins/session_view/public/components/SessionViewDetailPanel/index.tsx @@ -9,7 +9,7 @@ import MonacoEditor from 'react-monaco-editor'; import { partition } from 'lodash'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiSpacer, EuiSplitPanel, EuiTitle, EuiTabs, EuiTab } from '@elastic/eui'; -import { EventKind, Process } from '../../hooks/use_process_tree'; +import { EventKind, Process } from '../../../common/types/process_tree'; import { useStyles } from './styles'; interface SessionViewDetailPanelDeps { @@ -83,7 +83,7 @@ export const SessionViewDetailPanel = ({ const renderSelectedProcessCommandDetail = () => { if (selectedProcess) { return ( -
+
{ if (selectedProcess && selectedProcess.hasAlerts()) { return ( -
+
@@ -147,19 +147,26 @@ export const SessionViewDetailPanel = ({ onAnimationEnd={handleAnimationEnd} > {renderSelectedProcessCommandDetail()} - - - - - - {/* Add session detail */} +
+ + + + + + {/* Add session detail */} +
- - - - - - {/* Add server detail */} +
+ + + + + + {/* Add server detail */} +
{renderSelectedProcessAlertDetail()} diff --git a/x-pack/plugins/session_view/public/components/SessionViewPage/index.tsx b/x-pack/plugins/session_view/public/components/SessionViewPage/index.tsx index 9479aa252ede8..eae4ffc20c390 100644 --- a/x-pack/plugins/session_view/public/components/SessionViewPage/index.tsx +++ b/x-pack/plugins/session_view/public/components/SessionViewPage/index.tsx @@ -14,7 +14,7 @@ import { CoreStart } from '../../../../../../src/core/public'; import { RECENT_SESSION_ROUTE, BASE_PATH } from '../../../common/constants'; import { SessionView } from '../SessionView'; -import { ProcessEvent } from '../../hooks/use_process_tree'; +import { ProcessEvent } from '../../../common/types/process_tree'; interface RecentSessionResults { hits: any[]; diff --git a/x-pack/plugins/session_view/public/hooks/use_process_tree.ts b/x-pack/plugins/session_view/public/hooks/use_process_tree.ts index 8fd3d1dd7400b..becd2804d6252 100644 --- a/x-pack/plugins/session_view/public/hooks/use_process_tree.ts +++ b/x-pack/plugins/session_view/public/hooks/use_process_tree.ts @@ -6,6 +6,13 @@ */ import _ from 'lodash'; import { useState, useEffect } from 'react'; +import { + EventAction, + EventKind, + EventActionPartition, + Process, + ProcessEvent, +} from '../../common/types/process_tree'; interface UseProcessTreeDeps { sessionEntityId: string; @@ -14,120 +21,9 @@ interface UseProcessTreeDeps { searchQuery?: string; } -export enum EventKind { - event = 'event', - signal = 'signal', -} - -export enum EventAction { - fork = 'fork', - exec = 'exec', - exit = 'exit', - output = 'output', -} - -interface EventActionPartition { - fork: ProcessEvent[]; - exec: ProcessEvent[]; - exit: ProcessEvent[]; - output: ProcessEvent[]; -} - -interface User { - id: string; - name: string; -} - -interface ProcessFields { - args: string[]; - args_count: number; - command_line: string; - entity_id: string; - executable: string; - interactive: boolean; - name: string; - working_directory: string; - pid: number; - pgid: number; - user: User; - end?: string; - exit_code?: number; -} - -export interface ProcessSelf extends ProcessFields { - parent: ProcessFields; - session: ProcessFields; - entry: ProcessFields; - last_user_entered?: ProcessFields; -} - -export interface ProcessEvent { - '@timestamp': Date; - event: { - kind: EventKind; - category: string; - action: EventAction; - }; - host?: { - // optional for now (raw agent output doesn't have server identity) - architecture: string; - hostname: string; - id: string; - ip: string; - mac: string; - name: string; - os: { - family: string; - full: string; - kernel: string; - name: string; - platform: string; - type: string; - version: string; - }; - }; - process: ProcessSelf; - kibana?: { - alert: { - uuid: string; - reason: string; - workflow_status: string; - status: string; - original_time: Date; - original_event: { - action: string; - }; - rule: { - category: string; - consumer: string; - description: string; - enabled: boolean; - name: string; - query: string; - risk_score: number; - severity: string; - uuid: string; - }; - }; - }; -} - -export interface Process { - id: string; // the process entity_id - events: ProcessEvent[]; - children: Process[]; - parent: Process | undefined; - autoExpand: boolean; - searchMatched: string | null; // either false, or set to searchQuery - hasOutput(): boolean; - hasAlerts(): boolean; - getAlerts(): ProcessEvent[]; - hasExec(): boolean; - getOutput(): string; - getDetails(): ProcessEvent; - isUserEntered(): boolean; - getMaxAlertLevel(): number | null; -} +type ProcessMap = { + [key: string]: Process; +}; class ProcessImpl implements Process { id: string; @@ -212,10 +108,6 @@ class ProcessImpl implements Process { } } -type ProcessMap = { - [key: string]: Process; -}; - export const useProcessTree = ({ sessionEntityId, forward, @@ -261,7 +153,7 @@ export const useProcessTree = ({ const buildProcessTree = (events: ProcessEvent[], backwardDirection: boolean = false) => { events.forEach((event) => { const process = processMap[event.process.entity_id]; - const parentProcess = processMap[event.process.parent.entity_id]; + const parentProcess = processMap[event.process.parent?.entity_id]; if (parentProcess) { process.parent = parentProcess; // handy for recursive operations (like auto expand)