From df9fd9d0304a6d7c44c6b8542fb9943e29a3d0d2 Mon Sep 17 00:00:00 2001
From: Jordan <51442161+JordanSh@users.noreply.github.com>
Date: Thu, 28 Sep 2023 11:33:24 +0300
Subject: [PATCH] [Cloud Security] Azure support for dashboard and flyout and
PLG for dashboard (#167422)
---
.../common/constants.ts | 3 +
.../components/accounts_evaluated_widget.tsx | 132 +++++++++++-------
.../public/components/cis_benchmark_icon.tsx | 2 +
.../public/components/csp_counter_card.tsx | 39 +-----
.../summary_section.test.tsx | 14 +-
.../dashboard_sections/summary_section.tsx | 65 +++++----
.../translations/translations/fr-FR.json | 1 -
.../translations/translations/ja-JP.json | 1 -
.../translations/translations/zh-CN.json | 1 -
9 files changed, 131 insertions(+), 127 deletions(-)
diff --git a/x-pack/plugins/cloud_security_posture/common/constants.ts b/x-pack/plugins/cloud_security_posture/common/constants.ts
index 23de4b6d02e36..1cc356cbfd5e3 100644
--- a/x-pack/plugins/cloud_security_posture/common/constants.ts
+++ b/x-pack/plugins/cloud_security_posture/common/constants.ts
@@ -100,6 +100,9 @@ export const CLOUDBEAT_VULN_MGMT_GCP = 'cloudbeat/vuln_mgmt_gcp';
export const CLOUDBEAT_VULN_MGMT_AZURE = 'cloudbeat/vuln_mgmt_azure';
export const CIS_AWS = 'cis_aws';
export const CIS_GCP = 'cis_gcp';
+export const CIS_K8S = 'cis_k8s';
+export const CIS_EKS = 'cis_eks';
+export const CIS_AZURE = 'cis_azure';
export const KSPM_POLICY_TEMPLATE = 'kspm';
export const CSPM_POLICY_TEMPLATE = 'cspm';
export const VULN_MGMT_POLICY_TEMPLATE = 'vuln_mgmt';
diff --git a/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.tsx b/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.tsx
index 39b37c85aee39..418b1c37a1bdd 100644
--- a/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.tsx
@@ -5,13 +5,43 @@
* 2.0.
*/
import React from 'react';
-import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
-import { CIS_AWS, CIS_GCP } from '../../common/constants';
+import { EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui';
+import { css } from '@emotion/react';
+import { CIS_AWS, CIS_GCP, CIS_AZURE, CIS_K8S, CIS_EKS } from '../../common/constants';
import { Cluster } from '../../common/types';
import { CISBenchmarkIcon } from './cis_benchmark_icon';
import { CompactFormattedNumber } from './compact_formatted_number';
import { useNavigateFindings } from '../common/hooks/use_navigate_findings';
+// order in array will determine order of appearance in the dashboard
+const benchmarks = [
+ {
+ type: CIS_AWS,
+ name: 'Amazon Web Services (AWS)',
+ provider: 'aws',
+ },
+ {
+ type: CIS_GCP,
+ name: 'Google Cloud Platform (GCP)',
+ provider: 'gcp',
+ },
+ {
+ type: CIS_AZURE,
+ name: 'Azure',
+ provider: 'azure',
+ },
+ {
+ type: CIS_K8S,
+ name: 'Kubernetes',
+ benchmarkId: 'cis_k8s',
+ },
+ {
+ type: CIS_EKS,
+ name: 'Amazon Elastic Kubernetes Service (EKS)',
+ benchmarkId: 'cis_eks',
+ },
+];
+
export const AccountsEvaluatedWidget = ({
clusters,
benchmarkAbbreviateAbove = 999,
@@ -20,6 +50,8 @@ export const AccountsEvaluatedWidget = ({
/** numbers higher than the value of this field will be abbreviated using compact notation and have a tooltip displaying the full value */
benchmarkAbbreviateAbove?: number;
}) => {
+ const { euiTheme } = useEuiTheme();
+
const filterClustersById = (benchmarkId: string) => {
return clusters?.filter((obj) => obj?.meta.benchmark.id === benchmarkId) || [];
};
@@ -30,56 +62,52 @@ export const AccountsEvaluatedWidget = ({
navToFindings({ 'cloud.provider': provider });
};
- const cisAwsClusterAmount = filterClustersById(CIS_AWS).length;
- const cisGcpClusterAmount = filterClustersById(CIS_GCP).length;
+ const navToFindingsByCisBenchmark = (cisBenchmark: string) => {
+ navToFindings({ 'rule.benchmark.id': cisBenchmark });
+ };
+
+ const benchmarkElements = benchmarks.map((benchmark) => {
+ const clusterAmount = filterClustersById(benchmark.type).length;
+
+ return (
+ clusterAmount > 0 && (
+ {
+ if (benchmark.provider) {
+ navToFindingsByCloudProvider(benchmark.provider);
+ }
+ if (benchmark.benchmarkId) {
+ navToFindingsByCisBenchmark(benchmark.benchmarkId);
+ }
+ }}
+ css={css`
+ transition: ${euiTheme.animation.normal} ease-in;
+ border-bottom: ${euiTheme.border.thick};
+ border-color: transparent;
- const cisAwsBenchmarkName = 'Amazon Web Services (AWS)';
- const cisGcpBenchmarkName = 'Google Cloud Platform (GCP)';
+ :hover {
+ cursor: pointer;
+ border-color: ${euiTheme.colors.darkestShade};
+ }
+ `}
+ >
+
+
+
+
+
+
+
+
+
+ )
+ );
+ });
- return (
- <>
-
- {cisAwsClusterAmount > 0 && (
-
-
-
-
-
- {
- navToFindingsByCloudProvider('aws');
- }}
- >
-
-
-
-
- )}
- {cisGcpClusterAmount > 0 && (
-
-
-
-
-
- {
- navToFindingsByCloudProvider('gcp');
- }}
- >
-
-
-
-
- )}
-
- >
- );
+ // Render the benchmark elements
+ return {benchmarkElements};
};
diff --git a/x-pack/plugins/cloud_security_posture/public/components/cis_benchmark_icon.tsx b/x-pack/plugins/cloud_security_posture/public/components/cis_benchmark_icon.tsx
index a0048b21fb92f..50f9ca1b15d9d 100644
--- a/x-pack/plugins/cloud_security_posture/public/components/cis_benchmark_icon.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/components/cis_benchmark_icon.tsx
@@ -23,6 +23,8 @@ const getBenchmarkIdIconType = (props: Props): string => {
switch (props.type) {
case 'cis_eks':
return cisEksIcon;
+ case 'cis_azure':
+ return 'logoAzure';
case 'cis_aws':
return 'logoAWS';
case 'cis_gcp':
diff --git a/x-pack/plugins/cloud_security_posture/public/components/csp_counter_card.tsx b/x-pack/plugins/cloud_security_posture/public/components/csp_counter_card.tsx
index def19c1c871ec..9b07c0f3edded 100644
--- a/x-pack/plugins/cloud_security_posture/public/components/csp_counter_card.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/components/csp_counter_card.tsx
@@ -5,14 +5,13 @@
* 2.0.
*/
-import React, { MouseEventHandler } from 'react';
-import { css } from '@emotion/react';
-import { EuiIcon, EuiPanel, EuiStat, useEuiTheme } from '@elastic/eui';
+import React, { ReactNode } from 'react';
+import { EuiPanel, EuiStat, useEuiTheme, EuiHorizontalRule } from '@elastic/eui';
import type { EuiStatProps } from '@elastic/eui';
export interface CspCounterCardProps {
id: string;
- onClick?: MouseEventHandler;
+ button?: ReactNode;
title: EuiStatProps['title'];
titleColor?: EuiStatProps['titleColor'];
description: EuiStatProps['description'];
@@ -22,25 +21,10 @@ export const CspCounterCard = (counter: CspCounterCardProps) => {
const { euiTheme } = useEuiTheme();
return (
-
+
{
descriptionElement="h6"
description={counter.description}
/>
- {counter.onClick && (
-
- )}
+
+ {counter.button}
);
};
diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.test.tsx
index f78b596074349..0545d4f3bb429 100644
--- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.test.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.test.tsx
@@ -31,11 +31,7 @@ describe('', () => {
renderCloudSummarySection();
expectIdsInDoc({
- be: [
- DASHBOARD_COUNTER_CARDS.CLUSTERS_EVALUATED,
- DASHBOARD_COUNTER_CARDS.RESOURCES_EVALUATED,
- DASHBOARD_COUNTER_CARDS.FAILING_FINDINGS,
- ],
+ be: [DASHBOARD_COUNTER_CARDS.CLUSTERS_EVALUATED, DASHBOARD_COUNTER_CARDS.RESOURCES_EVALUATED],
});
});
@@ -46,7 +42,6 @@ describe('', () => {
expect(screen.getByTestId(DASHBOARD_COUNTER_CARDS.RESOURCES_EVALUATED)).toHaveTextContent(
'162'
);
- expect(screen.getByTestId(DASHBOARD_COUNTER_CARDS.FAILING_FINDINGS)).toHaveTextContent('17');
});
it('renders counters value in compact abbreviation if its above one million', () => {
@@ -55,12 +50,5 @@ describe('', () => {
expect(screen.getByTestId(DASHBOARD_COUNTER_CARDS.RESOURCES_EVALUATED)).toHaveTextContent(
'999,999'
);
- expect(screen.getByTestId(DASHBOARD_COUNTER_CARDS.FAILING_FINDINGS)).toHaveTextContent('1M');
- });
-
- it('renders N/A as an empty state', () => {
- renderCloudSummarySection({ stats: { totalFailed: undefined } });
-
- expect(screen.getByTestId(DASHBOARD_COUNTER_CARDS.FAILING_FINDINGS)).toHaveTextContent('N/A');
});
});
diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx
index 9837c531021f2..50d5493387466 100644
--- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx
@@ -6,10 +6,10 @@
*/
import React, { useMemo } from 'react';
-import { EuiFlexGroup, EuiFlexItem, EuiFlexItemProps } from '@elastic/eui';
+import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiFlexItemProps } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { css } from '@emotion/react';
-import { statusColors } from '../../../common/constants';
+import { useCspIntegrationLink } from '../../../common/navigation/use_csp_integration_link';
import { DASHBOARD_COUNTER_CARDS, DASHBOARD_SUMMARY_CONTAINER } from '../test_subjects';
import { CspCounterCard, CspCounterCardProps } from '../../../components/csp_counter_card';
import { CompactFormattedNumber } from '../../../components/compact_formatted_number';
@@ -56,6 +56,8 @@ export const SummarySection = ({
}) => {
const navToFindings = useNavigateFindings();
const navToFindingsByResource = useNavigateFindingsByResource();
+ const cspmIntegrationLink = useCspIntegrationLink(CSPM_POLICY_TEMPLATE);
+ const kspmIntegrationLink = useCspIntegrationLink(KSPM_POLICY_TEMPLATE);
const handleEvalCounterClick = (evaluation: Evaluation) => {
navToFindings({ 'result.evaluation': evaluation, ...getPolicyTemplateQuery(dashboardType) });
@@ -87,12 +89,26 @@ export const SummarySection = ({
'xpack.csp.dashboard.summarySection.counterCard.accountsEvaluatedDescription',
{ defaultMessage: 'Accounts Evaluated' }
),
- title:
- dashboardType === KSPM_POLICY_TEMPLATE ? (
-
- ) : (
-
- ),
+ title: ,
+ button: (
+
+ {dashboardType === KSPM_POLICY_TEMPLATE
+ ? i18n.translate(
+ 'xpack.csp.dashboard.summarySection.counterCard.clustersEvaluatedButtonTitle',
+ { defaultMessage: 'Enroll more clusters' }
+ )
+ : i18n.translate(
+ 'xpack.csp.dashboard.summarySection.counterCard.accountsEvaluatedButtonTitle',
+ { defaultMessage: 'Enroll more accounts' }
+ )}
+
+ ),
},
{
id: DASHBOARD_COUNTER_CARDS.RESOURCES_EVALUATED,
@@ -101,32 +117,27 @@ export const SummarySection = ({
{ defaultMessage: 'Resources Evaluated' }
),
title: ,
- onClick: () => {
- navToFindingsByResource(getPolicyTemplateQuery(dashboardType));
- },
- },
- {
- id: DASHBOARD_COUNTER_CARDS.FAILING_FINDINGS,
- description: i18n.translate(
- 'xpack.csp.dashboard.summarySection.counterCard.failingFindingsDescription',
- { defaultMessage: 'Failing Findings' }
+ button: (
+ {
+ navToFindingsByResource(getPolicyTemplateQuery(dashboardType));
+ }}
+ >
+ {i18n.translate(
+ 'xpack.csp.dashboard.summarySection.counterCard.resourcesEvaluatedButtonTitle',
+ { defaultMessage: 'View all resources' }
+ )}
+
),
- title: ,
- titleColor: complianceData.stats.totalFailed > 0 ? statusColors.failed : 'text',
- onClick: () => {
- navToFindings({
- 'result.evaluation': RULE_FAILED,
- ...getPolicyTemplateQuery(dashboardType),
- });
- },
},
],
[
complianceData.clusters,
complianceData.stats.resourcesEvaluated,
- complianceData.stats.totalFailed,
+ cspmIntegrationLink,
dashboardType,
- navToFindings,
+ kspmIntegrationLink,
navToFindingsByResource,
]
);
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json
index aa95ebb6e2aef..260328513d6c1 100644
--- a/x-pack/plugins/translations/translations/fr-FR.json
+++ b/x-pack/plugins/translations/translations/fr-FR.json
@@ -11377,7 +11377,6 @@
"xpack.csp.dashboard.summarySection.complianceByCisSectionPanelTitle": "Conformité par section CIS",
"xpack.csp.dashboard.summarySection.counterCard.accountsEvaluatedDescription": "Comptes évalués",
"xpack.csp.dashboard.summarySection.counterCard.clustersEvaluatedDescription": "Clusters évalués",
- "xpack.csp.dashboard.summarySection.counterCard.failingFindingsDescription": "Résultats en échec",
"xpack.csp.dashboard.summarySection.counterCard.resourcesEvaluatedDescription": "Ressources évaluées",
"xpack.csp.dashboardTabs.cloudTab.tabTitle": "Cloud",
"xpack.csp.dashboardTabs.kubernetesTab.tabTitle": "Kubernetes",
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 0c085d75d7902..db4e8cc674281 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -11392,7 +11392,6 @@
"xpack.csp.dashboard.summarySection.complianceByCisSectionPanelTitle": "CISセクション別のコンプライアンス",
"xpack.csp.dashboard.summarySection.counterCard.accountsEvaluatedDescription": "評価されたアカウント",
"xpack.csp.dashboard.summarySection.counterCard.clustersEvaluatedDescription": "評価されたクラスター",
- "xpack.csp.dashboard.summarySection.counterCard.failingFindingsDescription": "失敗した調査結果",
"xpack.csp.dashboard.summarySection.counterCard.resourcesEvaluatedDescription": "評価されたリソース",
"xpack.csp.dashboardTabs.cloudTab.tabTitle": "クラウド",
"xpack.csp.dashboardTabs.kubernetesTab.tabTitle": "Kubernetes",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 4cc2eb901cbbd..68e8ae1196d60 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -11392,7 +11392,6 @@
"xpack.csp.dashboard.summarySection.complianceByCisSectionPanelTitle": "合规性(按 CIS 部分)",
"xpack.csp.dashboard.summarySection.counterCard.accountsEvaluatedDescription": "已评估帐户",
"xpack.csp.dashboard.summarySection.counterCard.clustersEvaluatedDescription": "集群已评估",
- "xpack.csp.dashboard.summarySection.counterCard.failingFindingsDescription": "失败的结果",
"xpack.csp.dashboard.summarySection.counterCard.resourcesEvaluatedDescription": "资源已评估",
"xpack.csp.dashboardTabs.cloudTab.tabTitle": "云",
"xpack.csp.dashboardTabs.kubernetesTab.tabTitle": "Kubernetes",