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

Create Entity Analytics dashboard #137688

Merged
merged 29 commits into from
Aug 25, 2022
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
07fdd39
wip - create new page
machadoum Jul 26, 2022
9514aaa
Add Hosts risk dashboard to Entity analytics
machadoum Jul 28, 2022
12b8b10
Add entiry analytics to old menu
machadoum Jul 28, 2022
78b2539
Add entity analytics dashboard header
machadoum Jul 29, 2022
3f55204
Add User risk dashboard to Entity analytics
machadoum Jul 29, 2022
4846381
Improve entity analytics navigation links
machadoum Aug 1, 2022
70bebf8
Add entityAnalyticsDashoardEnabled feature flag
machadoum Aug 1, 2022
a14a85f
Fix type
machadoum Aug 1, 2022
8b51e93
Add user and host risk dashboard empty state
machadoum Aug 8, 2022
0e333ed
Improve entity analytics dashboard code reusability
machadoum Aug 9, 2022
db0a20b
Add unit tests
machadoum Aug 9, 2022
cc5d18c
Move useEnableHostRiskFromUrl to a shared folder
machadoum Aug 9, 2022
42b6c75
Improve entity analytics page when host/user flags are disabled
machadoum Aug 10, 2022
96f24ba
Add cypress tests
machadoum Aug 10, 2022
1a1e1c6
Small tooltip fix
machadoum Aug 10, 2022
eda3742
Delete comments
machadoum Aug 10, 2022
94bd983
Fix small cypress issue
machadoum Aug 10, 2022
c8a80df
Fix typo
machadoum Aug 10, 2022
cfa77e0
Fix unit tests
machadoum Aug 11, 2022
2542c03
Upgrade Entity analytics license to platinum
machadoum Aug 11, 2022
f7f6bfa
Merge branch 'main' into analytics-dashboard
kibanamachine Aug 11, 2022
e042239
Disable feature flag
machadoum Aug 12, 2022
06018de
Merge remote-tracking branch 'elastic/main' into analytics-dashboard
machadoum Aug 15, 2022
17c37e8
Fix broken link to user risk tab
machadoum Aug 16, 2022
9d87041
Fix typos
machadoum Aug 16, 2022
7348fa4
Add ml permission check for entity analytics dashboard old menu
machadoum Aug 16, 2022
de336dd
Merge remote-tracking branch 'elastic/main' into analytics-dashboard
machadoum Aug 24, 2022
3e94c5d
Fix merge issues
machadoum Aug 24, 2022
2b296b4
Code review improvements
machadoum Aug 25, 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
4 changes: 3 additions & 1 deletion x-pack/plugins/security_solution/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export enum SecurityPageName {
usersAuthentications = 'users-authentications',
usersEvents = 'users-events',
usersRisk = 'users-risk',
entityAnalytics = 'entity-analytics',
}

export const EXPLORE_PATH = '/explore' as const;
Expand Down Expand Up @@ -159,7 +160,7 @@ export const HOST_ISOLATION_EXCEPTIONS_PATH =
`${MANAGEMENT_PATH}/host_isolation_exceptions` as const;
export const BLOCKLIST_PATH = `${MANAGEMENT_PATH}/blocklist` as const;
export const RESPONSE_ACTIONS_PATH = `${MANAGEMENT_PATH}/response_actions` as const;

export const ENTITY_ANALYTICS_PATH = '/entity_analytics' as const;
export const APP_OVERVIEW_PATH = `${APP_PATH}${OVERVIEW_PATH}` as const;
export const APP_LANDING_PATH = `${APP_PATH}${LANDING_PATH}` as const;
export const APP_DETECTION_RESPONSE_PATH = `${APP_PATH}${DETECTION_RESPONSE_PATH}` as const;
Expand All @@ -183,6 +184,7 @@ export const APP_HOST_ISOLATION_EXCEPTIONS_PATH =
`${APP_PATH}${HOST_ISOLATION_EXCEPTIONS_PATH}` as const;
export const APP_BLOCKLIST_PATH = `${APP_PATH}${BLOCKLIST_PATH}` as const;
export const APP_RESPONSE_ACTIONS_PATH = `${APP_PATH}${RESPONSE_ACTIONS_PATH}` as const;
export const APP_ENTITY_ANALYTICS_PATH = `${APP_PATH}${ENTITY_ANALYTICS_PATH}` as const;

// cloud logs to exclude from default index pattern
export const EXCLUDE_ELASTIC_CLOUD_INDICES = ['-*elastic-cloud-logs-*'];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const allowedExperimentalValues = Object.freeze({
policyListEnabled: true,
policyResponseInFleetEnabled: true,
threatIntelligenceEnabled: false,
entityAnalyticsDashboardEnabled: false,

/**
* This is used for enabling the end-to-end tests for the security_solution telemetry.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* 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 { login, visit } from '../../tasks/login';

import { ENTITY_ANALYTICS_URL } from '../../urls/navigation';

import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver';
import { cleanKibana } from '../../tasks/common';
import {
ENABLE_HOST_RISK_SCORE_BUTTON,
ENABLE_USER_RISK_SCORE_BUTTON,
HOSTS_DONUT_CHART,
HOSTS_TABLE,
TABLE_ROWS,
USERS_DONUT_CHART,
USERS_TABLE,
} from '../../screens/entity_analytics';
import { openRiskTableFilterAndSelectTheLowOption } from '../../tasks/host_risk';

describe('Entity Analytics Dashboard', () => {
before(() => {
cleanKibana();
login();
});

describe('Without data', () => {
before(() => {
visit(ENTITY_ANALYTICS_URL);
});

it('shows enable host risk button', () => {
visit(ENTITY_ANALYTICS_URL);
machadoum marked this conversation as resolved.
Show resolved Hide resolved
cy.get(ENABLE_HOST_RISK_SCORE_BUTTON).should('be.visible');
});

it('shows enable user risk button', () => {
cy.get(ENABLE_USER_RISK_SCORE_BUTTON).should('be.visible');
});
});

describe('With host risk data', () => {
before(() => {
esArchiverLoad('risky_hosts');
visit(ENTITY_ANALYTICS_URL);
});

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

it('renders donut chart', () => {
cy.get(HOSTS_DONUT_CHART).should('be.visible');
machadoum marked this conversation as resolved.
Show resolved Hide resolved
cy.get(HOSTS_DONUT_CHART).should('include.text', '6Total');
});

it('renders table', () => {
cy.get(HOSTS_TABLE).should('be.visible');
cy.get(TABLE_ROWS).should('have.length', 5);
});

it('filters by risk classification', () => {
openRiskTableFilterAndSelectTheLowOption();

cy.get(HOSTS_DONUT_CHART).should('include.text', '1Total');
cy.get(TABLE_ROWS).should('have.length', 1);
});
});

describe('With user risk data', () => {
before(() => {
esArchiverLoad('risky_users');
visit(ENTITY_ANALYTICS_URL);
});

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

it('renders donut chart', () => {
cy.get(USERS_DONUT_CHART).should('be.visible');
machadoum marked this conversation as resolved.
Show resolved Hide resolved
cy.get(USERS_DONUT_CHART).should('include.text', '6Total');
});

it('renders table', () => {
cy.get(USERS_TABLE).should('be.visible');
cy.get(TABLE_ROWS).should('have.length', 5);
});

it('filters by risk classification', () => {
openRiskTableFilterAndSelectTheLowOption();

cy.get(USERS_DONUT_CHART).should('include.text', '1Total');
cy.get(TABLE_ROWS).should('have.length', 1);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
POLICIES,
EXPLORE,
MANAGE,
ENTITY_ANALYTICS,
} from '../../screens/security_header';

import { login, visit } from '../../tasks/login';
Expand Down Expand Up @@ -58,6 +59,7 @@ import {
CSP_BENCHMARKS_URL,
CSP_FINDINGS_URL,
POLICIES_URL,
ENTITY_ANALYTICS_URL,
INDICATORS_URL,
} from '../../urls/navigation';
import {
Expand Down Expand Up @@ -99,6 +101,11 @@ describe('top-level navigation common to all pages in the Security app', () => {
cy.url().should('include', DETECTION_RESPONSE_URL);
});

it('navigates to the Entity Analytics page', () => {
navigateFromHeaderTo(ENTITY_ANALYTICS);
cy.url().should('include', ENTITY_ANALYTICS_URL);
});

it('navigates to the Kubernetes page', () => {
navigateFromHeaderTo(KUBERNETES);
cy.url().should('include', KUBERNETES_URL);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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.
*/

export const ENABLE_HOST_RISK_SCORE_BUTTON = '[data-test-subj="enable_host_risk_score"]';

export const HOSTS_DONUT_CHART =
'[data-test-subj="entity_analytics_hosts"] [data-test-subj="donut-chart"]';

export const HOSTS_TABLE = '[data-test-subj="entity_analytics_hosts"] #hostRiskDashboardTable';

export const TABLE_ROWS = '.euiTableRow';

export const USERS_DONUT_CHART =
'[data-test-subj="entity_analytics_users"] [data-test-subj="donut-chart"]';

export const USERS_TABLE = '[data-test-subj="entity_analytics_users"] #userRiskDashboardTable';

export const ENABLE_USER_RISK_SCORE_BUTTON = '[data-test-subj="enable_user_risk_score"]';
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export const HOST_BY_RISK_TABLE_FILTER = '[data-test-subj="risk-filter-button"]'

export const HOST_BY_RISK_TABLE_FILTER_CRITICAL = '[data-test-subj="risk-filter-item-Critical"]';

export const HOST_BY_RISK_TABLE_FILTER_LOW = '[data-test-subj="risk-filter-item-Low"]';

export const HOST_BY_RISK_TABLE_PERPAGE_BUTTON =
'[data-test-subj="loadingMoreSizeRowPopover"] button';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export const OVERVIEW = '[data-test-subj="groupedNavPanelLink-overview"]';

export const DETECTION_RESPONSE = '[data-test-subj="groupedNavPanelLink-detection_response"]';

export const ENTITY_ANALYTICS = '[data-test-subj="groupedNavPanelLink-entity-analytics"]';

export const KUBERNETES = '[data-test-subj="groupedNavPanelLink-kubernetes"]';

export const CSP_DASHBOARD =
Expand Down Expand Up @@ -71,6 +73,7 @@ export const openNavigationPanelFor = (page: string) => {
case OVERVIEW:
case DETECTION_RESPONSE:
case KUBERNETES:
case ENTITY_ANALYTICS:
case CSP_DASHBOARD: {
panel = DASHBOARDS;
break;
Expand Down
8 changes: 8 additions & 0 deletions x-pack/plugins/security_solution/cypress/tasks/host_risk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import {
HOST_BY_RISK_TABLE_FILTER,
HOST_BY_RISK_TABLE_FILTER_CRITICAL,
HOST_BY_RISK_TABLE_FILTER_LOW,
HOST_BY_RISK_TABLE_PERPAGE_BUTTON,
HOST_BY_RISK_TABLE_PERPAGE_OPTIONS,
LOADING_SPINNER,
Expand All @@ -23,9 +24,16 @@ export const openRiskTableFilterAndSelectTheCriticalOption = () => {
cy.get(HOST_BY_RISK_TABLE_FILTER).click();
cy.get(HOST_BY_RISK_TABLE_FILTER_CRITICAL).click();
};

export const openRiskTableFilterAndSelectTheLowOption = () => {
cy.get(HOST_BY_RISK_TABLE_FILTER).click();
cy.get(HOST_BY_RISK_TABLE_FILTER_LOW).click();
};

export const removeCritialFilter = () => {
cy.get(HOST_BY_RISK_TABLE_FILTER_CRITICAL).click();
};

export const selectFiveItemsPerPageOption = () => {
cy.get(HOST_BY_RISK_TABLE_PERPAGE_BUTTON).click();
cy.get(HOST_BY_RISK_TABLE_PERPAGE_OPTIONS).first().click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const NETWORK_URL = '/app/security/network';
export const OVERVIEW_URL = '/app/security/overview';
export const DASHBOARDS_URL = '/app/security/dashboards';
export const DETECTION_RESPONSE_URL = '/app/security/detection_response';
export const ENTITY_ANALYTICS_URL = '/app/security/entity_analytics';
export const KUBERNETES_URL = '/app/security/kubernetes';
export const CSP_DASHBOARD_URL = '/app/security/cloud_security_posture/dashboard';
export const INDICATORS_URL = '/app/security/threat_intelligence/indicators';
Expand Down
15 changes: 15 additions & 0 deletions x-pack/plugins/security_solution/public/app/deep_links/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
OVERVIEW,
POLICIES,
RESPONSE_ACTIONS,
ENTITY_ANALYTICS,
RULES,
TIMELINES,
TRUSTED_APPLICATIONS,
Expand All @@ -65,6 +66,7 @@ import {
OVERVIEW_PATH,
POLICIES_PATH,
RESPONSE_ACTIONS_PATH,
ENTITY_ANALYTICS_PATH,
RULES_CREATE_PATH,
RULES_PATH,
SERVER_APP_ID,
Expand Down Expand Up @@ -166,6 +168,19 @@ export const securitySolutionsDeepLinks: SecuritySolutionDeepLink[] = [
...getSecuritySolutionLink<SecurityPageName>('dashboard'),
features: [FEATURE.general],
},
{
id: SecurityPageName.entityAnalytics,
title: ENTITY_ANALYTICS,
path: ENTITY_ANALYTICS_PATH,
features: [FEATURE.general],
experimentalKey: 'entityAnalyticsDashboardEnabled',
isPremium: true,
keywords: [
i18n.translate('xpack.securitySolution.search.entityAnalytics', {
defaultMessage: 'Entity Analytics',
}),
],
},
],
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
APP_KUBERNETES_PATH,
APP_LANDING_PATH,
APP_RESPONSE_ACTIONS_PATH,
APP_ENTITY_ANALYTICS_PATH,
APP_PATH,
} from '../../../common/constants';

Expand Down Expand Up @@ -188,6 +189,13 @@ export const navTabs: SecurityNav = {
...getSecuritySolutionCSPNavTab<SecurityPageName>('rules', APP_PATH),
urlKey: 'administration',
},
[SecurityPageName.entityAnalytics]: {
id: SecurityPageName.entityAnalytics,
name: i18n.ENTITY_ANALYTICS,
href: APP_ENTITY_ANALYTICS_PATH,
disabled: false,
urlKey: 'entity_analytics',
},
};

export const securityNavGroup: SecurityNavGroup = {
Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/security_solution/public/app/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ export const DETECTION_RESPONSE = i18n.translate(
}
);

export const ENTITY_ANALYTICS = i18n.translate(
'xpack.securitySolution.navigation.entityAnalytics',
{
defaultMessage: 'Entity Analytics',
}
);

export const HOSTS = i18n.translate('xpack.securitySolution.navigation.hosts', {
defaultMessage: 'Hosts',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ describe('DonutChart', () => {
const props: DonutChartProps = {
data: parsedMockAlertsData?.open?.severities,
label: 'Open',
link: null,
machadoum marked this conversation as resolved.
Show resolved Hide resolved
title: <ChartLabel count={parsedMockAlertsData?.open?.total} />,
fillColor: jest.fn(() => '#ccc'),
totalCount: parsedMockAlertsData?.open?.total,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,8 @@ export interface DonutChartProps {
data: DonutChartData[] | null | undefined;
fillColor: FillColor;
height?: number;
label: string;
label: React.ReactElement | string;
legendItems?: LegendItem[] | null | undefined;
link?: string | null;
title: React.ReactElement | string | number | null;
totalCount: number | null | undefined;
}
Expand All @@ -71,7 +70,6 @@ export const DonutChart = ({
height = 90,
label,
legendItems,
link,
title,
totalCount,
}: DonutChartProps) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const LegendItemComponent: React.FC<{

return (
<EuiText size="xs">
<EuiFlexGroup alignItems="center" gutterSize="none">
<EuiFlexGroup alignItems="center" gutterSize="none" responsive={false}>
machadoum marked this conversation as resolved.
Show resolved Hide resolved
{color != null && (
<EuiFlexItem grow={false}>
<EuiHealth data-test-subj="legend-color" color={color} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ export const getTabsOnUsersDetailsUrl = (
tabName: UsersTableType,
search?: string
) => `/name/${detailName}/${tabName}${appendSearch(search)}`;

export const getTabsOnUsersUrl = (tabName: UsersTableType, search?: string) =>
`/${tabName}${appendSearch(search)}`;
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ export type UrlStateType =
| 'dashboards'
| 'indicators'
| 'cloud_posture'
| 'findings';
| 'findings'
| 'entity_analytics';

export type SecurityNavGroup = Record<SecurityNavGroupKey, NavGroupTab>;
export interface NavTab {
Expand Down Expand Up @@ -87,6 +88,7 @@ export const securityNavKeys = [
SecurityPageName.cloudSecurityPostureFindings,
SecurityPageName.cloudSecurityPostureBenchmarks,
SecurityPageName.cloudSecurityPostureRules,
SecurityPageName.entityAnalytics,
] as const;
export type SecurityNavKey = typeof securityNavKeys[number];

Expand Down
Loading