Files
git.stella-ops.org/docs/modules/findings-ledger/openapi/findings-ledger.v1.yaml
StellaOps Bot 48702191be
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
feat(graph-api): Add schema review notes for upcoming Graph API changes
feat(sbomservice): Add placeholder for SHA256SUMS in LNM v1 fixtures

docs(devportal): Create README for SDK archives in public directory

build(devportal): Implement offline bundle build script

test(devportal): Add link checker script for validating links in documentation

test(devportal): Create performance check script for dist folder size

test(devportal): Implement accessibility check script using Playwright and Axe

docs(devportal): Add SDK quickstart guide with examples for Node.js, Python, and cURL

feat(excititor): Implement MongoDB storage for airgap import records

test(findings): Add unit tests for export filters hash determinism

feat(findings): Define attestation contracts for ledger web service

feat(graph): Add MongoDB options and service collection extensions for graph indexing

test(graph): Implement integration tests for MongoDB provider and service collection extensions

feat(zastava): Define configuration options for Zastava surface secrets

build(tests): Create script to run Concelier linkset tests with TRX output
2025-11-22 19:22:30 +02:00

672 lines
20 KiB
YAML

openapi: 3.0.3
info:
title: StellaOps Findings Ledger API
version: 1.0.0-beta1
description: >-
Canonical, aggregation-only surface for append-only findings events, projections, and
Merkle anchoring metadata. Aligns with schema in docs/modules/findings-ledger/schema.md.
servers:
- url: https://{env}.ledger.api.stellaops.local
description: Default environment-scoped host
variables:
env:
default: prod
enum: [dev, staging, prod, airgap]
- url: https://ledger.{region}.offline.bundle
description: Offline bundle host for air-gapped deployments
variables:
region:
default: local
enum: [local]
security:
- bearerAuth: []
- mTLS: []
paths:
/v1/ledger/events:
get:
summary: List ledger events
operationId: listLedgerEvents
tags: [ledger]
parameters:
- $ref: '#/components/parameters/TenantId'
- name: chainId
in: query
required: false
schema:
type: string
format: uuid
- name: sinceSequence
in: query
schema:
type: integer
minimum: 0
- name: limit
in: query
schema:
type: integer
default: 200
maximum: 1000
responses:
'200':
description: Paged ledger events in deterministic order (chainId, sequence_No asc)
headers:
Req-Cursor:
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/LedgerEventPage'
post:
summary: Append deterministic ledger event
operationId: appendLedgerEvent
tags: [ledger]
parameters:
- $ref: '#/components/parameters/TenantId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LedgerEventAppendRequest'
responses:
'201':
description: Event persisted
content:
application/json:
schema:
$ref: '#/components/schemas/LedgerEvent'
'409':
description: Hash/sequence conflict (non-deterministic input)
/v1/ledger/projections/findings:
get:
summary: Get latest projection for findings
operationId: listFindingProjections
tags: [projections]
parameters:
- $ref: '#/components/parameters/TenantId'
- name: findingId
in: query
schema:
type: string
- name: policyVersion
in: query
schema:
type: string
- name: status
in: query
schema:
type: string
- name: limit
in: query
schema:
type: integer
default: 200
maximum: 1000
responses:
'200':
description: Projection rows with cycleHash for replay validation
content:
application/json:
schema:
$ref: '#/components/schemas/FindingProjectionPage'
/v1/ledger/export/findings:
get:
summary: Export findings in deterministic order
operationId: exportFindings
tags: [export]
parameters:
- $ref: '#/components/parameters/TenantId'
- $ref: '#/components/parameters/Shape'
- $ref: '#/components/parameters/SinceSequence'
- $ref: '#/components/parameters/UntilSequence'
- $ref: '#/components/parameters/SinceObservedAt'
- $ref: '#/components/parameters/UntilObservedAt'
- name: finding_status
in: query
schema: { type: string }
- name: severity
in: query
schema: { type: number }
- name: risk_profile_version
in: query
schema: { type: string }
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/PageToken'
responses:
'200':
description: Paged findings export
headers:
X-Stella-Next-Page-Token:
schema: { type: string }
X-Stella-Result-Count:
schema: { type: integer }
content:
application/json:
schema:
$ref: '#/components/schemas/FindingExportPage'
application/x-ndjson:
schema:
type: string
description: NDJSON stream of FindingExportItem
/v1/ledger/export/vex:
get:
summary: Export VEX statements
operationId: exportVex
tags: [export]
parameters:
- $ref: '#/components/parameters/TenantId'
- $ref: '#/components/parameters/Shape'
- $ref: '#/components/parameters/SinceSequence'
- $ref: '#/components/parameters/UntilSequence'
- $ref: '#/components/parameters/SinceObservedAt'
- $ref: '#/components/parameters/UntilObservedAt'
- name: product_id
in: query
schema: { type: string }
- name: advisory_id
in: query
schema: { type: string }
- name: status
in: query
schema: { type: string }
- name: statement_type
in: query
schema: { type: string }
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/PageToken'
responses:
'200':
description: Paged VEX export
headers:
X-Stella-Next-Page-Token:
schema: { type: string }
X-Stella-Result-Count:
schema: { type: integer }
content:
application/json:
schema:
$ref: '#/components/schemas/VexExportPage'
application/x-ndjson:
schema:
type: string
description: NDJSON stream of VexExportItem
/v1/ledger/export/advisories:
get:
summary: Export advisories
operationId: exportAdvisories
tags: [export]
parameters:
- $ref: '#/components/parameters/TenantId'
- $ref: '#/components/parameters/Shape'
- $ref: '#/components/parameters/SinceSequence'
- $ref: '#/components/parameters/UntilSequence'
- $ref: '#/components/parameters/SinceObservedAt'
- $ref: '#/components/parameters/UntilObservedAt'
- name: severity
in: query
schema: { type: string }
- name: source
in: query
schema: { type: string }
- name: cwe_id
in: query
schema: { type: string }
- name: kev
in: query
schema: { type: boolean }
- name: cvss_version
in: query
schema: { type: string }
- name: cvss_score_min
in: query
schema: { type: number }
- name: cvss_score_max
in: query
schema: { type: number }
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/PageToken'
responses:
'200':
description: Paged advisory export
headers:
X-Stella-Next-Page-Token:
schema: { type: string }
X-Stella-Result-Count:
schema: { type: integer }
content:
application/json:
schema:
$ref: '#/components/schemas/AdvisoryExportPage'
application/x-ndjson:
schema:
type: string
description: NDJSON stream of AdvisoryExportItem
/v1/ledger/export/sboms:
get:
summary: Export SBOMs
operationId: exportSboms
tags: [export]
parameters:
- $ref: '#/components/parameters/TenantId'
- $ref: '#/components/parameters/Shape'
- $ref: '#/components/parameters/SinceSequence'
- $ref: '#/components/parameters/UntilSequence'
- $ref: '#/components/parameters/SinceObservedAt'
- $ref: '#/components/parameters/UntilObservedAt'
- name: subject_digest
in: query
schema: { type: string }
- name: sbom_format
in: query
schema: { type: string }
- name: component_purl
in: query
schema: { type: string }
- name: contains_native
in: query
schema: { type: boolean }
- name: slsa_build_type
in: query
schema: { type: string }
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/PageToken'
responses:
'200':
description: Paged SBOM export
headers:
X-Stella-Next-Page-Token:
schema: { type: string }
X-Stella-Result-Count:
schema: { type: integer }
content:
application/json:
schema:
$ref: '#/components/schemas/SbomExportPage'
application/x-ndjson:
schema:
type: string
description: NDJSON stream of SbomExportItem
/v1/ledger/attestations:
get:
summary: List attestation verifications
operationId: listLedgerAttestations
tags: [attestation]
parameters:
- $ref: '#/components/parameters/TenantId'
- name: artifactId
in: query
schema: { type: string }
- name: findingId
in: query
schema: { type: string }
- name: attestationId
in: query
schema: { type: string }
- name: status
in: query
schema:
type: string
enum: [verified, failed, unknown]
- name: sinceRecordedAt
in: query
schema: { type: string, format: date-time }
- name: untilRecordedAt
in: query
schema: { type: string, format: date-time }
- $ref: '#/components/parameters/AttestationLimit'
- $ref: '#/components/parameters/PageToken'
responses:
'200':
description: Paged attestation verifications
headers:
X-Stella-Next-Page-Token:
schema: { type: string }
X-Stella-Result-Count:
schema: { type: integer }
content:
application/json:
schema:
$ref: '#/components/schemas/AttestationExportPage'
application/x-ndjson:
schema:
type: string
description: NDJSON stream of AttestationExportItem
/.well-known/openapi:
get:
summary: Serve Findings Ledger OpenAPI document
operationId: getOpenApi
tags: [metadata]
responses:
'200':
description: OpenAPI YAML document
content:
application/yaml:
schema:
type: string
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
mTLS:
type: mutualTLS
parameters:
TenantId:
name: X-Stella-Tenant
in: header
required: true
schema:
type: string
Shape:
name: shape
in: query
required: true
schema:
type: string
enum: [canonical, compact]
SinceSequence:
name: since_sequence
in: query
schema:
type: integer
minimum: 0
UntilSequence:
name: until_sequence
in: query
schema:
type: integer
minimum: 0
SinceObservedAt:
name: since_observed_at
in: query
schema:
type: string
format: date-time
UntilObservedAt:
name: until_observed_at
in: query
schema:
type: string
format: date-time
PageSize:
name: page_size
in: query
schema:
type: integer
default: 500
maximum: 5000
PageToken:
name: page_token
in: query
schema:
type: string
AttestationLimit:
name: limit
in: query
schema:
type: integer
default: 200
maximum: 1000
schemas:
LedgerEvent:
type: object
required: [event]
properties:
event:
type: object
required: [id, type, tenant, chainId, sequence, policyVersion, occurredAt, recordedAt, payload]
properties:
id:
type: string
format: uuid
type:
type: string
description: ledger_event_type (see schema.md §2.2)
tenant:
type: string
chainId:
type: string
format: uuid
sequence:
type: integer
policyVersion:
type: string
finding:
type: object
properties:
id: { type: string }
artifactId: { type: string }
vulnId: { type: string }
actor:
type: object
properties:
id: { type: string }
type: { type: string }
occurredAt:
type: string
format: date-time
recordedAt:
type: string
format: date-time
payload:
type: object
additionalProperties: true
evidenceBundleRef:
type: string
eventHash:
type: string
previousHash:
type: string
merkleLeafHash:
type: string
LedgerEventPage:
type: object
required: [items]
properties:
items:
type: array
items:
$ref: '#/components/schemas/LedgerEvent'
nextCursor:
type: string
LedgerEventAppendRequest:
type: object
required: [id, type, tenant, chainId, sequence, policyVersion, occurredAt, payload]
properties:
id:
type: string
format: uuid
type:
type: string
tenant:
type: string
chainId:
type: string
format: uuid
sequence:
type: integer
policyVersion:
type: string
finding:
type: object
properties:
id: { type: string }
artifactId: { type: string }
vulnId: { type: string }
actor:
type: object
properties:
id: { type: string }
type: { type: string }
occurredAt:
type: string
format: date-time
payload:
type: object
additionalProperties: true
evidenceBundleRef:
type: string
previousHash:
type: string
description: Optional; validated if supplied
merkleLeafHash:
type: string
description: Optional; server recomputes to validate determinism
FindingProjection:
type: object
required: [tenantId, findingId, policyVersion, status, cycleHash]
properties:
tenantId: { type: string }
findingId: { type: string }
policyVersion: { type: string }
status: { type: string }
severity:
type: number
format: double
riskScore:
type: number
format: double
riskSeverity:
type: string
riskProfileVersion:
type: string
riskExplanationId:
type: string
format: uuid
labels:
type: object
additionalProperties: true
currentEventId:
type: string
format: uuid
cycleHash:
type: string
updatedAt:
type: string
format: date-time
FindingProjectionPage:
type: object
required: [items]
properties:
items:
type: array
items:
$ref: '#/components/schemas/FindingProjection'
nextCursor:
type: string
ExportProvenance:
type: object
properties:
policyVersion: { type: string }
cycleHash: { type: string }
ledgerEventHash: { type: string }
FindingExportItem:
type: object
properties:
eventSequence: { type: integer }
observedAt: { type: string, format: date-time }
findingId: { type: string }
policyVersion: { type: string }
status: { type: string }
severity: { type: number, format: double }
cycleHash: { type: string }
evidenceBundleRef: { type: string }
provenance:
$ref: '#/components/schemas/ExportProvenance'
labels:
type: object
additionalProperties: true
VexExportItem:
type: object
properties:
eventSequence: { type: integer }
observedAt: { type: string, format: date-time }
vexStatementId: { type: string }
productId: { type: string }
status: { type: string }
statementType: { type: string }
knownExploited: { type: boolean }
cycleHash: { type: string }
provenance:
$ref: '#/components/schemas/ExportProvenance'
AdvisoryExportItem:
type: object
properties:
eventSequence: { type: integer }
published: { type: string, format: date-time }
advisoryId: { type: string }
source: { type: string }
title: { type: string }
severity: { type: string }
cvssScore: { type: number, format: double }
cvssVector: { type: string }
kev: { type: boolean }
cycleHash: { type: string }
provenance:
$ref: '#/components/schemas/ExportProvenance'
SbomExportItem:
type: object
properties:
eventSequence: { type: integer }
createdAt: { type: string, format: date-time }
sbomId: { type: string }
subjectDigest: { type: string }
sbomFormat: { type: string }
componentsCount: { type: integer }
hasVulnerabilities: { type: boolean }
cycleHash: { type: string }
provenance:
$ref: '#/components/schemas/ExportProvenance'
FindingExportPage:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/FindingExportItem' }
nextPageToken: { type: string }
VexExportPage:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/VexExportItem' }
nextPageToken: { type: string }
AdvisoryExportPage:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/AdvisoryExportItem' }
nextPageToken: { type: string }
SbomExportPage:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/SbomExportItem' }
nextPageToken: { type: string }
AttestationExportItem:
type: object
properties:
attestationId: { type: string }
artifactId: { type: string }
findingId: { type: string }
verificationStatus: { type: string }
verificationTime: { type: string, format: date-time }
dsseDigest: { type: string }
rekorEntryId: { type: string }
evidenceBundleRef: { type: string }
ledgerEventId: { type: string, format: uuid }
recordedAt: { type: string, format: date-time }
merkleLeafHash: { type: string }
rootHash: { type: string }
AttestationExportPage:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/AttestationExportItem' }
nextPageToken: { type: string }