& {
diff --git a/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts b/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts
index 8612c754ac35c..fe80dda0155ed 100644
--- a/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts
+++ b/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts
@@ -47,7 +47,7 @@ export const MISCONFIGURATIONS_GROUPS_UNIT = (
});
default:
return i18n.translate('xpack.csp.findings.groupUnit', {
- values: { groupCount: totalCount },
+ values: { groupCount },
defaultMessage: `{groupCount} {groupCount, plural, =1 {group} other {groups}}`,
});
}
diff --git a/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.test.tsx b/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.test.tsx
new file mode 100644
index 0000000000000..2a8a878497f41
--- /dev/null
+++ b/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.test.tsx
@@ -0,0 +1,122 @@
+/*
+ * 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 { renderHook } from '@testing-library/react';
+import { useLatestFindingsGrouping } from './use_latest_findings_grouping';
+import { useCloudSecurityGrouping } from '../../../components/cloud_security_grouping';
+import { useDataViewContext } from '../../../common/contexts/data_view_context';
+import { useGetCspBenchmarkRulesStatesApi } from '@kbn/cloud-security-posture/src/hooks/use_get_benchmark_rules_state_api';
+import { getGroupingQuery } from '@kbn/grouping';
+import { useGroupedFindings } from './use_grouped_findings';
+
+jest.mock('../../../components/cloud_security_grouping');
+jest.mock('../../../common/contexts/data_view_context');
+jest.mock('@kbn/cloud-security-posture/src/hooks/use_get_benchmark_rules_state_api');
+jest.mock('@kbn/grouping', () => ({
+ getGroupingQuery: jest.fn().mockImplementation((params) => {
+ return {
+ query: { bool: {} },
+ };
+ }),
+ parseGroupingQuery: jest.fn().mockReturnValue({}),
+}));
+jest.mock('./use_grouped_findings');
+
+describe('useLatestFindingsGrouping', () => {
+ const mockGroupPanelRenderer = (
+ selectedGroup: string,
+ fieldBucket: any,
+ nullGroupMessage?: string,
+ isLoading?: boolean
+ ) => Mock Group Panel Renderer
;
+ const mockGetGroupStats = jest.fn();
+
+ beforeEach(() => {
+ (useCloudSecurityGrouping as jest.Mock).mockReturnValue({
+ grouping: { selectedGroups: ['cloud.account.id'] },
+ });
+ (useDataViewContext as jest.Mock).mockReturnValue({ dataView: {} });
+ (useGetCspBenchmarkRulesStatesApi as jest.Mock).mockReturnValue({ data: {} });
+ (useGroupedFindings as jest.Mock).mockReturnValue({
+ data: {},
+ isFetching: false,
+ });
+ });
+
+ it('calls getGroupingQuery with correct rootAggregations', () => {
+ renderHook(() =>
+ useLatestFindingsGrouping({
+ groupPanelRenderer: mockGroupPanelRenderer,
+ getGroupStats: mockGetGroupStats,
+ groupingLevel: 0,
+ groupFilters: [],
+ selectedGroup: 'cloud.account.id',
+ })
+ );
+
+ expect(getGroupingQuery).toHaveBeenCalledWith(
+ expect.objectContaining({
+ rootAggregations: [
+ {
+ failedFindings: {
+ filter: {
+ term: {
+ 'result.evaluation': { value: 'failed' },
+ },
+ },
+ },
+ passedFindings: {
+ filter: {
+ term: {
+ 'result.evaluation': { value: 'passed' },
+ },
+ },
+ },
+ nullGroupItems: {
+ missing: { field: 'cloud.account.id' },
+ },
+ },
+ ],
+ })
+ );
+ });
+
+ it('calls getGroupingQuery without nullGroupItems when selectedGroup is "none"', () => {
+ renderHook(() =>
+ useLatestFindingsGrouping({
+ groupPanelRenderer: mockGroupPanelRenderer,
+ getGroupStats: mockGetGroupStats,
+ groupingLevel: 0,
+ groupFilters: [],
+ selectedGroup: 'none',
+ })
+ );
+
+ expect(getGroupingQuery).toHaveBeenCalledWith(
+ expect.objectContaining({
+ rootAggregations: [
+ {
+ failedFindings: {
+ filter: {
+ term: {
+ 'result.evaluation': { value: 'failed' },
+ },
+ },
+ },
+ passedFindings: {
+ filter: {
+ term: {
+ 'result.evaluation': { value: 'passed' },
+ },
+ },
+ },
+ },
+ ],
+ })
+ );
+ });
+});
diff --git a/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx b/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx
index f591115792e08..fd277348d3dee 100644
--- a/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx
+++ b/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx
@@ -230,6 +230,11 @@ export const useLatestFindingsGrouping = ({
},
},
},
+ ...(!isNoneGroup([currentSelectedGroup]) && {
+ nullGroupItems: {
+ missing: { field: currentSelectedGroup },
+ },
+ }),
},
],
});
diff --git a/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_grouping.tsx b/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_grouping.tsx
index 1d73b21f083a5..43b22b60bcfac 100644
--- a/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_grouping.tsx
+++ b/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_grouping.tsx
@@ -187,6 +187,15 @@ export const useLatestVulnerabilitiesGrouping = ({
sort: [{ groupByField: { order: 'desc' } }],
statsAggregations: getAggregationsByGroupField(currentSelectedGroup),
runtimeMappings: getRuntimeMappingsByGroupField(currentSelectedGroup),
+ rootAggregations: [
+ {
+ ...(!isNoneGroup([currentSelectedGroup]) && {
+ nullGroupItems: {
+ missing: { field: currentSelectedGroup },
+ },
+ }),
+ },
+ ],
});
const { data, isFetching } = useGroupedVulnerabilities({
diff --git a/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/vulnerabilities/translations.ts b/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/vulnerabilities/translations.ts
index 2864ff7f29005..33fe66d61c81b 100644
--- a/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/vulnerabilities/translations.ts
+++ b/x-pack/solutions/security/plugins/cloud_security_posture/public/pages/vulnerabilities/translations.ts
@@ -44,7 +44,7 @@ export const VULNERABILITIES_GROUPS_UNIT = (
});
default:
return i18n.translate('xpack.csp.vulnerabilities.groupUnit', {
- values: { groupCount: totalCount },
+ values: { groupCount },
defaultMessage: `{groupCount} {groupCount, plural, =1 {group} other {groups}}`,
});
}