Files
git.stella-ops.org/docs/modules/findings-ledger/export-http-surface.md
master 79b8e53441
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Add new features and tests for AirGap and Time modules
- Introduced `SbomService` tasks documentation.
- Updated `StellaOps.sln` to include new projects: `StellaOps.AirGap.Time` and `StellaOps.AirGap.Importer`.
- Added unit tests for `BundleImportPlanner`, `DsseVerifier`, `ImportValidator`, and other components in the `StellaOps.AirGap.Importer.Tests` namespace.
- Implemented `InMemoryBundleRepositories` for testing bundle catalog and item repositories.
- Created `MerkleRootCalculator`, `RootRotationPolicy`, and `TufMetadataValidator` tests.
- Developed `StalenessCalculator` and `TimeAnchorLoader` tests in the `StellaOps.AirGap.Time.Tests` namespace.
- Added `fetch-sbomservice-deps.sh` script for offline dependency fetching.
2025-11-20 23:29:54 +02:00

5.3 KiB

Findings Ledger Export HTTP Surface

Prep task: PREP-LEDGER-EXPORT-35-001-NO-HTTP-API-SURFACE (Sprint 0121)

Goals

  • Publish an HTTP surface for deterministic, offline-friendly exports of Findings Ledger data (findings, VEX, advisories, SBOMs) so downstream SDK/OpenAPI tasks can proceed.
  • Define filter contract, pagination, media types, and provenance fields required by Evidence Locker and Policy Engine consumers.

Non-goals

  • Implementing the endpoints (covered by LEDGER-EXPORT-35-001).
  • Final OAS/SDK generation (tracked in PREP-LEDGER-OAS-61-001/002/62-001/63-001).

Base Service

  • Host: findings-ledger service (minimal API) under src/Findings/StellaOps.Findings.Ledger.
  • Base path: /ledger/export.
  • Auth: service-to-service bearer token; require scope=ledger.export.read.
  • Tenancy: X-Stella-Tenant header (strictly required); responses never mix tenants.
  • Determinism: server sorts by (event_sequence, projection_version, cycle_hash); pagination tokens encode the last emitted tuple and filter set. No wall-clock dependence.
  • Media types: default application/x-ndjson; clients may request application/json (array) for small result sets. Always emit Content-Encoding: gzip when Accept-Encoding allows.

Endpoints

1) Findings

  • GET /ledger/export/findings
  • Filters (all optional unless noted):
    • shape (required): canonical | compact (controls payload shape; compact strips verbose provenance fields for air-gap bundles)
    • since_sequence (long, ≥0), until_sequence (long, inclusive) — enables range slicing.
    • since_observed_at, until_observed_at (ISO-8601 UTC) — observation window.
    • advisory_id (repeatable), component_purl (repeatable), finding_status (open|fixed|dismissed), severity (critical|high|medium|low|unknown).
    • risk_profile_version (string) — filters by attached risk profile revision.
  • Response item (canonical shape):
    • finding_id, event_sequence, observed_at, component (purl, version, source), advisories (ids, cwes), status, severity, risk (score, severity, profile_version, explanation_id), projection_version, cycle_hash, evidence_bundle_ref (digest, dsse_digest, timeline_ref), provenance (ledger_root, projector_version, policy_version, datasource_ids).

2) VEX

  • GET /ledger/export/vex
  • Filters: shape, since_sequence/until_sequence, since_observed_at/until_observed_at, product_id (repeatable), advisory_id, status (affected|not_affected|under_investigation), statement_type (exploitation|justification).
  • Response item adds vex_statement_id, product (purl or CPE), status_justification, known_exploited (bool), timestamp, projection_version, cycle_hash, provenance.

3) Advisories

  • GET /ledger/export/advisories
  • Filters: shape, since_sequence/until_sequence, severity, source (feed id), cwe_id, kev (bool), cvss_version, cvss_score_min, cvss_score_max.
  • Response item: advisory_id, source, title, description, cwes, cvss (version, vector, base_score), published, modified, status, epss (score, percentile), projection_version, cycle_hash, provenance.

4) SBOMs

  • GET /ledger/export/sboms
  • Filters: shape, since_sequence/until_sequence, since_observed_at/until_observed_at, subject_digest (OCI digest), sbom_format (spdx-json | cyclonedx-json), component_purl (repeatable), contains_native (bool), slsa_build_type (string).
  • Response item: sbom_id, subject (digest, media_type), sbom_format, created_at, components_count, has_vulnerabilities (bool), materials (digests), projection_version, cycle_hash, provenance.

Pagination

  • Cursor param: page_token (opaque base64url JSON: { "last": { "event_sequence": long, "projection_version": string, "cycle_hash": string }, "filters_hash": sha256 }).
  • Page size: page_size (default 500, max 5000). Server rejects if page_size differs across pages for same token.
  • Response envelope (for both NDJSON and JSON array):
    • Header X-Stella-Next-Page-Token when more data exists.
    • Header X-Stella-Result-Count with items count.
    • When Prefer: return=minimal is set, omit envelope body for NDJSON; clients rely on headers.

Error Contract

  • 400: unknown filter, invalid range, or filter combination mismatch with filters_hash inside page_token.
  • 401/403: missing or insufficient scope.
  • 409: requested shape not compatible with downstream air-gap mode (compact requested where policy mandates canonical).
  • 429: enforcement of determinism guard (server detected projection drift vs cycle_hash); include X-Stella-Drift-Reason.

Observability & Determinism Hooks

  • Emit structured logs ledger.export.request and ledger.export.emit with tenant, endpoint, filters_hash, page_size, result_count, duration_ms.
  • Counters: ledger_export_items_total{endpoint,tenant} and ledger_export_failures_total{endpoint,reason}.
  • Traces: span name ledger.export.{endpoint}; attach filters_hash, page_size, next_page_token_present attributes.

artefact location

  • This document: docs/modules/findings-ledger/export-http-surface.md (hash stability: keep deterministic ordering as authored on 2025-11-20).
  • Link from sprint 0121 PREP-LEDGER-EXPORT-35-001; downstream tasks should reference this path for contract details.