mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-09-03 06:07:58 +00:00
fix: rank exploit-risk findings before the cap and disclose truncation (#1482)
The Security overview's top exploit-risk list is built from a query capped at 2000 rows. The query had no ORDER BY, so when a node had more findings than the cap the rows kept were arbitrary: the list could rank and display a subset that omitted higher-risk findings, and the frontend discarded the truncated flag the endpoint already returned, so nothing told the operator the list was partial. - The query now orders by known-exploited, then EPSS, then CVSS before the cap, so the rows that survive truncation are the highest-risk ones, matching the client-side ranking the list applies. - SecurityView keeps the truncated flag and threads it through to the list, which now shows a short "more exist than can be listed here" note when the set was capped. Also fixes a presentation regression: the list colored every non-Critical severity dot with the High color, so a Medium or Low known-exploited finding (now surfaced alongside Critical/High) showed as High. The dot now maps to the finding's actual severity.
This commit is contained in:
@@ -162,14 +162,29 @@ const EXPLOIT_PAGE_SIZE = 8;
|
||||
// horizontally instead; desktop is untouched by the `max-md:` prefix.
|
||||
const EXPLOIT_GRID = 'grid-cols-[10px_minmax(0,1.4fr)_minmax(0,1fr)_56px_52px] max-md:min-w-[480px]';
|
||||
|
||||
// Per-severity dot color. A KEV finding can now be any severity, so the dot must
|
||||
// reflect the row's real severity rather than collapsing everything non-Critical
|
||||
// to the High color. UNKNOWN gets the neutral subtitle tone (matching SeverityChip),
|
||||
// not the low color, so an UNKNOWN-severity finding is not understated as low risk.
|
||||
const SEV_DOT_VAR: Record<string, string> = {
|
||||
CRITICAL: 'var(--sev-critical)',
|
||||
HIGH: 'var(--sev-high)',
|
||||
MEDIUM: 'var(--sev-medium)',
|
||||
LOW: 'var(--sev-low)',
|
||||
UNKNOWN: 'var(--stat-subtitle)',
|
||||
};
|
||||
|
||||
/** Ranked, paginated table of the highest exploit-risk actionable findings; a row opens the scan.
|
||||
* Renders its own card chrome (header + pagination + column headers) so the Overview reads as a
|
||||
* table, mirroring the dashboard Stack-health table. */
|
||||
export function TopExploitRiskList({
|
||||
items,
|
||||
truncated = false,
|
||||
onInspect,
|
||||
}: {
|
||||
items: ExploitIntelFinding[];
|
||||
/** The backend capped the result; the highest-risk findings are shown, not all. */
|
||||
truncated?: boolean;
|
||||
onInspect: (scanId: number) => void;
|
||||
}) {
|
||||
const [page, setPage] = useState(0);
|
||||
@@ -231,7 +246,7 @@ export function TopExploitRiskList({
|
||||
>
|
||||
<span
|
||||
className="h-[7px] w-[7px] shrink-0 justify-self-center rounded-full"
|
||||
style={{ background: f.severity === 'CRITICAL' ? 'var(--sev-critical)' : 'var(--sev-high)' }}
|
||||
style={{ background: SEV_DOT_VAR[f.severity] ?? 'var(--stat-subtitle)' }}
|
||||
aria-hidden
|
||||
/>
|
||||
<span className="flex min-w-0 items-center gap-1.5">
|
||||
@@ -254,6 +269,11 @@ export function TopExploitRiskList({
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{truncated && (
|
||||
<p className="border-t border-border/40 px-4 py-2 text-[10px] leading-snug text-stat-subtitle">
|
||||
Showing the highest-risk findings; more exist than can be listed here.
|
||||
</p>
|
||||
)}
|
||||
{!anyIntel && (
|
||||
<p className="border-t border-border/40 px-4 py-2 text-[10px] leading-snug text-stat-subtitle">
|
||||
Ranked by severity. Enable exploit intelligence and re-scan to rank by known-exploited and EPSS.
|
||||
|
||||
Reference in New Issue
Block a user