Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display CPE Name ID and deprecation status at CPE details #4306

Merged
merged 1 commit into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion src/gmp/models/__tests__/cpe.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import Cpe from 'gmp/models/cpe';
import {isDate} from 'gmp/models/date';
import {testModel} from 'gmp/models/testing';

/* eslint-disable camelcase */

testModel(Cpe, 'cpe');

describe('CPE model tests', () => {
Expand Down Expand Up @@ -88,17 +90,72 @@ describe('CPE model tests', () => {
expect(isDate(cpe.updateTime)).toBe(true);
});

test('should parse deprecatedBy', () => {
test('should parse deprecatedBy from raw data', () => {
const cpe = Cpe.fromElement({
raw_data: {'cpe-item': {_deprecated_by: 'foo:/bar'}},
});
expect(cpe.deprecatedBy).toEqual('foo:/bar');

const cpe2 = Cpe.fromElement({
deprecated: 0,
deprecated_by: {_cpe_id: 'foo:/bar'},
raw_data: {'cpe-item': {_deprecated_by: 'foo:/baz'}},
});
expect(cpe2.deprecatedBy).toEqual('foo:/baz');
});

test('should parse deprecated', () => {
const cpe = Cpe.fromElement({
deprecated: 1,
});
expect(cpe.deprecated).toBe(true);

const cpe2 = Cpe.fromElement({
deprecated: 0,
});
expect(cpe2.deprecated).toBe(false);

const cpe3 = Cpe.fromElement({});
expect(cpe3.deprecated).toBe(false);
});

test('should parse deprecatedBy', () => {
const cpe = Cpe.fromElement({
deprecated: 1,
deprecated_by: {_cpe_id: 'foo:/bar'},
});
expect(cpe.deprecatedBy).toEqual('foo:/bar');

const cpe2 = Cpe.fromElement({
deprecated: 1,
deprecated_by: {_cpe_id: 'foo:/bar'},
raw_data: {'cpe-item': {_deprecated_by: 'foo:/baz'}},
});

expect(cpe2.deprecatedBy).toEqual('foo:/bar');
});

test('should not parse deprecatedBy', () => {
const cpe = Cpe.fromElement({raw_data: {'cpe-item': {}}});

expect(cpe.deprecatedBy).toBeUndefined();
});

test('should parse old nvd_id', () => {
const cpe = Cpe.fromElement({nvd_id: 'ABC'});

expect(cpe.cpeNameId).toEqual('ABC');
expect(cpe.nvd_id).toBeUndefined();
});

test('should parse cpeNameId', () => {
const cpe = Cpe.fromElement({cpe_name_id: 'ABC'});
const cpe2 = Cpe.fromElement({cpe_name_id: 'ABC', nvd_id: 'DEF'});

expect(cpe.cpeNameId).toEqual('ABC');
expect(cpe.cpe_name_id).toBeUndefined();

expect(cpe2.cpeNameId).toEqual('ABC');
expect(cpe2.cpe_name_id).toBeUndefined();
});
});
20 changes: 17 additions & 3 deletions src/gmp/models/cpe.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import {parseSeverity, parseDate} from 'gmp/parser';
import {parseSeverity, parseDate, parseBoolean} from 'gmp/parser';
import {map} from 'gmp/utils/array';
import {isDefined} from 'gmp/utils/identity';
import {isEmpty} from 'gmp/utils/string';
Expand Down Expand Up @@ -31,7 +31,14 @@ class Cpe extends Info {
}

if (isDefined(ret.nvd_id)) {
ret.nvdId = ret.nvd_id;
// old ID from nvd just kept for backwards compatibility and should be removed in future
ret.cpeNameId = ret.nvd_id;
delete ret.nvd_id;
}

if (isDefined(ret.cpe_name_id)) {
ret.cpeNameId = ret.cpe_name_id;
delete ret.cpe_name_id;
}

if (isDefined(ret.update_time)) {
Expand All @@ -44,8 +51,15 @@ class Cpe extends Info {
* Once `raw_data` is removed from the API, this backup check can be removed.
*/

if (ret.deprecated === 1 && isDefined(ret.deprecated_by)) {
if (isDefined(ret.deprecated)) {
ret.deprecated = parseBoolean(ret.deprecated);
} else {
ret.deprecated = false;
}

if (ret.deprecated === true && isDefined(ret.deprecated_by)) {
ret.deprecatedBy = ret.deprecated_by._cpe_id;
delete ret.deprecated_by;
} else if (isDefined(ret.raw_data?.['cpe-item']?._deprecated_by)) {
ret.deprecatedBy = ret.raw_data['cpe-item']._deprecated_by;
}
Expand Down
21 changes: 17 additions & 4 deletions src/web/pages/cpes/details.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,18 @@ import InfoTable from 'web/components/table/infotable';
import TableRow from 'web/components/table/row';
import {Col} from 'web/entity/page';
import PropTypes from 'web/utils/proptypes';
import {renderYesNo} from 'web/utils/render';

const CpeDetails = ({entity, links = true}) => {
const {title, nvdId, deprecatedBy, updateTime, status, severity} = entity;
const {
title,
cpeNameId,
deprecated,
deprecatedBy,
updateTime,
status,
severity,
} = entity;
return (
<Layout flex="column" grow="1">
{!isDefined(title) && (
Expand All @@ -42,12 +51,16 @@ const CpeDetails = ({entity, links = true}) => {
<TableData>{title}</TableData>
</TableRow>
)}
{isDefined(nvdId) && (
{isDefined(cpeNameId) && (
<TableRow>
<TableData>{_('NVD ID')}</TableData>
<TableData>{nvdId}</TableData>
<TableData>{_('CPE Name ID')}</TableData>
<TableData>{cpeNameId}</TableData>
</TableRow>
)}
<TableRow>
<TableData>{_('Deprecated')}</TableData>
<TableData>{renderYesNo(deprecated)}</TableData>
</TableRow>
{isDefined(deprecatedBy) && (
<TableRow>
<TableData>{_('Deprecated By')}</TableData>
Expand Down
Loading