feat(advisory): implement CSAF Overview tab with metadata, charts, refs, and history#1068
feat(advisory): implement CSAF Overview tab with metadata, charts, refs, and history#1068CryptoRodeo wants to merge 4 commits into
Conversation
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
…fs, and history Add CsafOverview component rendering: - Document metadata card (title, tracking ID, status, version, category, publisher, dates, generator, severity, TLP) - Impact summary bar showing CVE count per severity level - Remediation status donut chart (vendor_fix, workaround, etc.) - Document references as clickable external links - Revision history with version, date, and summary - Document-level notes with category headings All sections gracefully handle missing/empty optional CSAF fields. Implements TC-4620 Assisted-by: Claude Code
Reviewer's GuideImplements a CSAF-specific advisory details experience by adding a typed CSAF model, a new CSAF tabbed layout, and a CSAF Overview tab that renders document metadata, impact and remediation visualizations, references, revision history, and notes, wired to a new query that fetches and parses the raw CSAF JSON document when an advisory is labeled as CSAF. Sequence diagram for CSAF advisory details loading and overview renderingsequenceDiagram
actor User
participant AdvisoryDetails
participant CsafAdvisoryDetails
participant useFetchAdvisoryCsafById
participant downloadAdvisory
participant CsafOverview
User->>AdvisoryDetails: navigate to advisoryId
AdvisoryDetails->>AdvisoryDetails: check advisory.labels.type
alt isCsaf
AdvisoryDetails->>CsafAdvisoryDetails: render CsafAdvisoryDetails advisoryId
CsafAdvisoryDetails->>useFetchAdvisoryCsafById: useFetchAdvisoryCsafById id
useFetchAdvisoryCsafById->>downloadAdvisory: downloadAdvisory { client, path.key }
downloadAdvisory-->>useFetchAdvisoryCsafById: Blob
useFetchAdvisoryCsafById->>useFetchAdvisoryCsafById: blob.text()
useFetchAdvisoryCsafById->>useFetchAdvisoryCsafById: JSON.parse(text) as CsafDocument
useFetchAdvisoryCsafById-->>CsafAdvisoryDetails: csafDocument
CsafAdvisoryDetails->>CsafOverview: render CsafOverview csafDocument
else nonCsaf
AdvisoryDetails->>AdvisoryDetails: render Tabs Overview Vulnerabilities
end
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 3 issues, and left some high level feedback:
- In
CsafAdvisoryDetails, the tab content refs are created withReact.createRef()inside the component body, which recreates them on every render; switch these touseRefto keep stable refs across renders. - The new dependencies
echartsandecharts-for-reactare added toclient/package.jsonbut not used anywhere in the diff; consider removing them until they are actually needed. - In
useFetchAdvisoryCsafById,JSON.parseis called directly on the downloaded text without error handling; consider wrapping parsing in a try/catch and surfacing a clearer error if the payload is not valid CSAF JSON.
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; switch these to `useRef` to keep stable refs across renders.
- The new dependencies `echarts` and `echarts-for-react` are added to `client/package.json` but not used anywhere in the diff; consider removing them until they are actually needed.
- In `useFetchAdvisoryCsafById`, `JSON.parse` is called directly on the downloaded text without error handling; consider wrapping parsing in a try/catch and surfacing a clearer error if the payload is not valid CSAF JSON.
## Individual Comments
### Comment 1
<location path="client/src/app/pages/advisory-details/advisory-details.tsx" line_range="92" />
<code_context>
useDeleteAdvisoryMutation(onDeleteAdvisorySuccess, onDeleteAdvisoryError);
- // Tabs
+ const isCsaf = advisory?.labels.type === "csaf";
+
+ // Tabs (default non-CSAF layout)
</code_context>
<issue_to_address>
**issue (bug_risk):** Use optional chaining on `labels` as well to avoid a runtime error when `labels` is undefined.
`advisory?.labels.type` only protects against `advisory` being undefined. If `labels` itself is undefined/null, `.type` will still throw. Updating this to `advisory?.labels?.type === "csaf"` ensures the check is safe even when `labels` is missing.
</issue_to_address>
### Comment 2
<location path="client/src/app/pages/advisory-details/csaf-advisory-details.tsx" line_range="58-62" />
<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>
**suggestion (bug_risk):** Use `useRef` instead of `React.createRef` inside a function component to keep tab refs stable across renders.
Using `React.createRef` in a function component recreates the refs on every render, which can break components (e.g. PatternFly Tabs) that rely on stable refs for focus/scroll behavior. Switching to `const overviewTabRef = React.useRef<HTMLElement>(null);` (and similarly for the others) keeps each ref stable for the component’s lifetime.
Suggested implementation:
```typescript
const overviewTabRef = React.useRef<HTMLElement>(null);
const vulnerabilitiesTabRef = React.useRef<HTMLElement>(null);
const productTreeTabRef = React.useRef<HTMLElement>(null);
const relationshipTreeTabRef = React.useRef<HTMLElement>(null);
const sourceTabRef = React.useRef<HTMLElement>(null);
```
No further changes are required as long as `React` is already imported (which it is, since `React.createRef` was used). Any usage of these refs (e.g. passing them as `ref={overviewTabRef}`) will continue to work without modification.
</issue_to_address>
### Comment 3
<location path="client/src/app/pages/advisory-details/csaf-overview.tsx" line_range="177-189" />
<code_context>
+ </DescriptionListDescription>
+ </DescriptionListGroup>
+ )}
+ {doc.aggregate_severity && (
+ <DescriptionListGroup>
+ <DescriptionListTerm>Severity</DescriptionListTerm>
+ <DescriptionListDescription>
+ <SeverityShieldAndText
+ value={
+ doc.aggregate_severity.text.toLowerCase() as
+ | "critical"
+ | "important"
+ | "moderate"
+ | "low"
+ | "none"
+ }
+ score={null}
+ />
+ </DescriptionListDescription>
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Explicitly map CSAF severities to the `SeverityShieldAndText` accepted values instead of relying on a cast.
`doc.aggregate_severity.text.toLowerCase()` is being asserted as `"critical" | "important" | "moderate" | "low" | "none"`, but CSAF severities can differ (e.g. `"high"`, `"medium"`). This may pass unsupported values to `SeverityShieldAndText` at runtime. Please add an explicit mapping (e.g. `high → important`, `medium → moderate`, defaulting to `"none"`) instead of using a type assertion.
```suggestion
<DescriptionListDescription>
<SeverityShieldAndText
value={(() => {
const normalized = doc.aggregate_severity.text
.toLowerCase()
.trim();
switch (normalized) {
case "critical":
return "critical";
case "high":
return "important";
case "medium":
case "moderate":
return "moderate";
case "low":
return "low";
case "none":
return "none";
default:
return "none";
}
})()}
score={null}
/>
</DescriptionListDescription>
```
</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 #1068 +/- ##
==========================================
- Coverage 49.17% 48.37% -0.81%
==========================================
Files 253 255 +2
Lines 5499 5588 +89
Branches 1660 1700 +40
==========================================
- Hits 2704 2703 -1
- Misses 2519 2610 +91
+ Partials 276 275 -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:
|
… casts Change 'important'/'moderate' to 'high'/'medium' in SeverityShieldAndText value casts to match the actual Severity type union from the generated API client. Implements TC-4620 Assisted-by: Claude Code
Verification Report for TC-4620 (commit 9fe6d4a)
Overall: PASSThis comment was AI-generated by sdlc-workflow/verify-pr v0.9.1. |
Summary
CsafOverviewcomponent with document metadata card (title, tracking ID, status, version, category, publisher, dates, generator, severity, TLP)ChartDonut(vendor_fix, workaround, etc.)Test plan
npm run build -w client)Implements TC-4620
Assisted-by: Claude Code
Summary by Sourcery
Introduce a CSAF-specific advisory details view with a new overview tab and supporting CSAF data types.
New Features:
Enhancements:
Build: