Findings Ledger

The Findings Ledger is the immutable, append-only event store that records vulnerability findings, policy decisions, and workflow state changes across the Stella Ops platform. It gives operators and auditors a tamper-evident, replayable history of how every finding reached its current state.

Purpose

Consolidated modules (Sprint 207)

The src/Findings/ directory is the unified home for all findings-related services:

Previously archived docs for RiskEngine and VulnExplorer are in docs-archive/modules/risk-engine/ and docs-archive/modules/vuln-explorer/.

Core API surface (selected)

The Findings Ledger WebService (StellaOps.Findings.Ledger.WebService) hosts the ledger write/read surface plus the merged VulnExplorer, scoring, and runtime endpoints. Routes and authorization are grounded in Program.cs and the Endpoints/ handlers.

RouteVerbAuthorization policyScope grounding
/vuln/ledger/eventsPOSTledger.events.writeconfigured RequiredScopes (default vuln:operate)
/api/v1/findings/ledger/advanced-assurance/appendPOSTledger.events.writeconfigured RequiredScopes (default vuln:operate)
/api/v1/findings/ledgerGETledger.export.readconfigured RequiredScopes (default vuln:operate)
/api/v1/findings/ledger/{ledgerId:guid}/chain-verifyGETledger.export.readconfigured RequiredScopes (default vuln:operate)
/ledger/export/{findings,vex,advisories,sboms}GETledger.export.readconfigured RequiredScopes (default vuln:operate)
/api/v1/findings/{findingId}/statePATCH(default policy)configured RequiredScopes (default vuln:operate)
/api/v1/findings/{findingId}/score, /scoresPOSTscoring.writeconfigured RequiredScopes (default vuln:operate)
/api/v1/findings/{findingId}/scoreGETscoring.readconfigured RequiredScopes (default vuln:operate)
/api/v2/security/vulnerabilities/{identifier}GETscoring.readconfigured RequiredScopes (default vuln:operate)
/api/v1/findings/{findingId:guid}/runtime/tracesPOSTfindings.runtime.writefindings:write (StellaOpsScopes.FindingsWrite)
runtime list/score/timeline readsGETfindings.runtime.readfindings:read (StellaOpsScopes.FindingsRead)
/v1/vulns, /v1/vulns/{id}, /v1/vex-decisions (read), /v1/evidence-subgraph/{vulnId}GETVulnExplorer.Viewvuln:view (StellaOpsScopes.VulnView)
/v1/vex-decisions (POST/PATCH), /v1/fix-verifications (POST/PATCH)POST/PATCHVulnExplorer.Operatevuln:operate (StellaOpsScopes.VulnOperate)
/v1/audit-bundlesPOSTVulnExplorer.Auditvuln:audit (StellaOpsScopes.VulnAudit)

The ledger.* and scoring.* policies are bound to whatever findings:ledger:Authority:RequiredScopes resolves to (they do not pin a fixed scope constant); when that list is empty the service falls back to vuln:operate (StellaOpsScopes.VulnOperate). Only the runtime (findings.runtime.*) and VulnExplorer (VulnExplorer.*) policies pin specific scope constants. Tenant resolution uses X-StellaOps-TenantId / X-StellaOps-Tenant headers or the stellaops:tenant claim via StellaOpsTenantResolver. vuln:read is deprecated in favour of vuln:view.

Persistence (schema findings, owned tables in migrations/001_initial.sql and later): ledger_events (append-only, LIST-partitioned by tenant_id, hash-chained via event_hash/previous_hash/merkle_leaf_hash), ledger_merkle_roots, findings_projection, finding_history, and triage_actions. The ledger event-type enum (finding.created, finding.status_changed, …, finding.closed, plus airgap.*, orchestrator.export_recorded, attestation.pointer_linked, and the nis2.*/cra.* incident families) is defined in Domain/LedgerEventConstants.cs. The write path returns a LedgerWriteStatus of Success (201), Idempotent (200), ValidationFailed (400), or Conflict (409).

Compatibility read-model surfaces

Runtime cutover status

Implementation Status

Historical roadmap (largely delivered). The four delivery phases below were the original build-out plan. The code now reflects substantial completion of all four; the phase list is retained for traceability, with the current grounding noted inline. For the live, source-accurate surface, see architecture.mdand the Runtime cutover status section above.

Delivery Phases

Key Dependencies (historical)

Acceptance Criteria (historical)