Reachability Witnessing
Status: Implemented Owner shell: Security > Reachability Canonical routes: /security/reachability, /security/reachability/witnesses, /security/reachability/witnesses/:witnessId, /security/reachability/poe, /security/reachability/poe/:artifactId
Recommendation
Restore witness and proof-of-exposure UX as a deeper part of Security > Reachability, not as a standalone product.
- Canonical mount:
/security/reachability - Suggested user-facing title:
Reachability - Supporting label inside the shell:
Witnesses & Proof
This capability should strengthen security investigation, release gating, and evidence review through reusable witness detail pages and proof drawers.
Why This Is The Right Shape
ReachabilityCenterComponentalready owns the top-level reachability posture.WitnessPageComponentandPoEDrawerComponentare evidence and explanation layers of the same capability.- Reachability proof matters in findings, triage, policy/VEX decisions, and release gates, so it must be reusable from multiple contexts.
- A single shell prevents proof UX from fragmenting across security, evidence, and release flows.
Operator Modes
1. Investigation Mode
- Used by analysts validating whether a vulnerable path is reachable and why.
- Focus:
WitnessesandPoE / Exposure.
2. Release Context Mode
- Entered from release gates, policy/VEX decisions, or evidence review.
- Focus: witness explanation, proof verification, and return-to-release navigation.
Recommended IA
Primary tabs
Witnesses- searchable witness list and full witness detail page
PoE / Exposure- proof-of-exposure artifacts, export, verify, transparency status
Witness detail sections
- summary
- call path and gates
- confidence and caveats
- related findings and releases
- evidence chain and export actions
Page Anatomy
Witnesses tab
- list filters:
- artifact
- package
- CVE
- verdict
- confidence
- environment
- row preview:
- witness id
- subject
- vulnerability
- verdict
- confidence
- last observed
- witness detail page:
- proof summary header
- path explorer
- gates and confidence
- related evidence
- replay/verify/export actions
PoE / Exposure tab
- proof list with status chips
- right drawer for proof detail by default
- optional permalink route for export and audit deep links
Route Contract
Keep one canonical route family under security reachability.
Canonical routes
/security/reachability/security/reachability/witnesses/security/reachability/witnesses/:witnessId/security/reachability/poe/security/reachability/poe/:artifactId
Query-param state
tab=witnesses|poescanId=<scanId>selects the Scanner scan whose witnesses are listed. Scanner accepts trimmed nonblank opaque identifiers, including its 40-hex scan IDs; the Console rejects control characters without a UUID or hex-only whitelist. Values travel through normal query-parameter encoding. Absent or invalid IDs never become an empty successful read. Rejected access/input invalidates pending reads; scan/scope and request generation prevent older responses or cleanup from replacing a newer selection, including a return to the same scan. The current request is shared.findingId=<finding id>names the finding a handoff came from. A finding id is not a scan ID: withoutscanIdthe page states that no scan was handed over and loads nothing.:artifactIdon/security/reachability/poe/:artifactIdis the witness id. Several witnesses of one scan can name the same vulnerability, so each proof is keyed by its witness; an id that is not a witness of the loaded scan is reported and no other proof opens.panel=poe|evidence|relatedreturnTo=<encoded route>for findings, triage, evidence, or releases; only an application-local path is followed (an external or protocol-relative value is dropped).
Alias rules
- any future
evidenceorreleaseentry points should deep-link here rather than mount duplicate witness pages
What To Merge
Merge into the shell
ReachabilityCenterComponent
Merge into Witnesses
WitnessPageComponent
Merge into PoE / Exposure
PoEDrawerComponent
Preserve as shared behaviors
- export DOT and Mermaid actions
- proof verification actions
- evidence-chain cards
Single Actions And Supporting Surfaces
Witness detail
- full page under
Witnesses - preserve permalink and return-to-context behavior
PoE detail
- default to a right drawer from witness detail, finding detail, triage, or release context
- allow a standalone route for exports and audit deep links
Export or replay verify
- keep as actions on witness or PoE detail
- do not create separate pages per export type
Related finding navigation
- keep as contextual links in the witness detail sidebar
Cross-Product Entry Points
Security > Findings- open witness detail for a finding
Triage > Artifact Workspace- open witness or PoE from artifact detail
Evidence > Verify & Replay- open proof verification in the same witness/PoE model
Decisioning StudioorReleases- open witness and proof for gate verdict explanation
Shipped Behavior
Mounted shell
Witnessesis the default entry and requires an explicit Scanner scan ID.Witnessesships a searchable, filterable list with confidence and verdict filters.- List ordering uses the displayed verdict: known reachable, known unreachable, then unknown. Confidence tier and vulnerability ID remain the tie breakers within a state.
PoE / Exposurekeeps drawer-first inspection and supports direct permalink routes for export and audit use.- The former
/coverageand/gapspaths redirect to Witnesses. They do not ship as tabs because no production endpoint populates those row models.
Witness detail
- Loads the requested witness from the witness API. A failed read or a session without
scanner:readis stated; no cached or fixture witness is shown. - Shows only the requested witness: the previous witness is cleared while the next one loads, a late response for a witness the page has left is discarded, and a record whose id differs from the requested id is reported, not shown.
- Reads the canonical
stellaops.witness.v1payload inside the persisted owner record: nestedartifactandvuln, orderedpath, gates, evidence digests, build context, observations and symbolization. WrapperwitnessId, payloadwitness_id, scan and run identities are displayed with their own meanings. - The producer supplies no overall confidence, public reachability verdict or VEX recommendation. Their absence stays explicit and does not mean unreachable, not exploitable, zero confidence or verified. Unknown reachability is excluded from both the reachable and unreachable filters. Invalid nested fields leave independently recorded panels available; an unsupported schema is not interpreted.
- Verification uses the owner result for the selected witness. Missing, incoherent or failed responses stay non-successful and never receive an invented verification time. Read-time signature presence is shown separately from verification.
- DOT/Mermaid and PoE actions require a valid recorded path. Diagram position identifiers preserve loops and punctuation-distinct symbol IDs, which remain visible in each label. The existing JSON/SARIF download routes are not part of Scanner’s serving witness contract; their controls do not establish export support.
- The PoE permalink names the witness and carries the scan Scanner recorded for it (
scanId); Back withoutreturnToreturns to that scan’s witness list.
Proof-of-exposure detail
- Opens by default as a contextual drawer from witness or shell entry points.
- Supports direct navigation through
/security/reachability/poe/:artifactId(the witness id); the PoE tab lists every proof of the scan and opens none the operator did not choose. Verify checks the witness the proof was built from. - The drawer projects the selected witness; Scanner supplies no separate PoE artifact. It carries the recorded component PURL, vulnerability, scan, run and
evidence.build_id. The symbolization build identifies the binary separately. Policy id/digest, PoE hash, per-node module hash/address, image digest, scanner version and overall confidence remain “not recorded” andnullin the local projection when the witness supplies none. A surface digest is not an image digest, and path/callgraph digests are not policy or PoE digests. - The proof path preserves every canonical
pathposition and exactsymbol_id, including repeats, file, line and column. Separate entrypoint/sink metadata replaces no node; a one-node path is shown once with no edge. Edges carry no confidence. A missing identity or malformed node invalidates the path instead of inventing an identity or joining its neighbors. No valid path means no proof path: witness-detail PoE actions are disabled, while the scan-level drawer can still show independently recorded metadata and explicitly state that no path is recorded. - “DSSE Signed” means the owner recorded a shaped envelope; verification is separate (verified, failed or not recorded). Missing or malformed signature metadata is unknown. A timestamp or evidence URI does not prove Rekor inclusion. Observation time is never replaced by record creation time. Runtime observations show their recorded counts/source/context; no image relation or freshness is inferred.
- The local projection names witness, scan and run independently. Without a recorded vulnerability id its file is named after the witness only (
poe-<witness id>.json). - Preserves operator context with
returnTowhen launched from findings, triage, evidence replay, or release detail.
Cross-product handoffs
Security > Findingslinks into canonical witness routes instead of owning a second proof view. The selected disposition’ssourceScanIdtravels with the finding id, vulnerabilitysearch, scope andreturnTo; the Evidence tab shows its image digest and scan. The relation proves neither witness presence nor absence. Without a recorded relation, the page asks for a scan ID instead of choosing one. A changed finding or scope clears the previous disposition/handoff and discards its late results. Source behavior does not establish deployed real-witness or restricted-role acceptance.Triage > Artifact Workspacerestores the selected finding and tab when returning from reachability.Evidence > Verify & Replaylinks the current request into reachability proof review.Releases > Detaillinks release-gate investigation into reachability without branching to a parallel shell.
UI Standards For Implementation
- Keep witness detail as the canonical deep-link target.
- Default proof detail to a drawer to preserve investigation context.
- Preserve return-to-context links so operators can move back to findings or release flows.
- Reuse evidence cards and path visualizations across security, evidence, and release entry points.
- Keep graph and proof loading deterministic and evidence-first.
Verification Status
- Source payload behavior verified against
f26be185ea504d5253b7719eb17ab40a2a917748on 2026-10-15. Fromsrc/Web/StellaOps.Web, re-runnpx vitest run --config vitest.codex.config.ts src/app/core/api/witness-producer-contract.spec.ts src/app/features/reachability/witness-producer-rendering.spec.ts. These HTTP-client and rendered-consumer tests use JSON serialized by Scanner’s actual canonicalizer and owner DTOs. They establish source behavior only; deployed tenant witness navigation and restricted-role acceptance remain separate. - The two 2026-03-07 checks below are historical; they do not qualify the current bundle.
- Angular verification: targeted route, witness-detail, handoff, and release-context tests passed on 2026-03-07.
- Playwright verification: witness detail, PoE drawer/permalink, and Verify & Replay handoff passed on 2026-03-07.
- Checked feature note:
docs/features/checked/web/reachability-witnessing-ui.md
Non-Goals
- Do not create a top-level
Witnessingproduct. - Do not split coverage, witness, and proof UX across unrelated sidebar branches.
- Do not leave PoE as a drawer with no canonical parent route.
Source Inputs
docs/contracts/witness-v1.mddocs/architecture/EVIDENCE_PIPELINE_ARCHITECTURE.mddocs/modules/scanner/reachability.mddocs-archive/modules/ui/architecture-rework.mdsrc/Web/StellaOps.Web/src/app/features/reachability/reachability-center.component.tssrc/Web/StellaOps.Web/src/app/features/reachability/witness-page.component.tssrc/Web/StellaOps.Web/src/app/features/reachability/poe-drawer.component.tssrc/Web/StellaOps.Web/src/app/routes/security-risk.routes.tssrc/Web/StellaOps.Web/src/app/routes/evidence.routes.ts
