feat: include PkgPath information in image cve list and list export (#428)

Signed-off-by: Vishwas Rajashekar <vrajashe@cisco.com>
This commit is contained in:
Vishwas R 2024-02-29 15:53:15 +05:30 committed by GitHub
parent 33524ce3cc
commit e2367c2a33
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 220 additions and 27 deletions

View File

@ -1,4 +1,4 @@
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import { render, screen, waitFor, within, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MockThemeProvider from '__mocks__/MockThemeProvider';
import { api } from 'api';
@ -18,6 +18,52 @@ const StateVulnerabilitiesWrapper = () => {
);
};
const simpleMockCVEList = {
CVEListForImage: {
Tag: '',
Page: { ItemCount: 2, TotalCount: 2 },
Summary: {
Count: 2,
UnknownCount: 0,
LowCount: 0,
MediumCount: 1,
HighCount: 0,
CriticalCount: 1,
},
CVEList: [
{
Id: 'CVE-2020-16156',
Title: 'perl-CPAN: Bypass of verification of signatures in CHECKSUMS files',
Description: 'CPAN 2.28 allows Signature Verification Bypass.',
Severity: 'MEDIUM',
PackageList: [
{
Name: 'perl-base',
PackagePath: 'Not Specified',
InstalledVersion: '5.30.0-9ubuntu0.2',
FixedVersion: 'Not Specified'
}
]
},
{
Id: 'CVE-2016-1000027',
Title: 'spring: HttpInvokerServiceExporter readRemoteInvocation method untrusted java deserialization',
Description: "Pivotal Spring Framework through 5.3.16 suffers from a potential remote code execution (RCE) issue if used for Java deserialization of untrusted data. Depending on how the library is implemented within a product, this issue may or not occur, and authentication may be required. NOTE: the vendor's position is that untrusted data is not an intended use case. The product's behavior will not be changed because some users rely on deserialization of trusted data.",
Severity: 'CRITICAL',
Reference: 'https://avd.aquasec.com/nvd/cve-2016-1000027',
PackageList: [
{
Name: 'org.springframework:spring-web',
PackagePath: 'usr/local/tomcat/webapps/spring4shell.war/WEB-INF/lib/spring-web-5.3.15.jar',
InstalledVersion: '5.3.15',
FixedVersion: '6.0.0'
}
]
},
]
}
}
const mockCVEList = {
CVEListForImage: {
Tag: '',
@ -39,6 +85,7 @@ const mockCVEList = {
PackageList: [
{
Name: 'perl-base',
PackagePath: 'Not Specified',
InstalledVersion: '5.30.0-9ubuntu0.2',
FixedVersion: 'Not Specified'
}
@ -54,26 +101,31 @@ const mockCVEList = {
PackageList: [
{
Name: 'krb5-locales',
PackagePath: 'Not Specified',
InstalledVersion: '1.17-6ubuntu4.1',
FixedVersion: 'Not Specified'
},
{
Name: 'libgssapi-krb5-2',
PackagePath: 'Not Specified',
InstalledVersion: '1.17-6ubuntu4.1',
FixedVersion: 'Not Specified'
},
{
Name: 'libk5crypto3',
PackagePath: 'Not Specified',
InstalledVersion: '1.17-6ubuntu4.1',
FixedVersion: 'Not Specified'
},
{
Name: 'libkrb5-3',
PackagePath: 'Not Specified',
InstalledVersion: '1.17-6ubuntu4.1',
FixedVersion: 'Not Specified'
},
{
Name: 'libkrb5support0',
PackagePath: 'Not Specified',
InstalledVersion: '1.17-6ubuntu4.1',
FixedVersion: 'Not Specified'
}
@ -88,6 +140,7 @@ const mockCVEList = {
PackageList: [
{
Name: 'libgnutls30',
PackagePath: 'Not Specified',
InstalledVersion: '3.6.13-2ubuntu1.6',
FixedVersion: '3.6.13-2ubuntu1.7'
}
@ -102,6 +155,7 @@ const mockCVEList = {
PackageList: [
{
Name: 'libpcre2-8-0',
PackagePath: 'Not Specified',
InstalledVersion: '10.34-7',
FixedVersion: 'Not Specified'
}
@ -116,6 +170,7 @@ const mockCVEList = {
PackageList: [
{
Name: 'libsqlite3-0',
PackagePath: 'Not Specified',
InstalledVersion: '3.31.1-4ubuntu0.3',
FixedVersion: '3.31.1-4ubuntu0.4'
}
@ -130,6 +185,7 @@ const mockCVEList = {
PackageList: [
{
Name: 'libpcre3',
PackagePath: 'Not Specified',
InstalledVersion: '2:8.39-12ubuntu0.1',
FixedVersion: 'Not Specified'
}
@ -144,6 +200,7 @@ const mockCVEList = {
PackageList: [
{
Name: 'libsqlite3-0',
PackagePath: 'Not Specified',
InstalledVersion: '3.31.1-4ubuntu0.3',
FixedVersion: '3.31.1-4ubuntu0.4'
}
@ -158,11 +215,13 @@ const mockCVEList = {
PackageList: [
{
Name: 'login',
PackagePath: 'Not Specified',
InstalledVersion: '1:4.8.1-1ubuntu5.20.04.2',
FixedVersion: 'Not Specified'
},
{
Name: 'passwd',
PackagePath: 'Not Specified',
InstalledVersion: '1:4.8.1-1ubuntu5.20.04.2',
FixedVersion: 'Not Specified'
}
@ -177,6 +236,7 @@ const mockCVEList = {
PackageList: [
{
Name: 'libgmp10',
PackagePath: 'Not Specified',
InstalledVersion: '2:6.2.0+dfsg-4',
FixedVersion: 'Not Specified'
}
@ -191,6 +251,7 @@ const mockCVEList = {
PackageList: [
{
Name: 'libgnutls30',
PackagePath: 'Not Specified',
InstalledVersion: '3.6.13-2ubuntu1.6',
FixedVersion: '3.6.13-2ubuntu1.7'
}
@ -205,26 +266,31 @@ const mockCVEList = {
PackageList: [
{
Name: 'libncurses6',
PackagePath: 'Not Specified',
InstalledVersion: '6.2-0ubuntu2',
FixedVersion: 'Not Specified'
},
{
Name: 'libncursesw6',
PackagePath: 'Not Specified',
InstalledVersion: '6.2-0ubuntu2',
FixedVersion: 'Not Specified'
},
{
Name: 'libtinfo6',
PackagePath: 'Not Specified',
InstalledVersion: '6.2-0ubuntu2',
FixedVersion: 'Not Specified'
},
{
Name: 'ncurses-base',
PackagePath: 'Not Specified',
InstalledVersion: '6.2-0ubuntu2',
FixedVersion: 'Not Specified'
},
{
Name: 'ncurses-bin',
PackagePath: 'Not Specified',
InstalledVersion: '6.2-0ubuntu2',
FixedVersion: 'Not Specified'
}
@ -239,6 +305,7 @@ const mockCVEList = {
PackageList: [
{
Name: 'libpcre2-8-0',
PackagePath: 'Not Specified',
InstalledVersion: '10.34-7',
FixedVersion: 'Not Specified'
}
@ -253,26 +320,31 @@ const mockCVEList = {
PackageList: [
{
Name: 'libncurses6',
PackagePath: 'Not Specified',
InstalledVersion: '6.2-0ubuntu2',
FixedVersion: 'Not Specified'
},
{
Name: 'libncursesw6',
PackagePath: 'Not Specified',
InstalledVersion: '6.2-0ubuntu2',
FixedVersion: 'Not Specified'
},
{
Name: 'libtinfo6',
PackagePath: 'Not Specified',
InstalledVersion: '6.2-0ubuntu2',
FixedVersion: 'Not Specified'
},
{
Name: 'ncurses-base',
PackagePath: 'Not Specified',
InstalledVersion: '6.2-0ubuntu2',
FixedVersion: 'Not Specified'
},
{
Name: 'ncurses-bin',
PackagePath: 'Not Specified',
InstalledVersion: '6.2-0ubuntu2',
FixedVersion: 'Not Specified'
}
@ -287,6 +359,7 @@ const mockCVEList = {
PackageList: [
{
Name: 'coreutils',
PackagePath: 'Not Specified',
InstalledVersion: '8.30-3ubuntu2',
FixedVersion: 'Not Specified'
}
@ -301,46 +374,55 @@ const mockCVEList = {
PackageList: [
{
Name: 'libasn1-8-heimdal',
PackagePath: 'Not Specified',
InstalledVersion: '7.7.0+dfsg-1ubuntu1',
FixedVersion: 'Not Specified'
},
{
Name: 'libgssapi3-heimdal',
PackagePath: 'Not Specified',
InstalledVersion: '7.7.0+dfsg-1ubuntu1',
FixedVersion: 'Not Specified'
},
{
Name: 'libhcrypto4-heimdal',
PackagePath: 'Not Specified',
InstalledVersion: '7.7.0+dfsg-1ubuntu1',
FixedVersion: 'Not Specified'
},
{
Name: 'libheimbase1-heimdal',
PackagePath: 'Not Specified',
InstalledVersion: '7.7.0+dfsg-1ubuntu1',
FixedVersion: 'Not Specified'
},
{
Name: 'libheimntlm0-heimdal',
PackagePath: 'Not Specified',
InstalledVersion: '7.7.0+dfsg-1ubuntu1',
FixedVersion: 'Not Specified'
},
{
Name: 'libhx509-5-heimdal',
PackagePath: 'Not Specified',
InstalledVersion: '7.7.0+dfsg-1ubuntu1',
FixedVersion: 'Not Specified'
},
{
Name: 'libkrb5-26-heimdal',
PackagePath: 'Not Specified',
InstalledVersion: '7.7.0+dfsg-1ubuntu1',
FixedVersion: 'Not Specified'
},
{
Name: 'libroken18-heimdal',
PackagePath: 'Not Specified',
InstalledVersion: '7.7.0+dfsg-1ubuntu1',
FixedVersion: 'Not Specified'
},
{
Name: 'libwind0-heimdal',
PackagePath: 'Not Specified',
InstalledVersion: '7.7.0+dfsg-1ubuntu1',
FixedVersion: 'Not Specified'
}
@ -355,11 +437,13 @@ const mockCVEList = {
PackageList: [
{
Name: 'libc-bin',
PackagePath: 'Not Specified',
InstalledVersion: '2.31-0ubuntu9.9',
FixedVersion: 'Not Specified'
},
{
Name: 'libc6',
PackagePath: 'Not Specified',
InstalledVersion: '2.31-0ubuntu9.9',
FixedVersion: 'Not Specified'
}
@ -373,6 +457,7 @@ const mockCVEList = {
PackageList: [
{
Name: 'libcurl4',
PackagePath: 'Not Specified',
InstalledVersion: '7.68.0-1ubuntu2.12',
FixedVersion: '7.68.0-1ubuntu2.13'
}
@ -388,26 +473,31 @@ const mockCVEList = {
PackageList: [
{
Name: 'krb5-locales',
PackagePath: 'Not Specified',
InstalledVersion: '1.17-6ubuntu4.1',
FixedVersion: 'Not Specified'
},
{
Name: 'libgssapi-krb5-2',
PackagePath: 'Not Specified',
InstalledVersion: '1.17-6ubuntu4.1',
FixedVersion: 'Not Specified'
},
{
Name: 'libk5crypto3',
PackagePath: 'Not Specified',
InstalledVersion: '1.17-6ubuntu4.1',
FixedVersion: 'Not Specified'
},
{
Name: 'libkrb5-3',
PackagePath: 'Not Specified',
InstalledVersion: '1.17-6ubuntu4.1',
FixedVersion: 'Not Specified'
},
{
Name: 'libkrb5support0',
PackagePath: 'Not Specified',
InstalledVersion: '1.17-6ubuntu4.1',
FixedVersion: 'Not Specified'
}
@ -422,6 +512,7 @@ const mockCVEList = {
PackageList: [
{
Name: 'libsqlite3-0',
PackagePath: 'Not Specified',
InstalledVersion: '3.31.1-4ubuntu0.3',
FixedVersion: '3.31.1-4ubuntu0.4'
}
@ -437,6 +528,7 @@ const mockCVEList = {
PackageList: [
{
Name: 'zlib1g',
PackagePath: 'Not Specified',
InstalledVersion: '1:1.2.11.dfsg-2ubuntu1.3',
FixedVersion: 'Not Specified'
}
@ -667,6 +759,50 @@ describe('Vulnerabilties page', () => {
expect(await screen.findByText('latest')).toBeInTheDocument();
});
it('should show the list of vulnerable packages for the CVEs', async () => {
jest.spyOn(api, 'get').mockResolvedValueOnce({ status: 200, data: { data: simpleMockCVEList } })
render(<StateVulnerabilitiesWrapper />);
const expandListBtn = await screen.findByTestId('expand-list-view-toggle');
fireEvent.click(expandListBtn);
const packageLists = await screen.findAllByTestId('cve-package-list');
expect(packageLists.length).toEqual(2); // Data set has 2 CVEs, so 2 package lists
const expectedData = [
{
Name: 'perl-base',
PackagePath: 'Not Specified',
InstalledVersion: '5.30.0-9ubuntu0.2',
FixedVersion: 'Not Specified'
},
{
Name: 'org.springframework:spring-web',
PackagePath: 'usr/local/tomcat/webapps/spring4shell.war/WEB-INF/lib/spring-web-5.3.15.jar',
InstalledVersion: '5.3.15',
FixedVersion: '6.0.0'
}
];
for (let index = 0; index < 2; index++) {
const expectedPackageData = expectedData[index];
const container = packageLists[index];
const pkgName = await within(container).findAllByTestId('cve-info-pkg-name');
expect(pkgName).toHaveLength(1);
expect(pkgName[0]).toHaveTextContent(expectedPackageData.Name);
const pkgPath = await within(container).findAllByTestId('cve-info-pkg-path');
expect(pkgPath).toHaveLength(1);
expect(pkgPath[0]).toHaveTextContent(expectedPackageData.PackagePath);
const pkgInstalledVer = await within(container).findAllByTestId('cve-info-pkg-install-ver');
expect(pkgInstalledVer).toHaveLength(1);
expect(pkgInstalledVer[0]).toHaveTextContent(expectedPackageData.InstalledVersion);
const pkgFixedVer = await within(container).findAllByTestId('cve-info-pkg-fixed-ver');
expect(pkgFixedVer).toHaveLength(1);
expect(pkgFixedVer[0]).toHaveTextContent(expectedPackageData.FixedVersion);
}
});
it('should allow export of vulnerabilities list', async () => {
const xlsxMock = jest.createMockFromModule('xlsx');
xlsxMock.writeFile = jest.fn();

View File

@ -113,10 +113,10 @@ const endpoints = {
if (!isEmpty(severity)) {
query += `, severity: "${severity}"`;
}
return `${query}){Tag Page {TotalCount ItemCount} CVEList {Id Title Description Severity Reference PackageList {Name InstalledVersion FixedVersion}} Summary {Count UnknownCount LowCount MediumCount HighCount CriticalCount}}}`;
return `${query}){Tag Page {TotalCount ItemCount} CVEList {Id Title Description Severity Reference PackageList {Name PackagePath InstalledVersion FixedVersion}} Summary {Count UnknownCount LowCount MediumCount HighCount CriticalCount}}}`;
},
allVulnerabilitiesForRepo: (name) =>
`/v2/_zot/ext/search?query={CVEListForImage(image: "${name}"){Tag Page {TotalCount ItemCount} CVEList {Id Title Description Severity Reference PackageList {Name InstalledVersion FixedVersion}}}}`,
`/v2/_zot/ext/search?query={CVEListForImage(image: "${name}"){Tag Page {TotalCount ItemCount} CVEList {Id Title Description Severity Reference PackageList {Name PackagePath InstalledVersion FixedVersion}}}}`,
imageListWithCVEFixed: (cveId, repoName, { pageNumber = 1, pageSize = 3 }, filter = {}) => {
let filterParam = '';
if (filter.Os || filter.Arch) {

View File

@ -13,6 +13,7 @@ import { Link } from 'react-router-dom';
import { KeyboardArrowDown, KeyboardArrowRight } from '@mui/icons-material';
import { VulnerabilityChipCheck } from 'utilities/vulnerabilityAndSignatureCheck';
import { CVE_FIXEDIN_PAGE_SIZE } from 'utilities/paginationConstants';
import VulnerabilityPackageSection from './VulnerabilityPackageSection';
const useStyles = makeStyles((theme) => ({
card: {
@ -258,30 +259,14 @@ function VulnerabilitiyCard(props) {
<Typography variant="body2" align="left" className={classes.cveInfo}>
Packages
</Typography>
<Stack direction="column" sx={{ width: '100%', padding: '0.5rem 0' }}>
<Stack direction="row" spacing="1.25rem" display="flex">
<Typography variant="body1" flexBasis="33.33%">
Name
</Typography>
<Typography variant="body1" flexBasis="33.33%" textAlign="right">
Installed Version
</Typography>
<Typography variant="body1" flexBasis="33.33%" textAlign="right">
Fixed Version
</Typography>
</Stack>
{cve.packageList.map((el) => (
<Stack direction="row" key={cve.packageName} spacing="1.25rem" display="flex">
<Typography variant="body1" color="primary" flexBasis="33.33%">
{el.packageName}
</Typography>
<Typography variant="body1" color="primary" flexBasis="33.33%" textAlign="right">
{el.packageInstalledVersion}
</Typography>
<Typography variant="body1" color="primary" flexBasis="33.33%" textAlign="right">
{el.packageFixedVersion}
</Typography>
</Stack>
<Stack
direction="column"
spacing="0.3rem"
sx={{ width: '100%', padding: '0.5rem 0' }}
data-testid="cve-package-list"
>
{cve.packageList.map((pkg) => (
<VulnerabilityPackageSection key={`${cve.id}-${pkg.packageName}`} cve={pkg} />
))}
</Stack>
<Typography variant="body2" align="left" className={classes.cveInfo}>

View File

@ -0,0 +1,69 @@
import React from 'react';
import { Divider, Grid, Stack, Typography } from '@mui/material';
import makeStyles from '@mui/styles/makeStyles';
const useStyles = makeStyles(() => ({
cvePackageCard: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
background: '#FFFFFF',
boxShadow: '0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)',
border: '1px solid #E0E5EB',
borderRadius: '0.75rem',
flex: 'none',
alignSelf: 'stretch',
width: '100%'
},
cveInfo: {
marginTop: '2%'
},
vulnerabilityCardDivider: {
margin: '1rem 1rem'
}
}));
function VulnerabilityPackageSection(props) {
const { cve } = props;
const classes = useStyles();
return (
<Stack
direction="column"
spacing="0.2rem"
sx={{ width: '100%', padding: '0.2rem 0.5rem' }}
data-testid="cve-package-section"
>
<Typography variant="overline" color="primary" data-testid="cve-info-pkg-name" sx={{ fontWeight: 'bold' }}>
{cve.packageName}
</Typography>
<Typography variant="body2" className={classes.cveInfo}>
Package Path
</Typography>
<Typography variant="body1" color="primary" data-testid="cve-info-pkg-path">
{cve.packagePath}
</Typography>
<Grid container>
<Grid item xs={6}>
<Typography variant="body2" className={classes.cveInfo}>
Installed Version
</Typography>
<Typography variant="body1" color="primary" data-testid="cve-info-pkg-install-ver">
{cve.packageInstalledVersion}
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2" className={classes.cveInfo}>
Fixed Version
</Typography>
<Typography variant="body1" color="primary" data-testid="cve-info-pkg-fixed-ver">
{cve.packageFixedVersion}
</Typography>
</Grid>
</Grid>
<Divider className={classes.vulnerabilityCardDivider} />
</Stack>
);
}
export default VulnerabilityPackageSection;

View File

@ -411,6 +411,7 @@ function VulnerabilitiesDetails(props) {
className={classes.view}
selected={selectedViewMore}
onChange={() => setSelectedViewMore(true)}
data-testid="expand-list-view-toggle"
>
<ViewAgendaIcon />
</ToggleButton>

View File

@ -100,6 +100,7 @@ const mapCVEInfo = (cveInfo) => {
reference: cve.Reference,
packageList: cve.PackageList?.map((pkg) => ({
packageName: pkg.Name,
packagePath: pkg.PackagePath,
packageInstalledVersion: pkg.InstalledVersion,
packageFixedVersion: pkg.FixedVersion
}))
@ -118,6 +119,7 @@ const mapAllCVEInfo = (cveInfo) => {
description: cve.Description,
reference: cve.Reference,
packageName: packageInfo.Name,
packagePath: packageInfo.PackagePath,
packageInstalledVersion: packageInfo.InstalledVersion,
packageFixedVersion: packageInfo.FixedVersion
};