Skip to content

Commit

Permalink
Merge pull request #4077 from greenbone/add-epss-to-results
Browse files Browse the repository at this point in the history
Add: EPSS scoring info to results
  • Loading branch information
a-h-abdelsalam authored Jul 3, 2024
2 parents 639ce97 + 821926d commit 6751192
Show file tree
Hide file tree
Showing 7 changed files with 223 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/gmp/models/cve.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/


import {isArray, isDefined} from 'gmp/utils/identity';
import {isEmpty} from 'gmp/utils/string';
import {map} from 'gmp/utils/array';
Expand All @@ -27,6 +26,7 @@ class Cve extends Info {

ret.name = element.name;
ret.id = element.name;
ret.epss = element.epss;

return ret;
}
Expand Down
40 changes: 34 additions & 6 deletions src/web/pages/results/__tests__/detailspage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import Detailspage, {ToolBarIcons} from '../detailspage';

const reloadInterval = -1;
const manualUrl = 'test/';
const enableEPSS = true;

// mock entity

Expand All @@ -40,6 +41,24 @@ export const result = Result.fromElement({
type: 'nvt',
name: 'nvt1',
tags: 'cvss_base_vector=AV:N/AC:M/Au:N/C:P/I:N/A:N|summary=This is a mock result|insight=This is just a test|affected=Affects test cases only|impact=No real impact|solution=Keep writing tests|vuldetect=This is the detection method|solution_type=Mitigation',
epss: {
max_severity: {
score: 0.8765,
percentile: 0.8,
cve: {
_id: 'CVE-2019-1234',
severity: 5.0,
},
},
max_epss: {
score: 0.9876,
percentile: 0.9,
cve: {
_id: 'CVE-2020-5678',
severity: 2.0,
},
},
},
refs: {
ref: [
{_type: 'cve', _id: 'CVE-2019-1234'},
Expand Down Expand Up @@ -124,7 +143,7 @@ describe('Result Detailspage tests', () => {
permissions: {
get: getPermissions,
},
settings: {manualUrl, reloadInterval},
settings: {manualUrl, reloadInterval, enableEPSS},
user: {currentSettings, renewSession},
};

Expand Down Expand Up @@ -189,7 +208,16 @@ describe('Result Detailspage tests', () => {
expect(baseElement).toHaveTextContent('QoD80 %');
expect(baseElement).toHaveTextContent('Host109.876.54.321');
expect(baseElement).toHaveTextContent('Location80/tcp');

expect(baseElement).toHaveTextContent('EPSS (CVE with highest severity)');
expect(baseElement).toHaveTextContent('EPSS Score0.87650');
expect(baseElement).toHaveTextContent('EPSS Percentile0.80000');
expect(baseElement).toHaveTextContent('CVECVE-2019-1234');
expect(baseElement).toHaveTextContent('CVE Severity5.0 (Medium)');
expect(baseElement).toHaveTextContent('EPSS (highest EPSS score)');
expect(baseElement).toHaveTextContent('EPSS Score0.98760');
expect(baseElement).toHaveTextContent('EPSS Percentile0.90000');
expect(baseElement).toHaveTextContent('CVECVE-2020-5678');
expect(baseElement).toHaveTextContent('CVE Severity2.0 (Low)');
expect(heading[2]).toHaveTextContent('Summary');
expect(baseElement).toHaveTextContent('This is a mock result');

Expand Down Expand Up @@ -245,7 +273,7 @@ describe('Result Detailspage tests', () => {
permissions: {
get: getPermissions,
},
settings: {manualUrl, reloadInterval},
settings: {manualUrl, reloadInterval, enableEPSS},
user: {currentSettings, renewSession},
};

Expand Down Expand Up @@ -294,7 +322,7 @@ describe('Result Detailspage tests', () => {
users: {
get: getUsers,
},
settings: {manualUrl, reloadInterval},
settings: {manualUrl, reloadInterval, enableEPSS},
user: {currentSettings, renewSession},
};

Expand Down Expand Up @@ -339,7 +367,7 @@ describe('Result ToolBarIcons tests', () => {
const handleResultDownloadClick = testing.fn();
const handleTicketCreateClick = testing.fn();

const gmp = {settings: {manualUrl}};
const gmp = {settings: {manualUrl, enableEPSS}};

const {render} = rendererWith({
gmp,
Expand Down Expand Up @@ -390,7 +418,7 @@ describe('Result ToolBarIcons tests', () => {
const handleResultDownloadClick = testing.fn();
const handleTicketCreateClick = testing.fn();

const gmp = {settings: {manualUrl}};
const gmp = {settings: {manualUrl, enableEPSS}};

const {render} = rendererWith({
gmp,
Expand Down
55 changes: 53 additions & 2 deletions src/web/pages/results/__tests__/row.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,59 @@ import {rendererWith} from 'web/utils/testing';

import Row from '../row';

const gmp = {settings: {enableEPSS: true}};

describe('Should render EPSS fields', () => {
const {render} = rendererWith({gmp, store: true});

test('should render EPSS columns', () => {
const entity = Result.fromElement({
_id: '101',
name: 'Result 1',
host: {__text: '123.456.78.910', hostname: 'foo'},
port: '80/tcp',
severity: 10.0,
qod: {value: 80},
notes: [],
overrides: [],
tickets: [],
nvt: {
epss: {
max_severity: {
score: 0.8765,
percentile: 0.8,
cve: {
_id: 'CVE-2019-1234',
severity: 5.0,
},
},
max_epss: {
score: 0.9876,
percentile: 0.9,
cve: {
_id: 'CVE-2020-5678',
severity: 2.0,
},
},
},
},
});

const {element} = render(
<table>
<tbody>
<Row entity={entity}/>
</tbody>
</table>,
);

expect(element).toHaveTextContent("0.87650");
expect(element).toHaveTextContent("0.80000");
});
});

describe('Delta reports V2 with changed severity, qod and hostname', () => {
const {render} = rendererWith();
const {render} = rendererWith({gmp, store: true});

test('should render Delta Difference icon', () => {
const entity = Result.fromElement({
Expand Down Expand Up @@ -54,7 +105,7 @@ describe('Delta reports V2 with changed severity, qod and hostname', () => {
});

describe('Delta reports V2 with same severity, qod and hostname', () => {
const {render} = rendererWith();
const {render} = rendererWith({gmp, store: true});

test('should not render Delta Difference icon', () => {
const entity = Result.fromElement({
Expand Down
82 changes: 81 additions & 1 deletion src/web/pages/results/detailspage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import _ from 'gmp/locale';

import {MANUAL, TASK_SELECTED, RESULT_ANY} from 'gmp/models/override';

import {isDefined} from 'gmp/utils/identity';
import {isDefined, isNumber} from 'gmp/utils/identity';

import Badge from 'web/components/badge/badge';

Expand Down Expand Up @@ -70,6 +70,7 @@ import compose from 'web/utils/compose';
import {generateFilename} from 'web/utils/render';
import PropTypes from 'web/utils/proptypes';
import useCapabilities from 'web/hooks/useCapabilities';
import useGmp from 'web/hooks/useGmp';

import NoteComponent from '../notes/component';

Expand All @@ -78,6 +79,8 @@ import OverrideComponent from '../overrides/component';
import TicketComponent from '../tickets/component';

import ResultDetails from './details';
import CveLink from "web/components/link/cvelink.jsx";
import Severitybar from "web/components/bar/severitybar.jsx";

export const ToolBarIcons = ({
entity,
Expand Down Expand Up @@ -177,6 +180,9 @@ const Details = ({entity, ...props}) => {
const {notes, overrides, qod, host, userTags} = entity;
const active_notes = notes.filter(active_filter);
const active_overrides = overrides.filter(active_filter);
const epss = entity?.information?.epss
const gmp = useGmp()

return (
<React.Fragment>
<PageTitle title={_('Result: {{name}}', {name: entity.name})} />
Expand Down Expand Up @@ -230,6 +236,80 @@ const Details = ({entity, ...props}) => {
<TableData>{_('Location')}</TableData>
<TableData>{entity.port}</TableData>
</TableRow>
{ gmp.settings.enableEPSS && isDefined(epss?.max_severity) &&
<>
<TableData colSpan="2">
<b>{_('EPSS (CVE with highest severity)')}</b>
</TableData>
<TableRow>
<TableData>{_('EPSS Score')}</TableData>
<TableData>
{isNumber(epss?.max_severity?.score)
? epss?.max_severity?.score.toFixed(5) : _("N/A")}
</TableData>
</TableRow>
<TableRow>
<TableData>{_('EPSS Percentile')}</TableData>
<TableData>
{isNumber(epss?.max_severity?.percentile)
? epss?.max_severity?.percentile.toFixed(5) : _("N/A")}
</TableData>
</TableRow>
<TableRow>
<TableData>{_('CVE')}</TableData>
<TableData>
<CveLink id={epss?.max_severity?.cve?._id}>
{epss?.max_severity?.cve?._id}
</CveLink>
</TableData>
</TableRow>
<TableRow>
<TableData>{_('CVE Severity')}</TableData>
<Severitybar
severity={isDefined(epss?.max_severity?.cve?.severity)
? epss?.max_severity?.cve?.severity : _("N/A")}
/>
</TableRow>
</>
}
{ gmp.settings.enableEPSS && isDefined(epss?.max_epss) &&
<>
<TableData colSpan="2">
<b>{_('EPSS (highest EPSS score)')}</b>
</TableData>
<TableRow>
<TableData>{_('EPSS Score')}</TableData>
<TableData>
{isNumber(epss?.max_epss?.score)
? epss?.max_epss?.score.toFixed(5) : _("N/A")}
</TableData>
</TableRow>
<TableRow>
<TableData>{_('EPSS Percentile')}</TableData>
<TableData>
{isNumber(epss?.max_epss?.percentile)
? epss?.max_epss?.percentile.toFixed(5) : _("N/A")}
</TableData>
</TableRow>
<TableRow>
<TableData>{_('CVE')}</TableData>
<TableData>
<CveLink id={epss?.max_epss?.cve?._id}>
{epss?.max_epss?.cve?._id}
</CveLink>
</TableData>
</TableRow>
<TableRow>
<TableData>{_('CVE Severity')}</TableData>
<TableData>
<Severitybar
severity={isDefined(epss?.max_epss?.cve?.severity)
? epss?.max_epss?.cve?.severity : _("N/A")}
/>
</TableData>
</TableRow>
</>
}
</TableBody>
</InfoTable>
</Layout>
Expand Down
8 changes: 8 additions & 0 deletions src/web/pages/results/filterdialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ const SORT_FIELDS = [
name: 'modified',
displayName: _l('Modified'),
},
{
name: 'epss_score',
displayName: _l('EPSS Score'),
},
{
name: 'epss_percentile',
displayName: _l('EPSS Percentile'),
},
];

const ResultsFilterDialogComponent = ({
Expand Down
17 changes: 16 additions & 1 deletion src/web/pages/results/row.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import React from 'react';

import _ from 'gmp/locale';

import {isDefined} from 'gmp/utils/identity';
import {isDefined, isNumber} from 'gmp/utils/identity';

import {shorten} from 'gmp/utils/string';

Expand Down Expand Up @@ -38,6 +38,7 @@ import EntitiesActions from 'web/entities/actions';
import PropTypes from 'web/utils/proptypes';

import ResultDelta from './delta';
import useGmp from "web/hooks/useGmp";

const Row = ({
actionsComponent: ActionsComponent = EntitiesActions,
Expand All @@ -60,6 +61,9 @@ const Row = ({
const deltaSeverity = entity.delta?.result?.severity;
const deltaHostname = entity.delta?.result?.host?.hostname;
const deltaQoD = entity.delta?.result?.qod?.value;
const epssScore = entity?.information?.epss?.max_severity?.score
const epssPercentile = entity?.information?.epss?.max_severity?.percentile
const gmp = useGmp()
return (
<TableRow>
{delta && (
Expand Down Expand Up @@ -140,6 +144,17 @@ const Row = ({
</IconDivider>
</TableData>
<TableData>{entity.port}</TableData>
{
gmp.settings.enableEPSS &&
<>
<TableData>
{isNumber(epssScore) ? epssScore.toFixed(5) : _("N/A")}
</TableData>
<TableData>
{isNumber(epssPercentile) ? epssPercentile.toFixed(5) : _("N/A")}
</TableData>
</>
}
<TableData>
<DateTime date={entity.creationTime} />
</TableData>
Expand Down
Loading

0 comments on commit 6751192

Please sign in to comment.