Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.x] [Security Solution] Update alert kpi to exclude closed alerts in document details flyout (#200268) #200642

Merged
merged 1 commit into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import { HOST_PREVIEW_BANNER } from '../../right/components/host_entity_overview
import { UserPreviewPanelKey } from '../../../entity_details/user_right';
import { USER_PREVIEW_BANNER } from '../../right/components/user_entity_overview';
import { NetworkPanelKey, NETWORK_PREVIEW_BANNER } from '../../../network_details';
import { useSummaryChartData } from '../../../../detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data';
import { useAlertsByStatus } from '../../../../overview/components/detection_response/alerts_by_status/use_alerts_by_status';

jest.mock('@kbn/expandable-flyout');
jest.mock('@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview');
Expand Down Expand Up @@ -113,8 +113,17 @@ jest.mock('../../../../entity_analytics/api/hooks/use_risk_score');
const mockUseRiskScore = useRiskScore as jest.Mock;

jest.mock(
'../../../../detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data'
'../../../../overview/components/detection_response/alerts_by_status/use_alerts_by_status'
);
const mockAlertData = {
open: {
total: 2,
severities: [
{ key: 'high', value: 1, label: 'High' },
{ key: 'low', value: 1, label: 'Low' },
],
},
};

const timestamp = '2022-07-25T08:20:18.966Z';

Expand Down Expand Up @@ -172,7 +181,7 @@ describe('<HostDetails />', () => {
mockUseIsExperimentalFeatureEnabled.mockReturnValue(true);
(useMisconfigurationPreview as jest.Mock).mockReturnValue({});
(useVulnerabilitiesPreview as jest.Mock).mockReturnValue({});
(useSummaryChartData as jest.Mock).mockReturnValue({ isLoading: false, items: [] });
(useAlertsByStatus as jest.Mock).mockReturnValue({ isLoading: false, items: {} });
});

it('should render host details correctly', () => {
Expand Down Expand Up @@ -321,9 +330,9 @@ describe('<HostDetails />', () => {
});

it('should render alert count when data is available', () => {
(useSummaryChartData as jest.Mock).mockReturnValue({
(useAlertsByStatus as jest.Mock).mockReturnValue({
isLoading: false,
items: [{ key: 'high', value: 78, label: 'High' }],
items: mockAlertData,
});

const { getByTestId } = renderHostDetails(mockContextValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { HOST_PREVIEW_BANNER } from '../../right/components/host_entity_overview
import { UserPreviewPanelKey } from '../../../entity_details/user_right';
import { USER_PREVIEW_BANNER } from '../../right/components/user_entity_overview';
import { NetworkPanelKey, NETWORK_PREVIEW_BANNER } from '../../../network_details';
import { useSummaryChartData } from '../../../../detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data';
import { useAlertsByStatus } from '../../../../overview/components/detection_response/alerts_by_status/use_alerts_by_status';

jest.mock('@kbn/expandable-flyout');
jest.mock('@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview');
Expand Down Expand Up @@ -107,8 +107,17 @@ jest.mock('../../../../entity_analytics/api/hooks/use_risk_score');
const mockUseRiskScore = useRiskScore as jest.Mock;

jest.mock(
'../../../../detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data'
'../../../../overview/components/detection_response/alerts_by_status/use_alerts_by_status'
);
const mockAlertData = {
open: {
total: 2,
severities: [
{ key: 'high', value: 1, label: 'High' },
{ key: 'low', value: 1, label: 'Low' },
],
},
};

const timestamp = '2022-07-25T08:20:18.966Z';

Expand Down Expand Up @@ -165,7 +174,7 @@ describe('<UserDetails />', () => {
mockUseUsersRelatedHosts.mockReturnValue(mockRelatedHostsResponse);
mockUseIsExperimentalFeatureEnabled.mockReturnValue(true);
(useMisconfigurationPreview as jest.Mock).mockReturnValue({});
(useSummaryChartData as jest.Mock).mockReturnValue({ isLoading: false, items: [] });
(useAlertsByStatus as jest.Mock).mockReturnValue({ isLoading: false, items: {} });
});

it('should render user details correctly', () => {
Expand Down Expand Up @@ -298,9 +307,9 @@ describe('<UserDetails />', () => {
});

it('should render alert count when data is available', () => {
(useSummaryChartData as jest.Mock).mockReturnValue({
(useAlertsByStatus as jest.Mock).mockReturnValue({
isLoading: false,
items: [{ key: 'high', value: 78, label: 'High' }],
items: mockAlertData,
});

const { getByTestId } = renderUserDetails(mockContextValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { ENTITIES_TAB_ID } from '../../left/components/entities_details';
import { useRiskScore } from '../../../../entity_analytics/api/hooks/use_risk_score';
import { mockFlyoutApi } from '../../shared/mocks/mock_flyout_context';
import { createTelemetryServiceMock } from '../../../../common/lib/telemetry/telemetry_service.mock';
import { useSummaryChartData } from '../../../../detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data';
import { useAlertsByStatus } from '../../../../overview/components/detection_response/alerts_by_status/use_alerts_by_status';

const hostName = 'host';
const osFamily = 'Windows';
Expand All @@ -61,8 +61,17 @@ jest.mock('react-router-dom', () => {
});

jest.mock(
'../../../../detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data'
'../../../../overview/components/detection_response/alerts_by_status/use_alerts_by_status'
);
const mockAlertData = {
open: {
total: 2,
severities: [
{ key: 'high', value: 1, label: 'High' },
{ key: 'low', value: 1, label: 'Low' },
],
},
};

const mockedTelemetry = createTelemetryServiceMock();
jest.mock('../../../../common/lib/kibana', () => {
Expand Down Expand Up @@ -118,7 +127,7 @@ describe('<HostEntityContent />', () => {
mockUseIsExperimentalFeatureEnabled.mockReturnValue(true);
(useMisconfigurationPreview as jest.Mock).mockReturnValue({});
(useVulnerabilitiesPreview as jest.Mock).mockReturnValue({});
(useSummaryChartData as jest.Mock).mockReturnValue({ isLoading: false, items: [] });
(useAlertsByStatus as jest.Mock).mockReturnValue({ isLoading: false, items: {} });
});

describe('license is valid', () => {
Expand Down Expand Up @@ -248,9 +257,9 @@ describe('<HostEntityContent />', () => {
});

it('should render alert count when data is available', () => {
(useSummaryChartData as jest.Mock).mockReturnValue({
(useAlertsByStatus as jest.Mock).mockReturnValue({
isLoading: false,
items: [{ key: 'high', value: 78, label: 'High' }],
items: mockAlertData,
});

const { getByTestId } = renderHostEntityContent();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features';
import { mockFlyoutApi } from '../../shared/mocks/mock_flyout_context';
import { UserPreviewPanelKey } from '../../../entity_details/user_right';
import { useSummaryChartData } from '../../../../detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data';
import { useAlertsByStatus } from '../../../../overview/components/detection_response/alerts_by_status/use_alerts_by_status';

const userName = 'user';
const domain = 'n54bg2lfc7';
Expand Down Expand Up @@ -59,8 +59,17 @@ jest.mock('react-router-dom', () => {
});

jest.mock(
'../../../../detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data'
'../../../../overview/components/detection_response/alerts_by_status/use_alerts_by_status'
);
const mockAlertData = {
open: {
total: 2,
severities: [
{ key: 'high', value: 1, label: 'High' },
{ key: 'low', value: 1, label: 'Low' },
],
},
};

jest.mock('../../../../common/hooks/use_experimental_features');
const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock;
Expand Down Expand Up @@ -102,7 +111,7 @@ describe('<UserEntityOverview />', () => {
jest.mocked(useExpandableFlyoutApi).mockReturnValue(mockFlyoutApi);
mockUseIsExperimentalFeatureEnabled.mockReturnValue(true);
(useMisconfigurationPreview as jest.Mock).mockReturnValue({});
(useSummaryChartData as jest.Mock).mockReturnValue({ isLoading: false, items: [] });
(useAlertsByStatus as jest.Mock).mockReturnValue({ isLoading: false, items: {} });
});

describe('license is valid', () => {
Expand Down Expand Up @@ -245,9 +254,9 @@ describe('<UserEntityOverview />', () => {
});

it('should render alert count when data is available', () => {
(useSummaryChartData as jest.Mock).mockReturnValue({
(useAlertsByStatus as jest.Mock).mockReturnValue({
isLoading: false,
items: [{ key: 'high', value: 78, label: 'High' }],
items: mockAlertData,
});

const { getByTestId } = renderUserEntityOverview();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
import React from 'react';
import { render } from '@testing-library/react';
import { TestProviders } from '../../../../common/mock';
import { AlertCountInsight } from './alert_count_insight';
import { useSummaryChartData } from '../../../../detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data';
import { AlertCountInsight, getFormattedAlertStats } from './alert_count_insight';
import { useAlertsByStatus } from '../../../../overview/components/detection_response/alerts_by_status/use_alerts_by_status';
import type { ParsedAlertsData } from '../../../../overview/components/detection_response/alerts_by_status/types';
import { SEVERITY_COLOR } from '../../../../overview/components/detection_response/utils';

jest.mock('../../../../common/lib/kibana');

Expand All @@ -19,12 +21,41 @@ jest.mock('react-router-dom', () => {
});
jest.mock('@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview');
jest.mock(
'../../../../detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data'
'../../../../overview/components/detection_response/alerts_by_status/use_alerts_by_status'
);

const fieldName = 'host.name';
const name = 'test host';
const testId = 'test';
const mockAlertData: ParsedAlertsData = {
open: {
total: 4,
severities: [
{ key: 'high', value: 1, label: 'High' },
{ key: 'low', value: 1, label: 'Low' },
{ key: 'medium', value: 1, label: 'Medium' },
{ key: 'critical', value: 1, label: 'Critical' },
],
},
acknowledged: {
total: 4,
severities: [
{ key: 'high', value: 1, label: 'High' },
{ key: 'low', value: 1, label: 'Low' },
{ key: 'medium', value: 1, label: 'Medium' },
{ key: 'critical', value: 1, label: 'Critical' },
],
},
closed: {
total: 6,
severities: [
{ key: 'high', value: 1, label: 'High' },
{ key: 'low', value: 1, label: 'Low' },
{ key: 'medium', value: 2, label: 'Medium' },
{ key: 'critical', value: 2, label: 'Critical' },
],
},
};

const renderAlertCountInsight = () => {
return render(
Expand All @@ -36,30 +67,69 @@ const renderAlertCountInsight = () => {

describe('AlertCountInsight', () => {
it('renders', () => {
(useSummaryChartData as jest.Mock).mockReturnValue({
(useAlertsByStatus as jest.Mock).mockReturnValue({
isLoading: false,
items: [
{ key: 'high', value: 78, label: 'High' },
{ key: 'low', value: 46, label: 'Low' },
{ key: 'medium', value: 32, label: 'Medium' },
{ key: 'critical', value: 21, label: 'Critical' },
],
items: mockAlertData,
});
const { getByTestId } = renderAlertCountInsight();
expect(getByTestId(testId)).toBeInTheDocument();
expect(getByTestId(`${testId}-distribution-bar`)).toBeInTheDocument();
expect(getByTestId(`${testId}-count`)).toHaveTextContent('177');
expect(getByTestId(`${testId}-count`)).toHaveTextContent('8');
});

it('renders loading spinner if data is being fetched', () => {
(useSummaryChartData as jest.Mock).mockReturnValue({ isLoading: true, items: [] });
(useAlertsByStatus as jest.Mock).mockReturnValue({ isLoading: true, items: {} });
const { getByTestId } = renderAlertCountInsight();
expect(getByTestId(`${testId}-loading-spinner`)).toBeInTheDocument();
});

it('renders null if no misconfiguration data found', () => {
(useSummaryChartData as jest.Mock).mockReturnValue({ isLoading: false, items: [] });
it('renders null if no alert data found', () => {
(useAlertsByStatus as jest.Mock).mockReturnValue({ isLoading: false, items: {} });
const { container } = renderAlertCountInsight();
expect(container).toBeEmptyDOMElement();
});

it('renders null if no non-closed alert data found', () => {
(useAlertsByStatus as jest.Mock).mockReturnValue({
isLoading: false,
items: {
closed: {
total: 6,
severities: [
{ key: 'high', value: 1, label: 'High' },
{ key: 'low', value: 1, label: 'Low' },
{ key: 'medium', value: 2, label: 'Medium' },
{ key: 'critical', value: 2, label: 'Critical' },
],
},
},
});
const { container } = renderAlertCountInsight();
expect(container).toBeEmptyDOMElement();
});
});

describe('getFormattedAlertStats', () => {
it('should return alert stats', () => {
const alertStats = getFormattedAlertStats(mockAlertData);
expect(alertStats).toEqual([
{ key: 'High', count: 2, color: SEVERITY_COLOR.high },
{ key: 'Low', count: 2, color: SEVERITY_COLOR.low },
{ key: 'Medium', count: 2, color: SEVERITY_COLOR.medium },
{ key: 'Critical', count: 2, color: SEVERITY_COLOR.critical },
]);
});

it('should return empty array if no active alerts are available', () => {
const alertStats = getFormattedAlertStats({
closed: {
total: 2,
severities: [
{ key: 'high', value: 1, label: 'High' },
{ key: 'low', value: 1, label: 'Low' },
],
},
});
expect(alertStats).toEqual([]);
});
});
Loading