mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-18 06:23:18 +00:00
feat(security): action-posture Security dashboard with exploit intel and triage (#1424)
* feat(security): reframe masthead as action posture, not worst-CVE severity Derive the Security masthead from an action posture (Action needed / Monitoring / Secure / Unknown) instead of raw scanner severity, and label the raw Critical/High counts as scanner detections. "Secure" now means nothing is actionable right now, never a claim that no vulnerabilities exist; Unknown covers a missing scanner or a node with no completed scan. Phase-1 bootstrap: "actionable" is approximated from the overview facts that already exist (fixable findings, secrets, misconfigs); a later phase moves the bucketing to the backend. * feat(security): derive overview action posture from triaged facts Add deriveSecurityPosture as the single bucketing function and extend /security/overview with posture facts (fixableCriticalHigh, dangerousCompose, accepted, rawCritical/rawHigh, plus knownExploited/publiclyExposed placeholders that later phases populate) and the derived posture verb. Suppression- and acknowledgement-aware counts come from one bounded read-time pass over the latest-scan Critical/High findings, grouped per image so the existing read-time filters apply unchanged. The pass is capped and flags posturePartial, so a large node degrades gracefully instead of scanning every detail row. The masthead now prefers the backend posture and keeps the local bootstrap only as a fallback for older remote nodes reached through the proxy. * feat(security): capture Trivy finding enrichment (status, CVSS, vendor, purl, layer) parseTrivyOutput now keeps the per-finding fields Trivy already returns and we previously discarded: Status (fixed / will_not_fix / end_of_life / ...), CVSS (score + vector, preferring the NVD source then falling back), vendor severity, package URL, package path, and layer digest. Persisted on vulnerability_details via additive nullable columns (guarded ALTER), bound null when absent, and carried through the cached-scan reconstruction path. These fields separate scary from exploitable and feed the action posture and the per-finding evidence tags. Field paths verified against Trivy's documented image-scan JSON; covered by parse and insert/read round-trip tests. * feat(security): add CVE exploit-intel service (CISA KEV + FIRST EPSS) Add CveIntelService, a daily background cache of CISA KEV membership and FIRST EPSS scores stored in a new cve_intel table and joined to findings at read time by CVE id (never frozen onto scan rows, so a CVE entering KEV later lights up on scans already stored). EPSS is fetched only for CVE ids present in stored findings, batched; both feeds are best-effort and keep the last cache on failure, so the Security page degrades gracefully offline. Wired into startup/shutdown like the other background services. The overview now counts known-exploited Critical/High findings, and KEV membership escalates posture to Action needed even when no fix is available. A per-instance "Exploit intelligence" toggle on the scanner setup surface lets air-gapped or firewalled hosts disable the outbound fetch; the daily tick keeps running but skips the fetch body when it is off. * feat(security): show per-finding evidence tags (KEV, EPSS, vendor status, CVSS) The vulnerabilities endpoint joins read-time exploit intel (KEV membership and EPSS score) onto each finding by CVE id, and the scan sheet renders evidence tags beside each CVE: known-exploited, EPSS probability, vendor will-not-fix / end-of-life, and the CVSS score. Severity becomes one signal among several so an operator can tell scary from exploitable, with no invented composite score. * feat(security): evolve CVE suppressions into triage decisions Layer a triage status and optional OpenVEX justification onto CVE suppressions. Statuses: needs review / affected / not affected / accepted risk / fixed / false positive / ignored. Dismissing states (not affected, accepted, fixed, false positive, ignored) stop a finding from driving the action posture; needs review and affected stay actionable and are surfaced as counts. Existing rows default to "accepted" (the prior suppress behavior), so nothing changes for them. The overview now reports needsReview / notAffected / accepted as distinct facts derived from the triage status. The decision replicates across the fleet (snapshot + replicated-insert carry status + justification) so a replica's posture matches the control node. The inline suppress dialog gains a triage decision selector; the read-time filter surfaces the status and justification on every finding. * feat(security): export fleet triage decisions as OpenVEX (Admiral) Add an OpenVEX exporter that turns the instance's CVE triage decisions into a standard VEX document (not_affected / fixed / affected / under_investigation, with justifications), and a GET /security/vex/export endpoint to download it. Authoring fleet VEX is a governance capability, so it is gated to Admiral (paid) plus admin, mirroring the SARIF export gate; the Suppressions panel shows an Export VEX action only on Admiral. * docs(security): document action posture, evidence tags, exploit intel, and triage Update the Security page and CVE suppressions docs for the action-posture masthead (scanner detections vs product posture), per-finding evidence tags (KEV / EPSS / CVSS / vendor status), the exploit-intelligence toggle (CISA KEV + FIRST EPSS) on scanner setup, triage decisions layered on suppressions, and OpenVEX export of fleet triage decisions. * test(security): match intel hosts exactly in CveIntelService test Route the fetch stub and its call assertions by exact hostname (www.cisa.gov / api.first.org) instead of a domain substring check. Resolves the js/incomplete-url-substring-sanitization code-scanning alerts on the test's URL routing; behavior is unchanged.
This commit is contained in:
@@ -32,6 +32,7 @@ The dialog has the following fields:
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| **CVE or advisory ID** | Required. Accepts both `CVE-YYYY-NNNN` and `GHSA-xxxx-xxxx-xxxx`. |
|
||||
| **Triage decision** | How the finding was triaged: accepted risk (default), not affected, false positive, fixed, ignored, or needs review, with an optional OpenVEX justification. A decided state (accepted, not affected, false positive, fixed, ignored) stops the finding from driving the action posture; "needs review" keeps it counted but still actionable. |
|
||||
| **Package (optional)** | Leave blank to suppress every occurrence of this CVE across every package, or pin a specific package name (e.g. `openssl`) to narrow the scope. |
|
||||
| **Image pattern (optional)** | Glob applied to image references (`*` matches any sequence, case-sensitive). For example, `lscr.io/linuxserver/*` matches every LinuxServer image, and `*alpine*` matches anything containing `alpine`. Leave blank to apply fleet-wide. |
|
||||
| **Reason** | Required. A short note explaining why the CVE is accepted. Surfaced on every suppressed row and on the hover title in scan results. Do not paste credentials, tokens, or vendor secrets, since reasons replicate fleet-wide. |
|
||||
@@ -94,6 +95,8 @@ To change a suppression's scope (for example, to narrow an image pattern or exte
|
||||
|
||||
Suppressed findings carry through to the [SARIF export](/features/vulnerability-scanning#sarif-export) with a SARIF `suppressions` entry of `kind: external` and `status: accepted`. Code-scanning dashboards that respect SARIF suppressions dismiss those findings with the Reason you recorded.
|
||||
|
||||
Admiral instances can also export the full set of triage decisions as an **OpenVEX** document from the Suppressions panel. Each decision becomes a VEX statement (`not_affected`, `fixed`, `affected`, or `under_investigation`) with its justification, for use with VEX-aware scanners and supply-chain tooling.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<AccordionGroup>
|
||||
|
||||
@@ -12,12 +12,24 @@ The page is organized into tabs.
|
||||
|
||||
## Overview
|
||||
|
||||
The overview opens with a status masthead that reads your worst active severity at a glance,
|
||||
**Secure**, **At risk**, or **Critical**, alongside the critical and high counts and the time of the
|
||||
last successful scan. Below it, a signal rail summarizes the supporting numbers: scanned images,
|
||||
fixable findings, secrets, Compose misconfigurations, stale scans, and failed scans. A status strip
|
||||
shows scanner health (installed source and version, auto-update) and the active node's deploy
|
||||
enforcement posture.
|
||||
The overview opens with a status masthead that reads your **action posture** at a glance, the answer
|
||||
to "what can and should I do right now?":
|
||||
|
||||
- **Action needed**: something concrete to act on, such as a fixable Critical or High finding, a
|
||||
detected secret, a dangerous Compose setting, or a known-exploited (CISA KEV) CVE.
|
||||
- **Monitoring**: Critical or High findings exist, but none are currently actionable (no fix
|
||||
available, or already triaged).
|
||||
- **Secure**: nothing actionable right now. This is never a claim that no vulnerabilities exist.
|
||||
- **Unknown**: the scanner is not installed, or no scan has completed yet.
|
||||
|
||||
Raw Critical and High counts stay visible next to the posture as **scanner detections**, not as the
|
||||
posture itself: a vulnerable component being present is not the same as a reachable, exploitable risk.
|
||||
The masthead carries a standing note to that effect, and posture weighs fix availability, exploit
|
||||
intelligence, and triage decisions rather than raw severity alone.
|
||||
|
||||
Below it, a signal rail summarizes the supporting numbers: scanned images, fixable findings, secrets,
|
||||
Compose misconfigurations, stale scans, and failed scans. A status strip shows scanner health
|
||||
(installed source and version, auto-update) and the active node's deploy enforcement posture.
|
||||
|
||||
If a node does not report an overview (for example an older remote node), the page falls back to a
|
||||
clear "overview unavailable" state and the other tabs keep working.
|
||||
@@ -25,8 +37,10 @@ clear "overview unavailable" state and the other tabs keep working.
|
||||
## Images
|
||||
|
||||
Image findings list every scanned image on the active node with its highest severity. Selecting an
|
||||
image opens the full scan report, where you can review vulnerabilities, suppress a CVE, and export an
|
||||
SBOM.
|
||||
image opens the full scan report, where you can review vulnerabilities, triage a CVE, and export an
|
||||
SBOM. Each finding carries evidence tags so you can tell scary from exploitable at a glance:
|
||||
known-exploited (KEV), EPSS exploitation probability, the CVSS score, and vendor "will not fix"
|
||||
status, alongside whether a fix is available.
|
||||
|
||||
## Compose risks
|
||||
|
||||
@@ -54,6 +68,11 @@ CVE suppressions and misconfiguration acknowledgements are managed here, the sam
|
||||
in Settings. These are governed by the local instance, so this tab is shown when you are on the local
|
||||
node; switch to the local node to manage them.
|
||||
|
||||
Suppressing a CVE records a **triage decision**: accepted risk, not affected, false positive, fixed,
|
||||
ignored, or needs review, with an optional OpenVEX justification. Decided findings stop driving the
|
||||
action posture; a "needs review" decision stays counted but keeps the finding actionable. Admiral
|
||||
instances can export the fleet's triage decisions as an OpenVEX document for use with other tooling.
|
||||
|
||||
## History
|
||||
|
||||
The History tab opens the scan history sheet, listing completed scans grouped by image with search and
|
||||
@@ -66,6 +85,10 @@ Scanner setup manages the Trivy binary for the active node: install the managed
|
||||
a new release is available, and toggle automatic updates. Trivy is installed independently on each
|
||||
node. See [Installing Trivy](/operations/trivy-setup) for the full setup options.
|
||||
|
||||
It also toggles **exploit intelligence**: a daily background fetch of the CISA KEV catalog and FIRST
|
||||
EPSS scores that powers the known-exploited and EPSS evidence tags. It degrades gracefully when
|
||||
offline and can be turned off for air-gapped or firewalled hosts.
|
||||
|
||||
## What stays where
|
||||
|
||||
Resources keeps its per-image severity badges and scan actions, so you can still scan and inspect an
|
||||
|
||||
Reference in New Issue
Block a user