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

Affected packages #2763

Merged
merged 11 commits into from
Jul 11, 2024
14 changes: 14 additions & 0 deletions assets/js/lib/test-utils/factories/advisoryErrata.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@ import { faker } from '@faker-js/faker';
import { Factory } from 'fishery';
import { advisoryType } from './relevantPatches';

const affectedPackageFactory = Factory.define(({ sequence }) => ({
name: `${faker.animal.cat().toLowerCase()}${sequence}`,
arch_label: faker.helpers.arrayElement(['x86_64', 'i586', 'aarch64']),
version: faker.system.semver(),
release: `${faker.number.int({ min: 0, max: 100 })}`,
epoch: `${faker.number.int({ min: 0, max: 50 })}`,
}));

const affectedSystemFactory = Factory.define(({ sequence }) => ({
name: `${faker.string.uuid()}-${sequence}`,
}));

const fixMapFactory = Factory.define(({ transientParams }) => {
const { length = 1 } = transientParams;

Expand Down Expand Up @@ -31,6 +43,8 @@ export const advisoryErrataFactory = Factory.define(({ params }) => ({
{ transient: { length: faker.number.int({ min: 1, max: 10 }) } }
),
cves: cveFactory.buildList(10),
affected_packages: affectedPackageFactory.buildList(10),
affected_systems: affectedSystemFactory.buildList(10),
errata_details: {
id: faker.number.int({ min: 1, max: 65536 }),
issue_date: faker.date.recent({ days: 30 }),
Expand Down
37 changes: 29 additions & 8 deletions assets/js/pages/AdvisoryDetails/AdvisoryDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ import PageHeader from '@common/PageHeader';
import ListView from '@common/ListView';
import AdvisoryIcon from '@common/AdvisoryIcon';

const formatPackage = ({ name, version, epoch, release, arch_label }) =>
`${name}-${version}-${epoch}.${release}-${arch_label}`;

function EmptyData() {
return <p>No data available</p>;
}

function AdvisoryDetails({
advisoryName,
errata,
packages,
affectsPackageMaintanaceStack,
affectsPackageMaintenanceStack,
}) {
const {
issue_date: issueDate,
Expand All @@ -25,7 +27,12 @@ function AdvisoryDetails({
reboot_suggested: rebootSuggested,
} = errata.errata_details;

const { fixes, cves } = errata;
const {
fixes,
cves,
affected_packages: affectedPackages,
affected_systems: affectedSystems,
} = errata;

return (
<div>
Expand Down Expand Up @@ -60,8 +67,8 @@ function AdvisoryDetails({
content: rebootSuggested ? 'Yes' : 'No',
},
{
title: 'Affects Package Maintanace Stack',
content: affectsPackageMaintanaceStack ? 'Yes' : 'No',
title: 'Affects Package Maintenance Stack',
content: affectsPackageMaintenanceStack ? 'Yes' : 'No',
},
]}
/>
Expand Down Expand Up @@ -118,10 +125,24 @@ 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 ? (
{affectedPackages && affectedPackages.length ? (
<ul>
{affectedPackages.map((pkg) => (
<li key={formatPackage(pkg)}>{formatPackage(pkg)}</li>
))}
</ul>
) : (
<EmptyData />
)}
</div>
</div>
<div className="flex flex-col mb-4">
<h2 className="text-xl font-bold mb-2">Affected Systems</h2>
<div className="bg-white py-4 px-6 shadow shadow-md rounded-lg">
{affectedSystems && affectedSystems.length ? (
<ul>
{packages.map((pkg) => (
<li>{pkg}</li>
{affectedSystems.map(({ name }) => (
<li key={`system-${name}`}>{name}</li>
))}
</ul>
) : (
Expand Down
41 changes: 39 additions & 2 deletions assets/js/pages/AdvisoryDetails/AdvisoryDetails.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,45 @@ However, the post didn't come by today, and I am starting to wonder, if my Geeko
4815162342: 'Geekos unexpectedly eating quiches',
},
cves: ['CVE-2024-35938'],
affected_packages: [
{
name: 'libprocps7',
version: '3.3.15',
release: '7.34.1',
epoch: '150000',
arch_label: 'x86_64',
},
],
affected_systems: [
{
name: 'vmdrbddev01',
},
],
},
packages: undefined,
affectsPackageMaintanaceStack: false,
affectsPackageMaintenanceStack: false,
},
};

export const Empty = {
args: {
advisoryName: 'SUSE-15-SP4-2023-3369',
errata: {
errata_details: {
issue_date: Date.now(),
update_date: Date.now(),
synopsis: 'I think my Geekos ate my quiche 🦎🦎',
advisory_status: 'stable',
type: 'security_advisory',
description: `My Geekos really love the cakes I order from the crab bakery.
Yesterday, I left before the post arrived. Normally, the post just delivers my packages the next day.
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: {},
cves: [],
affected_packages: [],
affected_systems: [],
},
affectsPackageMaintenanceStack: false,
},
};
36 changes: 23 additions & 13 deletions assets/js/pages/AdvisoryDetails/AdvisoryDetails.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@ import AdvisoryDetails from './AdvisoryDetails';

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

render(
<AdvisoryDetails advisoryName={faker.lorem.word()} errata={errata} />
);

expect(screen.getAllByText('No data available').length).toBe(3);
expect(screen.getAllByText('No data available').length).toBe(4);
});

it('displays relevant errata data', () => {
Expand All @@ -34,22 +39,27 @@ describe('AdvisoryDetails', () => {
expect(screen.getByText(errata.errata_details.description)).toBeVisible();
});

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

const packages = faker.word.words(2).split(' ');
render(<AdvisoryDetails advisoryName={advisoryName} errata={errata} />);

render(
<AdvisoryDetails
advisoryName={advisoryName}
errata={errata}
packages={packages}
/>
);
errata.affected_packages.forEach(({ name }) => {
const el = screen.getByText(name, { exact: false });
expect(el).toBeVisible();
});
});

it('displays affected systems', () => {
const errata = advisoryErrataFactory.build();
const advisoryName = faker.lorem.word();

packages.forEach((expectedWord) => {
expect(screen.getByText(expectedWord)).toBeVisible();
render(<AdvisoryDetails advisoryName={advisoryName} errata={errata} />);

errata.affected_systems.forEach(({ name }) => {
const el = screen.getByText(name);
expect(el).toBeVisible();
});
});

Expand Down
14 changes: 14 additions & 0 deletions lib/trento_web/controllers/fallback_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,20 @@ defmodule TrentoWeb.FallbackController do
|> render(:"422", reason: "Unable to retrieve Bugzilla fixes for this advisory.")
end

def call(conn, {:error, :error_getting_affected_packages}) do
conn
|> put_status(:unprocessable_entity)
|> put_view(ErrorView)
|> render(:"422", reason: "Unable to retrieve affected packages for this advisory.")
end

def call(conn, {:error, :error_getting_affected_systems}) do
conn
|> put_status(:unprocessable_entity)
|> put_view(ErrorView)
|> render(:"422", reason: "Unable to retrieve affected systems for this advisory.")
end

def call(conn, {:error, :connection_test_failed}) do
conn
|> put_status(:unprocessable_entity)
Expand Down
12 changes: 10 additions & 2 deletions lib/trento_web/controllers/v1/suse_manager_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,16 @@ defmodule TrentoWeb.V1.SUSEManagerController do
def errata_details(conn, %{advisory_name: advisory_name}) do
with {:ok, errata_details} <- Discovery.get_errata_details(advisory_name),
{:ok, cves} <- Discovery.get_cves(advisory_name),
{:ok, fixes} <- Discovery.get_bugzilla_fixes(advisory_name) do
render(conn, %{errata_details: errata_details, cves: cves, fixes: fixes})
{:ok, fixes} <- Discovery.get_bugzilla_fixes(advisory_name),
{:ok, affected_packages} <- Discovery.get_affected_packages(advisory_name),
{:ok, affected_systems} <- Discovery.get_affected_systems(advisory_name) do
render(conn, %{
errata_details: errata_details,
cves: cves,
fixes: fixes,
affected_packages: affected_packages,
affected_systems: affected_systems
})
end
end
end
62 changes: 61 additions & 1 deletion lib/trento_web/openapi/v1/schema/available_software_updates.ex
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,64 @@ defmodule TrentoWeb.OpenApi.V1.Schema.AvailableSoftwareUpdates do
})
end

defmodule AffectedPackages do
@moduledoc false
OpenApiSpex.schema(%{
title: "AffectedPackages",
description: "Response returned from the get affected packages endpoint",
type: :array,
additionalProperties: false,
items: %Schema{
title: "AffectedPackage",
description: "Metadata for a package effected by an advisory",
type: :object,
properties: %{
name: %Schema{
type: :string,
description: "Package name"
},
arch_label: %Schema{
type: :string,
description: "Package architecture"
},
version: %Schema{
type: :string,
description: "Package upstream version"
},
release: %Schema{
type: :string,
description: "Package RPM release number"
},
epoch: %Schema{
type: :string,
description: "Package epoch number"
}
}
}
})
end

defmodule AffectedSystems do
@moduledoc false
OpenApiSpex.schema(%{
title: "AffectedSystems",
description: "Response returned from the get affected systems endpoint",
type: :array,
additionalProperties: false,
items: %Schema{
title: "AffectedSystem",
description: "Metadata for a system effected by an advisory",
type: :object,
properties: %{
name: %Schema{
type: :string,
description: "System name"
}
}
}
})
end

defmodule ErrataDetailsResponse do
@moduledoc false
OpenApiSpex.schema(%{
Expand All @@ -207,7 +265,9 @@ defmodule TrentoWeb.OpenApi.V1.Schema.AvailableSoftwareUpdates do
properties: %{
errata_details: ErrataDetails,
cves: CVEs,
fixes: AdvisoryFixes
fixes: AdvisoryFixes,
affected_packages: AffectedPackages,
affected_systems: AffectedSystems
}
})
end
Expand Down
8 changes: 6 additions & 2 deletions lib/trento_web/views/v1/suse_manager_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,18 @@ defmodule TrentoWeb.V1.SUSEManagerView do
def render("errata_details.json", %{
errata_details: errata_details = %{errataFrom: errataFrom},
cves: cves,
fixes: fixes
fixes: fixes,
affected_packages: affected_packages,
affected_systems: affected_systems
}),
do: %{
errata_details:
errata_details
|> Map.drop([:errataFrom])
|> Map.put(:errata_from, errataFrom),
cves: cves,
fixes: fixes
fixes: fixes,
affected_packages: affected_packages,
affected_systems: affected_systems
}
end
Loading