diff --git a/x-pack/packages/kbn-cloud-security-posture-common/index.ts b/x-pack/packages/kbn-cloud-security-posture-common/index.ts index dc4e930f537e6..e01401f37ef23 100644 --- a/x-pack/packages/kbn-cloud-security-posture-common/index.ts +++ b/x-pack/packages/kbn-cloud-security-posture-common/index.ts @@ -18,6 +18,7 @@ export type { CspSetupStatus, } from './types/status'; export type { CspFinding, CspFindingResult } from './types/findings'; +export type { CspVulnerabilityFinding } from './schema/vulnerabilities/csp_vulnerability_finding'; export type { BenchmarksCisId } from './types/benchmark'; export type { VulnSeverity } from './types/vulnerabilities'; export * from './constants'; diff --git a/x-pack/packages/kbn-cloud-security-posture-common/schema/vulnerabilities/csp_vulnerability_finding.ts b/x-pack/packages/kbn-cloud-security-posture-common/schema/vulnerabilities/csp_vulnerability_finding.ts index b2255b8fa51f8..51feb88d2d64d 100644 --- a/x-pack/packages/kbn-cloud-security-posture-common/schema/vulnerabilities/csp_vulnerability_finding.ts +++ b/x-pack/packages/kbn-cloud-security-posture-common/schema/vulnerabilities/csp_vulnerability_finding.ts @@ -6,7 +6,7 @@ */ // TODO: this needs to be defined in a versioned schema -import type { EcsEvent } from '@elastic/ecs'; +import type { EcsDataStream, EcsEvent, EcsObserver } from '@elastic/ecs'; import type { VulnSeverity } from '../../types/vulnerabilities'; export interface CspVulnerabilityFinding { @@ -75,7 +75,8 @@ export interface CspVulnerabilityFinding { name?: string; fixed_version?: string; }; - data_stream: { dataset: string }; + data_stream: EcsDataStream; + observer: EcsObserver; } export interface Vulnerability { diff --git a/x-pack/packages/kbn-cloud-security-posture-common/types/findings.ts b/x-pack/packages/kbn-cloud-security-posture-common/types/findings.ts index 52503b589c44a..a5a9244619980 100644 --- a/x-pack/packages/kbn-cloud-security-posture-common/types/findings.ts +++ b/x-pack/packages/kbn-cloud-security-posture-common/types/findings.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { EcsDataStream, EcsEvent } from '@elastic/ecs'; +import type { EcsDataStream, EcsEvent, EcsObserver } from '@elastic/ecs'; import type { CspBenchmarkRuleMetadata } from '../schema/rules/latest'; export interface CspFinding { @@ -19,6 +19,7 @@ export interface CspFinding { host: CspFindingHost; event: EcsEvent; data_stream: EcsDataStream; + observer: EcsObserver; agent: CspFindingAgent; ecs: { version: string; diff --git a/x-pack/plugins/cloud_security_posture/public/common/constants.ts b/x-pack/plugins/cloud_security_posture/public/common/constants.ts index f6726731cad95..50d191cf07167 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/constants.ts @@ -38,6 +38,9 @@ export const LOCAL_STORAGE_DASHBOARD_BENCHMARK_SORT_KEY = 'cloudPosture:complianceDashboard:benchmarkSort'; export const LOCAL_STORAGE_FINDINGS_LAST_SELECTED_TAB_KEY = 'cloudPosture:findings:lastSelectedTab'; +export const LOCAL_STORAGE_3P_INTEGRATIONS_CALLOUT_KEY = + 'cloudPosture:findings:3pIntegrationsCallout'; + export const LOCAL_STORAGE_VULNERABILITIES_GROUPING_KEY = 'cspLatestVulnerabilitiesGrouping'; export const LOCAL_STORAGE_FINDINGS_GROUPING_KEY = 'cspLatestFindingsGrouping'; @@ -230,6 +233,7 @@ export const FINDINGS_GROUPING_OPTIONS = { CLOUD_ACCOUNT_NAME: 'cloud.account.name', ORCHESTRATOR_CLUSTER_NAME: 'orchestrator.cluster.name', }; + export const VULNERABILITY_FIELDS = { VULNERABILITY_ID: 'vulnerability.id', SCORE_BASE: 'vulnerability.score.base', @@ -242,8 +246,9 @@ export const VULNERABILITY_FIELDS = { CLOUD_ACCOUNT_NAME: 'cloud.account.name', CLOUD_PROVIDER: 'cloud.provider', DESCRIPTION: 'vulnerability.description', - SOURCE: 'data_stream.dataset', + VENDOR: 'observer.vendor', } as const; + export const VULNERABILITY_GROUPING_OPTIONS = { NONE: 'none', RESOURCE_NAME: VULNERABILITY_FIELDS.RESOURCE_NAME, diff --git a/x-pack/plugins/cloud_security_posture/public/common/utils/get_dataset_display_name.test.ts b/x-pack/plugins/cloud_security_posture/public/common/utils/get_dataset_display_name.test.ts deleted file mode 100644 index 432de02699d31..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/common/utils/get_dataset_display_name.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 { - CSP_MISCONFIGURATIONS_DATASET, - CSP_VULN_DATASET, - getDatasetDisplayName, - WIZ_MISCONFIGURATIONS_DATASET, - WIZ_VULN_DATASET, -} from './get_dataset_display_name'; - -describe('getDatasetDisplayName', () => { - it('should return "Wiz" when dataset is from Wiz integration', () => { - const wizMisconfigsDatasetDisplayName = getDatasetDisplayName(WIZ_MISCONFIGURATIONS_DATASET); - expect(wizMisconfigsDatasetDisplayName).toBe('Wiz'); - const wizVulnDatasetDisplayName = getDatasetDisplayName(WIZ_VULN_DATASET); - expect(wizVulnDatasetDisplayName).toBe('Wiz'); - }); - - it('should return "Elastic CSP" when dataset is from Elastic CSP integration', () => { - const elasticCspMisconfigsDatasetDisplayName = getDatasetDisplayName( - CSP_MISCONFIGURATIONS_DATASET - ); - expect(elasticCspMisconfigsDatasetDisplayName).toBe('Elastic CSP'); - const elasticCspVulnDatasetDisplayName = getDatasetDisplayName(CSP_VULN_DATASET); - expect(elasticCspVulnDatasetDisplayName).toBe('Elastic CSP'); - }); - - it('should return undefined when dataset is undefined', () => { - const result = getDatasetDisplayName(undefined); - expect(result).toBeUndefined(); - }); - - it('should return undefined when dataset is an empty string', () => { - const result = getDatasetDisplayName(''); - expect(result).toBeUndefined(); - }); -}); diff --git a/x-pack/plugins/cloud_security_posture/public/common/utils/get_vendor_name.test.ts b/x-pack/plugins/cloud_security_posture/public/common/utils/get_vendor_name.test.ts new file mode 100644 index 0000000000000..70e0e5b957f7d --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/common/utils/get_vendor_name.test.ts @@ -0,0 +1,71 @@ +/* + * 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 { CspFinding, CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common'; +import { getVendorName } from './get_vendor_name'; + +describe('getVendorName', () => { + it('should return the vendor from the finding if available', () => { + const finding = { + observer: { vendor: 'SomeVendor' }, + data_stream: { dataset: 'some.dataset' }, + } as CspFinding; + + const result = getVendorName(finding); + expect(result).toBe('SomeVendor'); + }); + + it('should return "Wiz" for Wiz misconfiguration dataset', () => { + const finding = { + observer: {}, + data_stream: { dataset: 'wiz.cloud_configuration_finding' }, + } as CspFinding; + + const result = getVendorName(finding); + expect(result).toBe('Wiz'); + }); + + it('should return "Wiz" for Wiz vulnerability dataset', () => { + const finding = { + observer: {}, + data_stream: { dataset: 'wiz.vulnerability' }, + } as CspVulnerabilityFinding; + + const result = getVendorName(finding); + expect(result).toBe('Wiz'); + }); + + it('should return "Elastic" for Elastic misconfiguration dataset', () => { + const finding = { + observer: {}, + data_stream: { dataset: 'cloud_security_posture.findings' }, + } as CspFinding; + + const result = getVendorName(finding); + expect(result).toBe('Elastic'); + }); + + it('should return "Elastic" for Elastic vulnerability dataset', () => { + const finding = { + observer: {}, + data_stream: { dataset: 'cloud_security_posture.vulnerabilities' }, + } as CspVulnerabilityFinding; + + const result = getVendorName(finding); + expect(result).toBe('Elastic'); + }); + + it('should return undefined if no vendor or known dataset is provided', () => { + const finding = { + observer: {}, + data_stream: { dataset: 'unknown.dataset' }, + } as CspFinding; + + const result = getVendorName(finding); + expect(result).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/common/utils/get_dataset_display_name.ts b/x-pack/plugins/cloud_security_posture/public/common/utils/get_vendor_name.ts similarity index 61% rename from x-pack/plugins/cloud_security_posture/public/common/utils/get_dataset_display_name.ts rename to x-pack/plugins/cloud_security_posture/public/common/utils/get_vendor_name.ts index 7164135e1ef19..e3595c9ae65fd 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/utils/get_dataset_display_name.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/utils/get_vendor_name.ts @@ -5,15 +5,19 @@ * 2.0. */ -type Dataset = 'wiz.cloud_configuration_finding' | 'cloud_security_posture.findings'; +import { CspFinding, CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common'; +import { isNativeCspFinding } from './is_native_csp_finding'; export const CSP_MISCONFIGURATIONS_DATASET = 'cloud_security_posture.findings'; export const CSP_VULN_DATASET = 'cloud_security_posture.vulnerabilities'; export const WIZ_MISCONFIGURATIONS_DATASET = 'wiz.cloud_configuration_finding'; export const WIZ_VULN_DATASET = 'wiz.vulnerability'; -export const getDatasetDisplayName = (dataset?: Dataset | string) => { +export const getVendorName = (finding: CspFinding | CspVulnerabilityFinding) => { + if (finding.observer?.vendor) return finding.observer.vendor; + + const dataset = finding.data_stream?.dataset; + if (dataset === WIZ_MISCONFIGURATIONS_DATASET || dataset === WIZ_VULN_DATASET) return 'Wiz'; - if (dataset === CSP_MISCONFIGURATIONS_DATASET || dataset === CSP_VULN_DATASET) - return 'Elastic CSP'; + if (isNativeCspFinding(finding)) return 'Elastic'; }; diff --git a/x-pack/plugins/cloud_security_posture/public/common/utils/is_native_csp_finding.test.ts b/x-pack/plugins/cloud_security_posture/public/common/utils/is_native_csp_finding.test.ts new file mode 100644 index 0000000000000..1ebe6cb5c274e --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/common/utils/is_native_csp_finding.test.ts @@ -0,0 +1,56 @@ +/* + * 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 { CSP_MISCONFIGURATIONS_DATASET, CSP_VULN_DATASET } from './get_vendor_name'; +import { isNativeCspFinding } from './is_native_csp_finding'; +import { CspFinding } from '@kbn/cloud-security-posture-common'; +import { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/csp_vulnerability_finding'; + +describe('isNativeCspFinding', () => { + it("should return true when finding's dataset matches CSP_MISCONFIGURATIONS_DATASET", () => { + const finding = { + data_stream: { + dataset: CSP_MISCONFIGURATIONS_DATASET, + }, + } as CspFinding; + + expect(isNativeCspFinding(finding)).toBe(true); + }); + + it("should return true when finding's dataset matches CSP_VULN_DATASET", () => { + const finding = { + data_stream: { + dataset: CSP_VULN_DATASET, + }, + } as CspVulnerabilityFinding; + + expect(isNativeCspFinding(finding)).toBe(true); + }); + + it('should return false when finding object is missing data_stream property', () => { + const finding = {} as CspFinding; + + expect(isNativeCspFinding(finding)).toBe(false); + }); + + it('should return false when finding object has data_stream property but missing dataset property', () => { + const finding = { + data_stream: {}, + } as CspFinding; + + expect(isNativeCspFinding(finding)).toBe(false); + }); + + it('should return false when dataset property is null or undefined', () => { + const findingWithUndefinedDataset = { + data_stream: { + dataset: undefined, + }, + } as CspFinding; + + expect(isNativeCspFinding(findingWithUndefinedDataset)).toBe(false); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/common/utils/is_native_csp_finding.ts b/x-pack/plugins/cloud_security_posture/public/common/utils/is_native_csp_finding.ts new file mode 100644 index 0000000000000..0cad6fc7d542f --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/common/utils/is_native_csp_finding.ts @@ -0,0 +1,14 @@ +/* + * 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 { CspFinding } from '@kbn/cloud-security-posture-common'; +import { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/csp_vulnerability_finding'; +import { CSP_MISCONFIGURATIONS_DATASET, CSP_VULN_DATASET } from './get_vendor_name'; + +export const isNativeCspFinding = (finding: CspFinding | CspVulnerabilityFinding) => + finding.data_stream?.dataset === CSP_MISCONFIGURATIONS_DATASET || + finding.data_stream?.dataset === CSP_VULN_DATASET; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/__mocks__/findings.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/__mocks__/findings.ts index 4693459c0985d..43b1c859a44f5 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/__mocks__/findings.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/__mocks__/findings.ts @@ -118,6 +118,9 @@ export const mockFindingsHit: CspFinding = { data_stream: { dataset: 'cloud_security_posture.findings', }, + observer: { + vendor: 'Elastic', + }, }; export const mockWizFinding = { @@ -183,6 +186,9 @@ export const mockWizFinding = { type: 'logs', dataset: 'wiz.cloud_configuration_finding', }, + observer: { + vendor: 'Wiz', + }, event: { agent_id_status: 'auth_metadata_missing', ingested: '2024-07-15T10:49:45Z', diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts index 10e79145cd02e..be08984c16dbe 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts @@ -135,6 +135,9 @@ export const generateCspFinding = ( data_stream: { dataset: 'cloud_security_posture.findings', }, + observer: { + vendor: 'Elastic', + }, }; }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx index 2a45528ef49d1..462652b4869de 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx @@ -37,10 +37,12 @@ import { css } from '@emotion/react'; import { euiThemeVars } from '@kbn/ui-theme'; import { CspEvaluationBadge } from '@kbn/cloud-security-posture'; import type { CspFinding } from '@kbn/cloud-security-posture-common'; +import { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/csp_vulnerability_finding'; +import { isNativeCspFinding } from '../../../common/utils/is_native_csp_finding'; import { CSP_MISCONFIGURATIONS_DATASET, - getDatasetDisplayName, -} from '../../../common/utils/get_dataset_display_name'; + getVendorName, +} from '../../../common/utils/get_vendor_name'; import { truthy } from '../../../../common/utils/helpers'; import { benchmarksNavigation } from '../../../common/navigation/constants'; import cisLogoIcon from '../../../assets/icons/cis_logo.svg'; @@ -200,13 +202,13 @@ const FindingsTab = ({ tab, finding }: { finding: CspFinding; tab: FindingsTab } } }; -const isNativeCspFinding = (finding: CspFinding) => - finding.data_stream.dataset === CSP_MISCONFIGURATIONS_DATASET; - -const MissingFieldsCallout = ({ finding }: { finding: CspFinding }) => { +export const MissingFieldsCallout = ({ + finding, +}: { + finding: CspFinding | CspVulnerabilityFinding; +}) => { const { euiTheme } = useEuiTheme(); - const datasetDisplayName = - getDatasetDisplayName(finding.data_stream.dataset) || finding.data_stream.dataset; + const vendor = getVendorName(finding); return ( { @@ -285,7 +287,7 @@ export const FindingsRuleFlyout = ({ {!isNativeCspFinding(finding) && ['overview', 'rule'].includes(tab.id) && ( -
+
)} diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/overview_tab.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/overview_tab.tsx index 5f54e34846b98..9ffa3ae8580db 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/overview_tab.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/overview_tab.tsx @@ -26,7 +26,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { isEmpty } from 'lodash'; import type { CspFinding } from '@kbn/cloud-security-posture-common'; import { useDataView } from '@kbn/cloud-security-posture/src/hooks/use_data_view'; -import { getDatasetDisplayName } from '../../../common/utils/get_dataset_display_name'; +import { getVendorName } from '../../../common/utils/get_vendor_name'; import { truthy } from '../../../../common/utils/helpers'; import { CSP_MOMENT_FORMAT } from '../../../common/constants'; import { INTERNAL_FEATURE_FLAGS } from '../../../../common/constants'; @@ -107,11 +107,10 @@ const getDetailsList = ( description: data.rule?.section ? data.rule?.section : EMPTY_VALUE, }, { - title: i18n.translate('xpack.csp.findings.findingsFlyout.overviewTab.sourceTitle', { - defaultMessage: 'Source', + title: i18n.translate('xpack.csp.findings.findingsFlyout.overviewTab.vendorTitle', { + defaultMessage: 'Vendor', }), - description: - getDatasetDisplayName(data.data_stream?.dataset) || data.data_stream?.dataset || EMPTY_VALUE, + description: getVendorName(data) || EMPTY_VALUE, }, { title: i18n.translate('xpack.csp.findings.findingsFlyout.overviewTab.dataViewTitle', { diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/rule_tab.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/rule_tab.tsx index 26007205f43fe..2dcca4932935c 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/rule_tab.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/rule_tab.tsx @@ -43,13 +43,15 @@ export const getRuleList = ( defaultMessage: 'Alerts', }), description: - ruleState === 'unmuted' && rule?.benchmark?.name ? ( - - ) : ( + ruleState === 'muted' ? ( + ) : rule?.benchmark?.name ? ( + + ) : ( + EMPTY_VALUE ), }, { diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts index 9472a7064a6a4..d9f20e3e712eb 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts @@ -126,6 +126,6 @@ export const defaultColumns: CloudSecurityDefaultColumn[] = [ { id: 'rule.benchmark.rule_number' }, { id: 'rule.name' }, { id: 'rule.section' }, - { id: 'data_stream.dataset' }, + { id: 'observer.vendor' }, { id: '@timestamp' }, ]; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/findings_table_field_labels.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/findings_table_field_labels.ts index 75ffaef8085e9..b1e6196aec739 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/findings_table_field_labels.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/findings_table_field_labels.ts @@ -35,9 +35,9 @@ export const findingsTableFieldLabels: Record = { 'xpack.csp.findings.findingsTable.findingsTableColumn.ruleSectionColumnLabel', { defaultMessage: 'Framework Section' } ), - 'data_stream.dataset': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.sourceColumnLabel', - { defaultMessage: 'Source' } + 'observer.vendor': i18n.translate( + 'xpack.csp.findings.findingsTable.findingsTableColumn.vendorColumnLabel', + { defaultMessage: 'Vendor' } ), '@timestamp': i18n.translate( 'xpack.csp.findings.findingsTable.findingsTableColumn.lastCheckedColumnLabel', diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx index b8bd387ad57af..25546d2e02cb2 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx @@ -18,7 +18,7 @@ import { uiMetricService, } from '@kbn/cloud-security-posture-common/utils/ui_metrics'; import { METRIC_TYPE } from '@kbn/analytics'; -import { getDatasetDisplayName } from '../../../common/utils/get_dataset_display_name'; +import { getVendorName } from '../../../common/utils/get_vendor_name'; import * as TEST_SUBJECTS from '../test_subjects'; import { FindingsDistributionBar } from '../layout/findings_distribution_bar'; import { ErrorCallout } from '../layout/error_callout'; @@ -68,11 +68,13 @@ const customCellRenderer = (rows: DataTableRecord[]) => ({ return ; }, - 'data_stream.dataset': ({ rowIndex }: EuiDataGridCellValueElementProps) => { + 'observer.vendor': ({ rowIndex }: EuiDataGridCellValueElementProps) => { const finding = getCspFinding(rows[rowIndex].raw._source); - const source = getDatasetDisplayName(finding?.data_stream?.dataset); + if (!finding) return <>{''}; - return <>{source || finding?.data_stream?.dataset || ''}; + const vendor = getVendorName(finding); + + return <>{vendor || ''}; }, '@timestamp': ({ rowIndex }: EuiDataGridCellValueElementProps) => { const finding = getCspFinding(rows[rowIndex].raw._source); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/findings/findings.tsx b/x-pack/plugins/cloud_security_posture/public/pages/findings/findings.tsx index 00837a3629893..6b1dc4dacdf68 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/findings/findings.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/findings/findings.tsx @@ -6,15 +6,20 @@ */ import React from 'react'; import useLocalStorage from 'react-use/lib/useLocalStorage'; -import { EuiSpacer, EuiTab, EuiTabs, EuiTitle } from '@elastic/eui'; +import { EuiSpacer, EuiTab, EuiTabs, EuiTitle, EuiCallOut, EuiButton } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { Redirect, useHistory, useLocation, matchPath } from 'react-router-dom'; import { Routes, Route } from '@kbn/shared-ux-router'; import { findingsNavigation } from '@kbn/cloud-security-posture'; import { useCspSetupStatusApi } from '@kbn/cloud-security-posture/src/hooks/use_csp_setup_status_api'; +import { i18n } from '@kbn/i18n'; +import { useAdd3PIntegrationRoute } from '../../common/api/use_wiz_integration_route'; import { Configurations } from '../configurations'; import { cloudPosturePages } from '../../common/navigation/constants'; -import { LOCAL_STORAGE_FINDINGS_LAST_SELECTED_TAB_KEY } from '../../common/constants'; +import { + LOCAL_STORAGE_3P_INTEGRATIONS_CALLOUT_KEY, + LOCAL_STORAGE_FINDINGS_LAST_SELECTED_TAB_KEY, +} from '../../common/constants'; import { VULNERABILITIES_INDEX_NAME, FINDINGS_INDEX_NAME } from '../../../common/constants'; import { getStatusForIndexName } from '../../../common/utils/helpers'; import { Vulnerabilities } from '../vulnerabilities'; @@ -59,7 +64,10 @@ const FindingsTabRedirecter = ({ lastTabSelected }: { lastTabSelected?: Findings export const Findings = () => { const history = useHistory(); const location = useLocation(); - + const wizAddIntegrationLink = useAdd3PIntegrationRoute('wiz'); + const [userHasDismissedCallout, setUserHasDismissedCallout] = useLocalStorage( + LOCAL_STORAGE_3P_INTEGRATIONS_CALLOUT_KEY + ); // restore the users most recent tab selection const [lastTabSelected, setLastTabSelected] = useLocalStorage( LOCAL_STORAGE_FINDINGS_LAST_SELECTED_TAB_KEY @@ -101,6 +109,26 @@ export const Findings = () => { + {!userHasDismissedCallout && ( + <> + setUserHasDismissedCallout(true)} + > + + + + + + + )} ({ {({ finding }) => } ), - 'data_stream.dataset': ({ rowIndex }: EuiDataGridCellValueElementProps) => ( + 'observer.vendor': ({ rowIndex }: EuiDataGridCellValueElementProps) => ( - {({ finding }) => <>{getDatasetDisplayName(finding.data_stream.dataset) || '-'}} + {({ finding }) => <>{getVendorName(finding) || '-'}} ), }); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_detection_rule_counter.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_detection_rule_counter.tsx index facb4817cec51..1c726a450655b 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_detection_rule_counter.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_detection_rule_counter.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { HttpSetup } from '@kbn/core/public'; import type { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest'; -import { CSP_VULN_DATASET } from '../../../common/utils/get_dataset_display_name'; +import { isNativeCspFinding } from '../../../common/utils/is_native_csp_finding'; import { DetectionRuleCounter } from '../../../components/detection_rule_counter'; import { createDetectionRuleFromVulnerabilityFinding } from '../utils/create_detection_rule_from_vulnerability'; @@ -19,11 +19,12 @@ const CNVM_RULE_TAG_OS = 'OS: Linux'; const getTags = (vulnerabilityRecord: CspVulnerabilityFinding) => { let tags = [vulnerabilityRecord.vulnerability.id]; + const vendor = vulnerabilityRecord.observer?.vendor || vulnerabilityRecord?.data_stream?.dataset; - if (vulnerabilityRecord?.data_stream?.dataset === CSP_VULN_DATASET) { + if (isNativeCspFinding(vulnerabilityRecord)) { tags = [CNVM_TAG, CNVM_RULE_TAG_DATA_SOURCE, CNVM_RULE_TAG_USE_CASE, CNVM_RULE_TAG_OS, ...tags]; - } else { - tags.push(vulnerabilityRecord?.data_stream?.dataset); + } else if (!!vendor) { + tags.push(vendor); } return tags; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx index 8f3f37390cfae..d22d1fd802862 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx @@ -72,7 +72,7 @@ describe('', () => { ); getByText(mockVulnerabilityHit.vulnerability.data_source!.ID); - getByText('Elastic CSP'); + getByText('Elastic'); getByText(moment(mockVulnerabilityHit.vulnerability.published_date).format('LL').toString()); getByText(mockVulnerabilityHit.vulnerability.description); getAllByText(mockVulnerabilityHit.vulnerability?.cvss?.nvd?.V3Vector as string); @@ -93,13 +93,24 @@ describe('', () => { ); const dataSource = getByTestId(DATA_SOURCE_VULNERABILITY_FLYOUT); - const publisedDate = getByTestId(PUBLISHED_DATE_VULNERABILITY_FLYOUT); + const publishedDate = getByTestId(PUBLISHED_DATE_VULNERABILITY_FLYOUT); const vulnerabilityScores = getByTestId(VULNERABILITY_SCORES_FLYOUT); expect(dataSource.textContent).toEqual(`Data Source${EMPTY_VALUE}`); - expect(publisedDate.textContent).toEqual(`Published Date${EMPTY_VALUE}`); + expect(publishedDate.textContent).toEqual(`Published Date${EMPTY_VALUE}`); expect(vulnerabilityScores.textContent).toEqual(`Vulnerability Scores${EMPTY_VALUE}`); }); + it('displays missing info callout when data source is not CSP', () => { + const { getByText } = render(); + getByText('Some fields not provided by Wiz'); + }); + + it('does not display missing info callout when data source is CSP', () => { + const { queryByText } = render(); + const missingInfoCallout = queryByText('Some fields not provided by Wiz'); + expect(missingInfoCallout).toBeNull(); + }); + it('show empty state for no fixes', () => { const { getByText } = render( diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx index 102fc272801ea..8c7e3341424d9 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx @@ -28,6 +28,7 @@ import { euiThemeVars } from '@kbn/ui-theme'; import { css } from '@emotion/react'; import { HttpSetup } from '@kbn/core-http-browser'; import type { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest'; +import { isNativeCspFinding } from '../../../common/utils/is_native_csp_finding'; import { TakeAction } from '../../../components/take_action'; import { truthy } from '../../../../common/utils/helpers'; import { CspInlineDescriptionList } from '../../../components/csp_inline_description_list'; @@ -40,6 +41,7 @@ import { } from '../test_subjects'; import { VulnerabilityTableTab } from './vulnerability_table_tab'; import { createDetectionRuleFromVulnerabilityFinding } from '../utils/create_detection_rule_from_vulnerability'; +import { MissingFieldsCallout } from '../../configurations/findings_flyout/findings_flyout'; const overviewTabId = 'vuln-flyout-overview-tab'; const tableTabId = 'vuln-flyout-table-tab'; @@ -232,6 +234,11 @@ export const VulnerabilityFindingFlyout = ({ isLoading={isLoading} contentAriaLabel={LOADING_ARIA_LABEL} > + {!isNativeCspFinding(vulnerabilityRecord) && selectedTabId === overviewTabId && ( +
+ +
+ )} {selectedTabContent} diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_overview_tab.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_overview_tab.tsx index b050b374d692a..d67649c508c13 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_overview_tab.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_overview_tab.tsx @@ -24,12 +24,11 @@ import { CspVulnerabilityFinding, } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest'; import { METRIC_TYPE } from '@kbn/analytics'; - import { VULNERABILITIES_FLYOUT_VISITS, uiMetricService, } from '@kbn/cloud-security-posture-common/utils/ui_metrics'; -import { getDatasetDisplayName } from '../../../common/utils/get_dataset_display_name'; +import { getVendorName } from '../../../common/utils/get_vendor_name'; import { CspFlyoutMarkdown } from '../../configurations/findings_flyout/findings_flyout'; import { NvdLogo } from '../../../assets/icons/nvd_logo_svg'; import { CVSScoreBadge } from '../../../components/vulnerability_badges'; @@ -287,11 +286,11 @@ export const VulnerabilityOverviewTab = ({ vulnerabilityRecord }: VulnerabilityT

- {getDatasetDisplayName(vulnerabilityRecord.data_stream?.dataset) || EMPTY_VALUE} + {getVendorName(vulnerabilityRecord) || EMPTY_VALUE}
diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_table_field_labels.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_table_field_labels.ts index cc8e0bd75c460..761bbfa9b7ccf 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_table_field_labels.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_table_field_labels.ts @@ -39,8 +39,8 @@ export const vulnerabilitiesTableFieldLabels: Record = { 'xpack.csp.vulnerabilityFindings.vulnerabilityFindingsTable.vulnerabilityFindingsTableColumn.packageFixedVersionColumnLabel', { defaultMessage: 'Fix Version' } ), - 'data_stream.dataset': i18n.translate( - 'xpack.csp.vulnerabilityFindings.vulnerabilityFindingsTable.vulnerabilityFindingsTableColumn.sourceColumnLabel', - { defaultMessage: 'Source' } + 'observer.vendor': i18n.translate( + 'xpack.csp.vulnerabilityFindings.vulnerabilityFindingsTable.vulnerabilityFindingsTableColumn.vendorColumnLabel', + { defaultMessage: 'Vendor' } ), } as const;