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) => ( + + + + ))} + + ); +};