Skip to content

Commit 495308d

Browse files
[8.16] [Cloud Security] exclude unknown findings from compliance score calculation (#197829) (#198004)
# Backport This will backport the following commits from `main` to `8.16`: - [[Cloud Security] exclude unknown findings from compliance score calculation (#197829)](#197829) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Maxim Kholod","email":"maxim.kholod@elastic.co"},"sourceCommit":{"committedDate":"2024-10-28T14:09:47Z","message":"[Cloud Security] exclude unknown findings from compliance score calculation (#197829)\n\n## Summary\r\n\r\nFindings from 3rd party date can have `result.evaluation: unknown`. This\r\nleads to incorrect posture/compliance score in our flows. This PR\r\nremoves these findings from the score calculation and graphical\r\nrepresentation. properly introducing `unknown` in the compliance score\r\nUX flows will be solved separately\r\n\r\n- fixes https://github.com/elastic/security-team/issues/10913\r\n\r\n### Screenshots\r\n\r\n<img width=\"1473\" alt=\"Screenshot 2024-10-25 at 14 19 03\"\r\nsrc=\"https://github.com/user-attachments/assets/c69e45b0-7da1-4eb8-b83a-f895e7b7c3a4\">\r\n\r\n\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n- [x] Any text added follows [EUI's writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\r\nsentence case text and includes [i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n- [ ]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [x] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n- [ ] Any UI touched in this PR is usable by keyboard only (learn more\r\nabout [keyboard accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI touched in this PR does not create any new axe failures\r\n(run axe in browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n- [x] If a plugin configuration key changed, check if it needs to be\r\nallowlisted in the cloud and added to the [docker\r\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\r\n- [ ] This renders correctly on smaller devices using a responsive\r\nlayout. (You can test this [in your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n- [ ] This was checked for [cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)","sha":"3791a9bc6a7347bc4f0b4d9c754cc629204a05fd","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Cloud Security","backport:prev-minor","v8.16.0","backport:version","v8.17.0"],"title":"[Cloud Security] exclude unknown findings from compliance score calculation","number":197829,"url":"https://github.com/elastic/kibana/pull/197829","mergeCommit":{"message":"[Cloud Security] exclude unknown findings from compliance score calculation (#197829)\n\n## Summary\r\n\r\nFindings from 3rd party date can have `result.evaluation: unknown`. This\r\nleads to incorrect posture/compliance score in our flows. This PR\r\nremoves these findings from the score calculation and graphical\r\nrepresentation. properly introducing `unknown` in the compliance score\r\nUX flows will be solved separately\r\n\r\n- fixes https://github.com/elastic/security-team/issues/10913\r\n\r\n### Screenshots\r\n\r\n<img width=\"1473\" alt=\"Screenshot 2024-10-25 at 14 19 03\"\r\nsrc=\"https://github.com/user-attachments/assets/c69e45b0-7da1-4eb8-b83a-f895e7b7c3a4\">\r\n\r\n\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n- [x] Any text added follows [EUI's writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\r\nsentence case text and includes [i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n- [ ]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [x] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n- [ ] Any UI touched in this PR is usable by keyboard only (learn more\r\nabout [keyboard accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI touched in this PR does not create any new axe failures\r\n(run axe in browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n- [x] If a plugin configuration key changed, check if it needs to be\r\nallowlisted in the cloud and added to the [docker\r\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\r\n- [ ] This renders correctly on smaller devices using a responsive\r\nlayout. (You can test this [in your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n- [ ] This was checked for [cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)","sha":"3791a9bc6a7347bc4f0b4d9c754cc629204a05fd"}},"sourceBranch":"main","suggestedTargetBranches":["8.16","8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/197829","number":197829,"mergeCommit":{"message":"[Cloud Security] exclude unknown findings from compliance score calculation (#197829)\n\n## Summary\r\n\r\nFindings from 3rd party date can have `result.evaluation: unknown`. This\r\nleads to incorrect posture/compliance score in our flows. This PR\r\nremoves these findings from the score calculation and graphical\r\nrepresentation. properly introducing `unknown` in the compliance score\r\nUX flows will be solved separately\r\n\r\n- fixes https://github.com/elastic/security-team/issues/10913\r\n\r\n### Screenshots\r\n\r\n<img width=\"1473\" alt=\"Screenshot 2024-10-25 at 14 19 03\"\r\nsrc=\"https://github.com/user-attachments/assets/c69e45b0-7da1-4eb8-b83a-f895e7b7c3a4\">\r\n\r\n\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n- [x] Any text added follows [EUI's writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\r\nsentence case text and includes [i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n- [ ]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [x] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n- [ ] Any UI touched in this PR is usable by keyboard only (learn more\r\nabout [keyboard accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI touched in this PR does not create any new axe failures\r\n(run axe in browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n- [x] If a plugin configuration key changed, check if it needs to be\r\nallowlisted in the cloud and added to the [docker\r\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\r\n- [ ] This renders correctly on smaller devices using a responsive\r\nlayout. (You can test this [in your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n- [ ] This was checked for [cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)","sha":"3791a9bc6a7347bc4f0b4d9c754cc629204a05fd"}},{"branch":"8.16","label":"v8.16.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.x","label":"v8.17.0","branchLabelMappingKey":"^v8.17.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Maxim Kholod <maxim.kholod@elastic.co>
1 parent 9604402 commit 495308d

7 files changed

Lines changed: 181 additions & 11 deletions

File tree

x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ import { euiThemeVars } from '@kbn/ui-theme';
99
export const statusColors = {
1010
passed: euiThemeVars.euiColorSuccess,
1111
failed: euiThemeVars.euiColorVis9,
12+
unknown: euiThemeVars.euiColorLightShade,
1213
};
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import React from 'react';
9+
import { render, screen } from '@testing-library/react';
10+
import { ComplianceScoreBar } from './compliance_score_bar';
11+
import {
12+
COMPLIANCE_SCORE_BAR_UNKNOWN,
13+
COMPLIANCE_SCORE_BAR_PASSED,
14+
COMPLIANCE_SCORE_BAR_FAILED,
15+
} from './test_subjects';
16+
17+
describe('<ComplianceScoreBar />', () => {
18+
it('should display 0% compliance score with status unknown when both passed and failed are 0', () => {
19+
render(<ComplianceScoreBar totalPassed={0} totalFailed={0} />);
20+
expect(screen.getByText('0%')).toBeInTheDocument();
21+
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).not.toBeNull();
22+
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).toBeNull();
23+
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).toBeNull();
24+
});
25+
26+
it('should display 100% compliance score when passed is greater than 0 and failed is 0', () => {
27+
render(<ComplianceScoreBar totalPassed={10} totalFailed={0} />);
28+
expect(screen.getByText('100%')).toBeInTheDocument();
29+
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).not.toBeNull();
30+
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).toBeNull();
31+
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).toBeNull();
32+
});
33+
34+
it('should display 0% compliance score when passed is 0 and failed is greater than 0', () => {
35+
render(<ComplianceScoreBar totalPassed={0} totalFailed={10} />);
36+
expect(screen.getByText('0%')).toBeInTheDocument();
37+
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).not.toBeNull();
38+
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).toBeNull();
39+
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).toBeNull();
40+
});
41+
42+
it('should display 50% compliance score when passed is equal to failed', () => {
43+
render(<ComplianceScoreBar totalPassed={5} totalFailed={5} />);
44+
expect(screen.getByText('50%')).toBeInTheDocument();
45+
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).not.toBeNull();
46+
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).not.toBeNull();
47+
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).toBeNull();
48+
});
49+
});

x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ import { i18n } from '@kbn/i18n';
1111
import React from 'react';
1212
import { statusColors } from '@kbn/cloud-security-posture';
1313
import { calculatePostureScore } from '../../common/utils/helpers';
14-
import { CSP_FINDINGS_COMPLIANCE_SCORE } from './test_subjects';
14+
import {
15+
CSP_FINDINGS_COMPLIANCE_SCORE,
16+
COMPLIANCE_SCORE_BAR_UNKNOWN,
17+
COMPLIANCE_SCORE_BAR_FAILED,
18+
COMPLIANCE_SCORE_BAR_PASSED,
19+
} from './test_subjects';
1520

1621
/**
1722
* This component will take 100% of the width set by the parent
@@ -59,12 +64,22 @@ export const ComplianceScoreBar = ({
5964
gap: 1px;
6065
`}
6166
>
67+
{!totalPassed && !totalFailed && (
68+
<EuiFlexItem
69+
css={css`
70+
flex: 1;
71+
background: ${statusColors.unknown};
72+
`}
73+
data-test-subj={COMPLIANCE_SCORE_BAR_UNKNOWN}
74+
/>
75+
)}
6276
{!!totalPassed && (
6377
<EuiFlexItem
6478
css={css`
6579
flex: ${totalPassed};
6680
background: ${statusColors.passed};
6781
`}
82+
data-test-subj={COMPLIANCE_SCORE_BAR_PASSED}
6883
/>
6984
)}
7085
{!!totalFailed && (
@@ -73,6 +88,7 @@ export const ComplianceScoreBar = ({
7388
flex: ${totalFailed};
7489
background: ${statusColors.failed};
7590
`}
91+
data-test-subj={COMPLIANCE_SCORE_BAR_FAILED}
7692
/>
7793
)}
7894
</EuiFlexGroup>

x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,7 @@ export const CIS_GCP_INPUT_FIELDS_TEST_SUBJECTS = {
9292
};
9393

9494
export const SUBSCRIPTION_NOT_ALLOWED_TEST_SUBJECT = 'cloud_posture_page_subscription_not_allowed';
95+
96+
export const COMPLIANCE_SCORE_BAR_UNKNOWN = 'complianceScoreBarUnknown';
97+
export const COMPLIANCE_SCORE_BAR_FAILED = 'complianceScoreBarFailed';
98+
export const COMPLIANCE_SCORE_BAR_PASSED = 'complianceScoreBarPassed';
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import React from 'react';
9+
import { render } from '@testing-library/react';
10+
import { useEuiTheme } from '@elastic/eui';
11+
import { ComplianceBarComponent } from './latest_findings_group_renderer';
12+
import { RawBucket } from '@kbn/grouping/src';
13+
import { FindingsGroupingAggregation } from './use_grouped_findings';
14+
import { ComplianceScoreBar } from '../../../components/compliance_score_bar';
15+
16+
jest.mock('@elastic/eui', () => {
17+
const actual = jest.requireActual('@elastic/eui');
18+
return {
19+
...actual,
20+
useEuiTheme: jest.fn(),
21+
};
22+
});
23+
24+
jest.mock('../../../components/compliance_score_bar', () => ({
25+
ComplianceScoreBar: jest.fn(() => null),
26+
}));
27+
28+
jest.mock('../../../components/cloud_security_grouping');
29+
30+
describe('<ComplianceBarComponent />', () => {
31+
beforeEach(() => {
32+
(useEuiTheme as jest.Mock).mockReturnValue({ euiTheme: { size: { s: 's' } } });
33+
(ComplianceScoreBar as jest.Mock).mockClear();
34+
});
35+
36+
it('renders ComplianceScoreBar with correct totalFailed and totalPassed, when total = failed+passed', () => {
37+
const bucket = {
38+
doc_count: 10,
39+
failedFindings: {
40+
doc_count: 4,
41+
},
42+
passedFindings: {
43+
doc_count: 6,
44+
},
45+
} as RawBucket<FindingsGroupingAggregation>;
46+
47+
render(<ComplianceBarComponent bucket={bucket} />);
48+
49+
expect(ComplianceScoreBar).toHaveBeenCalledWith(
50+
expect.objectContaining({
51+
totalFailed: 4,
52+
totalPassed: 6,
53+
}),
54+
{}
55+
);
56+
});
57+
58+
it('renders ComplianceScoreBar with correct totalFailed and totalPassed, when there are unknown findings', () => {
59+
const bucket = {
60+
doc_count: 10,
61+
failedFindings: {
62+
doc_count: 3,
63+
},
64+
passedFindings: {
65+
doc_count: 6,
66+
},
67+
} as RawBucket<FindingsGroupingAggregation>;
68+
69+
render(<ComplianceBarComponent bucket={bucket} />);
70+
71+
expect(ComplianceScoreBar).toHaveBeenCalledWith(
72+
expect.objectContaining({
73+
totalFailed: 3,
74+
totalPassed: 6,
75+
}),
76+
{}
77+
);
78+
});
79+
80+
it('renders ComplianceScoreBar with correct totalFailed and totalPassed, when there are no findings', () => {
81+
const bucket = {
82+
doc_count: 10,
83+
failedFindings: {
84+
doc_count: 0,
85+
},
86+
passedFindings: {
87+
doc_count: 0,
88+
},
89+
} as RawBucket<FindingsGroupingAggregation>;
90+
91+
render(<ComplianceBarComponent bucket={bucket} />);
92+
93+
expect(ComplianceScoreBar).toHaveBeenCalledWith(
94+
expect.objectContaining({
95+
totalFailed: 0,
96+
totalPassed: 0,
97+
}),
98+
{}
99+
);
100+
});
101+
});

x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,11 +198,15 @@ const FindingsCountComponent = ({ bucket }: { bucket: RawBucket<FindingsGrouping
198198

199199
const FindingsCount = React.memo(FindingsCountComponent);
200200

201-
const ComplianceBarComponent = ({ bucket }: { bucket: RawBucket<FindingsGroupingAggregation> }) => {
201+
export const ComplianceBarComponent = ({
202+
bucket,
203+
}: {
204+
bucket: RawBucket<FindingsGroupingAggregation>;
205+
}) => {
202206
const { euiTheme } = useEuiTheme();
203207

204208
const totalFailed = bucket.failedFindings?.doc_count || 0;
205-
const totalPassed = bucket.doc_count - totalFailed;
209+
const totalPassed = bucket.passedFindings?.doc_count || 0;
206210
return (
207211
<ComplianceScoreBar
208212
size="l"

x-pack/plugins/security_solution/public/cloud_security_posture/components/misconfiguration/misconfiguration_preview.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,12 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, useEuiTheme, EuiTitle }
1212
import { FormattedMessage } from '@kbn/i18n-react';
1313
import { DistributionBar } from '@kbn/security-solution-distribution-bar';
1414
import { useMisconfigurationPreview } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview';
15-
import { euiThemeVars } from '@kbn/ui-theme';
1615
import { i18n } from '@kbn/i18n';
1716
import { ExpandablePanel } from '@kbn/security-solution-common';
1817
import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common';
1918
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
2019
import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview';
21-
import { hasVulnerabilitiesData } from '@kbn/cloud-security-posture';
20+
import { hasVulnerabilitiesData, statusColors } from '@kbn/cloud-security-posture';
2221
import { METRIC_TYPE } from '@kbn/analytics';
2322
import {
2423
ENTITY_FLYOUT_WITH_MISCONFIGURATION_VISIT,
@@ -51,7 +50,7 @@ export const getFindingsStats = (passedFindingsStats: number, failedFindingsStat
5150
}
5251
),
5352
count: passedFindingsStats,
54-
color: euiThemeVars.euiColorSuccess,
53+
color: statusColors.passed,
5554
},
5655
{
5756
key: i18n.translate(
@@ -61,7 +60,7 @@ export const getFindingsStats = (passedFindingsStats: number, failedFindingsStat
6160
}
6261
),
6362
count: failedFindingsStats,
64-
color: euiThemeVars.euiColorVis9,
63+
color: statusColors.failed,
6564
},
6665
];
6766
};
@@ -70,14 +69,10 @@ const MisconfigurationPreviewScore = ({
7069
passedFindings,
7170
failedFindings,
7271
euiTheme,
73-
numberOfPassedFindings,
74-
numberOfFailedFindings,
7572
}: {
7673
passedFindings: number;
7774
failedFindings: number;
7875
euiTheme: EuiThemeComputed<{}>;
79-
numberOfPassedFindings?: number;
80-
numberOfFailedFindings?: number;
8176
}) => {
8277
return (
8378
<EuiFlexItem>

0 commit comments

Comments
 (0)