-
Notifications
You must be signed in to change notification settings - Fork 8.6k
[Cloud Security] Misconfiguration preview & Refactor CSP Plugin to include new package PHASE 4 #191677
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 Security] Misconfiguration preview & Refactor CSP Plugin to include new package PHASE 4 #191677
Changes from 6 commits
61cc974
89eb0e7
199b8d0
0aa00d8
a683d21
750fa9b
0423a29
a31584c
1d6b486
f5656f6
574f2c4
292a222
62379d0
a303ddf
733111e
cae20ab
3ddc7b7
def06a5
fb41b2f
60bc1bf
6609c40
3d5b126
1f95ac2
842c829
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| /* | ||
| * 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 { useQuery } from '@tanstack/react-query'; | ||
| import { lastValueFrom } from 'rxjs'; | ||
| import type { IKibanaSearchResponse, IKibanaSearchRequest } from '@kbn/search-types'; | ||
| import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; | ||
| import { | ||
| CDR_MISCONFIGURATIONS_INDEX_PATTERN, | ||
| LATEST_FINDINGS_RETENTION_POLICY, | ||
| MAX_FINDINGS_TO_LOAD, | ||
| CspFinding, | ||
| } from '@kbn/cloud-security-posture-common'; | ||
| import type { CspBenchmarkRulesStates } from '@kbn/cloud-security-posture-common/schema/rules/latest'; | ||
| import { buildMutedRulesFilter } from '@kbn/cloud-security-posture-common'; | ||
| import { useKibana } from '@kbn/kibana-react-plugin/public'; | ||
| import type { CoreStart } from '@kbn/core/public'; | ||
| import { showErrorToast } from '../..'; | ||
| import type { CspClientPluginStartDeps } from '../../type'; | ||
| import type { FindingsBaseEsQuery } from '../../type'; | ||
| import { useGetCspBenchmarkRulesStatesApi } from './use_get_benchmark_rules_state_api'; | ||
|
|
||
| interface UseFindingsOptions extends FindingsBaseEsQuery { | ||
| sort: string[][]; | ||
| enabled: boolean; | ||
| pageSize: number; | ||
| } | ||
|
|
||
| type LatestFindingsRequest = IKibanaSearchRequest<estypes.SearchRequest>; | ||
| type LatestFindingsResponse = IKibanaSearchResponse< | ||
| estypes.SearchResponse<CspFinding, FindingsAggs> | ||
| >; | ||
|
|
||
| interface FindingsAggs { | ||
| count: estypes.AggregationsMultiBucketAggregateBase<estypes.AggregationsStringRareTermsBucketKeys>; | ||
| } | ||
|
|
||
| export const getFindingsCountAggQueryMisconfigurationPreview = () => ({ | ||
| count: { | ||
| filters: { | ||
| other_bucket_key: 'other_messages', | ||
|
maxcold marked this conversation as resolved.
Outdated
|
||
| filters: { | ||
| passed: { match: { 'result.evaluation': 'passed' } }, | ||
| failed: { match: { 'result.evaluation': 'failed' } }, | ||
| }, | ||
| }, | ||
| }, | ||
| }); | ||
|
|
||
| export const getMisconfigurationAggregationCount = ( | ||
| buckets: Array<estypes.AggregationsStringRareTermsBucketKeys | undefined> | ||
| ) => { | ||
| const passed = buckets.find((bucket) => bucket?.key === 'passed'); | ||
| const failed = buckets.find((bucket) => bucket?.key === 'failed'); | ||
| const noStatus = buckets.find((bucket) => bucket?.key === 'other_messages'); | ||
|
|
||
| return { | ||
| passed: passed?.doc_count || 0, | ||
| failed: failed?.doc_count || 0, | ||
| no_status: noStatus?.doc_count || 0, | ||
| }; | ||
| }; | ||
|
|
||
| export const getFindingsQuery = ( | ||
| { query, sort }: UseFindingsOptions, | ||
| rulesStates: CspBenchmarkRulesStates, | ||
| pageParam: any | ||
|
animehart marked this conversation as resolved.
Outdated
|
||
| ) => { | ||
| const mutedRulesFilterQuery = buildMutedRulesFilter(rulesStates); | ||
|
|
||
| return { | ||
| index: CDR_MISCONFIGURATIONS_INDEX_PATTERN, | ||
| size: MAX_FINDINGS_TO_LOAD, | ||
|
maxcold marked this conversation as resolved.
Outdated
|
||
| aggs: getFindingsCountAggQueryMisconfigurationPreview(), | ||
| ignore_unavailable: false, | ||
| query: { | ||
| ...query, | ||
| bool: { | ||
| ...query?.bool, | ||
| filter: [ | ||
| ...(query?.bool?.filter ?? []), | ||
| { | ||
| range: { | ||
| '@timestamp': { | ||
| gte: `now-${LATEST_FINDINGS_RETENTION_POLICY}`, | ||
| lte: 'now', | ||
| }, | ||
| }, | ||
| }, | ||
| ], | ||
| must_not: [...(query?.bool?.must_not ?? []), ...mutedRulesFilterQuery], | ||
| }, | ||
| }, | ||
| ...(pageParam ? { from: pageParam } : {}), | ||
| }; | ||
| }; | ||
|
animehart marked this conversation as resolved.
Outdated
|
||
|
|
||
| export const useMisconfigurationPreview = (options: UseFindingsOptions) => { | ||
| const { | ||
| data, | ||
| notifications: { toasts }, | ||
| } = useKibana<CoreStart & CspClientPluginStartDeps>().services; | ||
| const { data: rulesStates } = useGetCspBenchmarkRulesStatesApi(); | ||
|
|
||
| return useQuery( | ||
| ['csp_findings', { params: options }, rulesStates], | ||
|
maxcold marked this conversation as resolved.
Outdated
|
||
| async ({ pageParam }) => { | ||
| const { | ||
| rawResponse: { aggregations }, | ||
| } = await lastValueFrom( | ||
| data.search.search<LatestFindingsRequest, LatestFindingsResponse>({ | ||
| params: getFindingsQuery(options, rulesStates!, pageParam), | ||
| }) | ||
| ); | ||
| if (!aggregations) throw new Error('expected aggregations to be defined'); | ||
|
|
||
| return { | ||
| count: getMisconfigurationAggregationCount( | ||
| Object.entries(aggregations.count.buckets).map(([key, value]) => ({ | ||
| key, | ||
| doc_count: value.doc_count || 0, | ||
| })) | ||
| ), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since we already have a return {
count: getMisconfigurationAggregationCount(aggregations.count.buckets)
}; |
||
| }; | ||
| }, | ||
| { | ||
| enabled: options.enabled && !!rulesStates, | ||
| keepPreviousData: true, | ||
| onError: (err: Error) => showErrorToast(toasts, err), | ||
| } | ||
| ); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,5 +36,6 @@ | |
| "@kbn/kibana-react-plugin", | ||
| "@kbn/cloud-security-posture-common", | ||
| "@kbn/i18n", | ||
| "@kbn/search-types", | ||
| ] | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,57 @@ | ||||||||||||||||||
| /* | ||||||||||||||||||
| * 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 { EuiAccordion, EuiSpacer, EuiTitle, useEuiTheme } from '@elastic/eui'; | ||||||||||||||||||
|
|
||||||||||||||||||
| import React from 'react'; | ||||||||||||||||||
| import { css } from '@emotion/react'; | ||||||||||||||||||
| import { FormattedMessage } from '@kbn/i18n-react'; | ||||||||||||||||||
| import { useCspSetupStatusApi } from '@kbn/cloud-security-posture/src/hooks/use_csp_setup_status_api'; | ||||||||||||||||||
| import { MisconfigurationsOverview } from './misconfiguration/misconfiguration_overview'; | ||||||||||||||||||
|
|
||||||||||||||||||
| export const EntityInsight = <T,>({ hostName }: { hostName: string }) => { | ||||||||||||||||||
| const { euiTheme } = useEuiTheme(); | ||||||||||||||||||
| const getSetupStatus = useCspSetupStatusApi(); | ||||||||||||||||||
| const hasMisconfigurationFindings = getSetupStatus.data?.hasMisconfigurationsFindings; | ||||||||||||||||||
|
|
||||||||||||||||||
| return ( | ||||||||||||||||||
| <> | ||||||||||||||||||
| {hasMisconfigurationFindings && ( | ||||||||||||||||||
| <EuiAccordion | ||||||||||||||||||
| initialIsOpen={true} | ||||||||||||||||||
| id="observedEntity-accordion" | ||||||||||||||||||
| data-test-subj="entityInsightTestSubj" | ||||||||||||||||||
| buttonProps={{ | ||||||||||||||||||
| 'data-test-subj': 'observedEntity-accordion-button', | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. better avoid using existing identifiers:
Suggested change
|
||||||||||||||||||
| css: css` | ||||||||||||||||||
| color: ${euiTheme.colors.primary}; | ||||||||||||||||||
| `, | ||||||||||||||||||
| }} | ||||||||||||||||||
| buttonContent={ | ||||||||||||||||||
| <EuiTitle size="xs"> | ||||||||||||||||||
| <h3> | ||||||||||||||||||
| <FormattedMessage | ||||||||||||||||||
| id="xpack.securitySolution.flyout.entityDetails.insightsTitle" | ||||||||||||||||||
| defaultMessage="Insights" | ||||||||||||||||||
| /> | ||||||||||||||||||
| </h3> | ||||||||||||||||||
| </EuiTitle> | ||||||||||||||||||
| } | ||||||||||||||||||
| css={css` | ||||||||||||||||||
| .euiAccordion__optionalAction { | ||||||||||||||||||
| margin-left: auto; | ||||||||||||||||||
| } | ||||||||||||||||||
|
animehart marked this conversation as resolved.
Outdated
|
||||||||||||||||||
| `} | ||||||||||||||||||
| > | ||||||||||||||||||
| <EuiSpacer size="m" /> | ||||||||||||||||||
| <MisconfigurationsOverview hostName={hostName} /> | ||||||||||||||||||
| <EuiSpacer size="m" /> | ||||||||||||||||||
| </EuiAccordion> | ||||||||||||||||||
| )} | ||||||||||||||||||
| </> | ||||||||||||||||||
| ); | ||||||||||||||||||
| }; | ||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| /* | ||
| * 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. | ||
| */ | ||
|
|
||
| // Add stuff here | ||
| import { TestProviders } from '../../../common/mock'; | ||
| import { render } from '@testing-library/react'; | ||
| import React from 'react'; | ||
| import { MisconfigurationsOverview } from './misconfiguration_overview'; | ||
|
|
||
| const mockProps = { | ||
| hostName: 'testContextID', | ||
| }; | ||
|
|
||
| describe('MisconfigurationsOverview', () => { | ||
| it('renders', () => { | ||
| const { queryByTestId } = render(<MisconfigurationsOverview {...mockProps} />, { | ||
| wrapper: TestProviders, | ||
| }); | ||
| expect( | ||
| queryByTestId('securitySolutionFlyoutInsightsMisconfigurationsContent') | ||
| ).toBeInTheDocument(); | ||
| expect(queryByTestId('noFindingsDataTestSubj')).toBeInTheDocument(); | ||
| }); | ||
| }); |
Uh oh!
There was an error while loading. Please reload this page.