Skip to content

Commit

Permalink
[8.x] [Cloud Security] Refactor Contextual Flyout (#200291) (#201287)
Browse files Browse the repository at this point in the history
# Backport

This will backport the following commits from `main` to `8.x`:
- [[Cloud Security] Refactor Contextual Flyout
(#200291)](#200291)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Rickyanto
Ang","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-11-21T20:33:30Z","message":"[Cloud
Security] Refactor Contextual Flyout (#200291)\n\n## Summary\r\n\r\nThis
PR is for reducing code duplication by Encapsulating
Hooks,\r\nFunctions, constants that are used multiple times in a same
manner\r\naccross multiple files\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<[email protected]>\r\nCo-authored-by:
Maxim Kholod
<[email protected]>","sha":"c842db549ac55238499d63033f046d744ee18ba1","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Cloud
Security","backport:prev-minor","v8.18.0"],"title":"[Cloud Security]
Refactor Contextual
Flyout","number":200291,"url":"https://github.com/elastic/kibana/pull/200291","mergeCommit":{"message":"[Cloud
Security] Refactor Contextual Flyout (#200291)\n\n## Summary\r\n\r\nThis
PR is for reducing code duplication by Encapsulating
Hooks,\r\nFunctions, constants that are used multiple times in a same
manner\r\naccross multiple files\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<[email protected]>\r\nCo-authored-by:
Maxim Kholod
<[email protected]>","sha":"c842db549ac55238499d63033f046d744ee18ba1"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/200291","number":200291,"mergeCommit":{"message":"[Cloud
Security] Refactor Contextual Flyout (#200291)\n\n## Summary\r\n\r\nThis
PR is for reducing code duplication by Encapsulating
Hooks,\r\nFunctions, constants that are used multiple times in a same
manner\r\naccross multiple files\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<[email protected]>\r\nCo-authored-by:
Maxim Kholod
<[email protected]>","sha":"c842db549ac55238499d63033f046d744ee18ba1"}},{"branch":"8.x","label":"v8.18.0","branchLabelMappingKey":"^v8.18.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Rickyanto Ang <[email protected]>
  • Loading branch information
kibanamachine and animehart authored Nov 21, 2024
1 parent b42ac29 commit 4175ab6
Show file tree
Hide file tree
Showing 21 changed files with 360 additions and 463 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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 { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common';
import { useMisconfigurationPreview } from './use_misconfiguration_preview';

export const useHasMisconfigurations = (field: 'host.name' | 'user.name', value: string) => {
const { data } = useMisconfigurationPreview({
query: buildEntityFlyoutPreviewQuery(field, value),
sort: [],
enabled: true,
pageSize: 1,
});

const passedFindings = data?.count.passed || 0;
const failedFindings = data?.count.failed || 0;

const hasMisconfigurationFindings = passedFindings > 0 || failedFindings > 0;

return {
passedFindings,
failedFindings,
hasMisconfigurationFindings,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* 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 { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common';
import { useVulnerabilitiesPreview } from './use_vulnerabilities_preview';
import { hasVulnerabilitiesData } from '../utils/vulnerability_helpers';

export const useHasVulnerabilities = (field: 'host.name' | 'user.name', value: string) => {
const { data: vulnerabilitiesData } = useVulnerabilitiesPreview({
query: buildEntityFlyoutPreviewQuery(field, value),
sort: [],
enabled: true,
pageSize: 1,
});

const {
CRITICAL = 0,
HIGH = 0,
MEDIUM = 0,
LOW = 0,
NONE = 0,
} = vulnerabilitiesData?.count || {};

const counts = {
critical: CRITICAL,
high: HIGH,
medium: MEDIUM,
low: LOW,
none: NONE,
};

const hasVulnerabilitiesFindings = hasVulnerabilitiesData(counts);

return { counts, hasVulnerabilitiesFindings };
};
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('AlertsPreview', () => {
it('renders', () => {
const { getByTestId } = render(
<TestProviders>
<AlertsPreview alertsData={mockAlertsData} name="host1" fieldName="host.name" />
<AlertsPreview alertsData={mockAlertsData} value="host1" field="host.name" />
</TestProviders>
);

Expand All @@ -68,7 +68,7 @@ describe('AlertsPreview', () => {
it('renders correct alerts number', () => {
const { getByTestId } = render(
<TestProviders>
<AlertsPreview alertsData={mockAlertsData} name="host1" fieldName="host.name" />
<AlertsPreview alertsData={mockAlertsData} value="host1" field="host.name" />
</TestProviders>
);

Expand All @@ -78,7 +78,7 @@ describe('AlertsPreview', () => {
it('should render the correct number of distribution bar section based on the number of severities', () => {
const { queryAllByTestId } = render(
<TestProviders>
<AlertsPreview alertsData={mockAlertsData} name="host1" fieldName="host.name" />
<AlertsPreview alertsData={mockAlertsData} value="host1" field="host.name" />
</TestProviders>
);

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

import React, { useCallback, useMemo } from 'react';
import React, { useMemo } from 'react';
import { capitalize } from 'lodash';
import type { EuiThemeComputed } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTitle, useEuiTheme } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { DistributionBar } from '@kbn/security-solution-distribution-bar';
import {
buildEntityFlyoutPreviewQuery,
getAbbreviatedNumber,
} from '@kbn/cloud-security-posture-common';
import { hasVulnerabilitiesData } from '@kbn/cloud-security-posture';
import { useMisconfigurationPreview } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview';
import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import { getAbbreviatedNumber } from '@kbn/cloud-security-posture-common';
import type {
AlertsByStatus,
ParsedAlertsData,
} from '../../../overview/components/detection_response/alerts_by_status/types';
import { ExpandablePanel } from '../../../flyout/shared/components/expandable_panel';
import { getSeverityColor } from '../../../detections/components/alerts_kpis/severity_level_panel/helpers';
import type { HostRiskScore, UserRiskScore } from '../../../../common/search_strategy';
import {
buildHostNamesFilter,
buildUserNamesFilter,
RiskScoreEntity,
} from '../../../../common/search_strategy';
import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score';
import { FIRST_RECORD_PAGINATION } from '../../../entity_analytics/common';
import { HostDetailsPanelKey } from '../../../flyout/entity_details/host_details_left';
import {
EntityDetailsLeftPanelTab,
CspInsightLeftPanelSubTab,
} from '../../../flyout/entity_details/shared/components/left_panel/left_panel_header';
import { UserDetailsPanelKey } from '../../../flyout/entity_details/user_details_left';
import { CspInsightLeftPanelSubTab } from '../../../flyout/entity_details/shared/components/left_panel/left_panel_header';
import { useNavigateEntityInsight } from '../../hooks/use_entity_insight';

const AlertsCount = ({
alertsTotal,
Expand Down Expand Up @@ -77,13 +58,13 @@ const AlertsCount = ({

export const AlertsPreview = ({
alertsData,
fieldName,
name,
field,
value,
isPreviewMode,
}: {
alertsData: ParsedAlertsData;
fieldName: string;
name: string;
field: 'host.name' | 'user.name';
value: string;
isPreviewMode?: boolean;
}) => {
const { euiTheme } = useEuiTheme();
Expand All @@ -107,101 +88,14 @@ export const AlertsPreview = ({

const totalAlertsCount = alertStats.reduce((total, item) => total + item.count, 0);

const { data } = useMisconfigurationPreview({
query: buildEntityFlyoutPreviewQuery(fieldName, name),
sort: [],
enabled: true,
pageSize: 1,
ignore_unavailable: true,
});
const isUsingHostName = fieldName === 'host.name';
const passedFindings = data?.count.passed || 0;
const failedFindings = data?.count.failed || 0;

const hasMisconfigurationFindings = passedFindings > 0 || failedFindings > 0;

const { data: vulnerabilitiesData } = useVulnerabilitiesPreview({
query: buildEntityFlyoutPreviewQuery('host.name', name),
sort: [],
enabled: true,
pageSize: 1,
});

const {
CRITICAL = 0,
HIGH = 0,
MEDIUM = 0,
LOW = 0,
NONE = 0,
} = vulnerabilitiesData?.count || {};

const hasVulnerabilitiesFindings = hasVulnerabilitiesData({
critical: CRITICAL,
high: HIGH,
medium: MEDIUM,
low: LOW,
none: NONE,
});

const buildFilterQuery = useMemo(
() => (isUsingHostName ? buildHostNamesFilter([name]) : buildUserNamesFilter([name])),
[isUsingHostName, name]
);

const riskScoreState = useRiskScore({
riskEntity: isUsingHostName ? RiskScoreEntity.host : RiskScoreEntity.user,
filterQuery: buildFilterQuery,
onlyLatest: false,
pagination: FIRST_RECORD_PAGINATION,
});

const { data: hostRisk } = riskScoreState;

const riskData = hostRisk?.[0];

const isRiskScoreExist = isUsingHostName
? !!(riskData as HostRiskScore)?.host.risk
: !!(riskData as UserRiskScore)?.user.risk;

const hasNonClosedAlerts = totalAlertsCount > 0;

const { openLeftPanel } = useExpandableFlyoutApi();

const goToEntityInsightTab = useCallback(() => {
openLeftPanel({
id: isUsingHostName ? HostDetailsPanelKey : UserDetailsPanelKey,
params: isUsingHostName
? {
name,
isRiskScoreExist,
hasMisconfigurationFindings,
hasVulnerabilitiesFindings,
hasNonClosedAlerts,
path: {
tab: EntityDetailsLeftPanelTab.CSP_INSIGHTS,
subTab: CspInsightLeftPanelSubTab.ALERTS,
},
}
: {
user: { name },
isRiskScoreExist,
hasMisconfigurationFindings,
hasNonClosedAlerts,
path: {
tab: EntityDetailsLeftPanelTab.CSP_INSIGHTS,
subTab: CspInsightLeftPanelSubTab.ALERTS,
},
},
});
}, [
hasMisconfigurationFindings,
hasNonClosedAlerts,
hasVulnerabilitiesFindings,
isRiskScoreExist,
isUsingHostName,
name,
openLeftPanel,
]);
const { goToEntityInsightTab } = useNavigateEntityInsight({
field,
value,
queryIdExtension: 'ALERTS_PREVIEW',
subTab: CspInsightLeftPanelSubTab.ALERTS,
});
const link = useMemo(
() =>
!isPreviewMode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ interface AlertsDetailsFields {
}

export const AlertsDetailsTable = memo(
({ fieldName, queryName }: { fieldName: 'host.name' | 'user.name'; queryName: string }) => {
({ field, value }: { field: 'host.name' | 'user.name'; value: string }) => {
useEffect(() => {
uiMetricService.trackUiMetric(
METRIC_TYPE.COUNT,
Expand Down Expand Up @@ -90,7 +90,7 @@ export const AlertsDetailsTable = memo(
const { to, from } = useGlobalTime();
const { signalIndexName } = useSignalIndex();
const { data } = useQueryAlerts({
query: buildEntityAlertsQuery(fieldName, to, from, queryName, 500),
query: buildEntityAlertsQuery(field, to, from, value, 500),
queryName: ALERTS_QUERY_NAMES.BY_RULE_BY_STATUS,
indexName: signalIndexName,
});
Expand Down Expand Up @@ -216,11 +216,11 @@ export const AlertsDetailsTable = memo(
[
{
title:
fieldName === 'host.name'
field === 'host.name'
? OPEN_IN_ALERTS_TITLE_HOSTNAME
: OPEN_IN_ALERTS_TITLE_USERNAME,
selectedOptions: [queryName],
fieldName,
selectedOptions: [value],
fieldName: field,
},
{
title: OPEN_IN_ALERTS_TITLE_STATUS,
Expand All @@ -230,7 +230,7 @@ export const AlertsDetailsTable = memo(
],
true
),
[fieldName, openAlertsPageWithFilters, queryName]
[field, openAlertsPageWithFilters, value]
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function isCspFlyoutPanelProps(
}

export const InsightsTabCsp = memo(
({ name, fieldName }: { name: string; fieldName: 'host.name' | 'user.name' }) => {
({ value, field }: { value: string; field: 'host.name' | 'user.name' }) => {
const panels = useExpandableFlyoutState();

let hasMisconfigurationFindings = false;
Expand Down Expand Up @@ -150,11 +150,11 @@ export const InsightsTabCsp = memo(
/>
<EuiSpacer size="xl" />
{activeInsightsId === CspInsightLeftPanelSubTab.MISCONFIGURATIONS ? (
<MisconfigurationFindingsDetailsTable fieldName={fieldName} queryName={name} />
<MisconfigurationFindingsDetailsTable field={field} value={value} />
) : activeInsightsId === CspInsightLeftPanelSubTab.VULNERABILITIES ? (
<VulnerabilitiesFindingsDetailsTable queryName={name} />
<VulnerabilitiesFindingsDetailsTable value={value} />
) : (
<AlertsDetailsTable fieldName={fieldName} queryName={name} />
<AlertsDetailsTable field={field} value={value} />
)}
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const getFindingsStats = (passedFindingsStats: number, failedFindingsStats: numb
* Insights view displayed in the document details expandable flyout left section
*/
export const MisconfigurationFindingsDetailsTable = memo(
({ fieldName, queryName }: { fieldName: 'host.name' | 'user.name'; queryName: string }) => {
({ field, value }: { field: 'host.name' | 'user.name'; value: string }) => {
useEffect(() => {
uiMetricService.trackUiMetric(
METRIC_TYPE.COUNT,
Expand All @@ -68,7 +68,7 @@ export const MisconfigurationFindingsDetailsTable = memo(
}, []);

const { data } = useMisconfigurationFindings({
query: buildEntityFlyoutPreviewQuery(fieldName, queryName),
query: buildEntityFlyoutPreviewQuery(field, value),
sort: [],
enabled: true,
pageSize: 1,
Expand Down Expand Up @@ -183,7 +183,7 @@ export const MisconfigurationFindingsDetailsTable = memo(
<EuiPanel hasShadow={false}>
<SecuritySolutionLinkAnchor
deepLinkId={SecurityPageName.cloudSecurityPostureFindings}
path={`${getFindingsPageUrl(queryName, fieldName)}`}
path={`${getFindingsPageUrl(value, field)}`}
target={'_blank'}
external={false}
onClick={() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ interface VulnerabilitiesPackage extends Vulnerability {
};
}

export const VulnerabilitiesFindingsDetailsTable = memo(({ queryName }: { queryName: string }) => {
export const VulnerabilitiesFindingsDetailsTable = memo(({ value }: { value: string }) => {
useEffect(() => {
uiMetricService.trackUiMetric(
METRIC_TYPE.COUNT,
Expand All @@ -53,7 +53,7 @@ export const VulnerabilitiesFindingsDetailsTable = memo(({ queryName }: { queryN
}, []);

const { data } = useVulnerabilitiesFindings({
query: buildEntityFlyoutPreviewQuery('host.name', queryName),
query: buildEntityFlyoutPreviewQuery('host.name', value),
sort: [],
enabled: true,
pageSize: 1,
Expand Down Expand Up @@ -204,7 +204,7 @@ export const VulnerabilitiesFindingsDetailsTable = memo(({ queryName }: { queryN
<EuiPanel hasShadow={false}>
<SecuritySolutionLinkAnchor
deepLinkId={SecurityPageName.cloudSecurityPostureFindings}
path={`${getVulnerabilityUrl(queryName, 'host.name')}`}
path={`${getVulnerabilityUrl(value, 'host.name')}`}
target={'_blank'}
external={false}
onClick={() => {
Expand Down
Loading

0 comments on commit 4175ab6

Please sign in to comment.