Skip to content

Commit

Permalink
[Cloud Security] 3P integrations callouts (elastic#194362)
Browse files Browse the repository at this point in the history
  • Loading branch information
JordanSh authored and tiansivive committed Oct 7, 2024
1 parent 9313696 commit 359a564
Show file tree
Hide file tree
Showing 26 changed files with 277 additions and 100 deletions.
1 change: 1 addition & 0 deletions x-pack/packages/kbn-cloud-security-posture-common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -75,7 +75,8 @@ export interface CspVulnerabilityFinding {
name?: string;
fixed_version?: string;
};
data_stream: { dataset: string };
data_stream: EcsDataStream;
observer: EcsObserver;
}

export interface Vulnerability {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -19,6 +19,7 @@ export interface CspFinding {
host: CspFindingHost;
event: EcsEvent;
data_stream: EcsDataStream;
observer: EcsObserver;
agent: CspFindingAgent;
ecs: {
version: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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',
Expand All @@ -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,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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';
};
Original file line number Diff line number Diff line change
@@ -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);
});
});
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ export const mockFindingsHit: CspFinding = {
data_stream: {
dataset: 'cloud_security_posture.findings',
},
observer: {
vendor: 'Elastic',
},
};

export const mockWizFinding = {
Expand Down Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ export const generateCspFinding = (
data_stream: {
dataset: 'cloud_security_posture.findings',
},
observer: {
vendor: 'Elastic',
},
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 (
<EuiCallOut
Expand All @@ -220,9 +222,9 @@ const MissingFieldsCallout = ({ finding }: { finding: CspFinding }) => {
<span style={{ color: euiTheme.colors.text }}>
<FormattedMessage
id="xpack.csp.findings.findingsFlyout.calloutTitle"
defaultMessage="Some fields not provided by {datasource}"
defaultMessage="Some fields not provided by {vendor}"
values={{
datasource: datasetDisplayName || 'the data source',
vendor: vendor || 'the vendor',
}}
/>
</span>
Expand Down Expand Up @@ -285,7 +287,7 @@ export const FindingsRuleFlyout = ({
</EuiFlyoutHeader>
<EuiFlyoutBody key={tab.id}>
{!isNativeCspFinding(finding) && ['overview', 'rule'].includes(tab.id) && (
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: euiThemeVars.euiSize }}>
<MissingFieldsCallout finding={finding} />
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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', {
Expand Down
Loading

0 comments on commit 359a564

Please sign in to comment.