[Cloud Security] [Findings] [Vulnerabilities] [Alerts] - Create detection rule (#163545)

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Paulo Henrique 2023-08-14 17:23:00 -07:00 committed by GitHub
parent 365a8b93cf
commit 3045b1672c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 370 additions and 159 deletions

View file

@ -0,0 +1,114 @@
/*
* 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.
*/
// TODO: this needs to be defined in a versioned schema
import type { EcsEvent } from '@kbn/ecs';
import { VulnSeverity } from '../types';
export interface CspVulnerabilityFinding {
'@timestamp': string;
resource?: {
id: string;
name: string;
};
event: EcsEvent;
vulnerability: Vulnerability;
ecs: {
version: string;
};
host: {
os: {
name: string;
kernel: string;
codename: string;
type: string;
platform: string;
version: string;
family: string;
};
id: string;
name: string;
containerized: boolean;
ip: string[];
mac: string[];
hostname: string;
architecture: string;
};
agent: {
ephemeral_id: string;
id: string;
name: string;
type: string;
version: string;
};
cloud: {
image?: {
id: string;
};
provider?: string;
instance?: {
id: string;
};
machine?: {
type: string;
};
region: string;
availability_zone?: string;
service?: {
name: string;
};
account?: {
id: string;
};
};
cloudbeat: {
version: string;
commit_sha: string;
commit_time: string;
};
}
export interface Vulnerability {
published_date: string;
score: {
version: string;
base: number;
};
cwe: string[];
id: string;
title: string;
reference: string;
severity: VulnSeverity;
cvss: {
nvd: VectorScoreBase;
redhat?: VectorScoreBase;
ghsa?: VectorScoreBase;
};
data_source: {
ID: string;
Name: string;
URL: string;
};
enumeration: string;
description: string;
classification: string;
scanner: {
vendor: string;
};
package: {
version: string;
name: string;
fixed_version?: string;
};
}
export interface VectorScoreBase {
V3Score?: number;
V3Vector?: string;
V2Score?: number;
V2Vector?: string;
}

View file

@ -7,3 +7,4 @@
export * from './csp_rule_template_metadata';
export * from './csp_rule_template';
export * from './csp_vulnerability_finding';

View file

@ -38,6 +38,7 @@ interface RuleCreateProps {
name: string;
description: string;
tags: string[];
max_signals: number;
}
export interface RuleResponse extends RuleCreateProps {

View file

@ -0,0 +1,21 @@
/*
* 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 type { CspVulnerabilityFinding } from '../../../common/schemas';
export const getVulnerabilityReferenceUrl = (
finding: CspVulnerabilityFinding
): string | undefined => {
const nvdDomain = 'https://nvd';
const nvdWebsite = `${nvdDomain}.nist.gov/vuln/detail/${finding?.vulnerability?.id}`;
const vulnerabilityReference = finding.vulnerability?.cvss?.nvd
? nvdWebsite
: finding.vulnerability?.reference;
return vulnerabilityReference;
};

View file

@ -7,7 +7,10 @@
import { HttpSetup } from '@kbn/core/public';
import type { CspFinding } from '../../../../common/schemas/csp_finding';
import { LATEST_FINDINGS_INDEX_DEFAULT_NS } from '../../../../common/constants';
import {
FINDINGS_INDEX_PATTERN,
LATEST_FINDINGS_RETENTION_POLICY,
} from '../../../../common/constants';
import { createDetectionRule } from '../../../common/api/create_detection_rule';
const DEFAULT_RULE_RISK_SCORE = 0;
@ -15,6 +18,7 @@ const DEFAULT_RULE_SEVERITY = 'low';
const DEFAULT_RULE_ENABLED = true;
const DEFAULT_RULE_AUTHOR = 'Elastic';
const DEFAULT_RULE_LICENSE = 'Elastic License v2';
const DEFAULT_MAX_ALERTS_PER_RULE = 100;
const ALERT_SUPPRESSION_FIELD = 'resource.id';
const ALERT_TIMESTAMP_FIELD = 'event.ingested';
@ -40,23 +44,36 @@ const convertReferencesLinksToArray = (input: string | undefined) => {
return matches.map((link) => link.replace(/^\d+\. /, '').replace(/\n/g, ''));
};
const STATIC_RULE_TAGS = ['Elastic', 'Cloud Security'];
const CSP_RULE_TAG = 'Cloud Security';
const CSP_RULE_TAG_USE_CASE = 'Use Case: Configuration Audit';
const CSP_RULE_TAG_DATA_SOURCE_PREFIX = 'Data Source: ';
const generateMisconfigurationsTags = (finding: CspFinding) => {
const STATIC_RULE_TAGS = [CSP_RULE_TAG, CSP_RULE_TAG_USE_CASE];
const generateFindingsTags = (finding: CspFinding) => {
return [STATIC_RULE_TAGS]
.concat(finding.rule.tags)
.concat(
finding.rule.benchmark.posture_type ? [finding.rule.benchmark.posture_type.toUpperCase()] : []
finding.rule.benchmark.posture_type
? [
finding.rule.benchmark.posture_type.toUpperCase(),
`${CSP_RULE_TAG_DATA_SOURCE_PREFIX}${finding.rule.benchmark.posture_type.toUpperCase()}`,
]
: []
)
.concat(
finding.rule.benchmark.posture_type === 'cspm' ? ['Domain: Cloud'] : ['Domain: Container']
)
.flat();
};
const generateMisconfigurationsRuleQuery = (finding: CspFinding) => {
return `
rule.benchmark.rule_number: "${finding.rule.benchmark.rule_number}"
const generateFindingsRuleQuery = (finding: CspFinding) => {
const currentTimestamp = new Date().toISOString();
return `rule.benchmark.rule_number: "${finding.rule.benchmark.rule_number}"
AND rule.benchmark.id: "${finding.rule.benchmark.id}"
AND result.evaluation: "failed"
`;
AND event.ingested >= "${currentTimestamp}"`;
};
/*
@ -78,8 +95,9 @@ export const createDetectionRuleFromFinding = async (http: HttpSetup, finding: C
severity_mapping: [],
threat: [],
interval: '1h',
from: 'now-7200s',
from: `now-${LATEST_FINDINGS_RETENTION_POLICY}`,
to: 'now',
max_signals: DEFAULT_MAX_ALERTS_PER_RULE,
timestamp_override: ALERT_TIMESTAMP_FIELD,
timestamp_override_fallback_disabled: false,
actions: [],
@ -88,12 +106,12 @@ export const createDetectionRuleFromFinding = async (http: HttpSetup, finding: C
group_by: [ALERT_SUPPRESSION_FIELD],
missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.Suppress,
},
index: [LATEST_FINDINGS_INDEX_DEFAULT_NS],
query: generateMisconfigurationsRuleQuery(finding),
index: [FINDINGS_INDEX_PATTERN],
query: generateFindingsRuleQuery(finding),
references: convertReferencesLinksToArray(finding.rule.references),
name: finding.rule.name,
description: finding.rule.rationale,
tags: generateMisconfigurationsTags(finding),
tags: generateFindingsTags(finding),
},
});
};

View file

@ -5,9 +5,9 @@
* 2.0.
*/
import { VulnerabilityRecord } from '../types';
import { CspVulnerabilityFinding } from '../../../../common/schemas';
export const mockVulnerabilityHit: VulnerabilityRecord = {
export const mockVulnerabilityHit: CspVulnerabilityFinding = {
'@timestamp': '2023-03-30T10:27:35.013Z',
resource: { name: '634yfsdg2.dkr.ecr.eu-central-1.amazon.stage', id: 'ami_12328' },
agent: {

View file

@ -15,12 +15,12 @@ import {
AggregationsStringRareTermsBucketKeys,
Sort,
} from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { CspVulnerabilityFinding } from '../../../../common/schemas';
import { LATEST_VULNERABILITIES_INDEX_PATTERN } from '../../../../common/constants';
import { getSafeVulnerabilitiesQueryFilter } from '../../../../common/utils/get_safe_vulnerabilities_query_filter';
import { useKibana } from '../../../common/hooks/use_kibana';
import { showErrorToast } from '../../../common/utils/show_error_toast';
import { FindingsBaseEsQuery } from '../../../common/types';
import { VulnerabilityRecord } from '../types';
type LatestFindingsRequest = IKibanaSearchRequest<SearchRequest>;
type LatestFindingsResponse = IKibanaSearchResponse<SearchResponse<any, FindingsAggs>>;
@ -60,7 +60,7 @@ export const useLatestVulnerabilities = (options: VulnerabilitiesQuery) => {
);
return {
page: hits.hits.map((hit) => hit._source!) as VulnerabilityRecord[],
page: hits.hits.map((hit) => hit._source!) as CspVulnerabilityFinding[],
total: number.is(hits.total) ? hits.total : 0,
};
},

View file

@ -5,119 +5,7 @@
* 2.0.
*/
import { VulnSeverity } from '../../../common/types';
export interface VulnerabilityRecord {
'@timestamp': string;
resource?: {
id: string;
name: string;
};
event: {
type: string[];
category: string[];
created: string;
id: string;
kind: string;
sequence: number;
outcome: string;
};
vulnerability: Vulnerability;
ecs: {
version: string;
};
host: {
os: {
name: string;
kernel: string;
codename: string;
type: string;
platform: string;
version: string;
family: string;
};
id: string;
name: string;
containerized: boolean;
ip: string[];
mac: string[];
hostname: string;
architecture: string;
};
agent: {
ephemeral_id: string;
id: string;
name: string;
type: string;
version: string;
};
cloud: {
image?: {
id: string;
};
provider?: string;
instance?: {
id: string;
};
machine?: {
type: string;
};
region: string;
availability_zone?: string;
service?: {
name: string;
};
account?: {
id: string;
};
};
cloudbeat: {
version: string;
commit_sha: string;
commit_time: string;
};
}
export interface Vulnerability {
published_date: string;
score: {
version: string;
base: number;
};
cwe: string[];
id: string;
title: string;
reference: string;
severity: VulnSeverity;
cvss: {
nvd: VectorScoreBase;
redhat?: VectorScoreBase;
ghsa?: VectorScoreBase;
};
data_source: {
ID: string;
Name: string;
URL: string;
};
enumeration: string;
description: string;
classification: string;
scanner: {
vendor: string;
};
package: {
version: string;
name: string;
fixed_version?: string;
};
}
export interface VectorScoreBase {
V3Score?: number;
V3Vector?: string;
V2Score?: number;
V2Vector?: string;
}
import { VectorScoreBase, CspVulnerabilityFinding } from '../../../common/schemas';
export type Vendor = 'NVD' | 'Red Hat' | 'GHSA';
@ -133,7 +21,7 @@ export interface Vector {
}
export interface VulnerabilitiesQueryData {
page: VulnerabilityRecord[];
page: CspVulnerabilityFinding[];
total: number;
}

View file

@ -0,0 +1,150 @@
/*
* 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 { HttpSetup } from '@kbn/core/public';
import { i18n } from '@kbn/i18n';
import { getVulnerabilityReferenceUrl } from '../../../common/utils/get_vulnerability_reference_url';
import type { CspVulnerabilityFinding } from '../../../../common/schemas';
import {
LATEST_VULNERABILITIES_RETENTION_POLICY,
VULNERABILITIES_INDEX_PATTERN,
VULNERABILITIES_SEVERITY,
} from '../../../../common/constants';
import { createDetectionRule } from '../../../common/api/create_detection_rule';
const DEFAULT_RULE_RISK_SCORE = 0;
const DEFAULT_RULE_SEVERITY = 'low';
const DEFAULT_RULE_ENABLED = true;
const DEFAULT_RULE_AUTHOR = 'Elastic';
const DEFAULT_RULE_LICENSE = 'Elastic License v2';
const DEFAULT_MAX_ALERTS_PER_RULE = 100;
const ALERT_SUPPRESSION_FIELD = 'resource.id';
const ALERT_TIMESTAMP_FIELD = 'event.ingested';
const ALERT_SEVERITY_MAP_FIELD = 'vulnerability.severity';
enum RuleSeverityMapping {
Low = 'low',
Medium = 'medium',
High = 'high',
Critical = 'critical',
}
enum AlertSuppressionMissingFieldsStrategy {
// per each document a separate alert will be created
DoNotSuppress = 'doNotSuppress',
// only one alert will be created per suppress by bucket
Suppress = 'suppress',
}
const CSP_RULE_TAG = 'Cloud Security';
const CNVM_RULE_TAG = 'CNVM';
const CNVM_RULE_TAG_DATA_SOURCE = 'Data Source: Cloud Native Vulnerability Management';
const CNVM_RULE_TAG_USE_CASE = 'Use Case: Vulnerability';
const CNVM_RULE_TAG_OS = 'OS: Linux';
const STATIC_RULE_TAGS = [
CSP_RULE_TAG,
CNVM_RULE_TAG,
CNVM_RULE_TAG_DATA_SOURCE,
CNVM_RULE_TAG_USE_CASE,
CNVM_RULE_TAG_OS,
];
const generateVulnerabilitiesTags = (finding: CspVulnerabilityFinding) => {
return [...STATIC_RULE_TAGS, finding.vulnerability.id];
};
const getVulnerabilityRuleName = (finding: CspVulnerabilityFinding) => {
return i18n.translate('xpack.csp.vulnerabilities.detectionRuleNamePrefix', {
defaultMessage: 'Vulnerability: {vulnerabilityId}',
values: {
vulnerabilityId: finding.vulnerability.id,
},
});
};
const generateVulnerabilitiesRuleQuery = (finding: CspVulnerabilityFinding) => {
const currentTimestamp = new Date().toISOString();
return `vulnerability.id: "${finding.vulnerability.id}" AND event.ingested >= "${currentTimestamp}"`;
};
/*
* Creates a detection rule from a CspVulnerabilityFinding
*/
export const createDetectionRuleFromVulnerabilityFinding = async (
http: HttpSetup,
finding: CspVulnerabilityFinding
) => {
const referenceUrl = getVulnerabilityReferenceUrl(finding);
return await createDetectionRule({
http,
rule: {
type: 'query',
language: 'kuery',
license: DEFAULT_RULE_LICENSE,
author: [DEFAULT_RULE_AUTHOR],
filters: [],
false_positives: [],
risk_score: DEFAULT_RULE_RISK_SCORE,
risk_score_mapping: [],
severity: DEFAULT_RULE_SEVERITY,
severity_mapping: [
{
field: ALERT_SEVERITY_MAP_FIELD,
value: VULNERABILITIES_SEVERITY.LOW,
operator: 'equals',
severity: RuleSeverityMapping.Low,
},
{
field: ALERT_SEVERITY_MAP_FIELD,
value: VULNERABILITIES_SEVERITY.MEDIUM,
operator: 'equals',
severity: RuleSeverityMapping.Medium,
},
{
field: ALERT_SEVERITY_MAP_FIELD,
value: VULNERABILITIES_SEVERITY.HIGH,
operator: 'equals',
severity: RuleSeverityMapping.High,
},
{
field: ALERT_SEVERITY_MAP_FIELD,
value: VULNERABILITIES_SEVERITY.CRITICAL,
operator: 'equals',
severity: RuleSeverityMapping.Critical,
},
{
field: ALERT_SEVERITY_MAP_FIELD,
value: VULNERABILITIES_SEVERITY.UNKNOWN,
operator: 'equals',
severity: RuleSeverityMapping.Low,
},
],
threat: [],
interval: '1h',
from: `now-${LATEST_VULNERABILITIES_RETENTION_POLICY}`,
to: 'now',
max_signals: DEFAULT_MAX_ALERTS_PER_RULE,
timestamp_override: ALERT_TIMESTAMP_FIELD,
timestamp_override_fallback_disabled: false,
actions: [],
enabled: DEFAULT_RULE_ENABLED,
alert_suppression: {
group_by: [ALERT_SUPPRESSION_FIELD],
missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.Suppress,
},
index: [VULNERABILITIES_INDEX_PATTERN],
query: generateVulnerabilitiesRuleQuery(finding),
references: referenceUrl ? [referenceUrl] : [],
name: getVulnerabilityRuleName(finding),
description: finding.vulnerability.description,
tags: generateVulnerabilitiesTags(finding),
},
});
};

View file

@ -5,7 +5,8 @@
* 2.0.
*/
import { VectorScoreBase, Vector } from '../types';
import { VectorScoreBase } from '../../../../common/schemas';
import { Vector } from '../types';
export const getVectorScoreList = (vectorBaseScore: VectorScoreBase) => {
const result: Vector[] = [];

View file

@ -7,11 +7,13 @@
import React from 'react';
import { EuiDataGridColumn, EuiDataGridColumnCellAction, EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { VulnerabilityRecord } from '../types';
import { CspVulnerabilityFinding } from '../../../../common/schemas';
import { getFilters } from './get_filters';
import { FILTER_IN, FILTER_OUT } from '../translations';
export const getVulnerabilitiesGridCellActions = <T extends Array<Partial<VulnerabilityRecord>>>({
export const getVulnerabilitiesGridCellActions = <
T extends Array<Partial<CspVulnerabilityFinding>>
>({
data,
columns,
columnGridFn,

View file

@ -22,7 +22,7 @@ import { Routes, Route } from '@kbn/shared-ux-router';
import { LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY } from '../../common/constants';
import { useCloudPostureTable } from '../../common/hooks/use_cloud_posture_table';
import { useLatestVulnerabilities } from './hooks/use_latest_vulnerabilities';
import type { VulnerabilityRecord, VulnerabilitiesQueryData } from './types';
import type { VulnerabilitiesQueryData } from './types';
import { LATEST_VULNERABILITIES_INDEX_PATTERN } from '../../../common/constants';
import { ErrorCallout } from '../configurations/layout/error_callout';
import { FindingsSearchBar } from '../configurations/layout/findings_search_bar';
@ -160,9 +160,9 @@ const VulnerabilitiesDataGrid = ({
});
const onOpenFlyout = useCallback(
(vulnerabilityRow: VulnerabilityRecord) => {
(vulnerabilityRow: VulnerabilitiesQueryData['page'][number]) => {
const vulnerabilityIndex = data?.page.findIndex(
(vulnerabilityRecord: VulnerabilityRecord) =>
(vulnerabilityRecord: VulnerabilitiesQueryData['page'][number]) =>
vulnerabilityRecord.vulnerability?.id === vulnerabilityRow.vulnerability?.id &&
vulnerabilityRecord.resource?.id === vulnerabilityRow.resource?.id &&
vulnerabilityRecord.vulnerability.package.name ===
@ -204,7 +204,7 @@ const VulnerabilitiesDataGrid = ({
}): React.ReactElement | null => {
const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex;
const vulnerabilityRow = data?.page[rowIndexFromPage] as VulnerabilityRecord;
const vulnerabilityRow = data?.page[rowIndexFromPage];
useEffect(() => {
if (selectedVulnerabilityIndex === rowIndex) {

View file

@ -23,7 +23,7 @@ import type { BoolQuery } from '@kbn/es-query';
import { LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY } from '../../../../common/constants';
import { useCloudPostureTable } from '../../../../common/hooks/use_cloud_posture_table';
import { useLatestVulnerabilities } from '../../hooks/use_latest_vulnerabilities';
import type { VulnerabilityRecord, VulnerabilitiesQueryData } from '../../types';
import type { VulnerabilitiesQueryData } from '../../types';
import { ErrorCallout } from '../../../configurations/layout/error_callout';
import { FindingsSearchBar } from '../../../configurations/layout/findings_search_bar';
import { CVSScoreBadge, SeverityStatusBadge } from '../../../../components/vulnerability_badges';
@ -119,9 +119,9 @@ const ResourceVulnerabilitiesDataGrid = ({
};
const onOpenFlyout = useCallback(
(vulnerabilityRow: VulnerabilityRecord) => {
(vulnerabilityRow: VulnerabilitiesQueryData['page'][number]) => {
const vulnerabilityIndex = data?.page.findIndex(
(vulnerabilityRecord: VulnerabilityRecord) =>
(vulnerabilityRecord: VulnerabilitiesQueryData['page'][number]) =>
vulnerabilityRecord.vulnerability?.id === vulnerabilityRow.vulnerability?.id &&
vulnerabilityRecord.resource?.id === vulnerabilityRow.resource?.id &&
vulnerabilityRecord.vulnerability.package.name ===
@ -169,7 +169,7 @@ const ResourceVulnerabilitiesDataGrid = ({
}): React.ReactElement | null => {
const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex;
const vulnerabilityRow = data?.page[rowIndexFromPage] as VulnerabilityRecord;
const vulnerabilityRow = data?.page[rowIndexFromPage];
useEffect(() => {
if (selectedVulnerabilityIndex === rowIndex) {

View file

@ -19,30 +19,35 @@ import {
EuiSkeletonText,
EuiTab,
EuiTabs,
EuiText,
EuiTitle,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { euiThemeVars } from '@kbn/ui-theme';
import { css } from '@emotion/react';
import { HttpSetup } from '@kbn/core-http-browser';
import { TakeAction } from '../../../components/take_action';
import { getVulnerabilityReferenceUrl } from '../../../common/utils/get_vulnerability_reference_url';
import { truthy } from '../../../../common/utils/helpers';
import { CspInlineDescriptionList } from '../../../components/csp_inline_description_list';
import { VulnerabilityOverviewTab } from './vulnerability_overview_tab';
import { VulnerabilityJsonTab } from './vulnerability_json_tab';
import { SeverityStatusBadge } from '../../../components/vulnerability_badges';
import { VulnerabilityRecord } from '../types';
import type { CspVulnerabilityFinding } from '../../../../common/schemas';
import {
FINDINGS_VULNERABILITY_FLYOUT_DESCRIPTION_LIST,
TAB_ID_VULNERABILITY_FLYOUT,
} from '../test_subjects';
import { VulnerabilityTableTab } from './vulnerability_table_tab';
import { createDetectionRuleFromVulnerabilityFinding } from '../utils/create_detection_rule_from_vulnerability';
const overviewTabId = 'vuln-flyout-overview-tab';
const tableTabId = 'vuln-flyout-table-tab';
const jsonTabId = 'vuln-flyout-json-tab';
const getFlyoutDescriptionList = (
vulnerabilityRecord: VulnerabilityRecord
vulnerabilityRecord: CspVulnerabilityFinding
): EuiDescriptionListProps['listItems'] =>
[
vulnerabilityRecord.resource?.name && {
@ -80,7 +85,7 @@ export const VulnerabilityFindingFlyout = ({
onPaginate: (pageIndex: number) => void;
totalVulnerabilitiesCount: number;
flyoutIndex?: number;
vulnerabilityRecord: VulnerabilityRecord;
vulnerabilityRecord: CspVulnerabilityFinding;
isLoading: boolean;
}) => {
const [selectedTabId, setSelectedTabId] = useState(overviewTabId);
@ -140,16 +145,17 @@ export const VulnerabilityFindingFlyout = ({
() => tabs.find((obj) => obj.id === selectedTabId)?.content,
[selectedTabId, tabs]
);
const nvdDomain = 'https://nvd';
const nvdWebsite = `${nvdDomain}.nist.gov/vuln/detail/${vulnerabilityRecord?.vulnerability?.id}`;
const vulnerabilityReference = vulnerability?.cvss?.nvd ? nvdWebsite : vulnerability?.reference;
const LOADING_ARIA_LABEL = i18n.translate(
'xpack.csp.vulnerabilities.vulnerabilityFindingFlyout.loadingAriaLabel',
{ defaultMessage: 'Loading' }
);
const vulnerabilityReference = getVulnerabilityReferenceUrl(vulnerabilityRecord);
const createVulnerabilityRuleFn = async (http: HttpSetup) =>
await createDetectionRuleFromVulnerabilityFinding(http, vulnerabilityRecord);
return (
<EuiFlyout onClose={closeFlyout}>
<EuiFlyoutHeader>
@ -183,9 +189,13 @@ export const VulnerabilityFindingFlyout = ({
line-height: 32px;
`}
>
<EuiLink target={'_blank'} href={vulnerabilityReference}>
{vulnerability?.id}
</EuiLink>
{vulnerabilityReference ? (
<EuiLink target="_blank" href={vulnerabilityReference}>
{vulnerability?.id}
</EuiLink>
) : (
<EuiText>{vulnerability?.id}</EuiText>
)}
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem>
@ -220,7 +230,7 @@ export const VulnerabilityFindingFlyout = ({
</EuiSkeletonText>
</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiFlexGroup gutterSize="none" justifyContent="flexEnd">
<EuiFlexGroup gutterSize="none" alignItems="center" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiPagination
pageCount={totalVulnerabilitiesCount}
@ -229,6 +239,9 @@ export const VulnerabilityFindingFlyout = ({
compressed
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<TakeAction createRuleFn={createVulnerabilityRuleFn} />
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutFooter>
</EuiFlyout>

View file

@ -8,10 +8,10 @@
import { CodeEditor } from '@kbn/kibana-react-plugin/public';
import React from 'react';
import { XJsonLang } from '@kbn/monaco';
import { VulnerabilityRecord } from '../types';
import { CspVulnerabilityFinding } from '../../../../common/schemas';
import { JSON_TAB_VULNERABILITY_FLYOUT } from '../test_subjects';
interface VulnerabilityJsonTabProps {
vulnerabilityRecord: VulnerabilityRecord;
vulnerabilityRecord: CspVulnerabilityFinding;
}
export const VulnerabilityJsonTab = ({ vulnerabilityRecord }: VulnerabilityJsonTabProps) => {
const offsetTopHeight = 188;

View file

@ -19,10 +19,11 @@ import moment from 'moment';
import React from 'react';
import { euiThemeVars } from '@kbn/ui-theme';
import { i18n } from '@kbn/i18n';
import { VectorScoreBase, Vulnerability } from '../../../../common/schemas';
import { CspFlyoutMarkdown } from '../../configurations/findings_flyout/findings_flyout';
import { NvdLogo } from '../../../assets/icons/nvd_logo_svg';
import { CVSScoreBadge } from '../../../components/vulnerability_badges';
import { CVSScoreProps, VectorScoreBase, Vendor, Vulnerability } from '../types';
import { CVSScoreProps, Vendor } from '../types';
import { getVectorScoreList } from '../utils/get_vector_score_list';
import { OVERVIEW_TAB_VULNERABILITY_FLYOUT } from '../test_subjects';
import redhatLogo from '../../../assets/icons/redhat_logo.svg';

View file

@ -15,7 +15,7 @@ import {
import React from 'react';
import { getFlattenedObject } from '@kbn/std';
import { i18n } from '@kbn/i18n';
import { VulnerabilityRecord } from '../types';
import { CspVulnerabilityFinding } from '../../../../common/schemas';
interface FlattenedItem {
key: string; // flattened dot notation object path for Vulnerability;
@ -74,13 +74,13 @@ const columns: EuiInMemoryTableProps<FlattenedItem>['columns'] = [
},
];
const getFlattenedItems = (vulnerabilityRecord: VulnerabilityRecord) =>
const getFlattenedItems = (vulnerabilityRecord: CspVulnerabilityFinding) =>
Object.entries(getFlattenedObject(vulnerabilityRecord)).map(([key, value]) => ({ key, value }));
export const VulnerabilityTableTab = ({
vulnerabilityRecord,
}: {
vulnerabilityRecord: VulnerabilityRecord;
vulnerabilityRecord: CspVulnerabilityFinding;
}) => (
<EuiInMemoryTable
items={getFlattenedItems(vulnerabilityRecord)}

View file

@ -48,7 +48,8 @@
"@kbn/shared-ux-router",
"@kbn/core-saved-objects-server",
"@kbn/share-plugin",
"@kbn/core-http-server"
"@kbn/core-http-server",
"@kbn/core-http-browser"
],
"exclude": [
"target/**/*",