Findings Ledger Proxy Contract (Web V)

This contract defines how the Stella Ops Web gateway forwards vulnerability-finding workflow actions (open, ack, close, reopen, export) to the Findings Ledger service. It covers the required headers, idempotency and correlation semantics, retry and offline-kit behavior, and the deterministic error envelope clients can rely on.

Status

Purpose

Required Headers

NameRequirementNotes
Authorization: Bearer <jwt>RequiredRS256/ES256 service token. The Findings Ledger service enforces findings:read (reads) and findings:write (writes/appends); see StellaOps.Findings.Ledger.WebService/Program.cs. (There is no ledger:read/ledger:write scope; the aud=stellaops-ledger audience shown elsewhere is illustrative.)
X-StellaOps-TenantIdRequiredTenant slug/UUID (must align with tenant-auth contract).
X-StellaOps-ProjectConditionalRequired for project-scoped findings. (Legacy alias X-Stella-Project is accepted only when the gateway is started with EnableLegacyHeaders=true.)
X-Idempotency-KeyRequired on POST/PUTDeterministic BLAKE3-256(base64url(tenant + route + canonical_body)); 44 chars. TTL: 24h.
X-Correlation-IdRequiredUUID/ULID stable across gateway → ledger → notifier; echoed by responses.
Content-TypeRequiredapplication/json.
If-MatchOptionalWhen present, ledger enforces optimistic concurrency using the last ETag value.

Behavior

Payload Contract

{
  "action": "ack",               // open|ack|close|reopen|export
  "finding_id": "f-7e12d9",
  "reason_code": "triage_accept",
  "comment": "Owner acknowledged risk and started fix",
  "attachments": [ { "name": "triage.pdf", "digest": "sha256-..." } ],
  "actor": { "subject": "svc-console", "type": "service" },
  "metadata": { "policy_version": "2025.11.0", "vex_statement_id": "vex-123" }
}

Example Request

curl -X POST https://gateway.stellaops.local/ledger/findings/f-7e12d9/actions \
  -H "Authorization: Bearer $LEDGER_TOKEN" \
  -H "X-StellaOps-TenantId: acme-tenant" \
  -H "X-Correlation-Id: 01HXYZABCD1234567890" \
  -H "X-Idempotency-Key: 3cV1..." \
  -H "Content-Type: application/json" \
  --data '{"action":"ack","finding_id":"f-7e12d9","reason_code":"triage_accept","actor":{"subject":"svc-console","type":"service"}}'

Example Response

{
  "status": "accepted",
  "ledger_event_id": "ledg-01HF7T4X6E4S7A6PK8",
  "etag": "W/\"01-2a9c\"",
  "trace_id": "01HXYZABCD1234567890",
  "correlation_id": "01HXYZABCD1234567890"
}

Open Questions