From b64144ccd8cb7a7431be83a9770db2b61a50a94e Mon Sep 17 00:00:00 2001 From: Carlos Feria Date: Fri, 28 Jun 2024 11:22:42 +0200 Subject: [PATCH] feat: add vulnerabilities by package (#81) --- client/src/app/api/models.ts | 10 ++ client/src/app/components/LoadingWrapper.tsx | 6 +- .../pages/package-details/package-details.tsx | 21 +--- ...ves.tsx => vulnerabilities-by-package.tsx} | 96 +++++++++---------- client/src/app/queries/packages.ts | 2 +- 5 files changed, 66 insertions(+), 69 deletions(-) rename client/src/app/pages/package-details/{related-cves.tsx => vulnerabilities-by-package.tsx} (53%) diff --git a/client/src/app/api/models.ts b/client/src/app/api/models.ts index ea3ba7a3..a685406f 100644 --- a/client/src/app/api/models.ts +++ b/client/src/app/api/models.ts @@ -76,6 +76,15 @@ export interface AdvisoryWithinVulnerability { } } +export interface AdvisoryWithinPackage { + status: { + status: string, + vulnerability: { + identifier: string + } + }[] +} + // Vulnerability export interface Vulnerability { @@ -106,6 +115,7 @@ export interface VulnerabilityWithinAdvisory { export interface Package { uuid: string; purl: string; + advisories?: AdvisoryWithinPackage[] } export interface PackageWithinSBOM { diff --git a/client/src/app/components/LoadingWrapper.tsx b/client/src/app/components/LoadingWrapper.tsx index 19b69510..2c1e97e7 100644 --- a/client/src/app/components/LoadingWrapper.tsx +++ b/client/src/app/components/LoadingWrapper.tsx @@ -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; @@ -14,7 +16,7 @@ export const LoadingWrapper = (props: { ); } else if (props.fetchError) { - return ; + return ; } else { return props.children; } diff --git a/client/src/app/pages/package-details/package-details.tsx b/client/src/app/pages/package-details/package-details.tsx index 9521c759..63cb5924 100644 --- a/client/src/app/pages/package-details/package-details.tsx +++ b/client/src/app/pages/package-details/package-details.tsx @@ -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); @@ -60,17 +60,11 @@ export const PackageDetails: React.FC = () => { actionButtons={[]} tabs={[ { - eventKey: "cves", - title: "CVEs", + eventKey: "vulnerabilities", + title: "Vulnerabilities", children: (
- - {/* {pkg && } */} -

issue-412

-
+ {packageId && }
), }, @@ -79,12 +73,7 @@ export const PackageDetails: React.FC = () => { title: "SBOMs", children: (
- - {packageId && } - + {packageId && }
), }, diff --git a/client/src/app/pages/package-details/related-cves.tsx b/client/src/app/pages/package-details/vulnerabilities-by-package.tsx similarity index 53% rename from client/src/app/pages/package-details/related-cves.tsx rename to client/src/app/pages/package-details/vulnerabilities-by-package.tsx index 71c4cd3e..fdc05cb8 100644 --- a/client/src/app/pages/package-details/related-cves.tsx +++ b/client/src/app/pages/package-details/vulnerabilities-by-package.tsx @@ -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 = ({ cves }) => { +export const VulnerabilitiesByPackage: React.FC = ({ 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, @@ -69,7 +84,7 @@ export const RelatedCVEs: React.FC = ({ cves }) => { @@ -77,54 +92,35 @@ export const RelatedCVEs: React.FC = ({ cves }) => { - +
- {currentPageItems?.map((item) => { + {currentPageItems?.map((item, rowIndex) => { return ( - + - - - - + + ); @@ -132,7 +128,7 @@ export const RelatedCVEs: React.FC = ({ cves }) => {
- - -
- - {item.identifier} - - - {/* {item.description} */} - - - - {/* {formatDate(item.published)} */} - missing - + + {item.identifier} + +
{ const { data, isLoading, error } = useQuery({ - queryKey: [, id], + queryKey: [PackagesQueryKey, id], queryFn: () => id === undefined ? Promise.resolve(undefined) : getPackageById(id), });