Skip to content

perf: use pre-fetched advisory severity summary on SBOM list#1127

Open
ctron wants to merge 2 commits into
guacsec:mainfrom
ctron:feature/sbom-advisory-summary
Open

perf: use pre-fetched advisory severity summary on SBOM list#1127
ctron wants to merge 2 commits into
guacsec:mainfrom
ctron:feature/sbom-advisory-summary

Conversation

@ctron

@ctron ctron commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Consume the new ?advisories=true query parameter on the SBOM list endpoint to display severity counts per row
  • Eliminates N+1 requests to GET /sbom/{id}/advisory (~4s each) that were made per table row

Dependencies

Depends on backend PR: guacsec/trustify#2437 which adds the ?advisories=true query parameter to GET /v3/sbom.

Changes

  • SbomVulnerabilities.tsx - rewritten to accept pre-fetched advisory summary instead of fetching per row
  • sboms.ts - pass advisories: true in the list query
  • sbom-table.tsx - pass item.advisories to the component instead of item.id
  • sbom-context.ts - add advisories field to the item type
  • types.gen.ts - not committed (gitignored), will be regenerated from the updated OpenAPI spec

Test plan

  • SBOM list page loads severity badges without per-row API calls
  • Severity counts match those from individual GET /sbom/{id}/advisory responses
  • Page load time significantly reduced (from ~40s N+1 to single batch query)

🤖 Generated with Claude Code

Summary by Sourcery

Optimize SBOM list vulnerability display by consuming pre-fetched advisory summaries instead of per-row advisory API calls.

New Features:

  • Display SBOM vulnerability severities from advisory summaries returned by the SBOM list endpoint.

Enhancements:

  • Extend SBOM list items with optional advisory summary data and propagate it through the table context to the vulnerability gallery component.
  • Include the advisories flag in SBOM list queries to retrieve aggregated advisory severity data in a single request.

@sourcery-ai

sourcery-ai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Frontend now consumes pre-fetched advisory severity summaries from the SBOM list API (via the new ?advisories=true parameter) and passes them through context and table components to SBOMVulnerabilities, removing per-row advisory fetches and rendering severity badges directly from the list response.

Sequence diagram for SBOM list advisories prefetch

sequenceDiagram
    actor User
    participant SbomListPage
    participant useFetchSBOMs
    participant Backend as Backend_v3_sbom_API
    participant SbomTable
    participant SBOMVulnerabilities
    participant VulnerabilityGallery

    User ->> SbomListPage: Open SBOM list page
    SbomListPage ->> useFetchSBOMs: useFetchSBOMs(params)
    useFetchSBOMs ->> Backend: GET /v3/sbom?advisories=true
    Backend -->> useFetchSBOMs: SBOM list with advisories
    useFetchSBOMs -->> SbomListPage: items[{ id, advisories, ... }]
    SbomListPage ->> SbomTable: Render with items
    SbomTable ->> SBOMVulnerabilities: SBOMVulnerabilities(advisories)
    SBOMVulnerabilities ->> VulnerabilityGallery: VulnerabilityGallery(severities)
    Note over SBOMVulnerabilities,VulnerabilityGallery: No per-row GET /sbom/{id}/advisory requests
Loading

File-Level Changes

Change Details Files
SBOM vulnerabilities cell now renders from pre-fetched advisory summary instead of performing per-row API calls.
  • Change SBOMVulnerabilities props to accept an optional advisories summary object instead of an SBOM ID.
  • Remove usage of useVulnerabilitiesOfSbom and related loading/error UI, replacing it with a direct call to VulnerabilityGallery.
  • Introduce a DEFAULT_SEVERITIES map keyed by ExtendedSeverity and merge it with the provided advisories before rendering.
client/src/app/pages/sbom-list/components/SbomVulnerabilities.tsx
SBOM list data model and table wiring now carry advisory summaries from the list query into the vulnerabilities cell.
  • Extend the SBOM search/list context item type to include an optional advisories field with type SbomAdvisorySummary.
  • Update the SBOM table to pass item.advisories into SBOMVulnerabilities instead of item.id.
  • Ensure type imports include SbomAdvisorySummary alongside existing SBOM-related types.
client/src/app/pages/sbom-list/sbom-context.ts
client/src/app/pages/sbom-list/sbom-table.tsx
SBOM list query requests advisory summaries in bulk via the new backend flag.
  • Update the useFetchSBOMs query params to include advisories: true so the backend returns advisory severity summaries with each SBOM list item.
client/src/app/queries/sboms.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • Consider explicitly handling the case where item.advisories is undefined or null in SBOMVulnerabilities (e.g., via a fallback UI or prop type refinement) so the table cell behavior is clear when advisory data is missing.
  • The severities object in SBOMVulnerabilities is recreated on every render via object spread; if this component is used in a large table, memoizing or building it earlier (e.g., in the parent or via useMemo) could avoid unnecessary re-renders of VulnerabilityGallery.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider explicitly handling the case where `item.advisories` is `undefined` or `null` in `SBOMVulnerabilities` (e.g., via a fallback UI or prop type refinement) so the table cell behavior is clear when advisory data is missing.
- The `severities` object in `SBOMVulnerabilities` is recreated on every render via object spread; if this component is used in a large table, memoizing or building it earlier (e.g., in the parent or via `useMemo`) could avoid unnecessary re-renders of `VulnerabilityGallery`.

## Individual Comments

### Comment 1
<location path="client/src/app/pages/sbom-list/components/SbomVulnerabilities.tsx" line_range="23" />
<code_context>
+  advisories,
 }) => {
-  const { data, isFetching, fetchError } = useVulnerabilitiesOfSbom(sbomId);
+  const severities = { ...DEFAULT_SEVERITIES, ...advisories };

-  return (
</code_context>
<issue_to_address>
**issue (bug_risk):** Spreading a possibly null/undefined `advisories` object can throw at runtime.

Because `advisories` is now optional (`advisories?: SbomAdvisorySummary | null`), spreading it directly in `{ ...DEFAULT_SEVERITIES, ...advisories }` will throw if it’s `null` or `undefined`. Please guard or default it, e.g. `const severities = { ...DEFAULT_SEVERITIES, ...(advisories ?? {}) };`, or handle the missing data before rendering `VulnerabilityGallery`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread client/src/app/pages/sbom-list/components/SbomVulnerabilities.tsx Outdated
@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 53.27%. Comparing base (681d588) to head (591915b).

Files with missing lines Patch % Lines
client/src/app/components/VulnerabilityGallery.tsx 0.00% 2 Missing ⚠️
...pages/sbom-list/components/SbomVulnerabilities.tsx 0.00% 1 Missing ⚠️
client/src/app/queries/sboms.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1127      +/-   ##
==========================================
- Coverage   53.30%   53.27%   -0.04%     
==========================================
  Files         270      270              
  Lines        5879     5877       -2     
  Branches     1842     1845       +3     
==========================================
- Hits         3134     3131       -3     
- Misses       2443     2444       +1     
  Partials      302      302              
Flag Coverage Δ
unit 7.01% <0.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ctron ctron force-pushed the feature/sbom-advisory-summary branch 2 times, most recently from 503dd23 to 51635f1 Compare July 3, 2026 11:02
Consume the new `?advisories=true` query parameter on the SBOM list
endpoint to display severity counts per row, eliminating N+1 requests
to `GET /sbom/{id}/advisory` (~4s each).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ctron ctron force-pushed the feature/sbom-advisory-summary branch from 51635f1 to c07c1d9 Compare July 3, 2026 13:46

import { LoadingWrapper } from "@app/components/LoadingWrapper";
import { TableCellError } from "@app/components/TableCellError";
import type { SbomAdvisorySummary } from "@app/client";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the SbomAdvisorySummary type in openapi spec, there are only SbomAdvisory (that was used in getSbomAdvisories before) or a new type RequestedField_HashMap_HashMap (as was added in this commit ).

Comment on lines +11 to +23
const DEFAULT_SEVERITIES: { [key in ExtendedSeverity]: number } = {
unknown: 0,
none: 0,
low: 0,
medium: 0,
high: 0,
critical: 0,
};

export const SBOMVulnerabilities: React.FC<SBOMVulnerabilitiesProps> = ({
sbomId,
advisories,
}) => {
const { data, isFetching, fetchError } = useVulnerabilitiesOfSbom(sbomId);
const severities = { ...DEFAULT_SEVERITIES, ...advisories };

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the better pattern would be not to add const DEFAULT_SEVERITIES where everything is equals to zero but to change VulnerabilityGalleryProps from this:

interface VulnerabilityGalleryProps {
  severities: { [key in ExtendedSeverity]: number };
}

To this:

interface VulnerabilityGalleryProps {
  severities: Partial<{ [key in ExtendedSeverity]: number }>;
}

This would let us keep SBOMVulnerabilities component clean and just use it like that:

export const SBOMVulnerabilities: React.FC<SBOMVulnerabilitiesProps> = ({ advisories }) => (
  <VulnerabilityGallery severities={advisories ?? {}} />
);


import type { SbomHead, SourceDocument } from "@app/client";
import type {
SbomAdvisorySummary,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here as in the previous comment

I don't see the SbomAdvisorySummary type in openapi spec, there are only SbomAdvisory (that was used in getSbomAdvisories before) or a new type RequestedField_HashMap_HashMap

@ctron ctron added the backport release/0.5.z This PR should be backported to release/0.5.z branch. label Jul 6, 2026
Use generated RequestedFieldHashMapHashMap type instead of
non-existent SbomAdvisorySummary, make VulnerabilityGallery
accept partial severities, and simplify SBOMVulnerabilities.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ctron

ctron commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@stanislavsemeniuk tried to convince claude to fix the review comments. Maybe you can have another look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport release/0.5.z This PR should be backported to release/0.5.z branch.

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants