diff --git a/x-pack/plugins/cloud_security_posture/common/constants.ts b/x-pack/plugins/cloud_security_posture/common/constants.ts
index 77e2dd38f326d..f5f283daa38b7 100644
--- a/x-pack/plugins/cloud_security_posture/common/constants.ts
+++ b/x-pack/plugins/cloud_security_posture/common/constants.ts
@@ -51,6 +51,7 @@ export const LATEST_FINDINGS_INDEX_TEMPLATE_NAME = 'logs-cloud_security_posture.
export const LATEST_FINDINGS_INDEX_PATTERN = 'logs-cloud_security_posture.findings_latest-*';
export const LATEST_FINDINGS_INDEX_DEFAULT_NS =
'logs-cloud_security_posture.findings_latest-default';
+
export const LATEST_FINDINGS_RETENTION_POLICY = '26h';
export const BENCHMARK_SCORE_INDEX_TEMPLATE_NAME = 'logs-cloud_security_posture.scores';
diff --git a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx
index d469632e21bdb..a6853a20db3ad 100644
--- a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
import React, { useState, useMemo } from 'react';
-import { EuiPanel, EuiSpacer } from '@elastic/eui';
+import { EuiSpacer } from '@elastic/eui';
import { useParams } from 'react-router-dom';
import { buildRuleKey } from '../../../common/utils/rules_states';
import { extractErrorMessage } from '../../../common/utils/helpers';
@@ -22,6 +22,7 @@ import type {
RuleStateAttributes,
} from '../../../common/types/latest';
import { useCspGetRulesStates } from './use_csp_rules_state';
+import { RulesCounters } from './rules_counters';
export interface CspBenchmarkRulesWithStates {
metadata: CspBenchmarkRule['metadata'];
@@ -173,47 +174,47 @@ export const RulesContainer = () => {
return (
-
-
- setRulesQuery((currentQuery) => ({ ...currentQuery, section: value }))
- }
- onRuleNumberChange={(value) =>
- setRulesQuery((currentQuery) => ({ ...currentQuery, ruleNumber: value }))
- }
- sectionSelectOptions={cleanedSectionList}
- ruleNumberSelectOptions={cleanedRuleNumberList}
- search={(value) => setRulesQuery((currentQuery) => ({ ...currentQuery, search: value }))}
- searchValue={rulesQuery.search || ''}
- totalRulesCount={rulesPageData.all_rules.length}
- pageSize={rulesPageData.rules_page.length}
- isSearching={status === 'loading'}
- selectedRules={selectedRules}
- refetchRulesStates={rulesStates.refetch}
- setEnabledDisabledItemsFilter={setEnabledDisabledItemsFilter}
- currentEnabledDisabledItemsFilterState={enabledDisabledItemsFilter}
- setSelectAllRules={setSelectAllRules}
- setSelectedRules={setSelectedRules}
- />
-
- {
- setPageSize(paginationQuery.perPage);
- setRulesQuery((currentQuery) => ({ ...currentQuery, ...paginationQuery }));
- }}
- setSelectedRuleId={setSelectedRuleId}
- selectedRuleId={selectedRuleId}
- refetchRulesStates={rulesStates.refetch}
- selectedRules={selectedRules}
- setSelectedRules={setSelectedRules}
- />
-
+
+
+
+ setRulesQuery((currentQuery) => ({ ...currentQuery, section: value }))
+ }
+ onRuleNumberChange={(value) =>
+ setRulesQuery((currentQuery) => ({ ...currentQuery, ruleNumber: value }))
+ }
+ sectionSelectOptions={cleanedSectionList}
+ ruleNumberSelectOptions={cleanedRuleNumberList}
+ search={(value) => setRulesQuery((currentQuery) => ({ ...currentQuery, search: value }))}
+ searchValue={rulesQuery.search || ''}
+ totalRulesCount={rulesPageData.all_rules.length}
+ pageSize={rulesPageData.rules_page.length}
+ isSearching={status === 'loading'}
+ selectedRules={selectedRules}
+ refetchRulesStates={rulesStates.refetch}
+ setEnabledDisabledItemsFilter={setEnabledDisabledItemsFilter}
+ currentEnabledDisabledItemsFilterState={enabledDisabledItemsFilter}
+ setSelectAllRules={setSelectAllRules}
+ setSelectedRules={setSelectedRules}
+ />
+
+ {
+ setPageSize(paginationQuery.perPage);
+ setRulesQuery((currentQuery) => ({ ...currentQuery, ...paginationQuery }));
+ }}
+ setSelectedRuleId={setSelectedRuleId}
+ selectedRuleId={selectedRuleId}
+ refetchRulesStates={rulesStates.refetch}
+ selectedRules={selectedRules}
+ setSelectedRules={setSelectedRules}
+ />
{selectedRuleId && (
{
+ const {
+ services: { charts },
+ } = useKibana();
+
+ return (
+
+
+ d.value}
+ layout={PartitionLayout.sunburst}
+ layers={[
+ {
+ // grouping the pie chart by data labels and coloring the group by the label value
+ groupByRollup: (d: { label: string }) => d.label,
+ shape: {
+ fillColor: (label) =>
+ label.toLowerCase() === RULE_PASSED.toLowerCase()
+ ? statusColors.passed
+ : statusColors.failed,
+ },
+ },
+ ]}
+ />
+
+ );
+};
+
+export const RulesCounters = () => {
+ const { http } = useKibana().services;
+ const rulesPageParams = useParams<{ benchmarkId: string; benchmarkVersion: string }>();
+ const getBenchmarks = useCspBenchmarkIntegrationsV2();
+ const navToFindings = useNavigateFindings();
+ const cspmIntegrationLink = useCspIntegrationLink(CSPM_POLICY_TEMPLATE) || '';
+ const kspmIntegrationLink = useCspIntegrationLink(KSPM_POLICY_TEMPLATE) || '';
+
+ const benchmarkRulesStats = getBenchmarks.data?.items.find(
+ (benchmark) =>
+ benchmark.id === rulesPageParams.benchmarkId &&
+ benchmark.version === rulesPageParams.benchmarkVersion
+ );
+
+ if (!benchmarkRulesStats) {
+ return <>>;
+ }
+
+ const benchmarkDynamicValues: Record<
+ BenchmarksCisId,
+ {
+ integrationType: string;
+ integrationName: string;
+ resourceName: string;
+ integrationLink: string;
+ learnMoreLink: string;
+ }
+ > = {
+ cis_aws: {
+ integrationType: 'CSPM',
+ integrationName: 'AWS',
+ resourceName: 'Accounts',
+ integrationLink: cspmIntegrationLink,
+ learnMoreLink: 'https://ela.st/cspm-get-started',
+ },
+ cis_gcp: {
+ integrationType: 'CSPM',
+ integrationName: 'GCP',
+ resourceName: 'Projects',
+ integrationLink: cspmIntegrationLink,
+ learnMoreLink: 'https://ela.st/cspm-get-started',
+ },
+ cis_azure: {
+ integrationType: 'CSPM',
+ integrationName: 'Azure',
+ resourceName: 'Subscriptions',
+ integrationLink: cspmIntegrationLink,
+ learnMoreLink: 'https://ela.st/cspm-get-started',
+ },
+ cis_k8s: {
+ integrationType: 'KSPM',
+ integrationName: 'Kubernetes',
+ resourceName: 'Clusters',
+ integrationLink: kspmIntegrationLink,
+ learnMoreLink: 'https://ela.st/kspm-get-started',
+ },
+ cis_eks: {
+ integrationType: 'KSPM',
+ integrationName: 'EKS',
+ resourceName: 'Clusters',
+ integrationLink: kspmIntegrationLink,
+ learnMoreLink: 'https://ela.st/kspm-get-started',
+ },
+ };
+
+ if (benchmarkRulesStats.score.totalFindings === 0) {
+ return (
+
+ }
+ title={
+
+
+
+ }
+ body={
+
+
+
+ }
+ actions={[
+
+
+ ,
+
+
+ ,
+ ]}
+ layout="horizontal"
+ paddingSize="m"
+ />
+ );
+ }
+
+ const counters = [
+ {
+ id: 'rules-counters-posture-score',
+ description: i18n.translate('xpack.csp.rulesCounters.postureScoreTitle', {
+ defaultMessage: 'Posture Score',
+ }),
+ title: (
+
+
+
+
+ {`${benchmarkRulesStats.score.postureScore}%`}
+
+ ),
+ button: (
+
+ {i18n.translate('xpack.csp.rulesCounters.postureScoreButton', {
+ defaultMessage: 'Dashboard',
+ })}
+
+ ),
+ },
+ {
+ id: 'rules-counters-evaluated',
+ description: i18n.translate('xpack.csp.rulesCounters.accountsEvaluatedTitle', {
+ defaultMessage: '{resourceName} Evaluated',
+ values: {
+ resourceName: benchmarkDynamicValues[benchmarkRulesStats.id].resourceName,
+ },
+ }),
+ title: benchmarkRulesStats.evaluation || 0,
+ button: (
+
+ {i18n.translate('xpack.csp.rulesCounters.accountsEvaluatedButton', {
+ defaultMessage: 'Add more {resourceName}',
+ values: {
+ resourceName:
+ benchmarkDynamicValues[benchmarkRulesStats.id].resourceName.toLowerCase(),
+ },
+ })}
+
+ ),
+ },
+ {
+ id: 'rules-counters-failed-findings',
+ description: i18n.translate('xpack.csp.rulesCounters.failedFindingsTitle', {
+ defaultMessage: 'Failed Findings',
+ }),
+ title: benchmarkRulesStats.score.totalFailed,
+ titleColor: benchmarkRulesStats.score.totalFailed > 0 ? statusColors.failed : undefined,
+ button: (
+
+ navToFindings({
+ 'result.evaluation': RULE_FAILED,
+ 'rule.benchmark.id': benchmarkRulesStats.id || '',
+ 'rule.benchmark.version': `v${benchmarkRulesStats.version}`,
+ })
+ }
+ >
+ {i18n.translate('xpack.csp.rulesCounters.failedFindingsButton', {
+ defaultMessage: 'View all failed findings',
+ })}
+
+ ),
+ },
+ {
+ id: 'rules-counters-disabled-rules',
+ description: i18n.translate('xpack.csp.rulesCounters.disabledRulesCounterTitle', {
+ defaultMessage: 'Disabled Rules',
+ }),
+ title: 'WIP',
+ button: (
+
+ {i18n.translate('xpack.csp.rulesCounters.disabledRulesCounterButton', {
+ defaultMessage: 'View all disabled rules',
+ })}
+
+ ),
+ },
+ ];
+
+ return (
+
+ {counters.map((counter) => (
+
+
+
+ ))}
+
+ );
+};