mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[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)](https://github.com/elastic/kibana/pull/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>
This commit is contained in:
parent
9604402862
commit
495308d7b6
7 changed files with 181 additions and 11 deletions
|
@ -9,4 +9,5 @@ import { euiThemeVars } from '@kbn/ui-theme';
|
|||
export const statusColors = {
|
||||
passed: euiThemeVars.euiColorSuccess,
|
||||
failed: euiThemeVars.euiColorVis9,
|
||||
unknown: euiThemeVars.euiColorLightShade,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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, screen } from '@testing-library/react';
|
||||
import { ComplianceScoreBar } from './compliance_score_bar';
|
||||
import {
|
||||
COMPLIANCE_SCORE_BAR_UNKNOWN,
|
||||
COMPLIANCE_SCORE_BAR_PASSED,
|
||||
COMPLIANCE_SCORE_BAR_FAILED,
|
||||
} from './test_subjects';
|
||||
|
||||
describe('<ComplianceScoreBar />', () => {
|
||||
it('should display 0% compliance score with status unknown when both passed and failed are 0', () => {
|
||||
render(<ComplianceScoreBar totalPassed={0} totalFailed={0} />);
|
||||
expect(screen.getByText('0%')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).not.toBeNull();
|
||||
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).toBeNull();
|
||||
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).toBeNull();
|
||||
});
|
||||
|
||||
it('should display 100% compliance score when passed is greater than 0 and failed is 0', () => {
|
||||
render(<ComplianceScoreBar totalPassed={10} totalFailed={0} />);
|
||||
expect(screen.getByText('100%')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).not.toBeNull();
|
||||
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).toBeNull();
|
||||
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).toBeNull();
|
||||
});
|
||||
|
||||
it('should display 0% compliance score when passed is 0 and failed is greater than 0', () => {
|
||||
render(<ComplianceScoreBar totalPassed={0} totalFailed={10} />);
|
||||
expect(screen.getByText('0%')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).not.toBeNull();
|
||||
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).toBeNull();
|
||||
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).toBeNull();
|
||||
});
|
||||
|
||||
it('should display 50% compliance score when passed is equal to failed', () => {
|
||||
render(<ComplianceScoreBar totalPassed={5} totalFailed={5} />);
|
||||
expect(screen.getByText('50%')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).not.toBeNull();
|
||||
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).not.toBeNull();
|
||||
expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).toBeNull();
|
||||
});
|
||||
});
|
|
@ -11,7 +11,12 @@ import { i18n } from '@kbn/i18n';
|
|||
import React from 'react';
|
||||
import { statusColors } from '@kbn/cloud-security-posture';
|
||||
import { calculatePostureScore } from '../../common/utils/helpers';
|
||||
import { CSP_FINDINGS_COMPLIANCE_SCORE } from './test_subjects';
|
||||
import {
|
||||
CSP_FINDINGS_COMPLIANCE_SCORE,
|
||||
COMPLIANCE_SCORE_BAR_UNKNOWN,
|
||||
COMPLIANCE_SCORE_BAR_FAILED,
|
||||
COMPLIANCE_SCORE_BAR_PASSED,
|
||||
} from './test_subjects';
|
||||
|
||||
/**
|
||||
* This component will take 100% of the width set by the parent
|
||||
|
@ -59,12 +64,22 @@ export const ComplianceScoreBar = ({
|
|||
gap: 1px;
|
||||
`}
|
||||
>
|
||||
{!totalPassed && !totalFailed && (
|
||||
<EuiFlexItem
|
||||
css={css`
|
||||
flex: 1;
|
||||
background: ${statusColors.unknown};
|
||||
`}
|
||||
data-test-subj={COMPLIANCE_SCORE_BAR_UNKNOWN}
|
||||
/>
|
||||
)}
|
||||
{!!totalPassed && (
|
||||
<EuiFlexItem
|
||||
css={css`
|
||||
flex: ${totalPassed};
|
||||
background: ${statusColors.passed};
|
||||
`}
|
||||
data-test-subj={COMPLIANCE_SCORE_BAR_PASSED}
|
||||
/>
|
||||
)}
|
||||
{!!totalFailed && (
|
||||
|
@ -73,6 +88,7 @@ export const ComplianceScoreBar = ({
|
|||
flex: ${totalFailed};
|
||||
background: ${statusColors.failed};
|
||||
`}
|
||||
data-test-subj={COMPLIANCE_SCORE_BAR_FAILED}
|
||||
/>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -92,3 +92,7 @@ export const CIS_GCP_INPUT_FIELDS_TEST_SUBJECTS = {
|
|||
};
|
||||
|
||||
export const SUBSCRIPTION_NOT_ALLOWED_TEST_SUBJECT = 'cloud_posture_page_subscription_not_allowed';
|
||||
|
||||
export const COMPLIANCE_SCORE_BAR_UNKNOWN = 'complianceScoreBarUnknown';
|
||||
export const COMPLIANCE_SCORE_BAR_FAILED = 'complianceScoreBarFailed';
|
||||
export const COMPLIANCE_SCORE_BAR_PASSED = 'complianceScoreBarPassed';
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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 } from '@testing-library/react';
|
||||
import { useEuiTheme } from '@elastic/eui';
|
||||
import { ComplianceBarComponent } from './latest_findings_group_renderer';
|
||||
import { RawBucket } from '@kbn/grouping/src';
|
||||
import { FindingsGroupingAggregation } from './use_grouped_findings';
|
||||
import { ComplianceScoreBar } from '../../../components/compliance_score_bar';
|
||||
|
||||
jest.mock('@elastic/eui', () => {
|
||||
const actual = jest.requireActual('@elastic/eui');
|
||||
return {
|
||||
...actual,
|
||||
useEuiTheme: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../../../components/compliance_score_bar', () => ({
|
||||
ComplianceScoreBar: jest.fn(() => null),
|
||||
}));
|
||||
|
||||
jest.mock('../../../components/cloud_security_grouping');
|
||||
|
||||
describe('<ComplianceBarComponent />', () => {
|
||||
beforeEach(() => {
|
||||
(useEuiTheme as jest.Mock).mockReturnValue({ euiTheme: { size: { s: 's' } } });
|
||||
(ComplianceScoreBar as jest.Mock).mockClear();
|
||||
});
|
||||
|
||||
it('renders ComplianceScoreBar with correct totalFailed and totalPassed, when total = failed+passed', () => {
|
||||
const bucket = {
|
||||
doc_count: 10,
|
||||
failedFindings: {
|
||||
doc_count: 4,
|
||||
},
|
||||
passedFindings: {
|
||||
doc_count: 6,
|
||||
},
|
||||
} as RawBucket<FindingsGroupingAggregation>;
|
||||
|
||||
render(<ComplianceBarComponent bucket={bucket} />);
|
||||
|
||||
expect(ComplianceScoreBar).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
totalFailed: 4,
|
||||
totalPassed: 6,
|
||||
}),
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('renders ComplianceScoreBar with correct totalFailed and totalPassed, when there are unknown findings', () => {
|
||||
const bucket = {
|
||||
doc_count: 10,
|
||||
failedFindings: {
|
||||
doc_count: 3,
|
||||
},
|
||||
passedFindings: {
|
||||
doc_count: 6,
|
||||
},
|
||||
} as RawBucket<FindingsGroupingAggregation>;
|
||||
|
||||
render(<ComplianceBarComponent bucket={bucket} />);
|
||||
|
||||
expect(ComplianceScoreBar).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
totalFailed: 3,
|
||||
totalPassed: 6,
|
||||
}),
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('renders ComplianceScoreBar with correct totalFailed and totalPassed, when there are no findings', () => {
|
||||
const bucket = {
|
||||
doc_count: 10,
|
||||
failedFindings: {
|
||||
doc_count: 0,
|
||||
},
|
||||
passedFindings: {
|
||||
doc_count: 0,
|
||||
},
|
||||
} as RawBucket<FindingsGroupingAggregation>;
|
||||
|
||||
render(<ComplianceBarComponent bucket={bucket} />);
|
||||
|
||||
expect(ComplianceScoreBar).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
totalFailed: 0,
|
||||
totalPassed: 0,
|
||||
}),
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
|
@ -198,11 +198,15 @@ const FindingsCountComponent = ({ bucket }: { bucket: RawBucket<FindingsGrouping
|
|||
|
||||
const FindingsCount = React.memo(FindingsCountComponent);
|
||||
|
||||
const ComplianceBarComponent = ({ bucket }: { bucket: RawBucket<FindingsGroupingAggregation> }) => {
|
||||
export const ComplianceBarComponent = ({
|
||||
bucket,
|
||||
}: {
|
||||
bucket: RawBucket<FindingsGroupingAggregation>;
|
||||
}) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
|
||||
const totalFailed = bucket.failedFindings?.doc_count || 0;
|
||||
const totalPassed = bucket.doc_count - totalFailed;
|
||||
const totalPassed = bucket.passedFindings?.doc_count || 0;
|
||||
return (
|
||||
<ComplianceScoreBar
|
||||
size="l"
|
||||
|
|
|
@ -12,13 +12,12 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, useEuiTheme, EuiTitle }
|
|||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { DistributionBar } from '@kbn/security-solution-distribution-bar';
|
||||
import { useMisconfigurationPreview } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview';
|
||||
import { euiThemeVars } from '@kbn/ui-theme';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ExpandablePanel } from '@kbn/security-solution-common';
|
||||
import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common';
|
||||
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
|
||||
import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview';
|
||||
import { hasVulnerabilitiesData } from '@kbn/cloud-security-posture';
|
||||
import { hasVulnerabilitiesData, statusColors } from '@kbn/cloud-security-posture';
|
||||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import {
|
||||
ENTITY_FLYOUT_WITH_MISCONFIGURATION_VISIT,
|
||||
|
@ -51,7 +50,7 @@ export const getFindingsStats = (passedFindingsStats: number, failedFindingsStat
|
|||
}
|
||||
),
|
||||
count: passedFindingsStats,
|
||||
color: euiThemeVars.euiColorSuccess,
|
||||
color: statusColors.passed,
|
||||
},
|
||||
{
|
||||
key: i18n.translate(
|
||||
|
@ -61,7 +60,7 @@ export const getFindingsStats = (passedFindingsStats: number, failedFindingsStat
|
|||
}
|
||||
),
|
||||
count: failedFindingsStats,
|
||||
color: euiThemeVars.euiColorVis9,
|
||||
color: statusColors.failed,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
@ -70,14 +69,10 @@ const MisconfigurationPreviewScore = ({
|
|||
passedFindings,
|
||||
failedFindings,
|
||||
euiTheme,
|
||||
numberOfPassedFindings,
|
||||
numberOfFailedFindings,
|
||||
}: {
|
||||
passedFindings: number;
|
||||
failedFindings: number;
|
||||
euiTheme: EuiThemeComputed<{}>;
|
||||
numberOfPassedFindings?: number;
|
||||
numberOfFailedFindings?: number;
|
||||
}) => {
|
||||
return (
|
||||
<EuiFlexItem>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue