Files
git.stella-ops.org/docs/product-advisories/28-Nov-2025 - Vulnerability Triage UX & VEX-First Decisioning.md
StellaOps Bot 2548abc56f
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
up
2025-11-29 01:35:49 +02:00

16 KiB

Vulnerability Triage UX & VEX-First Decisioning

Version: 1.0 Date: 2025-11-28 Status: Canonical

This advisory defines the end-to-end UX and data contracts for vulnerability triage, VEX decisioning, evidence/explainability views, and audit export in Stella Ops. It synthesizes patterns from Snyk, GitLab SCA, Harbor/Trivy, and Anchore Enterprise into a converged UX layer.


1. Scope

This spec covers:

  1. Vulnerability triage (first touch)
  2. Suppression / "Not Affected" (VEX-aligned)
  3. Evidence & explainability views
  4. Audit export (immutable bundles)
  5. Attestations as the backbone of evidence and gating

Stella Ops is the converged UX layer over scanner backends (Snyk, Trivy, GitLab, Anchore, or others).


2. Industry Pattern Analysis

2.1 Triage (First Touch)

Tool Pattern Stella Ops Mirror
Snyk PR checks show before/after diffs; Fix PRs directly from Issues list Evidence-first cards with "Fix PR" CTA
GitLab SCA Vulnerability Report with Needs triage default state Status workflow starting at DETECTED
Harbor/Trivy Project -> Artifacts -> Vulnerabilities panel with Rescan CTA Artifact-centric navigation with scan badges
Anchore Images -> Vulnerabilities aligned to Policies (pass/fail) Policy gate indicators on all finding views

UI pattern to reuse: An evidence-first card per finding (CVE, package, version, path) with primary actions (Fix PR, Dismiss/Not Affected, View Evidence).

2.2 Suppression / "Not Affected" (VEX-Aligned)

Tool Pattern Stella Ops Mirror
Snyk "Ignore" with reason + expiry; org-restricted; PR checks skip ignored VEX statusJustification with validity window
GitLab Dismissed status with required comment; activity log VEX decisions with actor/timestamp/audit trail
Anchore Allowlists + Policy Gates + VEX annotations Allowlist integration + VEX buttons
Harbor/Trivy No native VEX; store as in-toto attestation Attestation-backed VEX decisions

UI pattern to reuse: An Actionable VEX button (Not Affected, Affected - mitigated, Fixed) that opens a compact form: justification, evidence links, scope, expiry -> generates/updates a signed VEX note.

2.3 Evidence View (Explainability)

Tool Pattern Stella Ops Mirror
Snyk PR context + Fix PR evidence + ignore policy display Explainability panel with PR/commit links
GitLab Vulnerability Report hub with lifecycle activity Decision history timeline
Anchore Policy Gates breakdown showing which trigger caused fail/pass Gate evaluation with trigger explanations
Harbor/Trivy Scanner DB date, version, attestation links Scanner metadata + attestation digest

UI pattern to reuse: An Explainability panel on the right: "Why this is flagged / Why it passed" with timestamps, rule IDs, feed freshness, and the Attestation digest.

2.4 Audit Export (Immutable)

Tool Export Contents
Snyk PR check results + Ignore ledger + Fix PRs
GitLab Vulnerability Report with status history
Anchore Policy Bundle eval JSON as primary audit unit
Harbor/Trivy Trivy report + signed attestation

UI pattern to reuse: "Create immutable audit bundle" CTA that writes a ZIP/OCI artifact containing reports, VEX, policy evals, and attestations, plus a top-level manifest with hashes.


3. Core Data Model

3.1 Artifact

Artifact
- id (string, stable)
- type (IMAGE | REPO | SBOM | FUNCTION | HOST)
- displayName
- coordinates (registry/repo URL, tag, branch, env, etc.)
- digests[] (e.g. sha256 for OCI images, commit SHA for repos)
- latestScanAttestations[] (AttestationRef)
- riskSummary (openCount, totalCount, maxSeverity, lastScanAt)

3.2 VulnerabilityFinding

VulnerabilityFinding
- id (string, internal stable ID)
- sourceFindingId (string, from Snyk/Trivy/etc.)
- scanner (name, version)
- artifactId
- vulnerabilityId (CVE, GHSA, etc.)
- title
- severity (CRITICAL | HIGH | MEDIUM | LOW | INFO)
- package (name, version, ecosystem)
- location (filePath, containerLayer, function, callPath[])
- introducedBy (commitId?, imageDigest?, buildId?)
- firstSeenAt
- lastSeenAt
- status (DETECTED | RESOLVED | NO_LONGER_DETECTED)
- currentVexDecisionId? (if a VEX decision is attached)
- evidenceAttestationRefs[] (AttestationRef[])

3.3 VEXDecision

Represents a VEX-style statement attached to a finding + subject.

VEXDecision
- id
- vulnerabilityId (CVE, etc.)
- subject (ArtifactRef / SBOM node ref)
- status (NOT_AFFECTED | AFFECTED_MITIGATED | AFFECTED_UNMITIGATED | FIXED)
- justificationType (enum; see section 7.3)
- justificationText (free text)
- evidenceRefs[] (links to PRs, commits, tickets, docs, etc.)
- scope (envs/projects where this decision applies)
- validFor (notBefore, notAfter?)
- attestationRef? (AttestationRef)
- supersedesDecisionId?
- createdBy (id, displayName)
- createdAt
- updatedAt

3.4 Attestation / AttestationRef

AttestationRef
- id
- type (VULN_SCAN | SBOM | VEX | POLICY_EVAL | OTHER)
- statementId (if DSSE/Intoto)
- subjectName
- subjectDigest (e.g. sha256)
- predicateType (URI)
- createdAt
- signer (name, keyId)
- storage (ociRef | bundlePath | url)

3.5 PolicyEvaluation

PolicyEvaluation
- id
- subject (ArtifactRef)
- policyBundleVersion
- overallResult (PASS | WARN | FAIL)
- gates[] (GateResult)
- attestationRef? (AttestationRef)
- evaluatedAt

3.6 AuditBundle

Represents a downloadable immutable bundle (ZIP or OCI artifact).

AuditBundle
- bundleId
- version
- createdAt
- createdBy
- subject (ArtifactRef)
- index (AuditBundleIndex) <- JSON index inside the bundle

4. Primary UX Surfaces

4.1 Artifacts List

Goal: High-level "what's risky?" view and entry point into triage.

Columns:

  • Artifact
  • Type
  • Environment(s)
  • Open / Total vulns
  • Max severity
  • Attestations (badge w/ count)
  • Last scan (timestamp + scanner)

Actions:

  • View vulnerabilities (primary)
  • View attestations
  • Create audit bundle

4.2 Vulnerability Workspace (per Artifact)

Split layout:

Left: Vulnerability list

  • Filters: severity, status, VEX status, scanner, package, introducedBy, env
  • Sort: severity, recency, package, path
  • Badges for:
    • New (first seen in last N scans)
    • VEX: Not affected
    • Policy: blocked / Policy: allowed

Right: Evidence / Explainability panel

Tabs:

  1. Overview
    • Title, severity, package, version, path
    • Scanner + db date
    • Finding history timeline
    • Current VEX decision summary (if any)
  2. Reachability
    • Call path, modules, runtime usage info (when available)
  3. Policy
    • Policy evaluation: which gate caused pass/fail
    • Links to gate definitions
  4. Attestations
    • All attestations that mention:
      • this artifact
      • this vulnerabilityId
      • this scan result

Primary actions per finding:

  • VEX: Set status -> opens VEX Modal (see 4.3)
  • Open Fix PR / View Fix (if available from Snyk/GitLab)
  • Attach Evidence (link tickets / docs)
  • Copy audit reference (findingId + attestation digest)

4.3 VEX Modal - "Affect & Justification"

Entry points:

  • From a finding row ("VEX" button)
  • From a policy failure explanation
  • From a bulk action on multiple findings

Fields (backed by VEXDecision):

  • Status (radio buttons):
    • Not affected
    • Affected - mitigated
    • Affected - not mitigated
    • Fixed
  • Justification type (select - see section 7.3)
  • Justification text (multi-line)
  • Scope:
    • Environments (multi-select)
    • Projects / services (multi-select)
  • Validity:
    • Start (defaults now)
    • Optional expiry (recommended)
  • Evidence:
    • Add links (PR, ticket, doc, commit)
    • Attach attestation (optional; pick from list)
  • Review:
    • Summary of what will be written to the VEX statement
    • "Will generate signed attestation" note (if enabled)

Actions:

  • Save (creates or updates VEXDecision, writes VEX attestation)
  • Cancel
  • View raw JSON (for power users)

4.4 Attestations View

Per artifact, tab: Attestations

Table of attestations:

  • Type (vuln scan, SBOM, VEX, policy)
  • Subject name (shortened)
  • Predicate type (URI)
  • Scanner / policy engine (derived from predicate)
  • Signer (keyId, trusted/not-trusted badge)
  • Created at
  • Verified (yes/no)

Click to open:

  • Header: statement id, subject, signer
  • Predicate preview:
    • For vuln scan: counts, scanner version, db date
    • For SBOM: bomRef, component counts
    • For VEX: decision status, vulnerabilityId, scope

4.5 Policy & Gating View

Per environment / pipeline:

  • Matrix of gates vs subject types:
    • e.g. CI Build, Registry Admission, Runtime Admission
  • Each gate shows:
    • Rule description (severity thresholds, allowlist usage, required attestations)
    • Last evaluation stats (pass/fail counts)
  • Clicking a gate shows:
    • Recent evaluations (with link to artifact & policy attestation)
    • Which condition failed

4.6 Audit Export - Bundle Creation

From:

  • Artifact page (button: "Create immutable audit bundle")
  • Pipeline run detail
  • Policy evaluation detail

Workflow:

  1. User selects:
    • Subject artifact + digest
    • Time window (e.g. "last 7 days of scans & decisions")
    • Included content (checklist):
      • Vuln reports
      • SBOM
      • VEX decisions
      • Policy evaluations
      • Raw attestations
  2. Backend generates:
    • ZIP or OCI artifact
    • audit-bundle-index.json at root
  3. UI shows:
    • Bundle ID & hash
    • Download button
    • OCI reference (if pushed to registry)

5. State Model

5.1 Finding Status vs VEX Status

Two separate but related states:

Finding.status:

  • DETECTED - currently reported by at least one scanner
  • NO_LONGER_DETECTED - was present, not in latest scan for this subject
  • RESOLVED - confirmed removed (e.g. package upgraded, image replaced)

VEXDecision.status:

  • NOT_AFFECTED
  • AFFECTED_MITIGATED
  • AFFECTED_UNMITIGATED
  • FIXED

UI rules:

  • If Finding.status = NO_LONGER_DETECTED and a VEXDecision still exists:
    • Show badge: "Historical VEX decision (finding no longer detected)"
  • If VEXDecision.status = NOT_AFFECTED:
    • Policy engines may treat this as non-blocking (configurable)

6. Interaction Patterns to Mirror

6.1 From Snyk

  • PR checks show before/after and don't fail on ignored issues
  • Action: "Fix PR" from a finding
  • Mapping:
    • Stella Ops should show "Fix PR" and "Compare before/after" where data exists
    • VEX NOT_AFFECTED should make future checks ignore that finding for that subject/scope

6.2 From GitLab SCA

  • Dismissed with reasons and activity log
  • Mapping:
    • VEX decisions must have reason + actor + timestamp
    • The activity log should show a full decision history

6.3 From Anchore

  • Policy gates & allowlists
  • Mapping:
    • Gate evaluation screen with clear "this gate failed because..." explanation

7. Enumerations & Conventions

7.1 VEX Status

NOT_AFFECTED
AFFECTED_MITIGATED
AFFECTED_UNMITIGATED
FIXED

7.2 VEX Scope

  • envs[]: e.g. ["prod", "staging"]
  • projects[]: service / app names
  • Default: applies to all unless restricted

7.3 Justification Type (inspired by CSAF/VEX)

CODE_NOT_PRESENT
CODE_NOT_REACHABLE
VULNERABLE_CODE_NOT_IN_EXECUTE_PATH
CONFIGURATION_NOT_AFFECTED
OS_NOT_AFFECTED
RUNTIME_MITIGATION_PRESENT
COMPENSATING_CONTROLS
ACCEPTED_BUSINESS_RISK
OTHER

8. Attestation Placement

8.1 Trivy + Cosign

Generate vulnerability-scan attestation and SBOM attestation; attach to image via OCI referrers. These attestations become the source of truth for evidence and audit export.

8.2 Harbor

Treat attestations as first-class accessories/refs to the image. Surface them next to the Vulnerabilities tab. Link them into the explainability panel.

8.3 Anchore

Reference attestation digests inside Policy evaluation output so pass/fail is traceable to signed inputs.

8.4 Snyk/GitLab

Surface attestation presence in PR/Security dashboards to prove findings came from a signed scan; link out to the OCI digest.

UI pattern: Small "Signed evidence" pill on each finding; clicking opens the attestation JSON (human-readable view) + verify command snippet.


9. Gating Controls

Tool Mechanism Stella Ops Mirror
Anchore Policy Gates/Triggers model for hard gates Gates per environment with trigger explainability
Snyk PR checks + Auto Fix PRs as soft gates PR integration with soft/hard gate toggles
GitLab MR approvals + Security Policies; auto-resolve on no-longer-detected Status-aware policies with auto-resolution
Harbor External policy engines (Kyverno/OPA) verify signatures/attestations Admission controller integration

10. Minimal UI Wireframe

10.1 Artifacts List

Image Tag Risk (open/total) Attestations Last scan
app/service v1.2.3 3/47 4 2h ago (Trivy)

10.2 Artifact -> Vulnerabilities Tab (Evidence-First)

+----------------------------------+-----------------------------------+
| Finding Cards (scrollable)       | Explainability Panel              |
|                                  |                                   |
| [CVE-2024-1234] CRITICAL         | Overview | Reachability | Policy  |
| openssl 3.0.14 -> 3.0.15         |                                   |
| [Fix PR] [VEX: Not Affected]     | Scanner: Trivy 0.53.0             |
| [Attach Evidence]                | DB: 2025-11-27                    |
|                                  | Attestation: sha256:2e61...       |
| [CVE-2024-5678] HIGH             |                                   |
| log4j 2.17.0                     | [Why flagged]                     |
| [VEX: Mitigated]                 | - version.match: 2.17.0 < 2.17.1  |
|                                  | - gate: severity >= HIGH          |
+----------------------------------+-----------------------------------+

10.3 Policy View

Gate rules (like Anchore) with preview + dry-run; show which triggers cause failure.

10.4 Audit

"Create immutable audit bundle" -> produces ZIP/OCI artifact with reports, VEX JSON, policy evals, and in-toto/DSSE attestations.

10.5 Registry/Admission

"Ready to deploy" badge when all gates met and required attestations verified.


11. API Endpoints (High-Level)

GET  /artifacts
GET  /artifacts/{id}/vulnerabilities
GET  /vulnerabilities/{id}
POST /vex-decisions
PATCH /vex-decisions/{id}
GET  /artifacts/{id}/attestations
POST /audit-bundles
GET  /audit-bundles/{bundleId}

12. JSON Schema Locations

The following schemas should be created/maintained:

  • docs/schemas/vex-decision.schema.json - VEX decision form schema
  • docs/schemas/attestation-vuln-scan.schema.json - Vulnerability scan attestation
  • docs/schemas/audit-bundle-index.schema.json - Audit bundle manifest

  • 27-Nov-2025 - Explainability Layer for Vulnerability Verdicts.md - Evidence chain model
  • 27-Nov-2025 - Making Graphs Understandable to Humans.md - Graph navigation UX
  • 25-Nov-2025 - Define Safe VEX 'Not Affected' Claims with Proofs.md - VEX proof requirements

14. Sprint Integration

This advisory maps to:

  • SPRINT_0215_0001_0001_vuln_triage_ux.md (NEW) - UI triage workspace implementation
  • SPRINT_210_ui_ii.md - VEX tab tasks (UI-LNM-22-003)
  • SPRINT_0334_docs_modules_vuln_explorer.md - Module documentation updates

Last updated: 2025-11-28