Skip to content

Commit

Permalink
[Cloud Posture] Vul mgmt flyout details panel (#154873)
Browse files Browse the repository at this point in the history
## Summary

Summarize your PR. If it involves visual changes include a screenshot or
gif.

<img width="1695" alt="Screen Shot 2023-04-12 at 5 04 30 PM"
src="https://user-images.githubusercontent.com/17135495/231596052-d47d0e7a-7abb-4aa1-a022-0fd1b1def981.png">
<img width="1656" alt="Screen Shot 2023-04-12 at 5 30 55 PM"
src="https://user-images.githubusercontent.com/17135495/231596060-89ea7d40-8727-4dab-a3ba-c57cf83ad0cc.png">
<img width="1659" alt="Screen Shot 2023-04-12 at 5 31 09 PM"
src="https://user-images.githubusercontent.com/17135495/231596067-839c0c1f-84a6-42b5-9683-77c70594af65.png">

Flyou details Feature includes:

Results are fetched from the
logs-cloud_security_posture.vulnerabilities-default index.
A Flyout opens when clicking the Expand Icon in the Vulnerabilities
table.
The Flyout has two tabs: Overview and JSON.
The Overview tab consists of four sections: CVSS, Data source, Publish
date, Description, Fixes, and Vulnerability Scores

TODO
Add pagination in follow up pr
Add unit tests
  • Loading branch information
Omolola-Akinleye authored Apr 17, 2023
1 parent d213107 commit eb6bfd8
Show file tree
Hide file tree
Showing 7 changed files with 616 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { EuiBadge, EuiIcon, EuiTextColor, useEuiFontSize } from '@elastic/eui';
import { EuiBadge, EuiIcon, EuiTextColor } from '@elastic/eui';
import React from 'react';
import { css } from '@emotion/react';
import { float } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
Expand All @@ -21,10 +21,6 @@ interface SeverityStatusBadgeProps {
score: float;
}

interface ExploitsStatusBadgeProps {
totalExploits: number;
}

export const CVSScoreBadge = ({ score, version }: CVSScoreBadgeProps) => {
const color = getCvsScoreColor(score);
const versionDisplay = version ? `v${version.split('.')[0]}` : null;
Expand Down Expand Up @@ -60,28 +56,15 @@ export const SeverityStatusBadge = ({ score, status }: SeverityStatusBadgeProps)
const color = getCvsScoreColor(score);

return (
<>
<EuiIcon type="dot" color={color} />
{status}
</>
);
};

export const ExploitsStatusBadge = ({ totalExploits }: ExploitsStatusBadgeProps) => {
const xxsFontSize = useEuiFontSize('xxs').fontSize;

return (
<EuiBadge
color={'hollow'}
iconType="bug"
<div
css={css`
.euiBadge__text {
font-weight: 400;
font-size: ${xxsFontSize};
}
display: flex;
flex-direction: row;
align-items: center;
`}
>
{totalExploits}
</EuiBadge>
<EuiIcon type="dot" color={color} />
{status}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,48 +20,7 @@ export interface VulnerabilityRecord {
sequence: number;
outcome: string;
};
vulnerability: {
score: {
version: string;
impact: number;
base: number;
};
cwe: string[];
id: string;
title: string;
reference: string;
severity: string;
cvss: {
nvd: {
V3Vector: string;
V3Score: number;
};
redhat?: {
V3Vector: string;
V3Score: number;
};
ghsa?: {
V3Vector: string;
V3Score: number;
};
};
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;
};
};
vulnerability: Vulnerability;
ecs: {
version: string;
};
Expand Down Expand Up @@ -116,3 +75,58 @@ export interface VulnerabilityRecord {
commit_time: string;
};
}

export interface Vulnerability {
published_at: string;
score: {
version: string;
impact: number;
base: number;
};
cwe: string[];
id: string;
title: string;
reference: string;
severity: string;
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;
}

export type Vendor = 'NVD' | 'Red Hat' | 'GHSA';

export interface CVSScoreProps {
vectorBaseScore: VectorScoreBase;
vendor: string;
}

export interface Vector {
version: string;
vector: string;
score: number | undefined;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import { EuiDataGridColumn } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { VectorScoreBase, Vector } from './types';

export const vulnerabilitiesColumns = {
actions: 'actions',
Expand Down Expand Up @@ -85,3 +86,29 @@ export const getVulnerabilitiesColumnsGrid = (): EuiDataGridColumn[] => {
},
];
};

export const getVectorScoreList = (vectorBaseScore: VectorScoreBase) => {
const result: Vector[] = [];
const v2Vector = vectorBaseScore?.V2Vector;
const v2Score = vectorBaseScore?.V2Score;
const v3Vector = vectorBaseScore?.V3Vector;
const v3Score = vectorBaseScore?.V3Score;

if (v2Vector) {
result.push({
version: '2.0',
vector: v2Vector,
score: v2Score,
});
}

if (v3Vector) {
result.push({
version: '2.0',
vector: v3Vector,
score: v3Score,
});
}

return result;
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import { css } from '@emotion/react';
import { FormattedMessage } from '@kbn/i18n-react';
import { DataView } from '@kbn/data-views-plugin/common';
import React, { useMemo } from 'react';
import React, { useMemo, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY } from '../../common/constants';
import { useCloudPostureTable } from '../../common/hooks/use_cloud_posture_table';
Expand All @@ -29,6 +29,7 @@ import { ErrorCallout } from '../configurations/layout/error_callout';
import { FindingsSearchBar } from '../configurations/layout/findings_search_bar';
import { useFilteredDataView } from '../../common/api/use_filtered_data_view';
import { CVSScoreBadge, SeverityStatusBadge } from '../../components/vulnerability_badges';
import { VulnerabilityFindingFlyout } from './vulnerabilities_finding_flyout/vulnerability_finding_flyout';
import { NoVulnerabilitiesStates } from '../../components/no_vulnerabilities_states';
import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api';

Expand Down Expand Up @@ -79,6 +80,21 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => {
enabled: !queryError,
});

const [isVulnerabilityDetailFlyoutVisible, setIsVulnerabilityDetailFlyoutVisible] =
useState(false);

const [vulnerability, setVulnerability] = useState<VulnerabilityRecord>();

const showFlyout = (vulnerabilityRecord: VulnerabilityRecord) => {
setIsVulnerabilityDetailFlyoutVisible(true);
setVulnerability(vulnerabilityRecord);
};

const hideFlyout = () => {
setIsVulnerabilityDetailFlyoutVisible(false);
setVulnerability(undefined);
};

const renderCellValue = useMemo(() => {
return ({ rowIndex, columnId }: EuiDataGridCellValueElementProps) => {
const vulnerabilityRow = data?.page[rowIndex] as VulnerabilityRecord;
Expand All @@ -92,7 +108,7 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => {
iconType="expand"
aria-label="View"
onClick={() => {
alert(`Flyout id ${vulnerabilityRow.vulnerability.id}`);
showFlyout(vulnerabilityRow);
}}
/>
);
Expand Down Expand Up @@ -181,64 +197,73 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => {
}
/>
) : (
<EuiDataGrid
css={css`
& .euiDataGridHeaderCell__icon {
display: none;
}
& .euiDataGrid__controls {
border-bottom: none;
}
& .euiButtonIcon {
color: ${euiTheme.colors.primary};
}
& .euiDataGridRowCell {
font-size: ${euiTheme.size.m};
}
`}
aria-label="Data grid styling demo"
columns={columns}
columnVisibility={{
visibleColumns: columns.map(({ id }) => id),
setVisibleColumns: () => {},
}}
rowCount={data?.total}
toolbarVisibility={{
showColumnSelector: false,
showDisplaySelector: false,
showKeyboardShortcuts: false,
additionalControls: {
left: {
prepend: (
<EuiButtonEmpty size="xs" color="text">
{i18n.translate('xpack.csp.vulnerabilities.totalVulnerabilities', {
defaultMessage:
'{total, plural, one {# Vulnerability} other {# Vulnerabilities}}',
values: { total: data?.total },
})}
</EuiButtonEmpty>
),
<>
<EuiDataGrid
css={css`
& .euiDataGridHeaderCell__icon {
display: none;
}
& .euiDataGrid__controls {
border-bottom: none;
}
& .euiButtonIcon {
color: ${euiTheme.colors.primary};
}
& .euiDataGridRowCell {
font-size: ${euiTheme.size.m};
}
`}
aria-label="Data grid styling demo"
columns={columns}
columnVisibility={{
visibleColumns: columns.map(({ id }) => id),
setVisibleColumns: () => {},
}}
rowCount={data?.total}
toolbarVisibility={{
showColumnSelector: false,
showDisplaySelector: false,
showKeyboardShortcuts: false,
additionalControls: {
left: {
prepend: (
<EuiButtonEmpty size="xs" color="text">
{i18n.translate('xpack.csp.vulnerabilities.totalVulnerabilities', {
defaultMessage:
'{total, plural, one {# Vulnerability} other {# Vulnerabilities}}',
values: { total: data?.total },
})}
</EuiButtonEmpty>
),
},
},
},
}}
gridStyle={{
border: 'horizontal',
cellPadding: 'l',
stripes: false,
rowHover: 'none',
header: 'underline',
}}
renderCellValue={renderCellValue}
inMemory={{ level: 'sorting' }}
sorting={{ columns: sort, onSort }}
pagination={{
pageIndex,
pageSize,
pageSizeOptions: [10, 25, 100],
onChangeItemsPerPage,
onChangePage,
}}
/>
}}
gridStyle={{
border: 'horizontal',
cellPadding: 'l',
stripes: false,
rowHover: 'none',
header: 'underline',
}}
renderCellValue={renderCellValue}
inMemory={{ level: 'sorting' }}
sorting={{ columns: sort, onSort }}
pagination={{
pageIndex,
pageSize,
pageSizeOptions: [10, 25, 100],
onChangeItemsPerPage,
onChangePage,
}}
/>
{/* Todo: Add Pagination */}
{isVulnerabilityDetailFlyoutVisible && !!vulnerability && (
<VulnerabilityFindingFlyout
vulnerabilityRecord={vulnerability}
closeFlyout={hideFlyout}
/>
)}
</>
)}
</>
);
Expand Down
Loading

0 comments on commit eb6bfd8

Please sign in to comment.