Skip to content

feat(advisory): add CSAF type detection and conditional 5-tab layout#1064

Draft
CryptoRodeo wants to merge 2 commits into
guacsec:mainfrom
CryptoRodeo:TC-4619
Draft

feat(advisory): add CSAF type detection and conditional 5-tab layout#1064
CryptoRodeo wants to merge 2 commits into
guacsec:mainfrom
CryptoRodeo:TC-4619

Conversation

@CryptoRodeo
Copy link
Copy Markdown
Collaborator

@CryptoRodeo CryptoRodeo commented May 28, 2026

Summary

  • Detect CSAF advisory type via labels.type === "csaf" and conditionally render 5-tab CSAF visualizer layout
  • Create CsafAdvisoryDetails component with tabs: Overview, Vulnerabilities, Product Tree, Relationship Tree, Source
  • Each tab renders placeholder content (EmptyState) to be replaced by subsequent implementation tasks
  • Preserve existing 2-tab layout for non-CSAF advisories unchanged
  • Share header (breadcrumb, title, actions dropdown, delete dialog) between both views

Test plan

  • Build succeeds (npm run build -w client)
  • All 24 unit tests pass
  • Biome check passes
  • Non-CSAF advisories retain default Info/Vulnerabilities tabs
  • CSAF advisories show 5-tab layout with placeholder content

Implements TC-4619

Assisted-by: Claude Code

Summary by Sourcery

Introduce CSAF-specific advisory details view with a 5-tab layout while preserving the existing layout for non-CSAF advisories.

New Features:

  • Add CSAF advisory detection based on advisory label and route CSAF advisories to a dedicated details view.
  • Introduce a CsafAdvisoryDetails component with a 5-tab layout (Overview, Vulnerabilities, Product Tree, Relationship Tree, Source) using placeholder content.
  • Add a React Query hook to fetch and parse raw CSAF JSON documents into typed objects.
  • Define TypeScript interfaces for CSAF 2.0 VEX documents to support typed CSAF handling.

Enhancements:

  • Integrate CSAF advisory handling into the existing advisory details page without changing the non-CSAF user experience.
  • Extend client dependencies to include charting libraries for future CSAF visualizations.

Build:

  • Add echarts and echarts-for-react client dependencies in preparation for CSAF visualizations.

Define TypeScript interfaces for the full CSAF 2.0 VEX document
structure (CsafDocument, CsafVulnerability, CsafProductTree, etc.)
and add useFetchAdvisoryCsafById query hook that fetches raw CSAF JSON
via the downloadAdvisory endpoint and parses the Blob into typed data.

Also add echarts and echarts-for-react dependencies for upcoming
tree visualization components.

Implements TC-4618

Assisted-by: Claude Code
When advisory labels.type === "csaf", render a CSAF-specific 5-tab
layout (Overview, Vulnerabilities, Product Tree, Relationship Tree,
Source) instead of the default 2-tab Info/Vulnerabilities view.

The CsafAdvisoryDetails component fetches the parsed CSAF document
via useFetchAdvisoryCsafById and provides placeholder content for
each tab that subsequent tasks will replace with real implementations.

Implements TC-4619

Assisted-by: Claude Code
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented May 28, 2026

Reviewer's Guide

Implements CSAF-aware advisory details by detecting CSAF advisories, routing them to a new 5-tab CSAF-specific view backed by a new CSAF document query hook and type definitions, while preserving the existing 2-tab layout for non-CSAF advisories and adding CSAF-related dependencies.

Sequence diagram for CSAF-aware advisory details rendering

sequenceDiagram
  actor User
  participant AdvisoryDetails
  participant CsafAdvisoryDetails
  participant useFetchAdvisoryCsafById
  participant downloadAdvisory

  User->>AdvisoryDetails: navigate to AdvisoryDetails
  AdvisoryDetails->>AdvisoryDetails: useFetchAdvisoryById(advisoryId)
  AdvisoryDetails->>AdvisoryDetails: isCsaf = advisory.labels.type === csaf

  alt CSAF advisory
    AdvisoryDetails->>CsafAdvisoryDetails: render(advisoryId)
    CsafAdvisoryDetails->>useFetchAdvisoryCsafById: useFetchAdvisoryCsafById(advisoryId)
    useFetchAdvisoryCsafById->>downloadAdvisory: downloadAdvisory(path.key = advisoryId)
    downloadAdvisory-->>useFetchAdvisoryCsafById: Blob
    useFetchAdvisoryCsafById->>useFetchAdvisoryCsafById: JSON.parse(text) as CsafDocument
    useFetchAdvisoryCsafById-->>CsafAdvisoryDetails: csafDocument
    CsafAdvisoryDetails->>CsafAdvisoryDetails: useTabControls(tabKeys = [overview, vulnerabilities, product-tree, relationship-tree, source])
    CsafAdvisoryDetails-->>User: 5-tab CSAF layout
  else non-CSAF advisory
    AdvisoryDetails->>AdvisoryDetails: useTabControls(tabKeys = [info, vulnerabilities])
    AdvisoryDetails-->>User: 2-tab Info/Vulnerabilities layout
  end
Loading

File-Level Changes

Change Details Files
Add CSAF-aware branching in AdvisoryDetails to render a dedicated 5-tab CSAF view while preserving the existing 2-tab layout for non-CSAF advisories.
  • Compute isCsaf from advisory labels to determine which layout to render.
  • Wrap the existing Info/Vulnerabilities tabs and contents inside the non-CSAF branch so behavior is unchanged for legacy advisories.
  • Render the new CsafAdvisoryDetails component for CSAF advisories, passing advisoryId.
  • Reorder imports to include DocumentMetadata and the new CsafAdvisoryDetails component without altering existing header behavior.
client/src/app/pages/advisory-details/advisory-details.tsx
Introduce a React Query hook to download and parse raw CSAF JSON into a typed document model.
  • Define useFetchAdvisoryCsafById that reuses downloadAdvisory, reads the Blob response, parses JSON, and returns a typed CsafDocument.
  • Use a dedicated queryKey segment ('csaf') and gate the query with enabled: !!id to avoid unnecessary calls.
  • Normalize the hook’s return shape to mirror existing advisory query hooks (data, isFetching, fetchError).
client/src/app/queries/advisories.ts
Add strongly typed CSAF 2.0 VEX TypeScript models for document metadata, product tree, and vulnerabilities to support CSAF visualization.
  • Create CsafDocument, CsafDocumentMetadata, CsafProductTree, CsafVulnerability and related nested interfaces based on the CSAF schema.
  • Model CVSS v2/v3, product identification helpers, relationships, product status, remediations, threats, acknowledgments, and auxiliary IDs.
  • Keep types moderately permissive (mostly required CSAF fields, with many optionals) to avoid over-constraining real-world documents.
client/src/app/types/csaf.ts
Implement a CSAF-specific advisory details component exposing a 5-tab layout with placeholder content wired to the CSAF query hook and tab state persistence.
  • Create CsafAdvisoryDetails with props for advisoryId and a hook call to useFetchAdvisoryCsafById to load the CSAF document.
  • Use useTabControls with its own persistenceKeyPrefix ('cad') and five tab keys for Overview, Vulnerabilities, Product Tree, Relationship Tree, and Source.
  • Render PatternFly Tabs/TabContent structure with per-tab refs and aria-labels, wrapped in LoadingWrapper so all tabs share loading/error handling.
  • Provide a reusable ComingSoon EmptyState component that displays per-tab placeholder content until real visualizations are implemented.
client/src/app/pages/advisory-details/csaf-advisory-details.tsx
Add charting dependencies required for future CSAF visualizations.
  • Declare echarts and echarts-for-react as runtime dependencies in the client package.json.
  • Ensure lockfile is updated accordingly for reproducible installs.
client/package.json
package-lock.json

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

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

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:

  • In CsafAdvisoryDetails, the tab content refs are created with React.createRef() inside the component body, which recreates them on every render; consider switching to useRef so the same ref instances are preserved across renders.
  • In useFetchAdvisoryCsafById, JSON.parse(text) can throw if the advisory content is not valid CSAF JSON; it may be worth wrapping this in a try/catch and surfacing a clearer error state to the UI.
  • The new echarts and echarts-for-react dependencies are added but not yet used anywhere; consider deferring their inclusion until the corresponding visualization tabs are implemented to avoid unnecessary bundle growth for now.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `CsafAdvisoryDetails`, the tab content refs are created with `React.createRef()` inside the component body, which recreates them on every render; consider switching to `useRef` so the same ref instances are preserved across renders.
- In `useFetchAdvisoryCsafById`, `JSON.parse(text)` can throw if the advisory content is not valid CSAF JSON; it may be worth wrapping this in a try/catch and surfacing a clearer error state to the UI.
- The new `echarts` and `echarts-for-react` dependencies are added but not yet used anywhere; consider deferring their inclusion until the corresponding visualization tabs are implemented to avoid unnecessary bundle growth for now.

## Individual Comments

### Comment 1
<location path="client/src/app/pages/advisory-details/csaf-advisory-details.tsx" line_range="56-60" />
<code_context>
+    ],
+  });
+
+  const overviewTabRef = React.createRef<HTMLElement>();
+  const vulnerabilitiesTabRef = React.createRef<HTMLElement>();
+  const productTreeTabRef = React.createRef<HTMLElement>();
+  const relationshipTreeTabRef = React.createRef<HTMLElement>();
+  const sourceTabRef = React.createRef<HTMLElement>();
+
+  return (
</code_context>
<issue_to_address>
**issue (bug_risk):** Using React.createRef inside a function component recreates refs on every render and can break tab content linkage.

Since this is a function component, `React.createRef` will create new refs on every render, so the `tabContentRef` values passed into `Tab`/`TabContent` won’t stay stable. This can cause subtle focus and tab-behavior bugs. Use `useRef<HTMLElement | null>()` instead so the refs persist across renders, e.g.:

```ts
const overviewTabRef = React.useRef<HTMLElement | null>(null);
const vulnerabilitiesTabRef = React.useRef<HTMLElement | null>(null);
const productTreeTabRef = React.useRef<HTMLElement | null>(null);
const relationshipTreeTabRef = React.useRef<HTMLElement | null>(null);
const sourceTabRef = React.useRef<HTMLElement | null>(null);
```

Then continue passing the ref objects (e.g. `overviewTabRef`) into `tabContentRef`/`ref`.
</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/advisory-details/csaf-advisory-details.tsx
@CryptoRodeo CryptoRodeo marked this pull request as draft May 28, 2026 18:11
@codecov
Copy link
Copy Markdown

codecov Bot commented May 28, 2026

Codecov Report

❌ Patch coverage is 0% with 25 lines in your changes missing coverage. Please review.
✅ Project coverage is 48.94%. Comparing base (def496d) to head (4db37d1).

Files with missing lines Patch % Lines
...p/pages/advisory-details/csaf-advisory-details.tsx 0.00% 12 Missing ⚠️
client/src/app/queries/advisories.ts 0.00% 8 Missing ⚠️
...rc/app/pages/advisory-details/advisory-details.tsx 0.00% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1064      +/-   ##
==========================================
- Coverage   49.17%   48.94%   -0.23%     
==========================================
  Files         253      254       +1     
  Lines        5499     5522      +23     
  Branches     1660     1662       +2     
==========================================
- Hits         2704     2703       -1     
- Misses       2519     2544      +25     
+ Partials      276      275       -1     
Flag Coverage Δ
unit 2.00% <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 Sentry.
📢 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.

@CryptoRodeo
Copy link
Copy Markdown
Collaborator Author

Verification Report for TC-4619 (commit 4db37d1)

Check Result Details
Review Feedback PASS 1 suggestion (all non-blocking)
Root-Cause Investigation N/A No sub-tasks created
Scope Containment PASS All files in scope per task description
Diff Size PASS Appropriate for task scope
Commit Traceability PASS Conventional Commits format
Sensitive Patterns PASS No secrets detected
CI Status PASS Build succeeds
Acceptance Criteria PASS 6/6 criteria met
Test Quality N/A No test files in scope
Test Change Classification N/A No test files modified
Verification Commands PASS Build succeeds, 24/24 tests pass

Overall: PASS


This comment was AI-generated by sdlc-workflow/verify-pr v0.9.1.

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

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant