consolidation of some of the modules, localization fixes, product advisories work, qa work

This commit is contained in:
master
2026-03-05 03:54:22 +02:00
parent 7bafcc3eef
commit 8e1cb9448d
3878 changed files with 72600 additions and 46861 deletions

View File

@@ -0,0 +1,35 @@
# Vulnerability Explorer agent guide
## Mission
Vulnerability Explorer delivers policy-aware triage, investigation, and reporting surfaces for effective findings.
## Key docs
- [Module README](./README.md)
- [Architecture](./architecture.md)
- [Implementation plan](./implementation_plan.md)
- [Task board](./TASKS.md)
## How to get started
1. Review ./architecture.md for ledger schema, workflow states, and export requirements.
2. Open sprint file `/docs/implplan/SPRINT_*.md` and locate stories for this component.
3. Check ./TASKS.md and update status before/after work.
4. Read README/architecture for design context and update as the implementation evolves.
## Guardrails
- Uphold Aggregation-Only Contract boundaries when consuming ingestion data.
- Preserve determinism and provenance in all derived outputs.
- Document offline/air-gap pathways for any new feature.
- Update telemetry/observability assets alongside feature work.
## Required Reading
- `docs/modules/vuln-explorer/README.md`
- `docs/modules/vuln-explorer/architecture.md`
- `docs/modules/vuln-explorer/implementation_plan.md`
- `docs/modules/platform/architecture-overview.md`
## Working Agreement
- 1. Update task status to `DOING`/`DONE` in both correspoding sprint file `/docs/implplan/SPRINT_*.md` and the local `TASKS.md` when you start or finish work.
- 2. Review this charter and the Required Reading documents before coding; confirm prerequisites are met.
- 3. Keep changes deterministic (stable ordering, timestamps, hashes) and align with offline/air-gap expectations.
- 4. Coordinate doc updates, tests, and cross-guild communication whenever contracts or workflows change.
- 5. Revert to `TODO` if you pause the task without shipping changes; leave notes in commit/PR descriptions for context.

View File

@@ -0,0 +1,95 @@
# StellaOps Vulnerability Explorer
Vulnerability Explorer delivers policy-aware triage, investigation, and reporting surfaces for effective findings.
## Latest updates (2025-11-30)
- Documentation refresh aligned to sprint 0334: added observability/runbook snapshot and cross-links to OpenAPI draft (`./api.md`) and schemas in `architecture.md`.
- New offline-friendly observability runbook at `runbooks/observability.md` plus stub Grafana JSON in `runbooks/dashboards/`.
- Retained 2025-11-03 access-control changes; verify Authority scopes before enabling attachment uploads (`docs/updates/2025-11-03-vuln-explorer-access-controls.md`).
## Responsibilities
- Present policy-evaluated findings with advisory, VEX, SBOM, and runtime context.
- Capture triage workflow in an immutable findings ledger with role-based access.
- Provide pivots, exports, and reports for auditors and operations teams.
- Integrate explain traces, remediation notes, and offline bundles.
## Key components
- Findings Ledger service + API.
- Console module and CLI verbs for triage workflows.
- Export integrations for reports and evidence packages.
## Integrations & dependencies
- Policy Engine for effective findings streams.
- Concelier/Excititor for evidence provenance.
- Scheduler for remediation/verification jobs.
- Notify for triage notifications.
## Operational notes
- Audit logging per Epic 6 requirements.
- Offline-ready CSV/PDF exports with deterministic hashes.
- Dashboards for MTTR and triage throughput.
- Observability runbook and dashboard stub: see `runbooks/observability.md` and `runbooks/dashboards/vuln-explorer-observability.json` (import locally).
## Implementation Status
### Phase 1 Findings Ledger & resolver (In Progress)
- Append-only ledger with Merkle root anchoring
- Projector to finding_records and finding_history tables
- Ecosystem resolvers: npm/Maven/PyPI/Go/RPM/DEB with canonical advisory keys
- Provenance hashing and time-travel snapshots
- Idempotent event processing
### Phase 2 API & simulation (Planned)
- REST endpoints: /v1/findings (list/detail/grouping/simulation)
- Batch evaluation with Policy Engine rationales
- Export orchestrator for JSON/CSV/PDF
- Simulation endpoint returning diffs without state mutation
### Phase 3 Console & CLI workflows (Planned)
- Triage UI: assignments, comments, remediation plans, simulation bar
- Detail tabs: policy, evidence, paths, remediation
- Keyboard accessibility, virtualization for large result sets
- CLI commands: stella vuln list/show/simulate/assign/accept-risk/verify-fix/export
### Phase 4 Automation & integrations (Planned)
- Advisory AI hints integration
- Zastava runtime exposure correlation
- Notify rules for SLA breaches and deadlines
- Scheduler follow-up scans and Graph Explorer deep links
### Phase 5 Exports & offline parity (Planned)
- Deterministic bundles: JSON, CSV, PDF formats
- Offline Kit manifests with signed reports
- Audit logs and compliance exports
- Evidence bundle viewer
### Phase 6 Observability & hardening (Planned)
- Dashboards: projection lag, MTTR, accepted-risk cadence
- Alerts: projector backlog, API 5xx, export failures, expiring accepted-risk
- Performance tuning for 5M findings/tenant
- Security/RBAC validation and attachment encryption
### Key Acceptance Criteria
- Ledger/event sourcing reproduces historical states byte-for-byte with Merkle verification
- Resolver respects ecosystem semantics, scope, runtime context
- Triage workflows enforce justification/approval with audit records
- Simulation returns policy diffs without mutating state; CLI/UI parity achieved
- Exports reproducible with signed manifests and provenance
- RBAC/ABAC validated; attachments encrypted; tenant isolation guaranteed
### Technical Decisions & Risks
- Advisory identity collisions: strict canonicalization, linkset references, raw evidence access
- Resolver inaccuracies: property-based tests, path verification, manual override workflows
- Projection lag/backlog: autoscaling, queue backpressure, alerting, pause controls
- Export size/performance: streaming NDJSON, size estimators, chunked downloads
- User confusion on suppression: rationale tab, explicit badges, explain traces
### Operational Assets (Sprint 0334 · 2025-11-30)
- Observability runbook: runbooks/observability.md
- Dashboard stub: runbooks/dashboards/vuln-explorer-observability.json
- OpenAPI draft: api.md and openapi/vuln-explorer.v1.yaml
- Access controls: docs/updates/2025-11-03-vuln-explorer-access-controls.md
## Epic alignment
- Epic 6: Vulnerability Explorer.
- VULN stories tracked in ../../TASKS.md and src/VulnExplorer/**/TASKS.md.

View File

@@ -0,0 +1,96 @@
# Vulnerability Explorer and Findings Ledger (Guide)
The Vulnerability Explorer is the StellaOps interface for vulnerability triage and remediation planning. It brings together SBOM facts, advisory/VEX evidence, reachability signals, and policy explanations into a single, auditable workflow.
This guide is intentionally conceptual. Concrete schemas, identifiers, and endpoint shapes are defined in the module dossiers and schema files.
## Core Objects
- **Finding record:** the current, enriched view of a vulnerability for a specific artifact/context (tenant, image digest/artifact id, policy version).
- **Finding history:** append-only state transitions (who/what changed status and why), suitable for audit replay.
- **Triage actions:** discrete operator actions (assignment, comment, mitigation note, ticket link, exception request) with provenance.
- **Evidence references:** stable pointers to SBOM slices, advisory observations, VEX observations/linksets, reachability proofs, and attestation bundles.
## Triage UX Contract (Console)
Every triage surface should answer, in order:
1. Can I ship this?
2. If not, what exactly blocks me?
3. What's the minimum safe change to unblock?
Key expectations:
- **Narrative-first:** the default view for a finding is a case-style summary ("why") plus a visible evidence rail.
- **Proof-linking is mandatory:** every chip/badge/assertion links to the evidence objects that justify it.
- **Quiet by default, never silent:** muted/non-actionable lanes are hidden by default but surfaced via counts and toggles; muting never deletes evidence.
- **Replayable:** the UI should support exporting a deterministic evidence bundle for offline/audit verification.
## Workflow (Operator View)
1. Start from a finding list filtered to the relevant tenant and time window.
2. Open a finding to review:
- Policy outcome (block/ship/needs exception)
- Effective VEX status (and the underlying issuer evidence)
- Reachability/impact signals (where available)
- Advisory provenance and conflicts
3. Record a triage action (assign, comment, request exception) with justification.
4. Export an evidence bundle when review, escalation, or offline verification is required.
The default posture is VEX-first: VEX evidence and issuer trust are treated as first-class inputs to decisioning and explainability.
## Lanes and Signed Decisions
Most UIs need "lanes" (visibility buckets) derived from deterministic risk and operator decisions. Common examples:
- `ACTIVE`
- `BLOCKED`
- `NEEDS_EXCEPTION`
- `MUTED_REACH` (not reachable)
- `MUTED_VEX` (effective VEX is not_affected)
- `COMPENSATED` (controls satisfy policy)
Decisions that change visibility or gating should be:
- Signed and auditable (who did what, when, and why).
- Append-only (revoke/expire instead of delete).
- Linked to the policy and evidence that justified the change.
## Smart-Diff History
The Explorer should make meaningful changes obvious:
- Maintain immutable snapshots of inputs/outputs for each finding.
- Highlight meaningful changes (verdict/lane changes, threshold crossings, reachability changes, effective VEX changes).
- Keep "details" available without overwhelming the default view.
## Determinism, Integrity, and Replay
The Explorer is designed to be replayable and tamper-evident:
- History and actions are append-only.
- Exports use deterministic ordering and UTC timestamps.
- Evidence bundles carry hashes/manifests so a third party can verify integrity without trusting a live service.
- When Merkle anchoring is enabled, exports can include roots and inclusion proofs for additional tamper evidence.
## Offline / Air-Gap Operation
- Explorer workflows must work against Offline Kit snapshots when running in sealed environments.
- The Console should surface snapshot identity and staleness (feeds, VEX, policy versions) rather than hiding it.
- Export bundles are the primary bridge between online and offline review.
## Integration Points
- **Console UI:** findings list + triage case view; evidence drawers; export/download flows.
- **Policy engine:** produces explainability traces and gates actions (for example, exception workflows).
- **Graph/Reachability:** overlays and evidence slices for reachable vs not reachable decisions where available.
- **VEX Lens / Excititor:** issuer trust, provenance, linksets, and effective status (see `docs/VEX_CONSENSUS_GUIDE.md`).
## Related Docs
- `docs/UI_GUIDE.md`
- `docs/VEX_CONSENSUS_GUIDE.md`
- `docs/modules/vuln-explorer/architecture.md`
- `docs/modules/findings-ledger/schema.md`
- `docs/modules/findings-ledger/merkle-anchor-policy.md`
- `docs/ARCHITECTURE_OVERVIEW.md`

View File

@@ -0,0 +1,7 @@
# Vuln Explorer API draft v1 (2025-11-25)
- OpenAPI: `docs/modules/vuln-explorer/openapi/vuln-explorer.v1.yaml`
- Scope: read-only vulnerability listing/detail for Console/CLI; deterministic ordering (score desc, id asc) with opaque page tokens.
- Required headers: `x-stella-tenant`; optional `policyVersion`.
- Filters: CVE, PURL, severity band, exploitability flag, fixAvailable.
- Responses include policyVersion + rationaleId for explainability; provenance anchors back to Findings Ledger/evidence bundles.

View File

@@ -0,0 +1,199 @@
# Vulnerability Explorer architecture
> Based on Epic6 Vulnerability Explorer; this specification summarises the ledger model, triage workflows, APIs, and export requirements.
## 1) Ledger data model
- See [`../findings-ledger/schema.md`](../findings-ledger/schema.md) for the canonical SQL schema, hashing strategy, and fixtures underpinning these collections.
- **Collections / tables**
- `finding_records` canonical, policy-derived findings enriched with advisory, VEX, SBOM, runtime context. Includes `policyVersion`, `advisoryRawIds`, `vexRawIds`, `sbomComponentId`, `policyRationale` (array of explain bundle URIs or remediation notes returned by `/api/policy/eval/batch`), and `explainBundleRef`.
- `finding_history` append-only state transitions (`new`, `triaged`, `accepted_risk`, `remediated`, `false_positive`, etc.) with timestamps, actor, and justification.
- `triage_actions` discrete operator actions (comment, assignment, remediation note, ticket link) with immutable provenance.
- `remediation_plans` structured remediation steps (affected assets, deadlines, recommended fixes, auto-generated from SRM/AI hints).
- `reports` saved report definitions, export manifests, and signatures.
- **Immutability & provenance** All updates are append-only; previous state is recoverable. Records capture `tenant`, `artifactId`, `findingKey`, `policyVersion`, `sourceRunId`, `sr mDigest`.
## 2) Triage workflow
1. **Ingest effective findings** from Policy Engine (stream `policy.finding.delta`) and on-demand batch evaluations. Projection workers call `/api/policy/eval/batch` with ledger event payloads to receive status/severity/label/rationale updates before writing `finding_records`. Each delta updates `finding_records`, generates history entries, and triggers notification rules.
2. **Prioritisation** uses contextual heuristics: runtime exposure, VEX status, policy severity, AI hints. Stored as `priorityScore` with provenance from Zastava/AI modules.
3. **Assignment & collaboration** Operators claim findings, add comments, attach evidence, and link tickets. Assignment uses Authority identities and RBAC.
4. **Remediation tracking** Link remediation plans, record progress, and integrate with Scheduler for follow-up scans once fixes deploy.
5. **Closure** When Policy or rescans mark finding resolved, system logs closure with explain trace and updates audit ledger.
State machine summary:
```
new -> (triage) triaged -> (remediate) in_progress -> (verify) awaiting_verification -> (scan) remediated
new -> (false_positive) closed_false_positive
new -> (risk_accept) accepted_risk
```
All transitions require justification; certain transitions (accepted risk) require multi-approver workflow defined by Policy Studio.
## 3) APIs
- `GET /v1/findings` — filtered listing with pagination, search (artifact, advisory, priority, status, assignee).
- `GET /v1/findings/{id}` — detail view (policy context, explain trace, evidence timeline).
- `POST /v1/findings/{id}/actions` — create triage action (assign, comment, status change, remediation, ticket link) with DSSE signature support.
- `POST /v1/reports` — generate report artifact (JSON, CSV, PDF) defined by saved templates; records manifest + signature.
- `GET /v1/exports/offline` — stream deterministic bundle for Offline Kit (findings JSON, history, attachments, manifest).
CLI mirrors these endpoints (`stella findings list|view|update|export`). Console UI consumes the same APIs via typed clients.
## 4) AI/automation integration
- Advisory AI contributes remediation hints and conflict explanations stored alongside findings (`aiInsights`).
- Scheduler integration triggers follow-up scans or policy re-evaluation when remediation plan reaches checkpoint.
- Zastava (Differential SBOM) feeds runtime exposure signals to reprioritise findings automatically.
## 5) Observability & compliance
- Metrics: `findings_open_total{severity,tenant}`, `findings_mttr_seconds`, `triage_actions_total{type}`, `report_generation_seconds`.
- Logs: structured with `findingId`, `artifactId`, `advisory`, `policyVersion`, `actor`, `actionType`.
- Audit exports: `audit_log.jsonl` appended whenever state changes; offline bundles include signed audit log and manifest.
- Compliance: accepted risk requires dual approval and stores justification plus expiry reminders (raised through Notify).
- Runbook and dashboard stub for demo snapshot: `runbooks/observability.md` and `runbooks/dashboards/vuln-explorer-observability.json` (offline import).
## 6) Identity & access integration
- **Scopes** `vuln:view`, `vuln:investigate`, `vuln:operate`, `vuln:audit` map to read-only, triage, workflow, and audit experiences respectively. The deprecated `vuln:read` scope is still honoured for legacy tokens but is no longer advertised.
- **Attribute filters (ABAC)** Authority enforces per-service-account filters via the client-credential parameters `vuln_env`, `vuln_owner`, and `vuln_business_tier`. Service accounts define the allowed values in `authority.yaml` (`attributes` block). Tokens include the resolved filters as claims (`stellaops:vuln_env`, `stellaops:vuln_owner`, `stellaops:vuln_business_tier`), and tokens persisted to PostgreSQL retain the same values for audit and revocation.
- **Audit trail** Every token issuance emits `authority.vuln_attr.*` audit properties that mirror the resolved filter set, along with `delegation.service_account` and ordered `delegation.actor[n]` entries so Vuln Explorer can correlate access decisions.
- **Permalinks** Signed permalinks inherit the callers ABAC filters; consuming services must enforce the embedded claims in addition to scope checks when resolving permalinks.
- **Attachment tokens** Authority mints short-lived tokens (`POST /vuln/attachments/tokens/issue`) to gate evidence downloads. Verification (`POST /vuln/attachments/tokens/verify`) enforces tenant, scope, and ABAC metadata, and emits `vuln.attachment.token.*` audit records.
- **Ledger verification** Offline workflows validate attachments by comparing the Authority-issued token, the Vuln Explorer ledger hash, and the downloaded artefact hash before distribution.
## 7) Offline bundle requirements
- Bundle structure:
- `manifest.json` (hashes, counts, policy version, generation timestamp).
- `findings.jsonl` (current open findings).
- `history.jsonl` (state changes).
- `actions.jsonl` (comments, assignments, tickets).
- `reports/` (generated PDFs/CSVs).
- `signatures/` (DSSE envelopes).
- Bundles produced deterministically; Export Center consumes them for mirror profiles.
## 8) VEX-First Triage UX
> Reference: Product advisory `docs/product/advisories/archived/27-Nov-2025-superseded/28-Nov-2025 - Vulnerability Triage UX & VEX-First Decisioning.md`
### 8.1 Evidence-First Finding Cards
Each vulnerability finding is displayed as an evidence-first card showing:
- CVE/vulnerability identifier with severity badge
- Package name, version, ecosystem
- Location (file path, container layer, function, call path)
- Scanner and database date
- Status badges: `New`, `VEX: Not affected`, `Policy: blocked`
Primary actions per card:
- **VEX: Set status** - Opens VEX decision modal
- **Fix PR / View Fix** - When available from connected scanners (Snyk/GitLab)
- **Attach Evidence** - Link PRs, tickets, docs, commits
- **Copy audit reference** - findingId + attestation digest
### 8.2 VEX Decision Model
VEX decisions follow the `VexDecision` schema (`docs/modules/vuln-explorer/schemas/vex-decision.schema.json`):
**Status values:**
- `NOT_AFFECTED` - Vulnerability does not apply to this artifact
- `AFFECTED_MITIGATED` - Vulnerable but mitigations in place
- `AFFECTED_UNMITIGATED` - Vulnerable without mitigations
- `FIXED` - Vulnerability has been remediated
**Justification types (CSAF/VEX aligned):**
- `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`
**Scope and validity:**
- Decisions can be scoped to specific environments and projects
- Validity windows with `notBefore` and `notAfter` timestamps
- Expired decisions are surfaced with warnings
### 8.3 Explainability Panel
Right-side panel with tabs for each finding:
**Overview tab:**
- Title, severity, package/version
- Scanner + DB date
- Finding history timeline
- Current VEX decision summary
**Reachability tab:**
- Call path visualization
- Module dependency list
- Runtime usage indicators (when available)
**Policy tab:**
- Policy evaluation result (PASS/WARN/FAIL)
- Gate details with "this gate failed because..." explanations
- Links to gate definitions
**Attestations tab:**
- Attestations mentioning this artifact/vulnerability/scan
- Type, subject, predicate, signer, verified status
- "Signed evidence" pill linking to attestation detail
### 8.4 VEX Decision APIs
New endpoints for VEX decisions:
- `POST /v1/vex-decisions` - Create new VEX decision with optional attestation
- `PATCH /v1/vex-decisions/{id}` - Update existing decision (creates superseding record)
- `GET /v1/vex-decisions` - List decisions with filters
- `GET /v1/vex-decisions/{id}` - Get decision detail
Request/response follows `VexDecisionDto` per schema.
### 8.5 Audit Bundle Export
Immutable audit bundles follow the `AuditBundleIndex` schema (`docs/modules/evidence-locker/schemas/audit-bundle-index.schema.json`):
**Bundle contents:**
- Vulnerability reports (scanner outputs)
- SBOM (CycloneDX/SPDX)
- VEX decisions
- Policy evaluations
- Raw attestations (DSSE envelopes)
- `audit-bundle-index.json` manifest with integrity hashes
**APIs:**
- `POST /v1/audit-bundles` - Create new bundle (async generation)
- `GET /v1/audit-bundles/{bundleId}` - Download bundle (ZIP or OCI)
- `GET /v1/audit-bundles` - List previously created bundles
`GET /v1/audit-bundles/{bundleId}` may use content negotiation: `Accept: application/json` returns job metadata; `Accept: application/octet-stream` streams bundle bytes.
### 8.6 Industry Pattern Alignment
The triage UX aligns with industry patterns from:
| Tool | Pattern Adopted |
|------|-----------------|
| **Snyk** | PR checks, Fix PRs, ignore with reasons |
| **GitLab SCA** | Vulnerability Report, status workflow, activity log |
| **Harbor/Trivy** | Artifact-centric navigation, attestation accessories |
| **Anchore** | Policy gates with trigger explanations, allowlists |
## 9) Schemas
The following JSON schemas define the data contracts for VEX and audit functionality:
- `docs/modules/vuln-explorer/schemas/vex-decision.schema.json` - VEX decision form and persistence
- `docs/modules/attestor/schemas/attestation-vuln-scan.schema.json` - Vulnerability scan attestation predicate
- `docs/modules/evidence-locker/schemas/audit-bundle-index.schema.json` - Audit bundle manifest
These schemas are referenced by both backend DTOs and frontend TypeScript interfaces.

View File

@@ -0,0 +1,51 @@
# Triage
**Status:** Design/Planning
**Source:** N/A (cross-cutting concept)
**Owner:** VulnExplorer Guild
## Purpose
Triage defines workflows and data structures for vulnerability triage, exploit path analysis, and proof bundle generation. Provides specifications for prioritization, evidence review, and decision capture used by VulnExplorer and Policy modules.
## Components
**Concept Documentation:**
- `exploit-path-inbox.md` - Exploit path inbox specification for automated triage
- `proof-bundle-spec.md` - Proof bundle format for evidence packaging
**Triage Workflows:**
- Automated triage (Signals-based prioritization)
- Manual triage (human review and decision)
- Exploit path analysis (reachability to exploitable sinks)
- Proof bundle generation (evidence packaging for decisions)
## Implementation Locations
Triage functionality is implemented across multiple modules:
- **VulnExplorer** - Triage UI and workflow orchestration
- **Signals** - Automated prioritization scoring
- **Policy Engine** - Exploit path analysis
- **EvidenceLocker** - Proof bundle storage
- **Notify** - Triage alert distribution
## Dependencies
- VulnExplorer (triage UI)
- Signals (prioritization)
- Policy Engine (exploit paths)
- EvidenceLocker (proof bundles)
- Notify (alerts)
## Related Documentation
- Exploit Path Inbox: `./exploit-path-inbox.md`
- Proof Bundle Spec: `./proof-bundle-spec.md`
- VulnExplorer: `../vuln-explorer/`
- Signals: `../signals/`
- Policy: `../policy/`
- EvidenceLocker: `../evidence-locker/`
## Current Status
Triage workflows documented in exploit-path-inbox.md and proof-bundle-spec.md. Implementation distributed across VulnExplorer (UI/workflows), Signals (scoring), Policy (analysis), and EvidenceLocker (proof storage) modules.

View File

@@ -0,0 +1,176 @@
# Exploit Path Inbox Architecture
## Overview
The Exploit Path Inbox provides a triage workflow that groups vulnerabilities by their complete attack chain rather than individual CVEs. This enables analysts to assess and remediate entire exploit paths at once, improving efficiency and ensuring comprehensive coverage.
## Key Concepts
### Exploit Path
An **Exploit Path** represents the complete chain from an entry point to a vulnerable symbol:
```
Artifact → Package → Vulnerable Symbol → Entry Point
```
For example:
```
sha256:abc... → pkg:npm/lodash@4.17.19 → _.template() → /api/render
```
### Path ID Generation
Path IDs are deterministic hashes ensuring stable references:
```
PathId = SHA256(artifactDigest | packagePurl | symbolName | entryPointName)
```
This allows:
- Consistent tracking across scans
- Stable exception targeting
- Reproducible audits
### Grouping Logic
Findings are grouped into exploit paths based on:
1. **Reachability Graph**: If reachability data exists, group by actual call paths
2. **Fallback**: If no reachability, group by package only
## Data Model
### ExploitPath
| Field | Type | Description |
|-------|------|-------------|
| `pathId` | string | Stable deterministic identifier |
| `artifactDigest` | string | Container image digest |
| `package` | PackageRef | Package containing vulnerability |
| `symbol` | VulnerableSymbol | Vulnerable function/method |
| `entryPoint` | EntryPoint | Entry point exposing the path |
| `cveIds` | string[] | All CVEs affecting this path |
| `reachability` | ReachabilityStatus | Reachability lattice state |
| `riskScore` | PathRiskScore | Aggregated risk metrics |
| `evidence` | PathEvidence | Supporting evidence |
| `activeExceptions` | ExceptionRef[] | Active suppressions |
| `isQuiet` | boolean | Whether path is suppressed |
### ReachabilityStatus
| State | Description |
|-------|-------------|
| `Unknown` | No reachability analysis performed |
| `StaticallyReachable` | Static analysis found a path |
| `RuntimeConfirmed` | Runtime observation confirmed reachability |
| `Unreachable` | Confirmed not reachable |
| `Contested` | Conflicting evidence |
## API Endpoints
### GET /triage/inbox
Returns exploit paths for a given scope.
**Query Parameters:**
- `artifactDigest` (string): Filter by artifact
- `environment` (string): Filter by environment
- `quiet` (boolean): Filter by suppression status
- `minCvss` (number): Minimum CVSS score
- `reachability` (string): Filter by reachability status
- `offset` (number): Pagination offset
- `limit` (number): Page size (default 50)
**Response:**
```json
{
"paths": [...],
"totalCount": 42,
"quietCount": 12,
"activeCount": 30,
"offset": 0,
"limit": 50
}
```
### GET /triage/paths/{pathId}
Returns detailed exploit path information.
### GET /triage/paths/{pathId}/proof
Returns proof bundle (see proof-bundle-spec.md).
## UI Components
### Three-Pane Layout
1. **Left Pane (Path List)**
- Exploit paths sorted by risk
- Quiet/Active toggle
- Search by CVE, package, symbol
- Risk score badges
2. **Center Pane (Path Detail)**
- CVE list with scores
- Package and symbol info
- Entry point context
- Active exceptions
- "Create Exception" button
3. **Right Pane (Proof Viewer)**
- Reach subgraph visualization
- Symbol map with source links
- VEX claims with trust badges
- "Export Proof" button
## Integration Points
### Exception System
Exceptions can target exploit paths via `pathId`:
```yaml
scope:
pathId: "path:abc123..."
```
This suppresses all CVEs in the path at once.
### Build Gates
Build gates can query by exploit path reachability:
```yaml
gates:
- name: block-reachable-critical
condition: reachability == "RuntimeConfirmed" && severity == "Critical"
action: block
```
### VEX Generation
VEX statements can reference exploit paths for context:
```json
{
"vulnerability": "CVE-2024-1234",
"product": "sha256:abc...",
"status": "not_affected",
"justification": "vulnerable_code_not_in_execute_path",
"context": {
"exploitPathId": "path:abc123..."
}
}
```
## Best Practices
1. **Triage by Path**: Address entire exploit paths, not individual CVEs
2. **Use Reachability**: Prioritize runtime-confirmed paths
3. **Document Evidence**: Attach proof bundles to exceptions
4. **Regular Review**: Re-evaluate paths when reachability changes
## Related Documentation
- [Proof Bundle Specification](./proof-bundle-spec.md)
- [Recheck Policy](../policy/recheck-policy.md)
- [Evidence Hooks](../policy/evidence-hooks.md)

View File

@@ -0,0 +1,235 @@
# Proof Bundle Specification
## Overview
A **Proof Bundle** aggregates all evidence supporting an exploit path assessment. It provides a complete, self-contained package for audit, compliance, and decision-making.
## Bundle Contents
### 1. Reach Subgraph
The reachability subgraph shows the call path from entry point to vulnerable symbol.
```json
{
"nodes": [
{
"id": "node-001",
"label": "handleRequest",
"type": "entryPoint",
"depth": 0,
"isVulnerable": false,
"isEntryPoint": true
},
{
"id": "node-002",
"label": "renderTemplate",
"type": "function",
"depth": 1,
"isVulnerable": false,
"isEntryPoint": false
},
{
"id": "node-003",
"label": "_.template",
"type": "vulnerableSymbol",
"depth": 2,
"isVulnerable": true,
"isEntryPoint": false
}
],
"edges": [
{
"sourceId": "node-001",
"targetId": "node-002",
"label": "calls",
"weight": 0.95
},
{
"sourceId": "node-002",
"targetId": "node-003",
"label": "calls",
"weight": 0.90
}
],
"entryPointId": "node-001",
"vulnerableSymbolId": "node-003",
"totalNodes": 3,
"totalEdges": 2
}
```
### 2. Symbol Map
Maps symbol identifiers to source code locations.
```json
{
"symbols": [
{
"id": "node-001",
"fullyQualifiedName": "src.api.handleRequest",
"sourceFile": "src/api/handler.js",
"lineNumber": 42,
"language": "javascript",
"signature": "function handleRequest(req, res)"
},
{
"id": "node-003",
"fullyQualifiedName": "lodash.template",
"sourceFile": "node_modules/lodash/template.js",
"lineNumber": 156,
"language": "javascript",
"signature": "function template(string, options)"
}
],
"sourceFiles": [
"src/api/handler.js",
"node_modules/lodash/template.js"
]
}
```
### 3. VEX Claims
VEX statements from various sources with trust scores.
```json
{
"vexClaims": [
{
"cveId": "CVE-2024-1234",
"status": "not_affected",
"justification": "vulnerable_code_not_in_execute_path",
"source": "vendor:lodash",
"trustScore": 0.95,
"timestamp": "2024-12-22T10:00:00Z",
"signatureValid": true
},
{
"cveId": "CVE-2024-1234",
"status": "affected",
"justification": null,
"source": "nvd",
"trustScore": 0.80,
"timestamp": "2024-12-20T08:00:00Z",
"signatureValid": false
}
]
}
```
### 4. Trust Scores
Aggregated confidence metrics.
```json
{
"trustScores": {
"reachabilityConfidence": 0.90,
"vexConfidence": 0.85,
"overallConfidence": 0.875,
"evidenceCount": 5
}
}
```
## API Endpoint
### GET /triage/paths/{pathId}/proof
Returns the complete proof bundle.
**Response:**
```json
{
"pathId": "path:abc123...",
"generatedAt": "2024-12-22T12:00:00Z",
"reachSubgraph": { ... },
"symbolMap": { ... },
"vexClaims": [ ... ],
"trustScores": { ... },
"bundleDigest": "sha256:def456..."
}
```
### GET /triage/paths/{pathId}/proof/export
Returns proof bundle as downloadable JSON file.
## Bundle Integrity
Each bundle includes a digest for integrity verification:
```
bundleDigest = SHA256(canonical_json(bundle_without_digest))
```
This allows:
- Tamper detection
- Audit trail verification
- Reproducible exports
## Visualization
### Reach Graph Rendering
Use Cytoscape.js or similar for interactive visualization:
- Nodes colored by type (entry point, intermediate, vulnerable)
- Edge width indicates confidence weight
- Collapsible for large graphs
### Symbol Navigation
Click-through from symbols to source code:
- IDE integration (VS Code, JetBrains)
- GitHub/GitLab links
- Line number highlighting
### VEX Claim Comparison
Side-by-side view of conflicting VEX statements:
- Trust score comparison
- Timestamp ordering
- Signature verification badges
## Use Cases
### Exception Creation
When creating an exception, attach proof bundle:
```yaml
exception:
pathId: "path:abc123..."
proofBundleDigest: "sha256:def456..."
evidence:
- type: proof-bundle
reference: "/triage/paths/path:abc123.../proof"
```
### Compliance Audit
Export proof bundles for compliance documentation:
1. Query all active exceptions
2. Export proof bundle for each
3. Generate PDF report with embedded evidence
### Dispute Resolution
When VEX claims conflict:
1. View all claims in proof bundle
2. Compare trust scores and timestamps
3. Document resolution rationale
## Schema Validation
Proof bundles must validate against JSON Schema:
```
$id: https://stellaops.io/schemas/proof-bundle/v1
```
## Related Documentation
- [Exploit Path Inbox](./exploit-path-inbox.md)
- [VEX Trust Scoring](../excititor/scoring.md)
- [Reachability Analysis](../scanner/operations/entrypoint.md)

View File

@@ -0,0 +1,25 @@
# Vulnerability Explorer Overview (Detailed)
The Vulnerability Explorer is the evidence-linked triage surface that brings together SBOM facts, advisory/VEX evidence, reachability signals, policy explainability, and operator decisions into a single auditable workflow.
This document complements the high-level guide `docs/VULNERABILITY_EXPLORER_GUIDE.md` with additional detail and cross-links.
## Core Objects
- **Finding record:** the current enriched view of a vulnerability for a specific artifact/context (tenant, artifact/image digest, policy version).
- **History:** append-only state transitions suitable for audit and replay.
- **Triage actions:** operator actions (assignment, comment, mitigation note, exception request) with provenance.
- **Evidence references:** stable pointers to evidence objects (SBOM slices, VEX observations/linksets, reachability proofs, explain traces, attestations).
## Key Properties
- **Narrative-first:** default view answers “Can I ship? If not, why? Whats the smallest safe change?”
- **Proof-linked:** every important fact links to evidence (no “trust the UI”).
- **Quiet by default, never silent:** suppression/muting is reversible and auditable.
- **Offline-ready:** evidence bundles are verifiable without online lookups.
## References
- High-level guide: `docs/VULNERABILITY_EXPLORER_GUIDE.md`
- Console operator guide: `docs/UI_GUIDE.md`
- Module dossier: `docs/modules/vuln-explorer/architecture.md`

View File

@@ -0,0 +1,32 @@
# Vulnerability Explorer Using the Console
This document describes the operator workflow for triaging findings in the Console. It is intentionally evidence-first and audit-oriented.
## Workflow (Typical)
1. Start from the findings list filtered to the tenant/environment you care about.
2. Open a finding to review:
- Verdict and “why” summary
- Effective VEX status and issuer provenance
- Reachability/impact signals (when available)
- Policy gate and explain trace
3. Record a triage action (assign/comment/mitigation/exception) with justification.
4. Export an evidence bundle when review, escalation, or offline verification is required.
## What to Expect in a Finding View
- Clear tenant context and artifact identifiers
- Evidence rail (SBOM, VEX, advisories, reachability, attestations)
- History/timeline of state changes and actions (append-only)
- Copyable identifiers (finding ID, digests, correlation IDs)
## Offline / Air-Gap Notes
- When operating from Offline Kit snapshots, the Console should surface snapshot identity and staleness budgets.
- Evidence bundle export is the primary bridge between online and offline review.
## References
- Console operator guide: `docs/UI_GUIDE.md`
- Vulnerability Explorer guide: `docs/VULNERABILITY_EXPLORER_GUIDE.md`
- Offline Kit: `docs/OFFLINE_KIT.md`

View File

@@ -0,0 +1,22 @@
# Findings Ledger and Replay (Vulnerability Explorer)
The Findings Ledger is the append-only backbone for auditable triage. It records current finding state, history transitions, and operator actions in a way that supports deterministic replay and offline verification.
This document provides a conceptual overview; the authoritative schema and hashing rules are in the Findings Ledger module docs.
## What the Ledger Stores
- **Finding records:** enriched, policy-derived findings (with references to advisories/VEX/SBOM/reachability and explain traces).
- **History:** append-only state transitions with actor identity, justification, and timestamps (UTC).
- **Triage actions:** discrete operator actions (comment, assignment, mitigation note, ticket link) with immutable provenance.
## Replay and Verification
- Replay reconstructs derived state from append-only history/actions and compares deterministic digests.
- Offline bundles include the ledger exports plus integrity metadata so auditors can verify without trusting a live service.
## References
- Findings Ledger schema: `docs/modules/findings-ledger/schema.md`
- Merkle anchoring policy: `docs/modules/findings-ledger/merkle-anchor-policy.md`
- Vulnerability Explorer dossier: `docs/modules/vuln-explorer/architecture.md`

View File

@@ -0,0 +1,247 @@
# Signed VEX Override Workflow
This guide describes how to create and manage signed VEX override decisions using DSSE attestations for audit-grade provenance.
## Overview
VEX (Vulnerability Exploitability eXchange) decisions allow operators to mark vulnerabilities as not-affected, mitigated, or accepted-risk. When attestation signing is enabled, each override produces a DSSE envelope that:
1. Cryptographically binds the decision to the operator's identity
2. Records the decision in an immutable attestation log
3. Optionally anchors the attestation to Sigstore Rekor for transparency
4. Enables downstream policy engines to require signed overrides
## API Endpoints
### Create Signed Override
```http
POST /v1/vex-decisions
Content-Type: application/json
Authorization: Bearer <token>
{
"findingId": "find-abc123",
"status": "NOT_AFFECTED",
"justification": "CODE_NOT_REACHABLE",
"justificationText": "Static analysis confirms code path is unreachable in production configuration",
"scope": {
"environments": ["production"],
"projects": ["myapp"]
},
"validity": {
"notBefore": "2026-01-15T00:00:00Z",
"notAfter": "2026-07-15T00:00:00Z"
},
"attestationOptions": {
"sign": true,
"keyRef": "default-signing-key",
"rekorUpload": true,
"predicateType": "https://stella.ops/predicates/vex-override/v1"
}
}
```
### Response with Attestation Reference
```json
{
"id": "vex-dec-xyz789",
"findingId": "find-abc123",
"status": "NOT_AFFECTED",
"justification": "CODE_NOT_REACHABLE",
"justificationText": "Static analysis confirms code path is unreachable in production configuration",
"createdAt": "2026-01-15T10:30:00Z",
"createdBy": "user@example.com",
"signedOverride": {
"envelopeDigest": "sha256:abc123def456...",
"signatureAlgorithm": "ECDSA_P256_SHA256",
"signedAt": "2026-01-15T10:30:01Z",
"keyId": "default-signing-key",
"rekorInfo": {
"logIndex": 123456789,
"entryId": "24296fb24b8ad77a...",
"integratedTime": "2026-01-15T10:30:02Z",
"logId": "c0d23d6ad406973f..."
},
"verificationStatus": "VERIFIED"
}
}
```
### Update Signed Override
Updates create superseding records while preserving history:
```http
PATCH /v1/vex-decisions/{id}
Content-Type: application/json
Authorization: Bearer <token>
{
"status": "AFFECTED_MITIGATED",
"justification": "COMPENSATING_CONTROLS",
"justificationText": "WAF rule deployed to block exploit vectors",
"attestationOptions": {
"sign": true,
"supersedes": "vex-dec-xyz789"
}
}
```
### List Decisions with Attestation Filter
```http
GET /v1/vex-decisions?signedOnly=true&rekorAnchored=true
```
### Verify Attestation
```http
POST /v1/vex-decisions/{id}/verify
```
Response:
```json
{
"verified": true,
"signatureValid": true,
"rekorEntryValid": true,
"certificateChain": ["CN=signing-key,..."],
"verifiedAt": "2026-01-15T10:35:00Z"
}
```
## CLI Usage
### Create Signed Override
```bash
stella vex create \
--finding find-abc123 \
--status NOT_AFFECTED \
--justification CODE_NOT_REACHABLE \
--reason "Static analysis confirms unreachable" \
--sign \
--key default-signing-key \
--rekor
```
### View Override with Attestation
```bash
stella vex show vex-dec-xyz789 --include-attestation
```
Output:
```
VEX Decision: vex-dec-xyz789
Finding: find-abc123
Status: NOT_AFFECTED
Justification: CODE_NOT_REACHABLE
Created: 2026-01-15T10:30:00Z
Created By: user@example.com
Attestation:
Envelope Digest: sha256:abc123def456...
Algorithm: ECDSA_P256_SHA256
Signed At: 2026-01-15T10:30:01Z
Verification: VERIFIED
Rekor Entry:
Log Index: 123456789
Entry ID: 24296fb24b8ad77a...
Integrated Time: 2026-01-15T10:30:02Z
```
### Verify Override Attestation
```bash
stella vex verify vex-dec-xyz789
```
### Export Override Evidence
```bash
stella vex export vex-dec-xyz789 \
--format bundle \
--output override-evidence.zip
```
## Policy Engine Integration
Signed overrides can be required by policy rules:
```yaml
# Policy requiring signed VEX overrides
rules:
- id: require-signed-vex
condition: |
vex.status in ["NOT_AFFECTED", "AFFECTED_MITIGATED"]
and (vex.signedOverride == null or vex.signedOverride.verificationStatus != "VERIFIED")
action: FAIL
message: "VEX overrides must be signed and verified"
```
## Attestation Predicate Schema
The VEX override predicate follows in-toto attestation format:
```json
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
{
"name": "finding:find-abc123",
"digest": { "sha256": "..." }
}
],
"predicateType": "https://stella.ops/predicates/vex-override/v1",
"predicate": {
"decision": {
"id": "vex-dec-xyz789",
"status": "NOT_AFFECTED",
"justification": "CODE_NOT_REACHABLE",
"justificationText": "...",
"scope": { "environments": ["production"] },
"validity": { "notBefore": "...", "notAfter": "..." }
},
"finding": {
"id": "find-abc123",
"cve": "CVE-2026-1234",
"package": "example-pkg",
"version": "1.2.3"
},
"operator": {
"identity": "user@example.com",
"authorizedAt": "2026-01-15T10:30:00Z"
},
"supersedes": null
}
}
```
## Security Considerations
1. **Key Management**: Signing keys should be managed through Authority with appropriate access controls
2. **Rekor Anchoring**: Enable Rekor upload for public transparency; disable for air-gapped deployments
3. **Expiry**: Set appropriate validity windows; expired overrides surface warnings
4. **Audit Trail**: All signed overrides are recorded in the findings ledger history
## Offline/Air-Gap Mode
For air-gapped deployments:
1. Rekor upload is disabled automatically
2. Attestations are stored locally with envelope digests
3. Verification uses local trust roots
4. Export bundles include all attestation evidence for manual verification
## Related Documentation
- [VEX Consensus Guide](../../../VEX_CONSENSUS_GUIDE.md)
- [Attestor Architecture](../../attestor/architecture.md)
- [Findings Ledger](./findings-ledger.md)
- [Policy Integration](../../policy/guides/vex-trust-model.md)

View File

@@ -0,0 +1,24 @@
# Vuln Explorer Implementation Plan
## Purpose
Provide a living plan for Vuln Explorer deliverables, dependencies, and evidence.
## Active work
- Track current sprints under `docs/implplan/SPRINT_*.md` for this module.
- Update this file when new scoped work is approved.
## Near-term deliverables
- TBD (add when sprint is staffed).
## Dependencies
- `docs/modules/vuln-explorer/architecture.md`
- `docs/modules/vuln-explorer/README.md`
- `docs/modules/platform/architecture-overview.md`
## Evidence of completion
- Code changes under `src/VulnExplorer/**`.
- Tests and fixtures under the module's `__Tests` / `__Libraries`.
- Docs and runbooks under `docs/modules/vuln-explorer/**`.
## Notes
- Keep deterministic and offline-first expectations aligned with module AGENTS.

View File

@@ -0,0 +1,188 @@
# Vuln Explorer API · v1 (draft 2025-11-25)
openapi: 3.0.3
info:
title: StellaOps Vuln Explorer API
version: "1.0.0-draft.2025-11-25"
description: >
Read-only vulnerability exploration surface. All responses are deterministic
under identical inputs and include policy version + rationale identifiers.
servers:
- url: https://{host}
variables:
host:
default: vuln-explorer.local
tags:
- name: Vulns
paths:
/vulns:
get:
summary: List vulnerabilities
tags: [Vulns]
parameters:
- $ref: '#/components/parameters/Tenant'
- $ref: '#/components/parameters/PolicyVersion'
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/PageToken'
- $ref: '#/components/parameters/Cve'
- $ref: '#/components/parameters/Purl'
- $ref: '#/components/parameters/Severity'
- $ref: '#/components/parameters/Exploitability'
- $ref: '#/components/parameters/FixAvailable'
responses:
'200':
description: Paged vulnerabilities ordered by (score desc, id asc).
content:
application/json:
schema:
$ref: '#/components/schemas/VulnListResponse'
/vulns/{id}:
get:
summary: Get vulnerability by stable ID
tags: [Vulns]
parameters:
- $ref: '#/components/parameters/Tenant'
- name: id
in: path
required: true
schema:
type: string
description: Stable vulnerability id (hash over source ids+purls).
responses:
'200':
description: Vulnerability detail with evidence/provenance.
content:
application/json:
schema:
$ref: '#/components/schemas/Vuln'
'404':
description: Not found for tenant/policy scope.
components:
parameters:
Tenant:
name: x-stella-tenant
in: header
required: true
schema: { type: string }
description: Tenant identifier; required for all endpoints.
PolicyVersion:
name: policyVersion
in: query
schema: { type: string }
description: Policy version/rationale to contextualise scores.
PageSize:
name: pageSize
in: query
schema:
type: integer
minimum: 1
maximum: 200
default: 50
description: Max items per page.
PageToken:
name: pageToken
in: query
schema: { type: string }
description: Opaque token encoding last (score,id) tuple.
Cve:
name: cve
in: query
schema: { type: array, items: { type: string }, minItems: 1 }
style: form
explode: true
description: Filter by CVE ids.
Purl:
name: purl
in: query
schema: { type: array, items: { type: string }, minItems: 1 }
style: form
explode: true
description: Filter by PURL(s); matches affected packages.
Severity:
name: severity
in: query
schema:
type: array
items:
type: string
enum: [CRITICAL, HIGH, MEDIUM, LOW, NONE]
style: form
explode: true
description: Filter by normalized severity band.
Exploitability:
name: exploitability
in: query
schema:
type: string
enum: [known, likely, unknown, none]
description: Derived exploitability flag (from KEV + VEX + telemetry).
FixAvailable:
name: fixAvailable
in: query
schema: { type: boolean }
description: Whether at least one fix is available.
schemas:
VulnListResponse:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/Vuln' }
nextPageToken:
type: string
description: Opaque token encoding last (score,id) tuple.
required: [items]
Vuln:
type: object
properties:
id: { type: string, description: Stable hash id }
source:
type: object
properties:
feed: { type: string, description: Original source/feed name }
advisoryId: { type: string }
cveIds:
type: array
items: { type: string }
ghsaIds:
type: array
items: { type: string }
purls:
type: array
items: { type: string }
severity: { type: string, enum: [CRITICAL, HIGH, MEDIUM, LOW, NONE] }
score: { type: number, format: double, minimum: 0, maximum: 10 }
kev: { type: boolean }
exploitability: { type: string, enum: [known, likely, unknown, none] }
fixAvailable: { type: boolean }
summary: { type: string }
affectedPackages:
type: array
items:
type: object
properties:
purl: { type: string }
versions: { type: array, items: { type: string } }
firstSeen: { type: string, format: date-time }
lastSeen: { type: string, format: date-time }
advisoryRefs:
type: array
items:
type: object
properties:
url: { type: string, format: uri }
title: { type: string }
policyVersion: { type: string }
rationaleId: { type: string }
provenance:
type: object
properties:
ledgerEntryId: { type: string }
evidenceBundleId: { type: string }
required:
- id
- severity
- score
- policyVersion
- rationaleId

View File

@@ -0,0 +1,6 @@
{
"_note": "Placeholder Grafana dashboard stub for offline import. Populate with panel definitions when metrics endpoints are available; see runbooks/observability.md for expected panels.",
"schemaVersion": 39,
"title": "Vuln Explorer Observability (stub)",
"panels": []
}

View File

@@ -0,0 +1,41 @@
# Vuln Explorer observability runbook (demo snapshot · 2025-11-29)
## Dashboards (offline-friendly)
- Grafana JSON: `docs/modules/vuln-explorer/runbooks/dashboards/vuln-explorer-observability.json` (import locally; no external data sources assumed).
- Ops dashboards: `ops/devops/vuln/dashboards/vuln-explorer.json` (CI/staging) adds API latency p95, projection lag, error rate, query budget enforcement.
## Key metrics
- `vuln_projection_lag_seconds{tenant}` seconds between latest ledger event and projector head.
- `vuln_findings_open_total{severity,tenant}` count of open findings by severity.
- `vuln_export_duration_seconds_bucket` histogram for export job runtime.
- `vuln_projection_backlog_total` queued events awaiting projection.
- `vuln_triage_actions_total{type}` immutable triage actions (assign, comment, risk_accept, remediation_note).
- `vuln_api_request_duration_seconds_bucket{route}` API latency for `GET /v1/findings*` and `POST /v1/reports`.
- `vuln_query_hashes_total{tenant,query_hash}` hashed query shapes (no PII) to observe cache effectiveness.
- `vuln_api_payload_bytes_bucket{direction}` request/response size histograms to spot oversized payloads.
## Logs & traces
- Correlate by `correlationId` and `findingId`. Structured fields: `tenant`, `advisoryKey`, `policyVersion`, `projectId`, `route`.
- Query PII guardrail: request filters are hashed (SHA-256 with deployment salt); raw filters are not logged. Strings longer than 128 chars are truncated; known PII fields (`email`, `userId`) are dropped before logging.
- Trace exemplar anchors: `traceparent` headers are copied into logs; exporters stay disabled by default for air-gap. Enable by setting `Telemetry:ExportEnabled=true` and pointing to on-prem Tempo/Jaeger.
## Health/diagnostics
- `/health/liveness` and `/health/readiness` (HTTP 200 expected; readiness checks PostgreSQL + cache reachability).
- `/status` returns build version, git commit, and enabled features; safe for anonymous fetch in sealed environments.
- Ledger replay check: `GET /v1/findings?projectionMode=verify` emits `X-Vuln-Projection-Head` for quick consistency probes.
## Alert hints (wire to local Alertmanager or watchdog)
- Projection lag > 120s for any tenant.
- API p99 latency > 800ms for `GET /v1/findings` or `POST /v1/reports`.
- Export failure rate > 2% over 10m window.
- Accepted-risk approaching expiry within 7d (emit Notify event `vuln.accepted_risk.expiring`).
## Offline verification steps
1) Import Grafana JSON locally and point to Prometheus scrape job `vuln-explorer`.
2) Run `stella vuln export --format json --manifest out/manifest.json` and validate hashes using `jq -r '.files[].sha256'` against generated bundle.
3) Use `curl -s "$BASEURL/status" | jq '{commit,version,features}'` to confirm expected build metadata matches the exported bundle manifest.
## Evidence locations
- Sprint alignment: `docs/implplan/SPRINT_0334_0001_0001_docs_modules_vuln_explorer.md`.
- API contract draft: `docs/modules/vuln-explorer/api.md` and OpenAPI at `docs/modules/vuln-explorer/openapi/vuln-explorer.v1.yaml`.
- Schema references: `docs/modules/vuln-explorer/architecture.md` (ledger model, VEX decision schemas).