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][Session view] - Add Sessions tab into the Hosts page #127920

Merged
merged 32 commits into from
Mar 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2539ce5
add Session Leader Table
opauloh Mar 8, 2022
0eb0f7e
Merge branch 'main' into add-session-leader-table
opauloh Mar 10, 2022
130d176
WIP: Session Leader Table
opauloh Mar 14, 2022
0564628
Merge branch 'main' into add-session-leader-table
opauloh Mar 14, 2022
e3e3501
sessions search strategy
opauloh Mar 16, 2022
e3eb4bc
session viewer component
opauloh Mar 16, 2022
89d8d31
add timelineId
opauloh Mar 16, 2022
1ea7f1f
remove session leader table
opauloh Mar 16, 2022
807c501
cleaning
opauloh Mar 16, 2022
30de4b6
cleaning
opauloh Mar 16, 2022
7ee4766
Merge branch 'main' into add-session-leader-table
opauloh Mar 16, 2022
4e5d445
updating search strategy
opauloh Mar 18, 2022
ea61910
add space for open in session viewer icon
opauloh Mar 18, 2022
bfd20bb
add sessionEntityId as key cache
opauloh Mar 18, 2022
4426ab7
updating deep links
opauloh Mar 23, 2022
c9f06e8
updating headers
opauloh Mar 23, 2022
b194aea
adding filterQuery
opauloh Mar 23, 2022
ff15e52
adding timeline
opauloh Mar 23, 2022
de69c73
add runtime fields to search strategy
opauloh Mar 23, 2022
4d37019
updating comment
opauloh Mar 23, 2022
fceb6af
Merge branch 'main' into add-session-leader-table
opauloh Mar 23, 2022
5fc9a8f
fixing tests
opauloh Mar 24, 2022
3d2a8d9
Merge branch 'main' into add-session-leader-table
opauloh Mar 24, 2022
3953391
removing unecessary intermediate component
opauloh Mar 25, 2022
cd04a4f
removing intermediary component
opauloh Mar 25, 2022
a9b44c5
adding tests for session viewer
opauloh Mar 25, 2022
a4effb0
Merge branch 'main' into add-session-leader-table
opauloh Mar 25, 2022
23be142
Merge branch 'main' into add-session-leader-table
opauloh Mar 25, 2022
9a59677
remove unnecessary runtime_mappings
opauloh Mar 28, 2022
ec90079
Merge remote-tracking branch 'origin/add-session-leader-table' into a…
opauloh Mar 28, 2022
607222b
Merge branch 'main' into add-session-leader-table
opauloh Mar 28, 2022
90a56ee
Merge branch 'main' into add-session-leader-table
kibanamachine Mar 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions x-pack/plugins/security_solution/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export enum SecurityPageName {
users = 'users',
usersAnomalies = 'users-anomalies',
usersRisk = 'users-risk',
sessions = 'sessions',
}

export const TIMELINES_PATH = '/timelines' as const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ export enum TimelineId {
usersPageExternalAlerts = 'users-page-external-alerts',
hostsPageEvents = 'hosts-page-events',
hostsPageExternalAlerts = 'hosts-page-external-alerts',
hostsPageSessions = 'hosts-page-sessions',
detectionsRulesDetailsPage = 'detections-rules-details-page',
detectionsPage = 'detections-page',
networkPageExternalAlerts = 'network-page-external-alerts',
Expand All @@ -332,6 +333,7 @@ export const TimelineIdLiteralRt = runtimeTypes.union([
runtimeTypes.literal(TimelineId.usersPageExternalAlerts),
runtimeTypes.literal(TimelineId.hostsPageEvents),
runtimeTypes.literal(TimelineId.hostsPageExternalAlerts),
runtimeTypes.literal(TimelineId.hostsPageSessions),
runtimeTypes.literal(TimelineId.detectionsRulesDetailsPage),
runtimeTypes.literal(TimelineId.detectionsPage),
runtimeTypes.literal(TimelineId.networkPageExternalAlerts),
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/security_solution/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"taskManager",
"timelines",
"triggersActionsUi",
"uiActions"
"uiActions",
"sessionView"
],
"optionalPlugins": [
"encryptedSavedObjects",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,13 @@ export const securitySolutionsDeepLinks: SecuritySolutionDeepLink[] = [
path: `${HOSTS_PATH}/anomalies`,
isPremium: true,
},
{
id: SecurityPageName.sessions,
title: i18n.translate('xpack.securitySolution.search.hosts.sessions', {
defaultMessage: 'Sessions',
}),
path: `${HOSTS_PATH}/sessions`,
},
],
},
{
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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 { ColumnHeaderOptions, RowRendererId } from '../../../../common/types/timeline';
import { defaultColumnHeaderType } from '../../../timelines/components/timeline/body/column_headers/default_headers';
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';

export const sessionsHeaders: ColumnHeaderOptions[] = [
{
columnHeaderType: defaultColumnHeaderType,
id: 'process.start',
initialWidth: DEFAULT_DATE_COLUMN_MIN_WIDTH,
},
// TODO: Using event.created as an way of getting the end time of the process. (Currently endpoint doesn't populate process.end)
// event.created of a 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 usually have three events per process.
{
columnHeaderType: defaultColumnHeaderType,
id: 'event.created',
display: 'process.end',
},
{
columnHeaderType: defaultColumnHeaderType,
id: 'process.executable',
},
{
columnHeaderType: defaultColumnHeaderType,
id: 'user.name',
},
{
columnHeaderType: defaultColumnHeaderType,
id: 'process.interactive',
},
{
columnHeaderType: defaultColumnHeaderType,
id: 'process.pid',
},
{
columnHeaderType: defaultColumnHeaderType,
id: 'host.hostname',
},
{
columnHeaderType: defaultColumnHeaderType,
id: 'process.entry_leader.entry_meta.type',
},
{
columnHeaderType: defaultColumnHeaderType,
id: 'process.entry_leader.entry_meta.source.ip',
},
];

export const sessionsDefaultModel: SubsetTimelineModel = {
...timelineDefaults,
columns: sessionsHeaders,
defaultColumns: sessionsHeaders,
excludedRowRendererIds: Object.values(RowRendererId),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* 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, { useEffect } from 'react';
import { waitFor, render } from '@testing-library/react';
import { TestProviders } from '../../mock';
import { TEST_ID, SessionsView, defaultSessionsFilter } from '.';
import { EntityType, TimelineId } from '../../../../../timelines/common';
import { SessionsComponentsProps } from './types';
import { TimelineModel } from '../../../timelines/store/timeline/model';

jest.mock('../../../common/lib/kibana');

jest.mock('../../components/url_state/normalize_time_range.ts');

const startDate = '2022-03-22T22:10:56.794Z';
const endDate = '2022-03-21T22:10:56.791Z';

const filterQuery =
'{"bool":{"must":[],"filter":[{"match_phrase":{"host.name":{"query":"ubuntu-impish"}}}],"should":[],"must_not":[]}}';

const testProps: SessionsComponentsProps = {
timelineId: TimelineId.hostsPageSessions,
entityType: 'sessions',
pageFilters: [],
startDate,
endDate,
filterQuery,
};

type Props = Partial<TimelineModel> & {
start: string;
end: string;
entityType: EntityType;
};

const TEST_PREFIX = 'security_solution:sessions_viewer:sessions_view';

const callFilters = jest.fn();

// creating a dummy component for testing TGrid to avoid mocking all the implementation details
// but still test if the TGrid will render properly
const SessionsViewerTGrid: React.FC<Props> = ({ columns, start, end, id, filters, entityType }) => {
useEffect(() => {
callFilters(filters);
}, [filters]);

return (
<div>
<div data-test-subj={`${TEST_PREFIX}:entityType`}>{entityType}</div>
<div data-test-subj={`${TEST_PREFIX}:startDate`}>{start}</div>
<div data-test-subj={`${TEST_PREFIX}:endDate`}>{end}</div>
<div data-test-subj={`${TEST_PREFIX}:timelineId`}>{id}</div>
{columns?.map((header) => (
<div key={header.id}>{header.display ?? header.id}</div>
))}
</div>
);
};

jest.mock('../../../../../timelines/public/mock/plugin_mock.tsx', () => {
const originalModule = jest.requireActual('../../../../../timelines/public/mock/plugin_mock.tsx');
return {
...originalModule,
createTGridMocks: () => ({
...originalModule.createTGridMocks,
getTGrid: SessionsViewerTGrid,
}),
};
});

describe('SessionsView', () => {
it('renders the session view', async () => {
const wrapper = render(
<TestProviders>
<SessionsView {...testProps} />
</TestProviders>
);

await waitFor(() => {
expect(wrapper.queryByTestId(TEST_ID)).toBeInTheDocument();
});
});

it('renders correctly against snapshot', async () => {
const { asFragment } = render(
<TestProviders>
<SessionsView {...testProps} />
</TestProviders>
);

await waitFor(() => {
expect(asFragment()).toMatchSnapshot();
});
});

it('passes in the right parameters to TGrid', async () => {
const wrapper = render(
<TestProviders>
<SessionsView {...testProps} />
</TestProviders>
);
await waitFor(() => {
expect(wrapper.getByTestId(`${TEST_PREFIX}:entityType`)).toHaveTextContent('sessions');
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'
);
});
});
it('passes in the right filters to TGrid', async () => {
render(
<TestProviders>
<SessionsView {...testProps} />
</TestProviders>
);
await waitFor(() => {
expect(callFilters).toHaveBeenCalledWith([
{
...defaultSessionsFilter,
query: {
...defaultSessionsFilter.query,
bool: {
...defaultSessionsFilter.query.bool,
filter: defaultSessionsFilter.query.bool.filter.concat(JSON.parse(filterQuery)),
},
},
},
]);
});
});
});
Loading