# Proof-Linked VEX UI Developer Guidelines Compiled: 2025-12-01 (UTC) ## Purpose Any VEX-influenced verdict a user sees (Findings, Advisories & VEX, Vuln Explorer, etc.) must be directly traceable to concrete evidence: normalized VEX claims, their DSSE/signatures, and the policy explain trace. Every "Not Affected" badge is a verifiable link to the proof. ## What this solves (in one line) Every "Not Affected" badge becomes a verifiable link to why it is safe. ## UX pattern (at a glance) - Badge: `Not Affected` (green pill) always renders as a link. - On click: open a right-side drawer with three tabs: 1. Evidence (DSSE / in-toto / Sigstore) 2. Attestation (predicate details + signer) 3. Reasoning Graph (the node + edges that justify the verdict) - Hover state: mini popover showing proof types available (e.g., "DSSE, SLSA attestation, Graph node"). ## Data model (API & DB) Canonical object returned by VEX API for each finding: ```json { "findingId": "vuln:CVE-2024-12345@pkg:docker/alpine@3.19", "status": "not_affected", "justificationCode": "vex:not_present", "proof": { "dsse": { "envelopeDigest": "sha256-…", "rekorEntryId": "e3f1…", "downloadUrl": "https://…/dsse/e3f1…", "signer": { "name": "StellaOps Authority", "keyId": "SHA256:…" } }, "attestation": { "predicateType": "slsa/v1", "attestationId": "att:01H…", "downloadUrl": "https://…/att/01H…" }, "graph": { "nodeId": "gx:NA-78f…", "revision": "gx-r:2025-11-30T12:01:22Z", "explainUrl": "https://…/graph?rev=gx-r:…&node=NA-78f…" } }, "receipt": { "algorithm": "CVSS:4.0", "inputsHash": "sha256-…", "computedAt": "2025-11-30T12:01:22Z" } } ``` Suggested Postgres tables: - vex_findings(finding_id, status, justification_code, graph_node_id, graph_rev, dsse_digest, rekor_id, attestation_id, created_at, updated_at) - proof_artifacts(id, type, digest, url, signer_keyid, meta jsonb) - graph_revisions(revision_id, created_at, root_hash) ## API contract (minimal) - GET /vex/findings/:id -> returns the object above. - GET /proofs/:type/:id -> streams artifact (with Content-Disposition: attachment). - GET /graph/explain?rev=…&node=… -> returns a JSON justification subgraph. - Security headers: Content-SHA256, Digest, X-Proof-Root (graph root hash), and X-Signer-KeyId. ## Angular UI spec (drop-in) Component: FindingStatusBadge ```html ``` Drawer layout (3 tabs): 1) Evidence - DSSE digest (copy button) - Rekor entry (open in new tab) - "Download envelope" 2) Attestation - Predicate type - Attestation ID - "Download attestation" 3) Reasoning Graph - Node ID + Revision - Inline explainer ("Why safe?" bullets) - "Open full graph" (routes to /graph?rev=…&node=…) Micro-interactions: - Copy-to-clipboard with toast ("Digest copied"). - If any artifact missing, show a yellow "Partial Proof" ribbon listing what is absent. Visual language: - Badges: Not Affected = solid green; Partial Proof = olive with warning dot; No Proof = gray outline (still clickable, explains absence). - Proof chips: small caps labels `DSSE`, `ATTESTATION`, `GRAPH`; each chip opens its subsection. Validation (trust & integrity): - On drawer open, the UI calls HEAD /proofs/... to fetch Digest header and X-Proof-Root; compare to stored digests. If mismatch, show red "Integrity Mismatch" banner with retry and report. Telemetry (debugging): - Emit events: proof_drawer_opened, proof_artifact_downloaded, graph_explain_viewed (include findingId, artifactType, latencyMs, integrityStatus). Developer checklist: - Every not_affected status must include at least one proof artifact. - Badge is never a dead label; always clickable. - Drawer validates artifact digests before rendering contents. - "Open full graph" deep-links with rev + node (stable and shareable). - Graceful partials: show what is present and what is missing. - Accessibility: focus trap in drawer, aria-labels for chips, keyboard nav. Test cases (quick): 1) Happy path: all three proofs present; digests match; downloads work. 2) Partial proof: DSSE present, attestation missing; drawer shows warning ribbon. 3) Integrity fail: server returns different digest; red banner appears; badge stays clickable. 4) Graph only: reasoning node present; DSSE/attestation absent; explains rationale clearly. Optional nice-to-haves: - Permalinks: copyable URL that re-opens the drawer to the same tab. - QR export: downloadable "proof card" PNG with digests + signer (for audit packets). - Offline kit: bundle DSSE, attestation, and a compact graph slice in a .tar.zst for air-gapped review. If needed, this can be turned into: - A small Angular module (ProofDrawerModule) + styles. - A .NET 10 controller stub with integrity headers. - Fixture JSON so teams can wire it up quickly. ## Context links (from source conversation) - docs/ui/console-overview.md - docs/ui/advisories-and-vex.md - docs/ui/findings.md - src/VexLens/StellaOps.VexLens/AGENTS.md and TASKS.md - docs/policy/overview.md