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

[Cloud Posture] [Dashboard] Add sorting by Compliance Score in the clusters section #149566

Merged
merged 13 commits into from
Jan 31, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export const DEFAULT_VISIBLE_ROWS_PER_PAGE = 25;
export const LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY = 'cloudPosture:findings:pageSize';
export const LOCAL_STORAGE_PAGE_SIZE_BENCHMARK_KEY = 'cloudPosture:benchmark:pageSize';
export const LOCAL_STORAGE_PAGE_SIZE_RULES_KEY = 'cloudPosture:rules:pageSize';
export const LOCAL_STORAGE_DASHBOARD_CLUSTER_SORT_KEY =
'cloudPosture:complianceDashboard:clusterSort';

export type CloudPostureIntegrations = Record<PosturePolicyTemplate, CloudPostureIntegrationProps>;
export interface CloudPostureIntegrationProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ import {
DASHBOARD_CONTAINER,
KUBERNETES_DASHBOARD_CONTAINER,
} from './test_subjects';
import { mockDashboardData } from './mock';
import { createReactQueryResponse } from '../../test/fixtures/react_query';
import { NO_FINDINGS_STATUS_TEST_SUBJ } from '../../components/test_subjects';
import { useCISIntegrationPoliciesLink } from '../../common/navigation/use_navigate_to_cis_integration_policies';
import { useCspIntegrationLink } from '../../common/navigation/use_csp_integration_link';
import { expectIdsInDoc } from '../../test/utils';
import { ComplianceDashboardData } from '../../../common/types';

jest.mock('../../common/api/use_setup_status_api');
jest.mock('../../common/api/use_stats_api');
Expand All @@ -34,166 +34,6 @@ jest.mock('../../common/navigation/use_csp_integration_link');

const chance = new Chance();

export const mockDashboardData: ComplianceDashboardData = {
stats: {
totalFailed: 17,
totalPassed: 155,
totalFindings: 172,
postureScore: 90.1,
resourcesEvaluated: 162,
},
groupedFindingsEvaluation: [
{
name: 'RBAC and Service Accounts',
totalFindings: 104,
totalFailed: 0,
totalPassed: 104,
postureScore: 100,
},
{
name: 'API Server',
totalFindings: 27,
totalFailed: 11,
totalPassed: 16,
postureScore: 59.2,
},
{
name: 'Master Node Configuration Files',
totalFindings: 17,
totalFailed: 1,
totalPassed: 16,
postureScore: 94.1,
},
{
name: 'Kubelet',
totalFindings: 11,
totalFailed: 4,
totalPassed: 7,
postureScore: 63.6,
},
{
name: 'etcd',
totalFindings: 6,
totalFailed: 0,
totalPassed: 6,
postureScore: 100,
},
{
name: 'Worker Node Configuration Files',
totalFindings: 5,
totalFailed: 0,
totalPassed: 5,
postureScore: 100,
},
{
name: 'Scheduler',
totalFindings: 2,
totalFailed: 1,
totalPassed: 1,
postureScore: 50.0,
},
],
clusters: [
{
meta: {
clusterId: '8f9c5b98-cc02-4827-8c82-316e2cc25870',
benchmarkName: 'CIS Kubernetes V1.20',
lastUpdate: '2022-11-07T13:14:34.990Z',
benchmarkId: 'cis_k8s',
},
stats: {
totalFailed: 17,
totalPassed: 155,
totalFindings: 172,
postureScore: 90.1,
},
groupedFindingsEvaluation: [
{
name: 'RBAC and Service Accounts',
totalFindings: 104,
totalFailed: 0,
totalPassed: 104,
postureScore: 100,
},
{
name: 'API Server',
totalFindings: 27,
totalFailed: 11,
totalPassed: 16,
postureScore: 59.2,
},
{
name: 'Master Node Configuration Files',
totalFindings: 17,
totalFailed: 1,
totalPassed: 16,
postureScore: 94.1,
},
{
name: 'Kubelet',
totalFindings: 11,
totalFailed: 4,
totalPassed: 7,
postureScore: 63.6,
},
{
name: 'etcd',
totalFindings: 6,
totalFailed: 0,
totalPassed: 6,
postureScore: 100,
},
{
name: 'Worker Node Configuration Files',
totalFindings: 5,
totalFailed: 0,
totalPassed: 5,
postureScore: 100,
},
{
name: 'Scheduler',
totalFindings: 2,
totalFailed: 1,
totalPassed: 1,
postureScore: 50.0,
},
],
trend: [
{
timestamp: '2022-05-22T11:03:00.000Z',
totalFindings: 172,
totalFailed: 17,
totalPassed: 155,
postureScore: 90.1,
},
{
timestamp: '2022-05-22T10:25:00.000Z',
totalFindings: 172,
totalFailed: 17,
totalPassed: 155,
postureScore: 90.1,
},
],
},
],
trend: [
{
timestamp: '2022-05-22T11:03:00.000Z',
totalFindings: 172,
totalFailed: 17,
totalPassed: 155,
postureScore: 90.1,
},
{
timestamp: '2022-05-22T10:25:00.000Z',
totalFindings: 172,
totalFailed: 17,
totalPassed: 155,
postureScore: 90.1,
},
],
};

describe('<ComplianceDashboard />', () => {
beforeEach(() => {
jest.resetAllMocks();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* 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 { render as reactRender, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import {
BenchmarksSection,
TABLE_COLUMN_SCORE_TEST_ID,
TABLE_HEADER_TEST_ID,
TABLE_HEADER_SCORE_TEST_ID,
} from './benchmarks_section';
import { mockDashboardData, clusterMockData } from '../mock';
import { TestProvider } from '../../../test/test_provider';
import { KSPM_POLICY_TEMPLATE, CSPM_POLICY_TEMPLATE } from '../../../../common/constants';

describe('<BenchmarksSection />', () => {
const render = (alterMockData = {}, dashboardType: 'kspm' | 'cspm' = KSPM_POLICY_TEMPLATE) =>
opauloh marked this conversation as resolved.
Show resolved Hide resolved
reactRender(
opauloh marked this conversation as resolved.
Show resolved Hide resolved
<TestProvider>
<BenchmarksSection
complianceData={{ ...mockDashboardData, ...alterMockData }}
dashboardType={dashboardType}
/>
</TestProvider>
);

describe('Sorting', () => {
const mockDashboardDataCopy = structuredClone(mockDashboardData);
const clusterMockDataCopy = structuredClone(clusterMockData);
clusterMockDataCopy.stats.postureScore = 50;
clusterMockDataCopy.meta.clusterId = '1';

const clusterMockDataCopy1 = structuredClone(clusterMockData);
clusterMockDataCopy1.stats.postureScore = 95;
clusterMockDataCopy1.meta.clusterId = '2';

const clusterMockDataCopy2 = structuredClone(clusterMockData);
clusterMockDataCopy2.stats.postureScore = 45;
clusterMockDataCopy2.meta.clusterId = '3';

mockDashboardDataCopy.clusters = [
clusterMockDataCopy,
clusterMockDataCopy1,
clusterMockDataCopy2,
];

it('Should init sorted by Compliance Score DESC', () => {
opauloh marked this conversation as resolved.
Show resolved Hide resolved
opauloh marked this conversation as resolved.
Show resolved Hide resolved
const { getAllByTestId } = render(mockDashboardDataCopy);

expect(getAllByTestId(TABLE_COLUMN_SCORE_TEST_ID)[0]).toHaveTextContent('95');
expect(getAllByTestId(TABLE_COLUMN_SCORE_TEST_ID)[1]).toHaveTextContent('50');
expect(getAllByTestId(TABLE_COLUMN_SCORE_TEST_ID)[2]).toHaveTextContent('45');
});

it('Should toggle sort order when clicking on Compliance Score', () => {
const { getAllByTestId } = render(mockDashboardDataCopy);

userEvent.click(screen.getByTestId(TABLE_HEADER_SCORE_TEST_ID));

expect(getAllByTestId(TABLE_COLUMN_SCORE_TEST_ID)[0]).toHaveTextContent('45');
expect(getAllByTestId(TABLE_COLUMN_SCORE_TEST_ID)[1]).toHaveTextContent('50');
expect(getAllByTestId(TABLE_COLUMN_SCORE_TEST_ID)[2]).toHaveTextContent('95');

userEvent.click(screen.getByTestId(TABLE_HEADER_SCORE_TEST_ID));

expect(getAllByTestId(TABLE_COLUMN_SCORE_TEST_ID)[0]).toHaveTextContent('95');
expect(getAllByTestId(TABLE_COLUMN_SCORE_TEST_ID)[1]).toHaveTextContent('50');
expect(getAllByTestId(TABLE_COLUMN_SCORE_TEST_ID)[2]).toHaveTextContent('45');
});
});

describe('KSPM Dashboard', () => {
it('Should render the column headers', () => {
const { getAllByTestId } = render();

const columns = ['Cluster Name', 'Compliance Score', 'Compliance by CIS Section'];
opauloh marked this conversation as resolved.
Show resolved Hide resolved

columns.forEach((name, idx) => {
expect(getAllByTestId(TABLE_HEADER_TEST_ID)[idx]).toHaveTextContent(name);
});
});

it.todo('Should navigate to the Findings page from the Cluster column');
it.todo('Should navigate to the Findings page from the CIS section column');
});

describe('CSPM Dashboard', () => {
it('Should render the column headers', () => {
const { getAllByTestId } = render({}, CSPM_POLICY_TEMPLATE);

const columns = ['Account Name', 'Compliance Score', 'Compliance by CIS Section'];

columns.forEach((name, idx) => {
expect(getAllByTestId(TABLE_HEADER_TEST_ID)[idx]).toHaveTextContent(name);
});
});

it.todo('Should navigate to the Findings page from the Cluster column');
it.todo('Should navigate to the Findings page from the CIS section column');
});
});
Loading