From 0a5b4233d16addb309eb9ca980fcf9af2cc68074 Mon Sep 17 00:00:00 2001 From: Karl Godard Date: Mon, 17 Apr 2023 16:22:28 -0700 Subject: [PATCH] Session view and k8s dashboard fixes (#154982) ## Summary - fixes some issues in session_view wrt to logs-cloud_defend.process* data. - added a 'collapse all' children feature. with sticky scroll session leader! - k8s dashboard session table: user.name -> user.id (id is more likely to be set for both endpoint and cloud-defend) - Fixed a major bug when 'searching within terminal'. If a process is highlighted it would cause kibana to blow up. - session view handling of session leader user info improved. - codeowners updated. awp-viz -> sec-cloudnative-integrations - a badge will be added to the selector header when it's not in used by a response flow ### Screenshots ![image](https://user-images.githubusercontent.com/16198204/232567236-98e57a3a-913c-4a25-8271-e1ee138b25dd.png) Sticky session leader demo: https://www.loom.com/share/b039e48fdfd647b291f293d643339660 ### Checklist Delete any items that are not applicable to this PR. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .github/CODEOWNERS | 8 ++-- api_docs/kubernetes_security.mdx | 2 +- api_docs/plugin_directory.mdx | 4 +- api_docs/session_view.mdx | 2 +- renovate.json | 2 +- .../cloud_defend/public/common/utils.test.ts | 3 +- .../components/control_general_view/index.tsx | 5 +++ .../control_general_view/translations.ts | 8 ++++ .../index.test.tsx | 7 +++ .../control_general_view_selector/index.tsx | 28 +++++++----- .../hooks/policy_schema.json | 20 --------- .../control_yaml_view/index.test.tsx | 2 +- .../plugins/cloud_defend/public/test/mocks.ts | 4 +- x-pack/plugins/cloud_defend/public/types.ts | 9 +--- .../plugins/kubernetes_security/kibana.jsonc | 2 +- .../__snapshots__/index.test.tsx.snap | 2 +- .../sessions_viewer/default_headers.ts | 6 +-- .../sessions_viewer/translations.ts | 6 +-- .../common/types/process_tree/index.ts | 2 +- x-pack/plugins/session_view/kibana.jsonc | 2 +- .../detail_panel_alert_list_item/index.tsx | 4 +- .../public/components/process_tree/helpers.ts | 14 ++++++ .../public/components/process_tree/index.tsx | 12 ++++++ .../public/components/process_tree/styles.ts | 2 - .../__snapshots__/index.test.tsx.snap | 2 + .../process_tree_node/index.test.tsx | 2 +- .../components/process_tree_node/index.tsx | 43 ++++++++++++++++--- .../components/process_tree_node/styles.ts | 26 ++++++++--- .../process_tree_node/text_highlight.tsx | 1 - .../public/components/session_view/index.tsx | 4 ++ .../utils/alert_category_display_test.test.ts | 10 ++--- .../utils/alert_category_display_text.ts | 2 +- .../translations/translations/fr-FR.json | 2 - .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 35 files changed, 162 insertions(+), 90 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d2825a26e3b15..80515067f7294 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -431,7 +431,7 @@ src/plugins/kibana_overview @elastic/appex-sharedux src/plugins/kibana_react @elastic/appex-sharedux src/plugins/kibana_usage_collection @elastic/kibana-core src/plugins/kibana_utils @elastic/kibana-app-services -x-pack/plugins/kubernetes_security @elastic/awp-viz +x-pack/plugins/kubernetes_security @elastic/sec-cloudnative-integrations packages/kbn-language-documentation-popover @elastic/kibana-visualizations x-pack/plugins/lens @elastic/kibana-visualizations x-pack/plugins/license_api_guard @elastic/platform-deployment-management @@ -567,7 +567,7 @@ packages/kbn-securitysolution-utils @elastic/security-solution-platform packages/kbn-server-http-tools @elastic/kibana-core packages/kbn-server-route-repository @elastic/apm-ui test/plugin_functional/plugins/session_notifications @elastic/kibana-core -x-pack/plugins/session_view @elastic/awp-viz +x-pack/plugins/session_view @elastic/sec-cloudnative-integrations packages/kbn-set-map @elastic/kibana-operations examples/share_examples @elastic/kibana-app-services src/plugins/share @elastic/appex-sharedux @@ -1176,8 +1176,8 @@ x-pack/plugins/security_solution/cypress/README.md @elastic/security-engineering x-pack/test/security_solution_cypress @elastic/security-engineering-productivity ## Security Solution sub teams - adaptive-workload-protection -x-pack/plugins/security_solution/public/common/components/sessions_viewer @elastic/awp-viz -x-pack/plugins/security_solution/public/kubernetes @elastic/awp-viz +x-pack/plugins/security_solution/public/common/components/sessions_viewer @elastic/sec-cloudnative-integrations +x-pack/plugins/security_solution/public/kubernetes @elastic/sec-cloudnative-integrations ## Security Solution sub teams - Protections Experience x-pack/plugins/security_solution/public/threat_intelligence @elastic/protections-experience diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index 29bf1e5b35372..9d881e0618bfe 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -15,7 +15,7 @@ import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; -Contact [@elastic/awp-viz](https://github.com/orgs/elastic/teams/awp-viz) for questions regarding this plugin. +Contact [@elastic/sec-cloudnative-integrations](https://github.com/orgs/elastic/teams/sec-cloudnative-integrations) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 5cc6aad4ef05d..ed98c651524f0 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -113,7 +113,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 185 | 1 | 153 | 5 | | kibanaUsageCollection | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/kibana-app-services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 609 | 3 | 416 | 9 | -| | [@elastic/awp-viz](https://github.com/orgs/elastic/teams/awp-viz) | - | 3 | 0 | 3 | 1 | +| | [@elastic/sec-cloudnative-integrations](https://github.com/orgs/elastic/teams/sec-cloudnative-integrations) | - | 3 | 0 | 3 | 1 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 608 | 0 | 513 | 53 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 8 | 0 | 8 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 4 | 0 | 4 | 1 | @@ -151,7 +151,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | searchprofiler | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 280 | 0 | 94 | 0 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 117 | 0 | 76 | 27 | -| | [@elastic/awp-viz](https://github.com/orgs/elastic/teams/awp-viz) | - | 7 | 0 | 7 | 1 | +| | [@elastic/sec-cloudnative-integrations](https://github.com/orgs/elastic/teams/sec-cloudnative-integrations) | - | 7 | 0 | 7 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Adds URL Service and sharing capabilities to Kibana | 118 | 0 | 59 | 10 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 22 | 1 | 22 | 1 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides the Spaces feature, which allows saved objects to be organized into meaningful categories. | 253 | 0 | 65 | 0 | diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index 7994a4b709546..4dd6c4cd77f66 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -15,7 +15,7 @@ import sessionViewObj from './session_view.devdocs.json'; -Contact [@elastic/awp-viz](https://github.com/orgs/elastic/teams/awp-viz) for questions regarding this plugin. +Contact [@elastic/sec-cloudnative-integrations](https://github.com/orgs/elastic/teams/sec-cloudnative-integrations) for questions regarding this plugin. **Code health stats** diff --git a/renovate.json b/renovate.json index ed5c6ee554f6a..bb1d043c30f48 100644 --- a/renovate.json +++ b/renovate.json @@ -270,7 +270,7 @@ { "groupName": "TTY Output", "matchPackageNames": ["xterm", "byte-size", "@types/byte-size"], - "reviewers": ["team:awp-viz"], + "reviewers": ["team:sec-cloudnative-integrations"], "matchBaseBranches": ["main"], "labels": ["Team: AWP: Visualization", "release_note:skip", "backport:skip"], "enabled": true, diff --git a/x-pack/plugins/cloud_defend/public/common/utils.test.ts b/x-pack/plugins/cloud_defend/public/common/utils.test.ts index f0342535d6d21..86f5d06b02365 100644 --- a/x-pack/plugins/cloud_defend/public/common/utils.test.ts +++ b/x-pack/plugins/cloud_defend/public/common/utils.test.ts @@ -54,7 +54,7 @@ describe('getSelectorConditions', () => { // check that process specific conditions are not included expect(options.includes('processExecutable')).toBeFalsy(); - expect(options.includes('processUserId')).toBeFalsy(); + expect(options.includes('sessionLeaderInteractive')).toBeFalsy(); }); it('grabs process conditions for process selectors', () => { @@ -70,7 +70,6 @@ describe('getSelectorConditions', () => { // check that process specific conditions are not included expect(options.includes('processExecutable')).toBeTruthy(); - expect(options.includes('processUserId')).toBeTruthy(); expect(options.includes('sessionLeaderInteractive')).toBeTruthy(); }); }); diff --git a/x-pack/plugins/cloud_defend/public/components/control_general_view/index.tsx b/x-pack/plugins/cloud_defend/public/components/control_general_view/index.tsx index 72a182820ae89..0a253b8c68a73 100644 --- a/x-pack/plugins/cloud_defend/public/components/control_general_view/index.tsx +++ b/x-pack/plugins/cloud_defend/public/components/control_general_view/index.tsx @@ -338,6 +338,10 @@ export const ControlGeneralView = ({ policy, onChange, show }: ViewDeps) => { {selectors.map((selector, i) => { + const usedByResponse = !!responses.find((response) => + response.match.includes(selector.name) + ); + return ( { index={i} selector={selector} selectors={selectors} + usedByResponse={usedByResponse} onDuplicate={onDuplicateSelector} onRemove={onRemoveSelector} onChange={onSelectorChange} diff --git a/x-pack/plugins/cloud_defend/public/components/control_general_view/translations.ts b/x-pack/plugins/cloud_defend/public/components/control_general_view/translations.ts index fc37da2fc6c86..d80ef8030ea6a 100644 --- a/x-pack/plugins/cloud_defend/public/components/control_general_view/translations.ts +++ b/x-pack/plugins/cloud_defend/public/components/control_general_view/translations.ts @@ -116,6 +116,14 @@ export const name = i18n.translate('xpack.cloudDefend.name', { defaultMessage: 'Name', }); +export const unusedSelector = i18n.translate('xpack.cloudDefend.unusedSelector', { + defaultMessage: 'Not in use', +}); + +export const unusedSelectorHelp = i18n.translate('xpack.cloudDefend.unusedSelectorHelp', { + defaultMessage: 'This selector is not in use by any response.', +}); + export const errorInvalidResourceLabel = i18n.translate( 'xpack.cloudDefend.errorInvalidResourceLabel', { diff --git a/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.test.tsx b/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.test.tsx index 4d3cfd0aa7623..df99541546c57 100644 --- a/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.test.tsx +++ b/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.test.tsx @@ -50,6 +50,7 @@ describe('', () => { onChange={onChange} onRemove={onRemove} onDuplicate={onDuplicate} + usedByResponse={false} /> ); @@ -68,6 +69,12 @@ describe('', () => { expect(getByTestId('cloud-defend-selectorcondition-operation')).toBeTruthy(); }); + it('renders a badge to show that the selector is unused', () => { + const { getByText } = render(); + + expect(getByText(i18n.unusedSelector)).toBeTruthy(); + }); + it('allows the user to add a limited set of operations', () => { const { getByTestId, rerender } = render(); diff --git a/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.tsx b/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.tsx index 6119e31386b5e..80ffff0a3bd6a 100644 --- a/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.tsx +++ b/x-pack/plugins/cloud_defend/public/components/control_general_view_selector/index.tsx @@ -184,6 +184,7 @@ const StringArrayCondition = ({ export const ControlGeneralViewSelector = ({ selector, selectors, + usedByResponse, index, onRemove, onDuplicate, @@ -393,17 +394,24 @@ export const ControlGeneralViewSelector = ({ css={styles.accordion} extraAction={ - {accordionState === 'closed' && ( -
- - {i18n.conditions} - - - {conditionsAdded.length} +
+ {accordionState === 'closed' && ( + <> + + {i18n.conditions} + + + {conditionsAdded.length} + + + )} + {!usedByResponse && ( + + {i18n.unusedSelector} -
-
- )} + )} +
+
', () => { ); expect(getByTestId('cloudDefendAdditionalErrors')).toBeTruthy(); - expect(getByText('"sessionLeaderName" values cannot exceed 16 bytes')).toBeTruthy(); + expect(getByText('"targetFilePath" values cannot exceed 255 bytes')).toBeTruthy(); }); }); diff --git a/x-pack/plugins/cloud_defend/public/test/mocks.ts b/x-pack/plugins/cloud_defend/public/test/mocks.ts index 0d90a8ed7ce1b..8ac1d9755bc03 100644 --- a/x-pack/plugins/cloud_defend/public/test/mocks.ts +++ b/x-pack/plugins/cloud_defend/public/test/mocks.ts @@ -55,8 +55,8 @@ export const MOCK_YAML_INVALID_STRING_ARRAY_CONDITION = `file: operation: - createExecutable - modifyExecutable - sessionLeaderName: - - reallylongsessionleadernamethatshouldnotbeallowed + targetFilePath: + - /bin/${new Array(256).fill('a').join()} responses: - match: - default diff --git a/x-pack/plugins/cloud_defend/public/types.ts b/x-pack/plugins/cloud_defend/public/types.ts index 7b35588d547e8..cd1135fefe5ac 100755 --- a/x-pack/plugins/cloud_defend/public/types.ts +++ b/x-pack/plugins/cloud_defend/public/types.ts @@ -78,9 +78,7 @@ export type SelectorCondition = | 'operation' | 'processExecutable' | 'processName' - | 'processUserId' - | 'sessionLeaderInteractive' - | 'sessionLeaderName'; + | 'sessionLeaderInteractive'; export interface SelectorConditionOptions { type: SelectorConditionType; @@ -141,9 +139,7 @@ export const SelectorConditionsMap: SelectorConditionsMapProps = { ignoreVolumeMounts: { selectorType: 'file', type: 'flag', not: ['ignoreVolumeFiles'] }, processExecutable: { selectorType: 'process', type: 'stringArray', not: ['processName'] }, processName: { selectorType: 'process', type: 'stringArray', not: ['processExecutable'] }, - processUserId: { selectorType: 'process', type: 'stringArray' }, sessionLeaderInteractive: { selectorType: 'process', type: 'boolean' }, - sessionLeaderName: { selectorType: 'process', type: 'stringArray', maxValueBytes: 16 }, }; export type ResponseAction = 'log' | 'alert' | 'block'; @@ -168,9 +164,7 @@ export interface Selector { // process selector properties processExecutable?: string[]; processName?: string[]; - processUserId?: string[]; sessionLeaderInteractive?: string[]; - sessionLeaderName?: string[]; // non yaml fields type: SelectorType; @@ -230,6 +224,7 @@ export interface ViewDeps extends SettingsDeps { export interface ControlGeneralViewSelectorDeps { selector: Selector; selectors: Selector[]; + usedByResponse: boolean; index: number; onChange(selector: Selector, index: number): void; onRemove(index: number): void; diff --git a/x-pack/plugins/kubernetes_security/kibana.jsonc b/x-pack/plugins/kubernetes_security/kibana.jsonc index e17a5dcde69d5..627ce99955b4c 100644 --- a/x-pack/plugins/kubernetes_security/kibana.jsonc +++ b/x-pack/plugins/kubernetes_security/kibana.jsonc @@ -1,7 +1,7 @@ { "type": "plugin", "id": "@kbn/kubernetes-security-plugin", - "owner": "@elastic/awp-viz", + "owner": "@elastic/sec-cloudnative-integrations", "plugin": { "id": "kubernetesSecurity", "server": true, diff --git a/x-pack/plugins/security_solution/public/common/components/sessions_viewer/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/sessions_viewer/__snapshots__/index.test.tsx.snap index 130ac64b48310..30be4aca57ad6 100644 --- a/x-pack/plugins/security_solution/public/common/components/sessions_viewer/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/common/components/sessions_viewer/__snapshots__/index.test.tsx.snap @@ -33,7 +33,7 @@ exports[`SessionsView renders correctly against snapshot 1`] = ` Executable
- User + User ID
Interactive diff --git a/x-pack/plugins/security_solution/public/common/components/sessions_viewer/default_headers.ts b/x-pack/plugins/security_solution/public/common/components/sessions_viewer/default_headers.ts index fe40ea78369f5..48ef68679933e 100644 --- a/x-pack/plugins/security_solution/public/common/components/sessions_viewer/default_headers.ts +++ b/x-pack/plugins/security_solution/public/common/components/sessions_viewer/default_headers.ts @@ -13,7 +13,7 @@ import { DEFAULT_DATE_COLUMN_MIN_WIDTH } from '../../../timelines/components/tim import { COLUMN_SESSION_START, COLUMN_EXECUTABLE, - COLUMN_ENTRY_USER, + COLUMN_ENTRY_USER_ID, COLUMN_INTERACTIVE, COLUMN_HOST_NAME, COLUMN_ENTRY_TYPE, @@ -34,8 +34,8 @@ export const sessionsHeaders: ColumnHeaderOptions[] = [ }, { columnHeaderType: defaultColumnHeaderType, - id: 'process.entry_leader.user.name', - display: COLUMN_ENTRY_USER, + id: 'process.entry_leader.user.id', + display: COLUMN_ENTRY_USER_ID, }, { columnHeaderType: defaultColumnHeaderType, diff --git a/x-pack/plugins/security_solution/public/common/components/sessions_viewer/translations.ts b/x-pack/plugins/security_solution/public/common/components/sessions_viewer/translations.ts index 15e12212bb998..ef16595b99742 100644 --- a/x-pack/plugins/security_solution/public/common/components/sessions_viewer/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/sessions_viewer/translations.ts @@ -39,10 +39,10 @@ export const COLUMN_EXECUTABLE = i18n.translate( } ); -export const COLUMN_ENTRY_USER = i18n.translate( - 'xpack.securitySolution.sessionsView.columnEntryUser', +export const COLUMN_ENTRY_USER_ID = i18n.translate( + 'xpack.securitySolution.sessionsView.columnEntryUserID', { - defaultMessage: 'User', + defaultMessage: 'User ID', } ); 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 index 4d8808d53999d..264d1685908ae 100644 --- a/x-pack/plugins/session_view/common/types/process_tree/index.ts +++ b/x-pack/plugins/session_view/common/types/process_tree/index.ts @@ -191,7 +191,7 @@ export interface ProcessEvent { '@timestamp'?: string; event?: { kind?: EventKind; - category?: string[]; + category?: string | string[]; action?: EventAction | EventAction[]; id?: string; }; diff --git a/x-pack/plugins/session_view/kibana.jsonc b/x-pack/plugins/session_view/kibana.jsonc index 647990ab6a977..47585565fffde 100644 --- a/x-pack/plugins/session_view/kibana.jsonc +++ b/x-pack/plugins/session_view/kibana.jsonc @@ -1,7 +1,7 @@ { "type": "plugin", "id": "@kbn/session-view-plugin", - "owner": "@elastic/awp-viz", + "owner": "@elastic/sec-cloudnative-integrations", "plugin": { "id": "sessionView", "server": true, diff --git a/x-pack/plugins/session_view/public/components/detail_panel_alert_list_item/index.tsx b/x-pack/plugins/session_view/public/components/detail_panel_alert_list_item/index.tsx index e6f68ce6ae230..cf1da761fde96 100644 --- a/x-pack/plugins/session_view/public/components/detail_panel_alert_list_item/index.tsx +++ b/x-pack/plugins/session_view/public/components/detail_panel_alert_list_item/index.tsx @@ -64,7 +64,9 @@ export const DetailPanelAlertListItem = ({ const { args, name: processName } = event.process ?? {}; const { event: processEvent } = event; const forceState = !isInvestigated ? 'open' : undefined; - const category = processEvent?.category?.[0]; + const category = Array.isArray(processEvent?.category) + ? processEvent?.category?.[0] + : processEvent?.category; const processEventAlertCategory = category ?? ProcessEventAlertCategory.process; const alertCategoryDetailDisplayText = category !== ProcessEventAlertCategory.process diff --git a/x-pack/plugins/session_view/public/components/process_tree/helpers.ts b/x-pack/plugins/session_view/public/components/process_tree/helpers.ts index 349a162d6b612..830306af4864f 100644 --- a/x-pack/plugins/session_view/public/components/process_tree/helpers.ts +++ b/x-pack/plugins/session_view/public/components/process_tree/helpers.ts @@ -266,6 +266,20 @@ export const autoExpandProcessTree = (processMap: ProcessMap, jumpToEntityId?: s return processMap; }; +// recusively collapses all children below provided node +export const collapseProcessTree = (node: Process) => { + if (!node.autoExpand) { + return; + } + + if (node.children) { + node.children.forEach((child) => { + child.autoExpand = false; + collapseProcessTree(child); + }); + } +}; + export const processNewEvents = ( eventsProcessMap: ProcessMap, events: ProcessEvent[] | undefined, diff --git a/x-pack/plugins/session_view/public/components/process_tree/index.tsx b/x-pack/plugins/session_view/public/components/process_tree/index.tsx index 9ba3845d0cab0..9dea1e07a8fdb 100644 --- a/x-pack/plugins/session_view/public/components/process_tree/index.tsx +++ b/x-pack/plugins/session_view/public/components/process_tree/index.tsx @@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n'; import { ProcessTreeNode } from '../process_tree_node'; import { BackToInvestigatedAlert } from '../back_to_investigated_alert'; import { useProcessTree } from './hooks'; +import { collapseProcessTree } from './helpers'; import { ProcessTreeLoadMoreButton } from '../process_tree_load_more_button'; import { AlertStatusEventEntityIdMap, @@ -97,6 +98,7 @@ export const ProcessTree = ({ verboseMode, jumpToEntityId, }); + const [forceRerender, setForceRerender] = useState(0); const eventsRemaining = useMemo(() => { const total = data?.[0]?.total || 0; @@ -126,6 +128,14 @@ export const ProcessTree = ({ setIsInvestigatedEventVisible(true); }, [onProcessSelected]); + const handleCollapseProcessTree = useCallback(() => { + collapseProcessTree(sessionLeader); + if (scrollerRef.current) { + scrollerRef.current.scrollTop = 0; + } + setForceRerender(Math.random()); + }, [sessionLeader]); + useEffect(() => { if (setSearchResults) { setSearchResults(searchResults); @@ -160,6 +170,7 @@ export const ProcessTree = ({ ref={scrollerRef} css={styles.sessionViewProcessTree} data-test-subj="sessionView:sessionViewProcessTree" + key={forceRerender} > {sessionLeader && ( { overflow: 'auto', height: '100%', backgroundColor: euiVars.euiColorLightestShade, - paddingTop: size.base, - paddingLeft: size.s, }; const selectionArea: CSSObject = { diff --git a/x-pack/plugins/session_view/public/components/process_tree_alert/__snapshots__/index.test.tsx.snap b/x-pack/plugins/session_view/public/components/process_tree_alert/__snapshots__/index.test.tsx.snap index c2b05ef38a3e0..39e1778dd1f4a 100644 --- a/x-pack/plugins/session_view/public/components/process_tree_alert/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/session_view/public/components/process_tree_alert/__snapshots__/index.test.tsx.snap @@ -54,6 +54,7 @@ Object { > cmd test alert
+
cmd test alert
+
{ renderResult = mockedContext.render(); expect(renderResult.container.textContent?.replace(/\s+/g, ' ')).toEqual( - ' bash started by vagrant' + ' bash started by vagrant ' ); }); diff --git a/x-pack/plugins/session_view/public/components/process_tree_node/index.tsx b/x-pack/plugins/session_view/public/components/process_tree_node/index.tsx index fa5c16bee19bd..6ffc4415fb47b 100644 --- a/x-pack/plugins/session_view/public/components/process_tree_node/index.tsx +++ b/x-pack/plugins/session_view/public/components/process_tree_node/index.tsx @@ -20,7 +20,7 @@ import React, { RefObject, ReactElement, } from 'react'; -import { EuiButton, EuiIcon, EuiToolTip, formatDate } from '@elastic/eui'; +import { EuiButton, EuiIcon, EuiToolTip, formatDate, EuiButtonIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { chain } from 'lodash'; @@ -61,6 +61,7 @@ export interface ProcessDeps { onJumpToOutput: (entityId: string) => void; loadNextButton?: ReactElement | null; loadPreviousButton?: ReactElement | null; + handleCollapseProcessTree?: () => void; } /** @@ -83,6 +84,7 @@ export function ProcessTreeNode({ onJumpToOutput, loadPreviousButton, loadNextButton, + handleCollapseProcessTree, }: ProcessDeps) { const [childrenExpanded, setChildrenExpanded] = useState(isSessionLeader || process.autoExpand); const [alertsExpanded, setAlertsExpanded] = useState(false); @@ -133,7 +135,15 @@ export function ProcessTreeNode({ const alertTypeCounts = useMemo(() => { const alertCounts: AlertTypeCount[] = chain(alerts) - .groupBy((alert) => alert.event?.category?.[0]) + .groupBy((alert) => { + const category = alert.event?.category; + + if (Array.isArray(category)) { + return category?.[0]; + } + + return category; + }) .map((processAlerts, alertCategory) => ({ category: alertCategory as ProcessEventAlertCategory, count: processAlerts.length, @@ -176,8 +186,12 @@ export function ProcessTreeNode({ } onProcessSelected?.(process); + + if (isSessionLeader && scrollerRef.current) { + scrollerRef.current.scrollTop = 0; + } }, - [onProcessSelected, process] + [isSessionLeader, onProcessSelected, process, scrollerRef] ); const processDetails = process.getDetails(); @@ -219,6 +233,19 @@ export function ProcessTreeNode({ const children = process.getChildren(verboseMode); + const user = processDetails?.process?.user; + const userName = useMemo(() => { + if (user?.name) { + return user.name; + } else if (user?.id === '0') { + return 'root'; + } else if (user?.id) { + return `uid: ${user?.id}`; + } + + return '-'; + }, [user?.id, user?.name]); + if (!processDetails?.process) { return null; } @@ -231,7 +258,6 @@ export function ProcessTreeNode({ parent, working_directory: workingDirectory, start, - user, } = processDetails.process; const shouldRenderChildren = isSessionLeader || (childrenExpanded && children?.length > 0); @@ -275,7 +301,14 @@ export function ProcessTreeNode({ - {user?.name || 'ID: ' + user?.id} + {userName} + + ) : ( <> diff --git a/x-pack/plugins/session_view/public/components/process_tree_node/styles.ts b/x-pack/plugins/session_view/public/components/process_tree_node/styles.ts index 3936fc35aac81..32048cfd97585 100644 --- a/x-pack/plugins/session_view/public/components/process_tree_node/styles.ts +++ b/x-pack/plugins/session_view/public/components/process_tree_node/styles.ts @@ -95,7 +95,6 @@ export const useStyles = ({ display: 'block', cursor: 'pointer', position: 'relative', - marginBottom: isSessionLeader ? size.s : '0px', '&:hover:before': { backgroundColor: hoverColor, }, @@ -114,6 +113,10 @@ export const useStyles = ({ }, }; + const jumpToTop: CSSObject = { + float: 'right', + }; + const textSection: CSSObject = { marginLeft: size.s, span: { @@ -131,13 +134,23 @@ export const useStyles = ({ display: 'inline-block', verticalAlign: 'middle', }, + paddingLeft: PROCESS_TREE_LEFT_PADDING, }; - const searchHighlight = ` - color: ${colors.fullShade}; - border-radius: '0px'; - background-color: ${searchResColor}; - `; + if (isSessionLeader) { + processNode.position = 'sticky'; + processNode.top = '-' + size.base; + processNode.zIndex = 1; + processNode.borderTop = `${size.base} solid transparent`; + processNode.backgroundColor = euiVars.euiColorLightestShade; + processNode.borderBottom = border.editable; + } + + const searchHighlight: CSSObject = { + color: colors.fullShade, + borderRadius: '0px', + backgroundColor: searchResColor, + }; const wrapper: CSSObject = { paddingLeft: size.s, @@ -188,6 +201,7 @@ export const useStyles = ({ icon, textSection, sessionLeader, + jumpToTop, }; }, [depth, euiTheme, hasAlerts, hasInvestigatedAlert, isSelected, euiVars, isSessionLeader]); diff --git a/x-pack/plugins/session_view/public/components/process_tree_node/text_highlight.tsx b/x-pack/plugins/session_view/public/components/process_tree_node/text_highlight.tsx index 6d21726e0d430..c06b208e6c262 100644 --- a/x-pack/plugins/session_view/public/components/process_tree_node/text_highlight.tsx +++ b/x-pack/plugins/session_view/public/components/process_tree_node/text_highlight.tsx @@ -20,7 +20,6 @@ const css: CSSObject = { display: 'inline', fontSize: 0, lineHeight: 0, - verticalAlign: 'middle', }, }; // Component that takes an array of matching indices in a text and pass down a highlight diff --git a/x-pack/plugins/session_view/public/components/session_view/index.tsx b/x-pack/plugins/session_view/public/components/session_view/index.tsx index 955b042ff9cfb..5f52f5ff8e935 100644 --- a/x-pack/plugins/session_view/public/components/session_view/index.tsx +++ b/x-pack/plugins/session_view/public/components/session_view/index.tsx @@ -201,6 +201,10 @@ export const SessionView = ({ [onProcessSelected, searchResults] ); + useEffect(() => { + onSearchIndexChange(0); + }, [onSearchIndexChange, searchResults]); + const handleOnAlertDetailsClosed = useCallback((alertUuid: string) => { setFetchAlertStatus([alertUuid]); }, []); diff --git a/x-pack/plugins/session_view/public/utils/alert_category_display_test.test.ts b/x-pack/plugins/session_view/public/utils/alert_category_display_test.test.ts index 24b474111b860..fdc5cbedfd82e 100644 --- a/x-pack/plugins/session_view/public/utils/alert_category_display_test.test.ts +++ b/x-pack/plugins/session_view/public/utils/alert_category_display_test.test.ts @@ -21,24 +21,22 @@ describe('getAlertCategoryDisplayText(alert, category)', () => { it('should display rule name when alert category is process', () => { expect(getAlertCategoryDisplayText(mockAlerts[0], ProcessEventAlertCategory.process)).toEqual( - undefined + '' ); }); it('should display rule name when alert category is undefined', () => { - expect(getAlertCategoryDisplayText(mockAlerts[0], undefined)).toEqual(undefined); + expect(getAlertCategoryDisplayText(mockAlerts[0], undefined)).toEqual(''); }); it('should display rule name when file path is undefined', () => { const fileAlert = { ...mockFileAlert, file: {} }; - expect(getAlertCategoryDisplayText(fileAlert, ProcessEventAlertCategory.file)).toEqual( - undefined - ); + expect(getAlertCategoryDisplayText(fileAlert, ProcessEventAlertCategory.file)).toEqual(''); }); it('should display rule name when destination address is undefined and alert category is network', () => { const networkAlert = { ...mockNetworkAlert, destination: undefined }; expect(getAlertCategoryDisplayText(networkAlert, ProcessEventAlertCategory.network)).toEqual( - undefined + '' ); }); }); diff --git a/x-pack/plugins/session_view/public/utils/alert_category_display_text.ts b/x-pack/plugins/session_view/public/utils/alert_category_display_text.ts index 3ac2658f37e28..bf4c74681a2be 100644 --- a/x-pack/plugins/session_view/public/utils/alert_category_display_text.ts +++ b/x-pack/plugins/session_view/public/utils/alert_category_display_text.ts @@ -19,7 +19,7 @@ export const getAlertCategoryDisplayText = (alert: ProcessEvent, category: strin if (filePath && category === ProcessEventAlertCategory.file) return dataOrDash(filePath); if (destination?.address && category === ProcessEventAlertCategory.network) return dataOrDash(getAlertNetworkDisplay(destination)); - return; + return ''; }; export const getAlertNetworkDisplay = (destination: ProcessEventIPAddress) => { diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 74138a250ee30..bd29bb8a2554f 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -31372,7 +31372,6 @@ "xpack.securitySolution.kpiUsers.totalUsers.title": "Utilisateurs", "xpack.securitySolution.kubernetes.columnContainer": "Conteneur", "xpack.securitySolution.kubernetes.columnEntryType": "Type d’entrée", - "xpack.securitySolution.kubernetes.columnEntryUser": "Utilisateur d’entrée de session", "xpack.securitySolution.kubernetes.columnExecutable": "Leader de session", "xpack.securitySolution.kubernetes.columnInteractive": "Interactivité", "xpack.securitySolution.kubernetes.columnNode": "Nœud", @@ -32041,7 +32040,6 @@ "xpack.securitySolution.selector.summaryView.options.summaryView.description": "Afficher un rendu du flux d'événements pour chaque alerte", "xpack.securitySolution.sessionsView.columnEntrySourceIp": "IP source", "xpack.securitySolution.sessionsView.columnEntryType": "Type", - "xpack.securitySolution.sessionsView.columnEntryUser": "Utilisateur", "xpack.securitySolution.sessionsView.columnExecutable": "Exécutable", "xpack.securitySolution.sessionsView.columnHostName": "Nom d'hôte", "xpack.securitySolution.sessionsView.columnInteractive": "Interactif", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index beb0affbe3348..ea8da1ed62a78 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -31351,7 +31351,6 @@ "xpack.securitySolution.kpiUsers.totalUsers.title": "ユーザー", "xpack.securitySolution.kubernetes.columnContainer": "コンテナー", "xpack.securitySolution.kubernetes.columnEntryType": "エントリタイプ", - "xpack.securitySolution.kubernetes.columnEntryUser": "セッションエントリユーザー", "xpack.securitySolution.kubernetes.columnExecutable": "セッションリーダー", "xpack.securitySolution.kubernetes.columnInteractive": "インタラクティブ", "xpack.securitySolution.kubernetes.columnNode": "ノード", @@ -32020,7 +32019,6 @@ "xpack.securitySolution.selector.summaryView.options.summaryView.description": "各アラートのイベントフローのレンダリングを表示", "xpack.securitySolution.sessionsView.columnEntrySourceIp": "ソース IP", "xpack.securitySolution.sessionsView.columnEntryType": "型", - "xpack.securitySolution.sessionsView.columnEntryUser": "ユーザー", "xpack.securitySolution.sessionsView.columnExecutable": "実行ファイル", "xpack.securitySolution.sessionsView.columnHostName": "ホスト名", "xpack.securitySolution.sessionsView.columnInteractive": "インタラクティブ", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 505f947f0cfb3..f5b0a3c84a6ee 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -31367,7 +31367,6 @@ "xpack.securitySolution.kpiUsers.totalUsers.title": "用户", "xpack.securitySolution.kubernetes.columnContainer": "容器", "xpack.securitySolution.kubernetes.columnEntryType": "条目类型", - "xpack.securitySolution.kubernetes.columnEntryUser": "会话条目用户", "xpack.securitySolution.kubernetes.columnExecutable": "会话 Leader", "xpack.securitySolution.kubernetes.columnInteractive": "交互性", "xpack.securitySolution.kubernetes.columnNode": "节点", @@ -32036,7 +32035,6 @@ "xpack.securitySolution.selector.summaryView.options.summaryView.description": "查看每个告警的事件渲染", "xpack.securitySolution.sessionsView.columnEntrySourceIp": "源 IP", "xpack.securitySolution.sessionsView.columnEntryType": "类型", - "xpack.securitySolution.sessionsView.columnEntryUser": "用户", "xpack.securitySolution.sessionsView.columnExecutable": "可执行", "xpack.securitySolution.sessionsView.columnHostName": "主机名", "xpack.securitySolution.sessionsView.columnInteractive": "交互",