mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Sessions tab improvements (#131583)
* session tab query modified query all events, not just entry leaders. solves a few problems wrt to query ability. default columns modified and display names provided for each * snapshot updated * readded test * Default sort set to process.entry_leader.start desc * sessions tab timeline id changed to cache bust localstorage for table column configs * missed a couple spots for session tab timeline id update Co-authored-by: mitodrummer <karlgodard@elastic.co>
This commit is contained in:
parent
37a27384a5
commit
743cce0a65
10 changed files with 99 additions and 82 deletions
|
@ -318,7 +318,7 @@ export enum TimelineId {
|
|||
usersPageExternalAlerts = 'users-page-external-alerts',
|
||||
hostsPageEvents = 'hosts-page-events',
|
||||
hostsPageExternalAlerts = 'hosts-page-external-alerts',
|
||||
hostsPageSessions = 'hosts-page-sessions',
|
||||
hostsPageSessions = 'hosts-page-sessions-v2', // the v2 is to cache bust localstorage settings as default columns were reworked.
|
||||
detectionsRulesDetailsPage = 'detections-rules-details-page',
|
||||
detectionsPage = 'detections-page',
|
||||
networkPageExternalAlerts = 'network-page-external-alerts',
|
||||
|
|
|
@ -70,34 +70,28 @@ exports[`SessionsView renders correctly against snapshot 1`] = `
|
|||
<div
|
||||
data-test-subj="security_solution:sessions_viewer:sessions_view:timelineId"
|
||||
>
|
||||
hosts-page-sessions
|
||||
hosts-page-sessions-v2
|
||||
</div>
|
||||
<div>
|
||||
process.start
|
||||
Started
|
||||
</div>
|
||||
<div>
|
||||
process.end
|
||||
Executable
|
||||
</div>
|
||||
<div>
|
||||
process.executable
|
||||
User
|
||||
</div>
|
||||
<div>
|
||||
user.name
|
||||
Interactive
|
||||
</div>
|
||||
<div>
|
||||
process.interactive
|
||||
Hostname
|
||||
</div>
|
||||
<div>
|
||||
process.pid
|
||||
Type
|
||||
</div>
|
||||
<div>
|
||||
host.hostname
|
||||
</div>
|
||||
<div>
|
||||
process.entry_leader.entry_meta.type
|
||||
</div>
|
||||
<div>
|
||||
process.entry_leader.entry_meta.source.ip
|
||||
Source IP
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* 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 { CellValueElementProps } from '../../../timelines/components/timeline/cell_rendering';
|
||||
import { DefaultCellRenderer } from '../../../timelines/components/timeline/cell_rendering/default_cell_renderer';
|
||||
import { getEmptyValue } from '../empty_value';
|
||||
import { MAPPED_PROCESS_END_COLUMN } from './default_headers';
|
||||
|
||||
const hasEcsDataEndEventAction = (ecsData: CellValueElementProps['ecsData']) => {
|
||||
return ecsData?.event?.action?.includes('end');
|
||||
};
|
||||
|
||||
export const CellRenderer: React.FC<CellValueElementProps> = (props: CellValueElementProps) => {
|
||||
// We only want to render process.end for event.actions of type 'end'
|
||||
if (props.columnId === MAPPED_PROCESS_END_COLUMN && !hasEcsDataEndEventAction(props.ecsData)) {
|
||||
return <>{getEmptyValue()}</>;
|
||||
}
|
||||
|
||||
return <DefaultCellRenderer {...props} />;
|
||||
};
|
|
@ -10,50 +10,52 @@ import { defaultColumnHeaderType } from '../../../timelines/components/timeline/
|
|||
import { DEFAULT_DATE_COLUMN_MIN_WIDTH } from '../../../timelines/components/timeline/body/constants';
|
||||
import { SubsetTimelineModel } from '../../../timelines/store/timeline/model';
|
||||
import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
|
||||
|
||||
// Using @timestamp as an way of getting the end time of the process. (Currently endpoint doesn't populate process.end)
|
||||
// @timestamp of an event.action with value of "end" is what we consider that to be the end time of the process
|
||||
// Current action are: 'start', 'exec', 'end', so we might have up to three events per process.
|
||||
export const MAPPED_PROCESS_END_COLUMN = '@timestamp';
|
||||
import {
|
||||
COLUMN_SESSION_START,
|
||||
COLUMN_EXECUTABLE,
|
||||
COLUMN_ENTRY_USER,
|
||||
COLUMN_INTERACTIVE,
|
||||
COLUMN_HOST_NAME,
|
||||
COLUMN_ENTRY_TYPE,
|
||||
COLUMN_ENTRY_IP,
|
||||
} from './translations';
|
||||
|
||||
export const sessionsHeaders: ColumnHeaderOptions[] = [
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: 'process.start',
|
||||
id: 'process.entry_leader.start',
|
||||
initialWidth: DEFAULT_DATE_COLUMN_MIN_WIDTH,
|
||||
display: COLUMN_SESSION_START,
|
||||
},
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: MAPPED_PROCESS_END_COLUMN,
|
||||
display: 'process.end',
|
||||
id: 'process.entry_leader.executable',
|
||||
display: COLUMN_EXECUTABLE,
|
||||
},
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: 'process.executable',
|
||||
id: 'process.entry_leader.user.name',
|
||||
display: COLUMN_ENTRY_USER,
|
||||
},
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: 'user.name',
|
||||
},
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: 'process.interactive',
|
||||
},
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: 'process.pid',
|
||||
id: 'process.entry_leader.interactive',
|
||||
display: COLUMN_INTERACTIVE,
|
||||
},
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: 'host.hostname',
|
||||
display: COLUMN_HOST_NAME,
|
||||
},
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: 'process.entry_leader.entry_meta.type',
|
||||
display: COLUMN_ENTRY_TYPE,
|
||||
},
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: 'process.entry_leader.entry_meta.source.ip',
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
display: COLUMN_ENTRY_IP,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -62,4 +64,11 @@ export const sessionsDefaultModel: SubsetTimelineModel = {
|
|||
columns: sessionsHeaders,
|
||||
defaultColumns: sessionsHeaders,
|
||||
excludedRowRendererIds: Object.values(RowRendererId),
|
||||
sort: [
|
||||
{
|
||||
columnId: 'process.entry_leader.start',
|
||||
columnType: 'date',
|
||||
sortDirection: 'desc',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -109,10 +109,11 @@ describe('SessionsView', () => {
|
|||
expect(wrapper.getByTestId(`${TEST_PREFIX}:startDate`)).toHaveTextContent(startDate);
|
||||
expect(wrapper.getByTestId(`${TEST_PREFIX}:endDate`)).toHaveTextContent(endDate);
|
||||
expect(wrapper.getByTestId(`${TEST_PREFIX}:timelineId`)).toHaveTextContent(
|
||||
'hosts-page-sessions'
|
||||
'hosts-page-sessions-v2'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('passes in the right filters to TGrid', async () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
|
|
|
@ -12,7 +12,7 @@ import { ESBoolQuery } from '../../../../common/typed_json';
|
|||
import { StatefulEventsViewer } from '../events_viewer';
|
||||
import { sessionsDefaultModel } from './default_headers';
|
||||
import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers';
|
||||
import { CellRenderer } from './cell_renderer';
|
||||
import { DefaultCellRenderer } from '../../../timelines/components/timeline/cell_rendering/default_cell_renderer';
|
||||
import * as i18n from './translations';
|
||||
import { SourcererScopeName } from '../../store/sourcerer/model';
|
||||
import { getDefaultControlColumn } from '../../../timelines/components/timeline/body/control_columns';
|
||||
|
@ -24,15 +24,8 @@ export const defaultSessionsFilter: Required<Pick<Filter, 'meta' | 'query'>> = {
|
|||
bool: {
|
||||
filter: [
|
||||
{
|
||||
bool: {
|
||||
should: [
|
||||
{
|
||||
match: {
|
||||
'process.entry_leader.same_as_process': true,
|
||||
},
|
||||
},
|
||||
],
|
||||
minimum_should_match: 1,
|
||||
exists: {
|
||||
field: 'process.entry_leader.entity_id', // to exclude any records which have no entry_leader.entity_id
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -41,10 +34,10 @@ export const defaultSessionsFilter: Required<Pick<Filter, 'meta' | 'query'>> = {
|
|||
meta: {
|
||||
alias: null,
|
||||
disabled: false,
|
||||
key: 'process.entry_leader.same_as_process',
|
||||
key: 'process.entry_leader.entity_id',
|
||||
negate: false,
|
||||
params: {},
|
||||
type: 'boolean',
|
||||
type: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -95,7 +88,7 @@ const SessionsViewComponent: React.FC<SessionsComponentsProps> = ({
|
|||
entityType={entityType}
|
||||
id={timelineId}
|
||||
leadingControlColumns={leadingControlColumns}
|
||||
renderCellValue={CellRenderer}
|
||||
renderCellValue={DefaultCellRenderer}
|
||||
rowRenderers={defaultRowRenderers}
|
||||
scopeId={SourcererScopeName.default}
|
||||
start={startDate}
|
||||
|
|
|
@ -20,3 +20,52 @@ export const SINGLE_COUNT_OF_SESSIONS = i18n.translate(
|
|||
defaultMessage: 'session',
|
||||
}
|
||||
);
|
||||
|
||||
export const COLUMN_SESSION_START = i18n.translate(
|
||||
'xpack.securitySolution.sessionsView.columnSessionStart',
|
||||
{
|
||||
defaultMessage: 'Started',
|
||||
}
|
||||
);
|
||||
|
||||
export const COLUMN_EXECUTABLE = i18n.translate(
|
||||
'xpack.securitySolution.sessionsView.columnExecutable',
|
||||
{
|
||||
defaultMessage: 'Executable',
|
||||
}
|
||||
);
|
||||
|
||||
export const COLUMN_ENTRY_USER = i18n.translate(
|
||||
'xpack.securitySolution.sessionsView.columnEntryUser',
|
||||
{
|
||||
defaultMessage: 'User',
|
||||
}
|
||||
);
|
||||
|
||||
export const COLUMN_INTERACTIVE = i18n.translate(
|
||||
'xpack.securitySolution.sessionsView.columnInteractive',
|
||||
{
|
||||
defaultMessage: 'Interactive',
|
||||
}
|
||||
);
|
||||
|
||||
export const COLUMN_HOST_NAME = i18n.translate(
|
||||
'xpack.securitySolution.sessionsView.columnHostName',
|
||||
{
|
||||
defaultMessage: 'Hostname',
|
||||
}
|
||||
);
|
||||
|
||||
export const COLUMN_ENTRY_TYPE = i18n.translate(
|
||||
'xpack.securitySolution.sessionsView.columnEntryType',
|
||||
{
|
||||
defaultMessage: 'Type',
|
||||
}
|
||||
);
|
||||
|
||||
export const COLUMN_ENTRY_IP = i18n.translate(
|
||||
'xpack.securitySolution.sessionsView.columnEntrySourceIp',
|
||||
{
|
||||
defaultMessage: 'Source IP',
|
||||
}
|
||||
);
|
||||
|
|
|
@ -314,7 +314,7 @@ export enum TimelineId {
|
|||
usersPageExternalAlerts = 'users-page-external-alerts',
|
||||
hostsPageEvents = 'hosts-page-events',
|
||||
hostsPageExternalAlerts = 'hosts-page-external-alerts',
|
||||
hostsPageSessions = 'hosts-page-sessions',
|
||||
hostsPageSessions = 'hosts-page-sessions-v2',
|
||||
detectionsRulesDetailsPage = 'detections-rules-details-page',
|
||||
detectionsPage = 'detections-page',
|
||||
networkPageExternalAlerts = 'network-page-external-alerts',
|
||||
|
|
|
@ -46,7 +46,7 @@ export enum TimelineId {
|
|||
usersPageExternalAlerts = 'users-page-external-alerts',
|
||||
hostsPageEvents = 'hosts-page-events',
|
||||
hostsPageExternalAlerts = 'hosts-page-external-alerts',
|
||||
hostsPageSessions = 'hosts-page-sessions',
|
||||
hostsPageSessions = 'hosts-page-sessions-v2',
|
||||
detectionsRulesDetailsPage = 'detections-rules-details-page',
|
||||
detectionsPage = 'detections-page',
|
||||
networkPageExternalAlerts = 'network-page-external-alerts',
|
||||
|
|
|
@ -209,17 +209,13 @@ const timelineSessionsSearchStrategy = <T extends TimelineFactoryQueryTypes>({
|
|||
};
|
||||
|
||||
const collapse = {
|
||||
field: 'process.entity_id',
|
||||
inner_hits: {
|
||||
name: 'last_event',
|
||||
size: 1,
|
||||
sort: [{ '@timestamp': 'desc' }],
|
||||
},
|
||||
field: 'process.entry_leader.entity_id',
|
||||
};
|
||||
|
||||
const aggs = {
|
||||
total: {
|
||||
cardinality: {
|
||||
field: 'process.entity_id',
|
||||
field: 'process.entry_leader.entity_id',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue