feat(csaf-visualizer): integrated CSAF VEX visualizer#1062
feat(csaf-visualizer): integrated CSAF VEX visualizer#1062carlosthe19916 wants to merge 5 commits into
Conversation
Add echarts and echarts-for-react as dependencies for interactive tree visualizations. Create TypeScript type definitions for the complete CSAF 2.0 document structure and utility functions for product tree traversal and relationship resolution. Implements TC-4598 Assisted-by: Claude Code
… Source tab Add conditional rendering in advisory-details.tsx to show CSAF visualizer tabs when advisory type is "csaf". Create useFetchCsafSource query hook to fetch and parse raw CSAF JSON. Implement Source tab with CodeBlock display and self-reference link. Create placeholder stubs for Overview, Vulnerabilities, Product Tree, and Relationship Tree tabs. Implements TC-4601 Assisted-by: Claude Code
Add document metadata cards (document info, publisher, tracking), impact summary with severity-colored bars, remediation status donut chart, references list, revision history, and notes section. All sections handle missing/optional CSAF fields gracefully. Implements TC-4602 Assisted-by: Claude Code
Add per-CVE cards sorted by CVSS score with severity shield, expandable CVSS v3 breakdown, affected products with "+N more" toggle, remediations with linkified URLs, references, threats, and notes. Includes empty state for advisories with no vulnerabilities. Implements TC-4603 Assisted-by: Claude Code
Add interactive ECharts tree visualizations for CSAF product hierarchy and product relationships. Product Tree shows color-coded nodes by category with auto-collapse for large subtrees. Relationship Tree groups components by target product with color-coded edge styles. Both support zoom, pan, and expand/collapse interactions. Implements TC-4604 Assisted-by: Claude Code
Reviewer's GuideImplements a CSAF-specific advisory visualization experience by introducing a typed CSAF document model, a dedicated CSAF tab container with five tabs, React Query hook to fetch and parse the CSAF source, and multiple PatternFly/ECharts-based views (overview, vulnerabilities, product tree, relationship tree, and source) wired into advisory details for advisories labeled as CSAF. Sequence diagram for CSAF advisory visualization flowsequenceDiagram
actor User
participant AdvisoryDetails
participant CsafAdvisoryTabs
participant useFetchCsafSource
participant downloadAdvisory
participant DocumentOverview
participant VulnerabilitySection
participant ProductsTable
participant RelationshipTree
participant SourceView
User->>AdvisoryDetails: navigate to advisory
AdvisoryDetails->>AdvisoryDetails: load advisory
AdvisoryDetails-->>AdvisoryDetails: advisory.labels.type === csaf
AdvisoryDetails->>CsafAdvisoryTabs: render CsafAdvisoryTabs(advisoryId)
CsafAdvisoryTabs->>useFetchCsafSource: useFetchCsafSource(advisoryId)
useFetchCsafSource->>downloadAdvisory: downloadAdvisory(path: { key: id })
downloadAdvisory-->>useFetchCsafSource: response.data
useFetchCsafSource-->>CsafAdvisoryTabs: { csafDocument, isFetching, fetchError }
CsafAdvisoryTabs-->>DocumentOverview: csafDocument (Overview tab)
CsafAdvisoryTabs-->>VulnerabilitySection: csafDocument (Vulnerabilities tab)
CsafAdvisoryTabs-->>ProductsTable: csafDocument (Product Tree tab)
CsafAdvisoryTabs-->>RelationshipTree: csafDocument (Relationship Tree tab)
CsafAdvisoryTabs-->>SourceView: csafDocument (Source tab)
User-->>CsafAdvisoryTabs: switch tabs
CsafAdvisoryTabs-->>User: render selected CSAF view
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In
VulnerabilitySection.LinkifiedText, using a globalURL_REGEXwithRegExp.testinside themapwill mutatelastIndexand lead to intermittent failures to detect URLs; consider either removing thegflag and usingtest, or precomputing which segments are URLs (e.g., viaparts.map((part, i) => ({ part, isUrl: URL_REGEX_NO_G.test(part) }))). - In
CsafAdvisoryTabs, the tab content refs are created withReact.createRef()inside the component body, which recreates them on every render; switch these touseRefhooks so the same ref objects are preserved across renders and to avoid subtle focus or mount issues. - In
useFetchCsafSource, theJSON.parsecall onrawDatais not guarded and will throw if the backend ever returns invalid JSON or an unexpected type; consider wrapping parsing in a try/catch and surfacing a controlled error state instead of crashing the component tree.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `VulnerabilitySection.LinkifiedText`, using a global `URL_REGEX` with `RegExp.test` inside the `map` will mutate `lastIndex` and lead to intermittent failures to detect URLs; consider either removing the `g` flag and using `test`, or precomputing which segments are URLs (e.g., via `parts.map((part, i) => ({ part, isUrl: URL_REGEX_NO_G.test(part) }))`).
- In `CsafAdvisoryTabs`, the tab content refs are created with `React.createRef()` inside the component body, which recreates them on every render; switch these to `useRef` hooks so the same ref objects are preserved across renders and to avoid subtle focus or mount issues.
- In `useFetchCsafSource`, the `JSON.parse` call on `rawData` is not guarded and will throw if the backend ever returns invalid JSON or an unexpected type; consider wrapping parsing in a try/catch and surfacing a controlled error state instead of crashing the component tree.
## Individual Comments
### Comment 1
<location path="client/src/app/pages/csaf-visualizer/components/VulnerabilitySection.tsx" line_range="49-56" />
<code_context>
+ none_available: "None Available",
+};
+
+const URL_REGEX = /(https?:\/\/[^\s<]+)/g;
+
+/** Renders text with URLs auto-linkified. */
+const LinkifiedText: React.FC<{ text: string }> = ({ text }) => {
+ const parts = text.split(URL_REGEX);
+ return (
+ <>
+ {parts.map((part, i) =>
+ URL_REGEX.test(part) ? (
+ <a key={i} href={part} target="_blank" rel="noopener noreferrer">
</code_context>
<issue_to_address>
**issue (bug_risk):** Using a global RegExp with `.test` inside render can skip matches due to `lastIndex` statefulness.
Because `URL_REGEX` is global and reused in the `map`, repeated `.test(part)` calls will mutate `lastIndex` and can cause some URL segments to be missed and not linkified. To avoid this stateful behavior, either use a non-global regex for `test`, construct a fresh `RegExp` before splitting, or replace the regex check with a simple prefix check (e.g. `part.startsWith('http://') || part.startsWith('https://')`) since the split has already isolated URL-like parts.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1062 +/- ##
==========================================
- Coverage 49.15% 47.04% -2.12%
==========================================
Files 253 260 +7
Lines 5499 5782 +283
Branches 1660 1780 +120
==========================================
+ Hits 2703 2720 +17
- Misses 2521 2788 +267
+ Partials 275 274 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| /> | ||
| </TabContent> | ||
| </PageSection> | ||
| {advisory?.labels.type === "csaf" ? ( |
There was a problem hiding this comment.
This should contain a comment with a joke to enhance the quality of the code
There was a problem hiding this comment.
[sdlc-workflow/verify-pr] Classified as nit — this is a minor non-functional suggestion that does not affect correctness or maintainability. No sub-task created.
There was a problem hiding this comment.
If you don't write a joke this can be considered a high critical bug, fix it
| useFetchAdvisoryById, | ||
| } from "@app/queries/advisories"; | ||
|
|
||
| import { CsafAdvisoryTabs } from "./csaf-advisory-tabs"; |
There was a problem hiding this comment.
Add a comment explaining why the import was done. Otherwise this is a potential bug
There was a problem hiding this comment.
[sdlc-workflow/verify-pr] Classified as code change request — sub-task TC-4632 created to address this feedback.
Verification Report for TC-4601 (commit 0432dd8)
Overall: FAILTwo issues require attention before merge:
This comment was AI-generated by sdlc-workflow/verify-pr v0.9.1. |
Verification Report for TC-4601 (commit 0432dd8) — Run 2
Overall: FAILThree blocking sub-tasks must be resolved before merge:
Changes since Run 1: 2 new review comments processed (1 code change request → TC-4632, 1 nit dismissed). Import order convention violation identified ( This comment was AI-generated by sdlc-workflow/verify-pr v0.9.1. |
Verification Report for TC-4601 (commit 0432dd8) — Run 3
Overall: FAILSame commit as Runs 1–2 (0432dd8). No new review comments or code changes. Three blocking sub-tasks remain unresolved:
This comment was AI-generated by sdlc-workflow/verify-pr v0.9.1. |
Summary
labels.type === "csaf"),useFetchCsafSourcequery hook, Source tab with raw JSON display, and placeholder stubs for remaining tabsTest plan
npm run lint -w clientpassesnpm run format -w clientpassesnpm run build -w clientsucceedsImplements TC-4601, TC-4602, TC-4603, TC-4604
🤖 Generated with Claude Code
Summary by Sourcery
Add a CSAF-specific advisory visualization experience with dedicated tabs, leveraging parsed CSAF source data and new charting dependencies.
New Features:
Build:
Tests: