Skip to content

Commit

Permalink
feat: add vulnerabilities by package (#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
carlosthe19916 authored Jun 28, 2024
1 parent 8d5f23a commit b64144c
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 69 deletions.
10 changes: 10 additions & 0 deletions client/src/app/api/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ export interface AdvisoryWithinVulnerability {
}
}

export interface AdvisoryWithinPackage {
status: {
status: string,
vulnerability: {
identifier: string
}
}[]
}

// Vulnerability

export interface Vulnerability {
Expand Down Expand Up @@ -106,6 +115,7 @@ export interface VulnerabilityWithinAdvisory {
export interface Package {
uuid: string;
purl: string;
advisories?: AdvisoryWithinPackage[]
}

export interface PackageWithinSBOM {
Expand Down
6 changes: 4 additions & 2 deletions client/src/app/components/LoadingWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from "react";
import ErrorState from "@patternfly/react-component-groups/dist/esm/ErrorState";

import { Bullseye, Spinner } from "@patternfly/react-core";

import { StateError } from "./StateError";

export const LoadingWrapper = (props: {
isFetching: boolean;
fetchError?: Error;
Expand All @@ -14,7 +16,7 @@ export const LoadingWrapper = (props: {
</Bullseye>
);
} else if (props.fetchError) {
return <ErrorState errorTitle="Error" />;
return <StateError />;
} else {
return props.children;
}
Expand Down
21 changes: 5 additions & 16 deletions client/src/app/pages/package-details/package-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import {
import DetailsPage from "@patternfly/react-component-groups/dist/dynamic/DetailsPage";

import { PathParam, useRouteParams } from "@app/Routes";
import { LoadingWrapper } from "@app/components/LoadingWrapper";
import { useFetchPackageById } from "@app/queries/packages";
import { decomposePurl } from "@app/utils/utils";

import { SbomsByPackage } from "./sboms-by-package";
import { VulnerabilitiesByPackage } from "./vulnerabilities-by-package";

export const PackageDetails: React.FC = () => {
const packageId = useRouteParams(PathParam.PACKAGE_ID);
Expand Down Expand Up @@ -60,17 +60,11 @@ export const PackageDetails: React.FC = () => {
actionButtons={[]}
tabs={[
{
eventKey: "cves",
title: "CVEs",
eventKey: "vulnerabilities",
title: "Vulnerabilities",
children: (
<div className="pf-v5-u-m-md">
<LoadingWrapper
isFetching={isFetchingSbom}
fetchError={fetchErrorSbom}
>
{/* {pkg && <RelatedCVEs cves={pkg?.related_cves || []} />} */}
<p style={{ color: "red" }}>issue-412</p>
</LoadingWrapper>
{packageId && <VulnerabilitiesByPackage packageId={packageId} />}
</div>
),
},
Expand All @@ -79,12 +73,7 @@ export const PackageDetails: React.FC = () => {
title: "SBOMs",
children: (
<div className="pf-v5-u-m-md">
<LoadingWrapper
isFetching={isFetchingSbom}
fetchError={fetchErrorSbom}
>
{packageId && <SbomsByPackage packageId={packageId} />}
</LoadingWrapper>
{packageId && <SbomsByPackage packageId={packageId} />}
</div>
),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,46 @@ import { NavLink } from "react-router-dom";
import { Toolbar, ToolbarContent, ToolbarItem } from "@patternfly/react-core";
import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";

import { VulnerabilityWithinAdvisory } from "@app/api/models";
import { FilterToolbar, FilterType } from "@app/components/FilterToolbar";
import { SeverityShieldAndText } from "@app/components/SeverityShieldAndText";
import { SimplePagination } from "@app/components/SimplePagination";
import {
ConditionalTableBody,
TableHeaderContentWithControls,
ConditionalTableBody,
TableHeaderContentWithControls,
TableRowContentWithControls,
} from "@app/components/TableControls";
import { useLocalTableControls } from "@app/hooks/table-controls";
import { useFetchPackageById } from "@app/queries/packages";
import { useWithUiId } from "@app/utils/query-utils";

interface RelatedCVEsProps {
cves: VulnerabilityWithinAdvisory[];
interface VulnerabilitiesByPackageProps {
packageId: string;
}

export const RelatedCVEs: React.FC<RelatedCVEsProps> = ({ cves }) => {
export const VulnerabilitiesByPackage: React.FC<VulnerabilitiesByPackageProps> = ({ packageId }) => {
const {
pkg,
isFetching: isFetching,
fetchError: fetchError,
} = useFetchPackageById(packageId);

const tableData = React.useMemo(() => {
return (pkg?.advisories ?? []).flatMap(advisory => {
return advisory.status.map(status => ({ identifier: status.vulnerability.identifier }))
})
}, [pkg]);

const tableDataWithUiId = useWithUiId(
tableData,
(d) => `${d.identifier}-${Math.floor(Math.random() * 10000)}`
);

const tableControls = useLocalTableControls({
tableName: "cves-table",
idProperty: "identifier",
items: cves,
tableName: "vulnerability-table",
idProperty: "_ui_unique_id",
items: tableDataWithUiId,
isLoading: false,
columnNames: {
id: "ID",
description: "Description",
severity: "Severity",
datePublished: "Date published",
},
hasActionsColumn: true,
isSortEnabled: false,
Expand Down Expand Up @@ -69,70 +84,51 @@ export const RelatedCVEs: React.FC<RelatedCVEsProps> = ({ cves }) => {
<FilterToolbar showFiltersSideBySide {...filterToolbarProps} />
<ToolbarItem {...paginationToolbarItemProps}>
<SimplePagination
idPrefix="cves-table"
idPrefix="vulnerability-table"
isTop
paginationProps={paginationProps}
/>
</ToolbarItem>
</ToolbarContent>
</Toolbar>

<Table {...tableProps} aria-label="CVEs table">
<Table {...tableProps} aria-label="vulnerability table">
<Thead>
<Tr>
<TableHeaderContentWithControls {...tableControls}>
<Th {...getThProps({ columnKey: "id" })} />
<Th {...getThProps({ columnKey: "description" })} />
<Th {...getThProps({ columnKey: "severity" })} />
<Th {...getThProps({ columnKey: "datePublished" })} />
</TableHeaderContentWithControls>
</Tr>
</Thead>
<ConditionalTableBody
isLoading={false}
isError={undefined}
isNoData={cves.length === 0}
isLoading={isFetching}
isError={!!fetchError}
isNoData={tableDataWithUiId.length === 0}
numRenderedColumns={numRenderedColumns}
>
{currentPageItems?.map((item) => {
{currentPageItems?.map((item, rowIndex) => {
return (
<Tbody key={item.identifier}>
<Tbody key={item._ui_unique_id}>
<Tr {...getTrProps({ item })}>
<Td width={15} {...getTdProps({ columnKey: "id" })}>
<NavLink to={`/cves/${item.identifier}`}>
{item.identifier}
</NavLink>
</Td>
<Td
width={50}
modifier="truncate"
{...getTdProps({ columnKey: "description" })}
>
{/* {item.description} */}
</Td>
<Td
width={15}
modifier="truncate"
{...getTdProps({ columnKey: "severity" })}
>
<SeverityShieldAndText value={item.severity} />
</Td>
<Td
width={15}
modifier="truncate"
{...getTdProps({ columnKey: "datePublished" })}
<TableRowContentWithControls
{...tableControls}
item={item}
rowIndex={rowIndex}
>
{/* {formatDate(item.published)} */}
missing
</Td>
<Td width={15} {...getTdProps({ columnKey: "id" })}>
<NavLink to={`/vulnerabilities/${item.identifier}`}>
{item.identifier}
</NavLink>
</Td>
</TableRowContentWithControls>
</Tr>
</Tbody>
);
})}
</ConditionalTableBody>
</Table>
<SimplePagination
idPrefix="cves-table"
idPrefix="vulnerability-table"
isTop={false}
isCompact
paginationProps={paginationProps}
Expand Down
2 changes: 1 addition & 1 deletion client/src/app/queries/packages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const useFetchPackages = (

export const useFetchPackageById = (id?: number | string) => {
const { data, isLoading, error } = useQuery({
queryKey: [, id],
queryKey: [PackagesQueryKey, id],
queryFn: () =>
id === undefined ? Promise.resolve(undefined) : getPackageById(id),
});
Expand Down

0 comments on commit b64144c

Please sign in to comment.