From 1a69a86ccf5c4103574e7497ae47d16740a7565d Mon Sep 17 00:00:00 2001 From: Lola Date: Mon, 27 Feb 2023 10:22:06 -0500 Subject: [PATCH] [Cloud Security Posture][bug] broken resource findings table with cis aws (#151950) ## Summary Problem: cis aws `resource.id` has `/` characters which break the page. When we use `useParams()`. We are getting an `\` as encoded `%2F`. Afterward, we pass param resourceId with the encoded `\` to `useResourceFindings` which returns no results Solution: We can fix the broken resource findings table by encoding the `resourceid` before navigating to resource findings. Once `ResourceFindingsContainer ` mounts then we need to decode resourceId and pass `resourceId` as another parameter to the `userResourceFindings` hook. image --- .../findings_by_resource_table.tsx | 6 ++++-- .../resource_findings_container.tsx | 14 ++++++++++++-- .../resource_findings/use_resource_findings.ts | 7 ++++++- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/findings_by_resource_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/findings_by_resource_table.tsx index f8ac3dc3ad53a..b25149208ce1a 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/findings_by_resource_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/findings_by_resource_table.tsx @@ -16,7 +16,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import numeral from '@elastic/numeral'; -import { Link, generatePath } from 'react-router-dom'; +import { generatePath, Link } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; import { ColumnNameWithTooltip } from '../../../components/column_name_with_tooltip'; import { ComplianceScoreBar } from '../../../components/compliance_score_bar'; @@ -126,7 +126,9 @@ const baseColumns: Array> = width: '15%', render: (resourceId: FindingsByResourcePage['resource_id']) => ( diff --git a/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/resource_findings/resource_findings_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/resource_findings/resource_findings_container.tsx index 268ea6f393a99..a9598b228f3ae 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/resource_findings/resource_findings_container.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/resource_findings/resource_findings_container.tsx @@ -69,6 +69,7 @@ const getResourceFindingSharedValues = (sharedValues: { resourceSubType: string; resourceName: string; clusterId: string; + cloudAccountName: string; }): EuiDescriptionListProps['listItems'] => [ { title: i18n.translate('xpack.csp.findings.resourceFindingsSharedValues.resourceTypeTitle', { @@ -88,10 +89,18 @@ const getResourceFindingSharedValues = (sharedValues: { }), description: sharedValues.clusterId, }, + { + title: i18n.translate('xpack.csp.findings.resourceFindingsSharedValues.cloudAccountName', { + defaultMessage: 'Cloud Account Name', + }), + description: sharedValues.cloudAccountName, + }, ]; export const ResourceFindings = ({ dataView }: FindingsBaseProps) => { const params = useParams<{ resourceId: string }>(); + const decodedResourceId = decodeURIComponent(params.resourceId); + const getPersistedDefaultQuery = usePersistedQuery(getDefaultQuery); const { urlQuery, setUrlQuery } = useUrlQuery(getPersistedDefaultQuery); const { pageSize, setPageSize } = usePageSize(LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY); @@ -111,7 +120,7 @@ export const ResourceFindings = ({ dataView }: FindingsBaseProps) => { const resourceFindings = useResourceFindings({ sort: urlQuery.sort, query: baseEsQuery.query, - resourceId: params.resourceId, + resourceId: decodedResourceId, enabled: !baseEsQuery.error, }); @@ -213,10 +222,11 @@ export const ResourceFindings = ({ dataView }: FindingsBaseProps) => { resourceFindings.data && ( ) diff --git a/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/resource_findings/use_resource_findings.ts b/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/resource_findings/use_resource_findings.ts index a2314dc50b50d..17520e68bceb9 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/resource_findings/use_resource_findings.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/findings/latest_findings_by_resource/resource_findings/use_resource_findings.ts @@ -35,7 +35,7 @@ type ResourceFindingsResponse = IKibanaSearchResponse< >; export type ResourceFindingsResponseAggs = Record< - 'count' | 'clusterId' | 'resourceSubType' | 'resourceName', + 'count' | 'clusterId' | 'resourceSubType' | 'resourceName' | 'cloudAccountName', estypes.AggregationsMultiBucketAggregateBase< estypes.AggregationsStringRareTermsBucketKeys | undefined > @@ -59,6 +59,9 @@ const getResourceFindingsQuery = ({ sort: [{ [sort.field]: sort.direction }], aggs: { ...getFindingsCountAggQuery(), + cloudAccountName: { + terms: { field: 'cloud.account.name' }, + }, clusterId: { terms: { field: 'cluster_id' }, }, @@ -98,6 +101,7 @@ export const useResourceFindings = (options: UseResourceFindingsOptions) => { assertNonBucketsArray(aggregations.clusterId?.buckets); assertNonBucketsArray(aggregations.resourceSubType?.buckets); assertNonBucketsArray(aggregations.resourceName?.buckets); + assertNonBucketsArray(aggregations.cloudAccountName?.buckets); return { page: hits.hits.map((hit) => hit._source!), @@ -106,6 +110,7 @@ export const useResourceFindings = (options: UseResourceFindingsOptions) => { clusterId: getFirstBucketKey(aggregations.clusterId?.buckets), resourceSubType: getFirstBucketKey(aggregations.resourceSubType?.buckets), resourceName: getFirstBucketKey(aggregations.resourceName?.buckets), + cloudAccountName: getFirstBucketKey(aggregations.cloudAccountName?.buckets), }; }, onError: (err: Error) => showErrorToast(toasts, err),