From 530d78807a514350dae936235987ea065d7a6cfc Mon Sep 17 00:00:00 2001 From: Michael Olorunnisola Date: Tue, 2 Mar 2021 08:37:30 -0500 Subject: [PATCH] [Security Solution] - Bug fixes (#92294) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../overview_description_list/index.tsx | 4 +- .../network/components/details/index.tsx | 6 +- .../host_overview/endpoint_overview/index.tsx | 134 ++-- .../components/host_overview/index.tsx | 12 +- .../view/resolver_no_process_events.tsx | 2 +- .../__snapshots__/index.test.tsx.snap | 36 +- .../event_details/expandable_event.tsx | 2 +- .../expandable_host.test.tsx.snap | 669 ++++++++++++++++++ .../host_details/expandable_host.test.tsx | 78 ++ .../host_details/expandable_host.tsx | 25 +- .../side_panel/host_details/index.tsx | 25 +- .../timelines/components/side_panel/index.tsx | 11 +- .../side_panel/network_details/index.tsx | 22 +- 13 files changed, 888 insertions(+), 138 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/__snapshots__/expandable_host.test.tsx.snap create mode 100644 x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.test.tsx diff --git a/x-pack/plugins/security_solution/public/common/components/overview_description_list/index.tsx b/x-pack/plugins/security_solution/public/common/components/overview_description_list/index.tsx index 570ac4e9577b7..606991bc08910 100644 --- a/x-pack/plugins/security_solution/public/common/components/overview_description_list/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/overview_description_list/index.tsx @@ -14,13 +14,11 @@ import { DescriptionListStyled } from '../../../common/components/page'; export const OverviewDescriptionList = ({ dataTestSubj, descriptionList, - isInDetailsSidePanel = false, }: { dataTestSubj?: string; descriptionList: DescriptionList[]; - isInDetailsSidePanel: boolean; }) => ( - + ); diff --git a/x-pack/plugins/security_solution/public/network/components/details/index.tsx b/x-pack/plugins/security_solution/public/network/components/details/index.tsx index e263d49e22fc0..851197a78520b 100644 --- a/x-pack/plugins/security_solution/public/network/components/details/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/details/index.tsx @@ -144,11 +144,7 @@ export const IpOverview = React.memo( )} {descriptionLists.map((descriptionList, index) => ( - + ))} {loading && ( diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx index 0d8e763b649bf..4caf854278cc2 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx @@ -20,79 +20,73 @@ import * as i18n from './translations'; interface Props { contextID?: string; data: EndpointFields | null; - isInDetailsSidePanel?: boolean; } -export const EndpointOverview = React.memo( - ({ contextID, data, isInDetailsSidePanel = false }) => { - const getDefaultRenderer = useCallback( - (fieldName: string, fieldData: EndpointFields, attrName: string) => ( - - ), - [contextID] - ); - const descriptionLists: Readonly = useMemo( - () => [ - [ - { - title: i18n.ENDPOINT_POLICY, - description: - data != null && data.endpointPolicy != null - ? data.endpointPolicy - : getEmptyTagValue(), - }, - ], - [ - { - title: i18n.POLICY_STATUS, - description: - data != null && data.policyStatus != null ? ( - - {data.policyStatus} - - ) : ( - getEmptyTagValue() - ), - }, - ], - [ - { - title: i18n.SENSORVERSION, - description: - data != null && data.sensorVersion != null - ? getDefaultRenderer('sensorVersion', data, 'agent.version') - : getEmptyTagValue(), - }, - ], - [], // needs 4 columns for design +export const EndpointOverview = React.memo(({ contextID, data }) => { + const getDefaultRenderer = useCallback( + (fieldName: string, fieldData: EndpointFields, attrName: string) => ( + + ), + [contextID] + ); + const descriptionLists: Readonly = useMemo( + () => [ + [ + { + title: i18n.ENDPOINT_POLICY, + description: + data != null && data.endpointPolicy != null ? data.endpointPolicy : getEmptyTagValue(), + }, + ], + [ + { + title: i18n.POLICY_STATUS, + description: + data != null && data.policyStatus != null ? ( + + {data.policyStatus} + + ) : ( + getEmptyTagValue() + ), + }, ], - [data, getDefaultRenderer] - ); + [ + { + title: i18n.SENSORVERSION, + description: + data != null && data.sensorVersion != null + ? getDefaultRenderer('sensorVersion', data, 'agent.version') + : getEmptyTagValue(), + }, + ], + [], // needs 4 columns for design + ], + [data, getDefaultRenderer] + ); - return ( - <> - {descriptionLists.map((descriptionList, index) => ( - - ))} - - ); - } -); + return ( + <> + {descriptionLists.map((descriptionList, index) => ( + + ))} + + ); +}); EndpointOverview.displayName = 'EndpointOverview'; diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx index de0d782b3ceb7..c5d51a9466235 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx @@ -207,11 +207,7 @@ export const HostOverview = React.memo( )} {descriptionLists.map((descriptionList, index) => ( - + ))} {loading && ( @@ -229,11 +225,7 @@ export const HostOverview = React.memo( <> - + {loading && ( ( - {"event.category: 'process'"} + {'event.category: "process"'} ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap index aece377ee4f2d..a55710f346141 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap @@ -24,9 +24,9 @@ exports[`Details Panel Component DetailsPanel: rendering it should not render th exports[`Details Panel Component DetailsPanel:EventDetails: rendering it should render the Details Panel when the panelView is set and the associated params are set 1`] = ` .c0 { - -webkit-flex: 0; - -ms-flex: 0; - flex: 0; + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + flex: 0 1 auto; }
, .c1 { - -webkit-flex: 0; - -ms-flex: 0; - flex: 0; + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + flex: 0 1 auto; } .c2 .euiFlyoutBody__overflow { @@ -541,7 +541,7 @@ Array [ className="c0" data-test-subj="timeline:details-panel:flyout" onClose={[Function]} - size="s" + size="m" >
, .c1 { - -webkit-flex: 0; - -ms-flex: 0; - flex: 0; + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + flex: 0 1 auto; } .c2 .euiFlyoutBody__overflow { @@ -804,7 +804,7 @@ Array [ }
+ + + + + + +`; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.test.tsx new file mode 100644 index 0000000000000..2ce7090a5b83a --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.test.tsx @@ -0,0 +1,78 @@ +/* + * 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 { mount } from 'enzyme'; +import React from 'react'; + +import '../../../../common/mock/match_media'; +import { + apolloClientObservable, + mockGlobalState, + TestProviders, + SUB_PLUGINS_REDUCER, + kibanaObservable, + createSecuritySolutionStorageMock, +} from '../../../../common/mock'; +import { createStore, State } from '../../../../common/store'; +import { ExpandableHostDetails } from './expandable_host'; + +jest.mock('react-apollo', () => { + const original = jest.requireActual('react-apollo'); + return { + ...original, + // eslint-disable-next-line react/display-name + Query: () => <>, + }; +}); + +describe('Expandable Host Component', () => { + const state: State = { + ...mockGlobalState, + sourcerer: { + ...mockGlobalState.sourcerer, + configIndexPatterns: ['IShouldBeUsed'], + }, + }; + + const { storage } = createSecuritySolutionStorageMock(); + const store = createStore( + state, + SUB_PLUGINS_REDUCER, + apolloClientObservable, + kibanaObservable, + storage + ); + + const mockProps = { + contextID: 'text-context', + hostName: 'testHostName', + }; + + describe('ExpandableHostDetails: rendering', () => { + test('it should render the HostOverview of the ExpandableHostDetails', () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find('ExpandableHostDetails')).toMatchSnapshot(); + }); + + test('it should render the HostOverview of the ExpandableHostDetails with the correct indices', () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find('HostOverviewByNameComponentQuery').prop('indexNames')).toStrictEqual([ + 'IShouldBeUsed', + ]); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx index 8fce9a186bbd4..78367d17d7b62 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx @@ -5,10 +5,11 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import styled from 'styled-components'; import { i18n } from '@kbn/i18n'; import { EuiTitle } from '@elastic/eui'; +import { sourcererSelectors } from '../../../../common/store/sourcerer'; import { HostDetailsLink } from '../../../../common/components/links'; import { useGlobalTime } from '../../../../common/containers/use_global_time'; import { useSourcererScope } from '../../../../common/containers/sourcerer'; @@ -19,6 +20,7 @@ import { AnomalyTableProvider } from '../../../../common/components/ml/anomaly/a import { hostToCriteria } from '../../../../common/components/ml/criteria/host_to_criteria'; import { scoreIntervalToDateTime } from '../../../../common/components/ml/score/score_interval_to_datetime'; import { HostOverviewByNameQuery } from '../../../../hosts/containers/hosts/details'; +import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; interface ExpandableHostProps { hostName: string; @@ -54,10 +56,25 @@ export const ExpandableHostDetails = ({ hostName, }: ExpandableHostProps & { contextID: string }) => { const { to, from, isInitializing } = useGlobalTime(); - const { docValueFields, selectedPatterns } = useSourcererScope(); + const { docValueFields } = useSourcererScope(); + /* + Normally `selectedPatterns` from useSourcerScope would be where we obtain the indices, + but those indices are only loaded when viewing the pages where the sourcerer is initialized (i.e. Hosts and Overview) + When a user goes directly to the detections page, the patterns have not been loaded yet + as that information isn't used for the detections page. With this details component being accessible + from the detections page, the decision was made to get all existing index names to account for this. + Otherwise, an empty array is defaulted for the `indexNames` in the query which leads to inconsistencies in the data returned + (i.e. extraneous endpoint data is retrieved from the backend leading to endpoint data not being returned) + */ + const allExistingIndexNamesSelector = useMemo( + () => sourcererSelectors.getAllExistingIndexNamesSelector(), + [] + ); + const allPatterns = useDeepEqualSelector(allExistingIndexNamesSelector); + return ( `${theme.eui.paddingSizes.xs} ${theme.eui.paddingSizes.m} 64px`}; + margin-bottom: ${({ theme }) => `${theme.eui.paddingSizes.l}`}; + padding: ${({ theme }) => `${theme.eui.paddingSizes.xs} ${theme.eui.paddingSizes.m} 0px`}; } } `; const StyledEuiFlexGroup = styled(EuiFlexGroup)` - flex: 0; -`; - -const StyledEuiFlexItem = styled(EuiFlexItem)` - &.euiFlexItem { - flex: 1 0 0; - overflow-y: scroll; - overflow-x: hidden; - } + flex: 1 0 auto; `; const StyledEuiFlexButtonWrapper = styled(EuiFlexItem)` align-self: flex-start; + flex: 1 0 auto; +`; + +const StyledPanelContent = styled.div` + display: block; + height: 100%; + overflow-y: scroll; + overflow-x: hidden; `; interface HostDetailsProps { @@ -107,9 +108,9 @@ export const HostDetailsPanel: React.FC = React.memo( - + - + ); } diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx index 0482491562f57..177cd2e5ded41 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx @@ -7,7 +7,7 @@ import React, { useCallback, useMemo } from 'react'; import { useDispatch } from 'react-redux'; -import { EuiFlyout } from '@elastic/eui'; +import { EuiFlyout, EuiFlyoutProps } from '@elastic/eui'; import styled from 'styled-components'; import { timelineActions, timelineSelectors } from '../../store/timeline'; import { timelineDefaults } from '../../store/timeline/defaults'; @@ -69,9 +69,10 @@ export const DetailsPanel = React.memo( if (!currentTabDetail?.panelView) return null; let visiblePanel = null; // store in variable to make return statement more readable + let panelSize: EuiFlyoutProps['size'] = 's'; const contextID = `${timelineId}-${activeTab}`; - if (currentTabDetail?.panelView === 'eventDetail' && currentTabDetail?.params?.eventId) { + panelSize = 'm'; visiblePanel = ( + {visiblePanel} ) : ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/index.tsx index e05c9435fc456..ea857da926f84 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/index.tsx @@ -42,19 +42,19 @@ const StyledEuiFlyoutBody = styled(EuiFlyoutBody)` `; const StyledEuiFlexGroup = styled(EuiFlexGroup)` - flex: 0; -`; - -const StyledEuiFlexItem = styled(EuiFlexItem)` - &.euiFlexItem { - flex: 1 0 0; - overflow-y: scroll; - overflow-x: hidden; - } + flex: 1 0 auto; `; const StyledEuiFlexButtonWrapper = styled(EuiFlexItem)` align-self: flex-start; + flex: 1 0 auto; +`; + +const StyledPanelContent = styled.div` + display: block; + height: 100%; + overflow-y: scroll; + overflow-x: hidden; `; interface NetworkDetailsProps { @@ -104,9 +104,9 @@ export const NetworkDetailsPanel = React.memo( - + - + ); }