Skip to content

Commit

Permalink
[Cloud Security] [Posture Dashboard] Update links to the findings pag…
Browse files Browse the repository at this point in the history
…e with groupBy option (#176463)
  • Loading branch information
opauloh authored Feb 8, 2024
1 parent b620110 commit 3d431f3
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 55 deletions.
11 changes: 10 additions & 1 deletion x-pack/plugins/cloud_security_posture/common/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,15 @@ const CLOUD_PROVIDER_NAMES = {
GCP: 'Google Cloud Platform',
};

export const CLOUD_PROVIDERS = {
AWS: 'aws',
AZURE: 'azure',
GCP: 'gcp',
};

/**
* Returns the cloud provider name or benchmark applicable name for the given benchmark id
*/
export const getBenchmarkApplicableTo = (benchmarkId: BenchmarksCisId) => {
switch (benchmarkId) {
case 'cis_k8s':
Expand All @@ -205,7 +214,7 @@ export const getBenchmarkApplicableTo = (benchmarkId: BenchmarksCisId) => {
case 'cis_aws':
return CLOUD_PROVIDER_NAMES.AWS;
case 'cis_eks':
return 'Amazon Elastic Kubernetes Service';
return 'Amazon Elastic Kubernetes Service (EKS)';
case 'cis_gcp':
return CLOUD_PROVIDER_NAMES.GCP;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,10 @@ export const DETECTION_ENGINE_RULES_KEY = 'detection_engine_rules';
export const DETECTION_ENGINE_ALERTS_KEY = 'detection_engine_alerts';

export const DEFAULT_GROUPING_TABLE_HEIGHT = 512;

export const FINDINGS_GROUPING_OPTIONS = {
RESOURCE_NAME: 'resource.name',
RULE_NAME: 'rule.name',
CLOUD_ACCOUNT_NAME: 'cloud.account.name',
ORCHESTRATOR_CLUSTER_NAME: 'orchestrator.cluster.name',
};
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const useNavigate = (pathname: string, dataViewId = SECURITY_DEFAULT_DATA_VIEW_I
const { services } = useKibana();

return useCallback(
(filterParams: NavFilter = {}) => {
(filterParams: NavFilter = {}, groupBy?: string[]) => {
const filters = Object.entries(filterParams).map(([key, filterValue]) =>
createFilter(key, filterValue, dataViewId)
);
Expand All @@ -68,10 +68,11 @@ const useNavigate = (pathname: string, dataViewId = SECURITY_DEFAULT_DATA_VIEW_I
// Set query language from user's preference
query: services.data.query.queryString.getDefaultQuery(),
filters,
...(groupBy && { groupBy }),
}),
});
},
[pathname, history, services.data.query.queryString, dataViewId]
[history, pathname, services.data.query.queryString, dataViewId]
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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 React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { AccountsEvaluatedWidget } from './accounts_evaluated_widget';
import { BenchmarkData } from '../../common/types_old';
import { TestProvider } from '../test/test_provider';

const mockNavToFindings = jest.fn();
jest.mock('../common/hooks/use_navigate_findings', () => ({
useNavigateFindings: () => mockNavToFindings,
}));

describe('AccountsEvaluatedWidget', () => {
const benchmarkAssets = [
{ meta: { benchmarkId: 'cis_aws', assetCount: 10 } },
{ meta: { benchmarkId: 'cis_k8s', assetCount: 20 } },
] as BenchmarkData[];

it('renders the component with benchmark data correctly', () => {
const { getByText } = render(
<TestProvider>
<AccountsEvaluatedWidget benchmarkAssets={benchmarkAssets} benchmarkAbbreviateAbove={999} />
</TestProvider>
);

expect(getByText('10')).toBeInTheDocument();
expect(getByText('20')).toBeInTheDocument();
});

it('calls navToFindingsByCloudProvider when a benchmark with provider is clicked', () => {
const { getByText } = render(
<TestProvider>
<AccountsEvaluatedWidget benchmarkAssets={benchmarkAssets} benchmarkAbbreviateAbove={999} />
</TestProvider>
);

fireEvent.click(getByText('10'));

expect(mockNavToFindings).toHaveBeenCalledWith(
{
'cloud.provider': 'aws',
},
['cloud.account.name']
);
});

it('calls navToFindingsByCisBenchmark when a benchmark with benchmarkId is clicked', () => {
const { getByText } = render(
<TestProvider>
<AccountsEvaluatedWidget benchmarkAssets={benchmarkAssets} benchmarkAbbreviateAbove={999} />
</TestProvider>
);

fireEvent.click(getByText('20'));

expect(mockNavToFindings).toHaveBeenCalledWith(
{
'rule.benchmark.id': 'cis_k8s',
},
['orchestrator.cluster.name']
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,40 @@
import React from 'react';
import { EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui';
import { css } from '@emotion/react';
import { CLOUD_PROVIDERS, getBenchmarkApplicableTo } from '../../common/utils/helpers';
import { CIS_AWS, CIS_GCP, CIS_AZURE, CIS_K8S, CIS_EKS } from '../../common/constants';
import { CISBenchmarkIcon } from './cis_benchmark_icon';
import { CompactFormattedNumber } from './compact_formatted_number';
import { useNavigateFindings } from '../common/hooks/use_navigate_findings';
import { BenchmarkData } from '../../common/types_old';
import { FINDINGS_GROUPING_OPTIONS } from '../common/constants';

// order in array will determine order of appearance in the dashboard
const benchmarks = [
{
type: CIS_AWS,
name: 'Amazon Web Services (AWS)',
provider: 'aws',
name: getBenchmarkApplicableTo(CIS_AWS),
provider: CLOUD_PROVIDERS.AWS,
},
{
type: CIS_GCP,
name: 'Google Cloud Platform (GCP)',
provider: 'gcp',
name: getBenchmarkApplicableTo(CIS_GCP),
provider: CLOUD_PROVIDERS.GCP,
},
{
type: CIS_AZURE,
name: 'Azure',
provider: 'azure',
name: getBenchmarkApplicableTo(CIS_AZURE),
provider: CLOUD_PROVIDERS.AZURE,
},
{
type: CIS_K8S,
name: 'Kubernetes',
benchmarkId: 'cis_k8s',
name: getBenchmarkApplicableTo(CIS_K8S),
benchmarkId: CIS_K8S,
},
{
type: CIS_EKS,
name: 'Amazon Elastic Kubernetes Service (EKS)',
benchmarkId: 'cis_eks',
name: getBenchmarkApplicableTo(CIS_EKS),
benchmarkId: CIS_EKS,
},
];

Expand All @@ -59,11 +61,13 @@ export const AccountsEvaluatedWidget = ({
const navToFindings = useNavigateFindings();

const navToFindingsByCloudProvider = (provider: string) => {
navToFindings({ 'cloud.provider': provider });
navToFindings({ 'cloud.provider': provider }, [FINDINGS_GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME]);
};

const navToFindingsByCisBenchmark = (cisBenchmark: string) => {
navToFindings({ 'rule.benchmark.id': cisBenchmark });
navToFindings({ 'rule.benchmark.id': cisBenchmark }, [
FINDINGS_GROUPING_OPTIONS.ORCHESTRATOR_CLUSTER_NAME,
]);
};

const benchmarkElements = benchmarks.map((benchmark) => {
Expand All @@ -75,10 +79,10 @@ export const AccountsEvaluatedWidget = ({
key={benchmark.type}
onClick={() => {
if (benchmark.provider) {
navToFindingsByCloudProvider(benchmark.provider);
return navToFindingsByCloudProvider(benchmark.provider);
}
if (benchmark.benchmarkId) {
navToFindingsByCisBenchmark(benchmark.benchmarkId);
return navToFindingsByCisBenchmark(benchmark.benchmarkId);
}
}}
css={css`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,32 @@ import {
import { FormattedMessage } from '@kbn/i18n-react';
import React from 'react';
import { i18n } from '@kbn/i18n';
import { FINDINGS_GROUPING_OPTIONS } from '../../../common/constants';
import { getBenchmarkIdQuery } from './benchmarks_section';
import { BenchmarkData } from '../../../../common/types_old';
import { useNavigateFindings } from '../../../common/hooks/use_navigate_findings';
import { CISBenchmarkIcon } from '../../../components/cis_benchmark_icon';
import cisLogoIcon from '../../../assets/icons/cis_logo.svg';

interface BenchmarkInfo {
name: string;
assetType: string;
handleClick: () => void;
}

export const BenchmarkDetailsBox = ({ benchmark }: { benchmark: BenchmarkData }) => {
const navToFindings = useNavigateFindings();

const handleBenchmarkClick = () => {
return navToFindings(getBenchmarkIdQuery(benchmark));
};
const handleClickCloudProvider = () =>
navToFindings(getBenchmarkIdQuery(benchmark), [FINDINGS_GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME]);

const handleClickCluster = () =>
navToFindings(getBenchmarkIdQuery(benchmark), [
FINDINGS_GROUPING_OPTIONS.ORCHESTRATOR_CLUSTER_NAME,
]);

const getBenchmarkInfo = (
benchmarkId: string,
cloudAssetCount: number
): { name: string; assetType: string } => {
const benchmarks: Record<string, { name: string; assetType: string }> = {
const getBenchmarkInfo = (benchmarkId: string, cloudAssetCount: number): BenchmarkInfo => {
const benchmarks: Record<string, BenchmarkInfo> = {
cis_gcp: {
name: i18n.translate(
'xpack.csp.dashboard.benchmarkSection.benchmarkName.cisGcpBenchmarkName',
Expand All @@ -48,6 +57,7 @@ export const BenchmarkDetailsBox = ({ benchmark }: { benchmark: BenchmarkData })
values: { count: cloudAssetCount },
}
),
handleClick: handleClickCloudProvider,
},
cis_aws: {
name: i18n.translate(
Expand All @@ -63,6 +73,7 @@ export const BenchmarkDetailsBox = ({ benchmark }: { benchmark: BenchmarkData })
values: { count: cloudAssetCount },
}
),
handleClick: handleClickCloudProvider,
},
cis_azure: {
name: i18n.translate(
Expand All @@ -78,6 +89,7 @@ export const BenchmarkDetailsBox = ({ benchmark }: { benchmark: BenchmarkData })
values: { count: cloudAssetCount },
}
),
handleClick: handleClickCloudProvider,
},
cis_k8s: {
name: i18n.translate(
Expand All @@ -93,6 +105,7 @@ export const BenchmarkDetailsBox = ({ benchmark }: { benchmark: BenchmarkData })
values: { count: cloudAssetCount },
}
),
handleClick: handleClickCluster,
},
cis_eks: {
name: i18n.translate(
Expand All @@ -108,6 +121,7 @@ export const BenchmarkDetailsBox = ({ benchmark }: { benchmark: BenchmarkData })
values: { count: cloudAssetCount },
}
),
handleClick: handleClickCluster,
},
};
return benchmarks[benchmarkId];
Expand Down Expand Up @@ -149,14 +163,14 @@ export const BenchmarkDetailsBox = ({ benchmark }: { benchmark: BenchmarkData })
</EuiText>
}
>
<EuiLink onClick={handleBenchmarkClick} color="text">
<EuiLink onClick={benchmarkInfo.handleClick} color="text">
<EuiTitle css={{ fontSize: 20 }}>
<h5>{benchmarkInfo.name}</h5>
</EuiTitle>
</EuiLink>
</EuiToolTip>

<EuiLink onClick={handleBenchmarkClick} color="text">
<EuiLink onClick={benchmarkInfo.handleClick} color="text">
<EuiText size="xs">{benchmarkInfo.assetType}</EuiText>
</EuiLink>
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import { i18n } from '@kbn/i18n';
import { GroupOption } from '@kbn/securitysolution-grouping';
import { FINDINGS_GROUPING_OPTIONS } from '../../../common/constants';
import { FindingsBaseURLQuery } from '../../../common/types';
import { CloudSecurityDefaultColumn } from '../../../components/cloud_security_data_table';

Expand All @@ -16,13 +17,6 @@ export const FINDINGS_UNIT = (totalCount: number) =>
defaultMessage: `{totalCount, plural, =1 {finding} other {findings}}`,
});

export const GROUPING_OPTIONS = {
RESOURCE_NAME: 'resource.name',
RULE_NAME: 'rule.name',
CLOUD_ACCOUNT_NAME: 'cloud.account.name',
ORCHESTRATOR_CLUSTER_NAME: 'orchestrator.cluster.name',
};

export const NULL_GROUPING_UNIT = i18n.translate('xpack.csp.findings.grouping.nullGroupUnit', {
defaultMessage: 'findings',
});
Expand Down Expand Up @@ -51,25 +45,25 @@ export const defaultGroupingOptions: GroupOption[] = [
label: i18n.translate('xpack.csp.findings.latestFindings.groupByResource', {
defaultMessage: 'Resource',
}),
key: GROUPING_OPTIONS.RESOURCE_NAME,
key: FINDINGS_GROUPING_OPTIONS.RESOURCE_NAME,
},
{
label: i18n.translate('xpack.csp.findings.latestFindings.groupByRuleName', {
defaultMessage: 'Rule name',
}),
key: GROUPING_OPTIONS.RULE_NAME,
key: FINDINGS_GROUPING_OPTIONS.RULE_NAME,
},
{
label: i18n.translate('xpack.csp.findings.latestFindings.groupByCloudAccount', {
defaultMessage: 'Cloud account',
}),
key: GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME,
key: FINDINGS_GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME,
},
{
label: i18n.translate('xpack.csp.findings.latestFindings.groupByKubernetesCluster', {
defaultMessage: 'Kubernetes cluster',
}),
key: GROUPING_OPTIONS.ORCHESTRATOR_CLUSTER_NAME,
key: FINDINGS_GROUPING_OPTIONS.ORCHESTRATOR_CLUSTER_NAME,
},
];

Expand Down
Loading

0 comments on commit 3d431f3

Please sign in to comment.