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 CVEs and fixes in the advisory details page #2735

Merged
merged 8 commits into from
Jul 4, 2024
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
68 changes: 49 additions & 19 deletions assets/js/lib/test-utils/factories/advisoryErrata.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,53 @@ import { faker } from '@faker-js/faker';
import { Factory } from 'fishery';
import { advisoryType } from './relevantPatches';

export const advisoryErrataFactory = Factory.define(() => ({
id: faker.number.int({ min: 1, max: 65536 }),
issue_date: faker.date.recent({ days: 30 }),
update_date: faker.date.recent({ days: 30 }),
last_modified_date: faker.date.recent({ days: 30 }),
synopsis: faker.lorem.sentence(),
release: faker.number.int({ min: 1, max: 256 }),
advisory_status: 'stable',
vendor_advisory: faker.lorem.word(),
type: faker.helpers.arrayElement(advisoryType),
product: faker.internet.userName(),
errata_from: faker.lorem.word(),
topic: faker.animal.cat(),
description: faker.lorem.sentence(),
references: faker.lorem.sentence(),
notes: faker.lorem.sentence(),
solution: faker.lorem.sentence(),
reboot_suggested: faker.datatype.boolean(),
restart_suggested: faker.datatype.boolean(),
const fixMapFactory = Factory.define(({ transientParams }) => {
const { length = 1 } = transientParams;

return Object.fromEntries(
new Array(length)
.fill(0)
.map(() => [
faker.number.int({ min: 1, max: 65536 }),
faker.lorem.sentence(),
])
);
});

export const cveFactory = Factory.define(
() =>
`CVE-${faker.number.int({ min: 1991, max: 2024 })}-${faker.number.int({
min: 0,
max: 9999,
})}`
);

export const advisoryErrataFactory = Factory.define(({ params }) => ({
fixes:
params.fixes ||
fixMapFactory.build(
{},
{ transient: { length: faker.number.int({ min: 1, max: 10 }) } }
),
cves: cveFactory.buildList(10),
errata_details: {
id: faker.number.int({ min: 1, max: 65536 }),
issue_date: faker.date.recent({ days: 30 }),
update_date: faker.date.recent({ days: 30 }),
last_modified_date: faker.date.recent({ days: 30 }),
synopsis: faker.lorem.sentence(),
release: faker.number.int({ min: 1, max: 256 }),
advisory_status: 'stable',
vendor_advisory: faker.lorem.word(),
type: faker.helpers.arrayElement(advisoryType),
product: faker.internet.userName(),
errata_from: faker.lorem.word(),
topic: faker.animal.cat(),
description: faker.lorem.sentence(),
references: faker.lorem.sentence(),
notes: faker.lorem.sentence(),
solution: faker.lorem.sentence(),
reboot_suggested: faker.datatype.boolean(),
restart_suggested: faker.datatype.boolean(),
},
}));
2 changes: 1 addition & 1 deletion assets/js/lib/test-utils/factories/upgradablePackage.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const releaseVersionFactory = () =>
export const upgradablePackageFactory = Factory.define(() => ({
from_epoch: faker.date.anytime(),
to_release: releaseVersionFactory(),
name: faker.company.buzzNoun(),
name: faker.word.noun(),
from_release: releaseVersionFactory(),
to_epoch: faker.date.anytime(),
arch: faker.airline.flightNumber(),
Expand Down
32 changes: 23 additions & 9 deletions assets/js/pages/AdvisoryDetails/AdvisoryDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ function EmptyData() {
function AdvisoryDetails({
advisoryName,
errata,
fixes,
cves,
packages,
affectsPackageMaintanaceStack,
}) {
Expand All @@ -25,7 +23,9 @@ function AdvisoryDetails({
type,
description,
reboot_suggested: rebootSuggested,
} = errata;
} = errata.errata_details;

const { fixes, cves } = errata;

return (
<div>
Expand Down Expand Up @@ -76,10 +76,17 @@ function AdvisoryDetails({
<div className="flex flex-col mb-4">
<h2 className="text-xl font-bold mb-2">Fixes</h2>
<div className="bg-white py-4 px-6 shadow shadow-md rounded-lg">
{fixes && fixes.length > 1 ? (
{fixes && Object.keys(fixes).length ? (
<ul>
{fixes.map((fix) => (
<li>{fix}</li>
{Object.entries(fixes).map(([id, fix]) => (
<li key={`bug-${id}`}>
<a
className="text-jungle-green-500 hover:opacity-75"
href={`https://bugzilla.suse.com/show_bug.cgi?id=${id}`}
>
{fix}
</a>
</li>
))}
</ul>
) : (
Expand All @@ -90,10 +97,17 @@ function AdvisoryDetails({
<div className="flex flex-col mb-4">
<h2 className="text-xl font-bold mb-2">CVEs</h2>
<div className="bg-white py-4 px-6 shadow shadow-md rounded-lg">
{cves && cves.length > 1 ? (
{cves && cves.length ? (
<ul>
{cves.map((cve) => (
<li>{cve}</li>
<li key={cve}>
<a
className="text-jungle-green-500 hover:opacity-75"
href={`https://cve.mitre.org/cgi-bin/cvename.cgi?name=${cve}`}
>
{cve}
</a>
</li>
))}
</ul>
) : (
Expand All @@ -104,7 +118,7 @@ function AdvisoryDetails({
<div className="flex flex-col mb-4">
<h2 className="text-xl font-bold mb-2">Affected Packages</h2>
<div className="bg-white py-4 px-6 shadow shadow-md rounded-lg">
{packages && packages.length > 1 ? (
{packages && packages.length ? (
<ul>
{packages.map((pkg) => (
<li>{pkg}</li>
Expand Down
2 changes: 0 additions & 2 deletions assets/js/pages/AdvisoryDetails/AdvisoryDetails.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ Yesterday, I left before the post arrived. Normally, the post just delivers my p
However, the post didn't come by today, and I am starting to wonder, if my Geekos ate my quiche. AITA? 😟`,
reboot_suggested: true,
},
fixes: undefined,
cves: undefined,
packages: undefined,
affectsPackageMaintanaceStack: false,
},
Expand Down
75 changes: 60 additions & 15 deletions assets/js/pages/AdvisoryDetails/AdvisoryDetails.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import '@testing-library/jest-dom';
import { faker } from '@faker-js/faker';

import { renderWithRouter as render } from '@lib/test-utils';
import { advisoryErrataFactory } from '@lib/test-utils/factories';
import { advisoryErrataFactory, cveFactory } from '@lib/test-utils/factories';

import AdvisoryDetails from './AdvisoryDetails';

describe('AdvisoryDetails', () => {
it('displays a message, when the CVE, packages or fixes section is empty', () => {
const errata = advisoryErrataFactory.build();
const errata = advisoryErrataFactory.build({ cves: [], fixes: {} });

render(
<AdvisoryDetails advisoryName={faker.lorem.word()} errata={errata} />
Expand All @@ -27,39 +27,84 @@ describe('AdvisoryDetails', () => {
render(<AdvisoryDetails advisoryName={advisoryName} errata={errata} />);

expect(screen.getByText(advisoryName)).toBeVisible();
expect(screen.getByText(errata.synopsis)).toBeVisible();
expect(screen.getByText(errata.advisory_status)).toBeVisible();
expect(screen.getByText(errata.description)).toBeVisible();
expect(screen.getByText(errata.errata_details.synopsis)).toBeVisible();
expect(
screen.getByText(errata.errata_details.advisory_status)
).toBeVisible();
expect(screen.getByText(errata.errata_details.description)).toBeVisible();
});

it('displays CVEs, packages and fixes', () => {
it('displays packages', () => {
const errata = advisoryErrataFactory.build();
const advisoryName = faker.lorem.word();

const fixes = faker.word.words(2).split(' ');
const packages = faker.word.words(2).split(' ');
const cves = faker.word.words(2).split(' ');

render(
<AdvisoryDetails
advisoryName={advisoryName}
errata={errata}
fixes={fixes}
cves={cves}
packages={packages}
/>
);

fixes.forEach((expectedWord) => {
packages.forEach((expectedWord) => {
expect(screen.getByText(expectedWord)).toBeVisible();
});
});

cves.forEach((expectedWord) => {
expect(screen.getByText(expectedWord)).toBeVisible();
it('displays fixes with a valid link', () => {
const errata = advisoryErrataFactory.build();
const advisoryName = faker.lorem.word();

render(<AdvisoryDetails advisoryName={advisoryName} errata={errata} />);

Object.entries(errata.fixes).forEach(([id, fixText]) => {
const el = screen.getByText(fixText);
expect(el.href.includes(id)).toBe(true);
expect(el).toBeVisible();
});
});

packages.forEach((expectedWord) => {
expect(screen.getByText(expectedWord)).toBeVisible();
it('displays CVEs with a valid link', () => {
const errata = advisoryErrataFactory.build({
cves: cveFactory.buildList(faker.number.int({ min: 2, max: 10 })),
});

const advisoryName = faker.lorem.word();

render(<AdvisoryDetails advisoryName={advisoryName} errata={errata} />);

errata.cves.forEach((cve) => {
const el = screen.getByText(cve);
expect(el.href.includes(cve)).toBe(true);
expect(el).toBeVisible();
});
});

it('displays a single fix with a valid link', () => {
const errata = advisoryErrataFactory.build();
const advisoryName = faker.lorem.word();

render(<AdvisoryDetails advisoryName={advisoryName} errata={errata} />);

Object.entries(errata.fixes).forEach(([id, fixText]) => {
const el = screen.getByText(fixText);
expect(el.href.includes(id)).toBe(true);
expect(el).toBeVisible();
});
});

it('displays a single CVE with a valid link', () => {
const errata = advisoryErrataFactory.build();
const advisoryName = faker.lorem.word();

render(<AdvisoryDetails advisoryName={advisoryName} errata={errata} />);

errata.cves.forEach((cve) => {
const el = screen.getByText(cve);
expect(el.href.includes(cve)).toBe(true);
expect(el).toBeVisible();
});
});
});