Skip to content

Commit

Permalink
Add host risk tab to Hosts page (#122980)
Browse files Browse the repository at this point in the history
* Add host risk tab to Hosts page

Co-authored-by: Steph Milovic <stephanie.milovic@elastic.co>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
3 people authored Feb 1, 2022
1 parent 934302d commit d862d9b
Show file tree
Hide file tree
Showing 77 changed files with 3,472 additions and 2,138 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { CloudEcs } from '../../../../ecs/cloud';
import { HostEcs, OsEcs } from '../../../../ecs/host';
import { Hit, Hits, Maybe, SearchHit, StringOrNumber, TotalValue } from '../../../common';
import { EndpointPendingActions, HostStatus } from '../../../../endpoint/types';
import { HostRiskSeverity } from '../kpi';

export enum HostPolicyResponseActionStatus {
success = 'success',
Expand Down Expand Up @@ -126,3 +127,21 @@ export interface HostHit extends Hit {
}

export type HostHits = Hits<number, HostHit>;

export const enum HostRiskScoreFields {
timestamp = '@timestamp',
hostName = 'host.name',
riskScore = 'risk_stats.risk_score',
risk = 'risk',
// TODO: Steph/Host Risk
// ruleRisks = 'rule_risks',
}

export interface HostRiskScoreItem {
_id?: Maybe<string>;
[HostRiskScoreFields.hostName]: Maybe<string>;
[HostRiskScoreFields.risk]: Maybe<HostRiskSeverity>;
[HostRiskScoreFields.riskScore]: Maybe<number>;
// TODO: Steph/Host Risk
// [HostRiskScoreFields.ruleRisks]: Maybe<RuleRisk[]>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface HostsKpiRiskyHostsStrategyResponse extends IEsSearchResponse {
};
}

export enum HostRiskSeverity {
export const enum HostRiskSeverity {
unknown = 'Unknown',
low = 'Low',
moderate = 'Moderate',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,32 @@
* 2.0.
*/

import { FactoryQueryTypes } from '../..';
import { FactoryQueryTypes, HostRiskScoreFields } from '../..';
import type {
IEsSearchRequest,
IEsSearchResponse,
} from '../../../../../../../../src/plugins/data/common';
import { RISKY_HOSTS_INDEX_PREFIX } from '../../../../constants';
import { Direction, Inspect, Maybe, TimerangeInput } from '../../../common';
import { ESQuery } from '../../../../typed_json';
import { Inspect, Maybe, SortField, TimerangeInput } from '../../../common';

export interface HostsRiskScoreRequestOptions extends IEsSearchRequest {
defaultIndex: string[];
factoryQueryType?: FactoryQueryTypes;
hostNames?: string[];
timerange?: TimerangeInput;
onlyLatest?: boolean;
limit?: number;
sortOrder?: Direction.asc | Direction.desc;
pagination?: {
cursorStart: number;
querySize: number;
};
sort?: HostRiskScoreSortField;
filterQuery?: ESQuery | string | undefined;
}

export interface HostsRiskScoreStrategyResponse extends IEsSearchResponse {
inspect?: Maybe<Inspect>;
totalCount: number;
}

export interface HostsRiskScore {
Expand All @@ -42,8 +48,11 @@ export interface HostsRiskScore {
export interface RuleRisk {
rule_name: string;
rule_risk: number;
rule_id?: string; // TODO Remove the '?' when the new transform is delivered
}

export const getHostRiskIndex = (spaceId: string, onlyLatest: boolean = true): string => {
return `${RISKY_HOSTS_INDEX_PREFIX}${onlyLatest ? 'latest_' : ''}${spaceId}`;
};

export type HostRiskScoreSortField = SortField<HostRiskScoreFields>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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 { loginAndWaitForHostDetailsPage } from '../../tasks/login';

import { cleanKibana } from '../../tasks/common';
import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver';
import { TABLE_CELL, TABLE_ROWS } from '../../screens/alerts_details';

describe('risk tab', () => {
before(() => {
cleanKibana();
esArchiverLoad('risky_hosts');
});

after(() => {
esArchiverUnload('risky_hosts');
});

it('renders risk tab', () => {
loginAndWaitForHostDetailsPage('siem-kibana');
cy.get('[data-test-subj="navigation-hostRisk"]').click();
waitForTableToLoad();

cy.get('[data-test-subj="topHostScoreContributors"]')
.find(TABLE_ROWS)
.within(() => {
cy.get(TABLE_CELL).contains('Unusual Linux Username');
});
});

it('shows risk information overlay when button is clicked', () => {
loginAndWaitForHostDetailsPage('siem-kibana');
cy.get('[data-test-subj="navigation-hostRisk"]').click();
waitForTableToLoad();

cy.get('[data-test-subj="open-risk-information-flyout-trigger"]').click();

cy.get('[data-test-subj="open-risk-information-flyout"] .euiFlyoutHeader').contains(
'How is host risk calculated?'
);
});
});

export const waitForTableToLoad = () => {
cy.get('.euiBasicTable-loading').should('exist');
cy.get('.euiBasicTable-loading').should('not.exist');
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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 { cleanKibana } from '../../tasks/common';
import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver';
import { navigateToHostRiskDetailTab } from '../../tasks/host_risk';
import {
HOST_BY_RISK_TABLE_CELL,
HOST_BY_RISK_TABLE_FILTER,
HOST_BY_RISK_TABLE_FILTER_CRITICAL,
} from '../../screens/hosts/host_risk';
import { loginAndWaitForPage } from '../../tasks/login';
import { HOSTS_URL } from '../../urls/navigation';

describe('risk tab', () => {
before(() => {
cleanKibana();
esArchiverLoad('risky_hosts');
loginAndWaitForPage(HOSTS_URL);
navigateToHostRiskDetailTab();
});

after(() => {
esArchiverUnload('risky_hosts');
});

it('renders the table', () => {
cy.get(HOST_BY_RISK_TABLE_CELL).eq(3).should('have.text', 'siem-kibana');
cy.get(HOST_BY_RISK_TABLE_CELL).eq(4).should('have.text', '21.00');
cy.get(HOST_BY_RISK_TABLE_CELL).eq(5).should('have.text', 'Low');
});

it('filters the table', () => {
cy.get(HOST_BY_RISK_TABLE_FILTER).click();
cy.get(HOST_BY_RISK_TABLE_FILTER_CRITICAL).click();

cy.get(HOST_BY_RISK_TABLE_CELL).eq(3).should('not.have.text', 'siem-kibana');
});
});

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

export const RULE_NAME = '[data-test-subj="topHostScoreContributors"] .euiTableCellContent__text';
export const RULE_NAME = '[data-test-subj="topHostScoreContributors"] .euiTableCellContent';

export const RISK_FLYOUT = '[data-test-subj="open-risk-information-flyout"] .euiFlyoutHeader';

Expand All @@ -14,3 +14,13 @@ export const RISK_DETAILS_NAV = '[data-test-subj="navigation-hostRisk"]';
export const RISK_FLYOUT_TRIGGER = '[data-test-subj="open-risk-information-flyout-trigger"]';

export const LOADING_TABLE = '.euiBasicTable-loading';

export const HOST_BY_RISK_TABLE = '.table-hostRisk-loading-false';

export const HOST_BY_RISK_TABLE_CELL =
'[data-test-subj="table-hostRisk-loading-false"] .euiTableCellContent';

export const HOST_BY_RISK_TABLE_FILTER = '[data-test-subj="host-risk-filter-button"]';

export const HOST_BY_RISK_TABLE_FILTER_CRITICAL =
'[data-test-subj="host-risk-filter-item-Critical"]';
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import { EuiLoadingSpinner, EuiPanel, EuiSpacer, EuiLink, EuiText } from '@elast
import { FormattedMessage } from '@kbn/i18n-react';
import * as i18n from './translations';
import { RISKY_HOSTS_DOC_LINK } from '../../../../overview/components/overview_risky_host_links/risky_hosts_disabled_module';
import type { HostRisk } from '../../../containers/hosts_risk/use_hosts_risk_score';
import { EnrichedDataRow, ThreatSummaryPanelHeader } from './threat_summary_view';
import { HostRisk } from '../../../containers/hosts_risk/types';
import { HostRiskScore } from '../../../../hosts/components/common/host_risk_score';
import { HostRiskSeverity } from '../../../../../common/search_strategy';

const HostRiskSummaryComponent: React.FC<{
hostRisk: HostRisk;
Expand Down Expand Up @@ -51,7 +53,15 @@ const HostRiskSummaryComponent: React.FC<{

{hostRisk.isModuleEnabled && hostRisk.result && hostRisk.result.length > 0 && (
<>
<EnrichedDataRow field={'host.risk.keyword'} value={hostRisk.result[0].risk} />
<EnrichedDataRow
field={'host.risk.keyword'}
value={
<HostRiskScore
severity={hostRisk.result[0].risk as HostRiskSeverity}
hideBackgroundColor
/>
}
/>
</>
)}
</EuiPanel>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ import {
BrowserFields,
TimelineEventsDetailsItem,
} from '../../../../../common/search_strategy';
import { HostRisk } from '../../../containers/hosts_risk/use_hosts_risk_score';
import { HostRiskSummary } from './host_risk_summary';
import { EnrichmentSummary } from './enrichment_summary';
import { HostRisk } from '../../../containers/hosts_risk/types';

export interface ThreatSummaryDescription {
browserField: BrowserField;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,9 @@ import {
} from './cti_details/helpers';
import { EnrichmentRangePicker } from './cti_details/enrichment_range_picker';
import { Reason } from './reason';

import { InvestigationGuideView } from './investigation_guide_view';

import { HostRisk } from '../../containers/hosts_risk/use_hosts_risk_score';
import { Overview } from './overview';
import { HostRisk } from '../../containers/hosts_risk/types';

type EventViewTab = EuiTabbedContentTab;

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
Expand Up @@ -39,10 +39,12 @@ Header.displayName = 'Header';

export interface HeaderSectionProps extends HeaderProps {
children?: React.ReactNode;
headerFilters?: string | React.ReactNode;
height?: number;
id?: string;
isInspectDisabled?: boolean;
split?: boolean;
stackHeader?: boolean;
subtitle?: string | React.ReactNode;
title: string | React.ReactNode;
titleSize?: EuiTitleSize;
Expand All @@ -55,10 +57,12 @@ export interface HeaderSectionProps extends HeaderProps {
const HeaderSectionComponent: React.FC<HeaderSectionProps> = ({
border,
children,
headerFilters,
height,
id,
isInspectDisabled,
split,
stackHeader,
subtitle,
title,
titleSize = 'm',
Expand All @@ -68,7 +72,11 @@ const HeaderSectionComponent: React.FC<HeaderSectionProps> = ({
hideSubtitle = false,
}) => (
<Header data-test-subj="header-section" border={border} height={height}>
<EuiFlexGroup alignItems="center" gutterSize="s">
<EuiFlexGroup
alignItems={stackHeader ? undefined : 'center'}
direction={stackHeader ? 'column' : 'row'}
gutterSize="s"
>
<EuiFlexItem grow={growLeftSplit}>
<EuiFlexGroup alignItems="center" responsive={false} gutterSize="s">
<EuiFlexItem>
Expand Down Expand Up @@ -99,6 +107,8 @@ const HeaderSectionComponent: React.FC<HeaderSectionProps> = ({
/>
</EuiFlexItem>
)}

{headerFilters && <EuiFlexItem grow={false}>{headerFilters}</EuiFlexItem>}
</EuiFlexGroup>
</EuiFlexItem>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { SecurityPageName } from '../../../app/types';

export { getDetectionEngineUrl, getRuleDetailsUrl } from './redirect_to_detection_engine';
export { getAppOverviewUrl } from './redirect_to_overview';
export { getHostDetailsUrl, getHostsUrl } from './redirect_to_hosts';
export { getHostDetailsUrl, getTabsOnHostDetailsUrl, getHostsUrl } from './redirect_to_hosts';
export { getNetworkUrl, getNetworkDetailsUrl } from './redirect_to_network';
export { getTimelineTabsUrl, getTimelineUrl } from './redirect_to_timelines';
export {
Expand Down
Loading

0 comments on commit d862d9b

Please sign in to comment.