705 lines
18 KiB
YAML
705 lines
18 KiB
YAML
openapi: 3.1.0
|
|
info:
|
|
title: StellaOps Evidence & Decision API
|
|
description: |
|
|
REST API for evidence retrieval and decision recording.
|
|
Sprint: SPRINT_3602_0001_0001
|
|
Updated: SPRINT_20260112_005_BE_evidence_card_api (EVPCARD-BE-002)
|
|
version: 1.1.0
|
|
license:
|
|
name: BUSL-1.1
|
|
url: https://spdx.org/licenses/BUSL-1.1.html
|
|
|
|
servers:
|
|
- url: /v1
|
|
description: API v1
|
|
|
|
security:
|
|
- bearerAuth: []
|
|
|
|
paths:
|
|
/alerts:
|
|
get:
|
|
operationId: listAlerts
|
|
summary: List alerts with filtering and pagination
|
|
tags:
|
|
- Alerts
|
|
parameters:
|
|
- name: band
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [critical, high, medium, low, info]
|
|
- name: severity
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: status
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [open, acknowledged, resolved, suppressed]
|
|
- name: artifactId
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: vulnId
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: componentPurl
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 50
|
|
maximum: 500
|
|
- name: offset
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 0
|
|
responses:
|
|
'200':
|
|
description: Alert list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AlertListResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/alerts/{alertId}:
|
|
get:
|
|
operationId: getAlert
|
|
summary: Get alert details
|
|
tags:
|
|
- Alerts
|
|
parameters:
|
|
- $ref: '#/components/parameters/alertId'
|
|
responses:
|
|
'200':
|
|
description: Alert details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AlertSummary'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/alerts/{alertId}/evidence:
|
|
get:
|
|
operationId: getAlertEvidence
|
|
summary: Get evidence bundle for an alert
|
|
tags:
|
|
- Evidence
|
|
parameters:
|
|
- $ref: '#/components/parameters/alertId'
|
|
responses:
|
|
'200':
|
|
description: Evidence payload
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EvidencePayloadResponse'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/alerts/{alertId}/decisions:
|
|
post:
|
|
operationId: recordDecision
|
|
summary: Record a decision for an alert
|
|
tags:
|
|
- Decisions
|
|
parameters:
|
|
- $ref: '#/components/parameters/alertId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DecisionRequest'
|
|
responses:
|
|
'201':
|
|
description: Decision recorded
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DecisionResponse'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
|
|
/alerts/{alertId}/audit:
|
|
get:
|
|
operationId: getAlertAudit
|
|
summary: Get audit timeline for an alert
|
|
tags:
|
|
- Audit
|
|
parameters:
|
|
- $ref: '#/components/parameters/alertId'
|
|
responses:
|
|
'200':
|
|
description: Audit timeline
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AuditTimelineResponse'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/alerts/{alertId}/bundle:
|
|
get:
|
|
operationId: downloadAlertBundle
|
|
summary: Download evidence bundle as tar.gz
|
|
tags:
|
|
- Bundles
|
|
parameters:
|
|
- $ref: '#/components/parameters/alertId'
|
|
responses:
|
|
'200':
|
|
description: Evidence bundle file
|
|
content:
|
|
application/gzip:
|
|
schema:
|
|
type: string
|
|
format: binary
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/alerts/{alertId}/bundle/verify:
|
|
post:
|
|
operationId: verifyAlertBundle
|
|
summary: Verify evidence bundle integrity
|
|
tags:
|
|
- Bundles
|
|
parameters:
|
|
- $ref: '#/components/parameters/alertId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/BundleVerificationRequest'
|
|
responses:
|
|
'200':
|
|
description: Verification result
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/BundleVerificationResponse'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
# Sprint: SPRINT_20260112_005_BE_evidence_card_api (EVPCARD-BE-002)
|
|
/evidence-packs/{packId}/export:
|
|
get:
|
|
operationId: exportEvidencePack
|
|
summary: Export evidence pack in various formats
|
|
description: |
|
|
Exports an evidence pack in the specified format. Supports JSON, signed JSON,
|
|
Markdown, HTML, PDF, and evidence-card formats.
|
|
|
|
**Evidence Card formats** (v1.1):
|
|
- `evidence-card`: Full evidence card with SBOM excerpt, DSSE envelope, and Rekor receipt
|
|
- `card-compact`: Compact evidence card without full SBOM
|
|
tags:
|
|
- EvidencePacks
|
|
parameters:
|
|
- name: packId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
description: Evidence pack identifier
|
|
- name: format
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: string
|
|
enum: [json, signedjson, markdown, md, html, pdf, evidence-card, evidencecard, card, card-compact, evidencecardcompact]
|
|
default: json
|
|
description: |
|
|
Export format. Format aliases:
|
|
- `evidence-card`, `evidencecard`, `card` → Evidence Card
|
|
- `card-compact`, `evidencecardcompact` → Compact Evidence Card
|
|
responses:
|
|
'200':
|
|
description: Exported evidence pack
|
|
headers:
|
|
X-Evidence-Pack-Id:
|
|
schema:
|
|
type: string
|
|
description: Evidence pack identifier
|
|
X-Content-Digest:
|
|
schema:
|
|
type: string
|
|
description: SHA-256 content digest of the pack
|
|
X-Evidence-Card-Version:
|
|
schema:
|
|
type: string
|
|
description: Evidence card schema version (only for evidence-card formats)
|
|
X-Rekor-Log-Index:
|
|
schema:
|
|
type: integer
|
|
format: int64
|
|
description: Rekor transparency log index (only for evidence-card formats with Rekor receipt)
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EvidencePackExport'
|
|
application/vnd.stellaops.evidence-card+json:
|
|
schema:
|
|
$ref: '#/components/schemas/EvidenceCard'
|
|
text/markdown:
|
|
schema:
|
|
type: string
|
|
text/html:
|
|
schema:
|
|
type: string
|
|
application/pdf:
|
|
schema:
|
|
type: string
|
|
format: binary
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
components:
|
|
securitySchemes:
|
|
bearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
|
|
parameters:
|
|
alertId:
|
|
name: alertId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
description: Alert identifier
|
|
|
|
responses:
|
|
BadRequest:
|
|
description: Bad request
|
|
content:
|
|
application/problem+json:
|
|
schema:
|
|
$ref: '#/components/schemas/ProblemDetails'
|
|
Unauthorized:
|
|
description: Unauthorized
|
|
NotFound:
|
|
description: Resource not found
|
|
|
|
schemas:
|
|
AlertListResponse:
|
|
type: object
|
|
required:
|
|
- items
|
|
- total_count
|
|
properties:
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AlertSummary'
|
|
total_count:
|
|
type: integer
|
|
next_page_token:
|
|
type: string
|
|
|
|
AlertSummary:
|
|
type: object
|
|
required:
|
|
- alert_id
|
|
- artifact_id
|
|
- vuln_id
|
|
- severity
|
|
- band
|
|
- status
|
|
- created_at
|
|
properties:
|
|
alert_id:
|
|
type: string
|
|
artifact_id:
|
|
type: string
|
|
vuln_id:
|
|
type: string
|
|
component_purl:
|
|
type: string
|
|
severity:
|
|
type: string
|
|
band:
|
|
type: string
|
|
enum: [critical, high, medium, low, info]
|
|
status:
|
|
type: string
|
|
enum: [open, acknowledged, resolved, suppressed]
|
|
score:
|
|
type: number
|
|
format: double
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
decision_count:
|
|
type: integer
|
|
|
|
EvidencePayloadResponse:
|
|
type: object
|
|
required:
|
|
- alert_id
|
|
properties:
|
|
alert_id:
|
|
type: string
|
|
reachability:
|
|
$ref: '#/components/schemas/EvidenceSection'
|
|
callstack:
|
|
$ref: '#/components/schemas/EvidenceSection'
|
|
vex:
|
|
$ref: '#/components/schemas/EvidenceSection'
|
|
|
|
EvidenceSection:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
hash:
|
|
type: string
|
|
source:
|
|
type: string
|
|
|
|
DecisionRequest:
|
|
type: object
|
|
required:
|
|
- decision
|
|
- rationale
|
|
properties:
|
|
decision:
|
|
type: string
|
|
enum: [accept_risk, mitigate, suppress, escalate]
|
|
rationale:
|
|
type: string
|
|
minLength: 10
|
|
maxLength: 2000
|
|
justification_code:
|
|
type: string
|
|
metadata:
|
|
type: object
|
|
|
|
DecisionResponse:
|
|
type: object
|
|
required:
|
|
- decision_id
|
|
- alert_id
|
|
- decision
|
|
- recorded_at
|
|
properties:
|
|
decision_id:
|
|
type: string
|
|
alert_id:
|
|
type: string
|
|
decision:
|
|
type: string
|
|
rationale:
|
|
type: string
|
|
recorded_at:
|
|
type: string
|
|
format: date-time
|
|
recorded_by:
|
|
type: string
|
|
replay_token:
|
|
type: string
|
|
|
|
AuditTimelineResponse:
|
|
type: object
|
|
required:
|
|
- alert_id
|
|
- events
|
|
- total_count
|
|
properties:
|
|
alert_id:
|
|
type: string
|
|
events:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AuditEvent'
|
|
total_count:
|
|
type: integer
|
|
|
|
AuditEvent:
|
|
type: object
|
|
required:
|
|
- event_id
|
|
- event_type
|
|
- timestamp
|
|
properties:
|
|
event_id:
|
|
type: string
|
|
event_type:
|
|
type: string
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
actor:
|
|
type: string
|
|
details:
|
|
type: object
|
|
replay_token:
|
|
type: string
|
|
|
|
BundleVerificationRequest:
|
|
type: object
|
|
required:
|
|
- bundle_hash
|
|
properties:
|
|
bundle_hash:
|
|
type: string
|
|
description: SHA-256 hash of the bundle
|
|
signature:
|
|
type: string
|
|
description: Optional DSSE signature
|
|
|
|
BundleVerificationResponse:
|
|
type: object
|
|
required:
|
|
- alert_id
|
|
- is_valid
|
|
- verified_at
|
|
properties:
|
|
alert_id:
|
|
type: string
|
|
is_valid:
|
|
type: boolean
|
|
verified_at:
|
|
type: string
|
|
format: date-time
|
|
signature_valid:
|
|
type: boolean
|
|
hash_valid:
|
|
type: boolean
|
|
chain_valid:
|
|
type: boolean
|
|
errors:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
ProblemDetails:
|
|
type: object
|
|
properties:
|
|
type:
|
|
type: string
|
|
title:
|
|
type: string
|
|
status:
|
|
type: integer
|
|
detail:
|
|
type: string
|
|
instance:
|
|
type: string
|
|
|
|
# Sprint: SPRINT_20260112_005_BE_evidence_card_api (EVPCARD-BE-002)
|
|
EvidencePackExport:
|
|
type: object
|
|
required:
|
|
- pack_id
|
|
- format
|
|
- content_type
|
|
- file_name
|
|
properties:
|
|
pack_id:
|
|
type: string
|
|
description: Evidence pack identifier
|
|
format:
|
|
type: string
|
|
enum: [json, signedjson, markdown, html, pdf, evidence-card, evidence-card-compact]
|
|
description: Export format used
|
|
content_type:
|
|
type: string
|
|
description: MIME content type
|
|
file_name:
|
|
type: string
|
|
description: Suggested filename for download
|
|
content_digest:
|
|
type: string
|
|
description: SHA-256 digest of the content
|
|
|
|
EvidenceCard:
|
|
type: object
|
|
description: |
|
|
Single-file evidence card packaging SBOM excerpt, DSSE envelope, and Rekor receipt.
|
|
Designed for offline verification and audit trail.
|
|
required:
|
|
- card_id
|
|
- version
|
|
- pack_id
|
|
- created_at
|
|
- subject
|
|
- envelope
|
|
properties:
|
|
card_id:
|
|
type: string
|
|
description: Unique evidence card identifier
|
|
version:
|
|
type: string
|
|
description: Evidence card schema version (e.g., "1.0.0")
|
|
pack_id:
|
|
type: string
|
|
description: Source evidence pack identifier
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
description: Card creation timestamp (ISO 8601 UTC)
|
|
subject:
|
|
$ref: '#/components/schemas/EvidenceCardSubject'
|
|
envelope:
|
|
$ref: '#/components/schemas/DsseEnvelope'
|
|
sbom_excerpt:
|
|
$ref: '#/components/schemas/SbomExcerpt'
|
|
rekor_receipt:
|
|
$ref: '#/components/schemas/RekorReceipt'
|
|
content_digest:
|
|
type: string
|
|
description: SHA-256 digest of canonical card content
|
|
|
|
EvidenceCardSubject:
|
|
type: object
|
|
required:
|
|
- type
|
|
properties:
|
|
type:
|
|
type: string
|
|
enum: [finding, cve, component, image, policy, custom]
|
|
finding_id:
|
|
type: string
|
|
cve_id:
|
|
type: string
|
|
component:
|
|
type: string
|
|
description: Component PURL
|
|
image_digest:
|
|
type: string
|
|
|
|
DsseEnvelope:
|
|
type: object
|
|
description: Dead Simple Signing Envelope (DSSE) per https://github.com/secure-systems-lab/dsse
|
|
required:
|
|
- payload_type
|
|
- payload
|
|
- signatures
|
|
properties:
|
|
payload_type:
|
|
type: string
|
|
description: Media type of the payload
|
|
payload:
|
|
type: string
|
|
format: byte
|
|
description: Base64-encoded payload
|
|
signatures:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/DsseSignature'
|
|
|
|
DsseSignature:
|
|
type: object
|
|
required:
|
|
- sig
|
|
properties:
|
|
keyid:
|
|
type: string
|
|
description: Key identifier
|
|
sig:
|
|
type: string
|
|
format: byte
|
|
description: Base64-encoded signature
|
|
|
|
SbomExcerpt:
|
|
type: object
|
|
description: Relevant excerpt from the SBOM for the evidence subject
|
|
properties:
|
|
format:
|
|
type: string
|
|
enum: [spdx-2.2, spdx-2.3, cyclonedx-1.5, cyclonedx-1.6]
|
|
component_name:
|
|
type: string
|
|
component_version:
|
|
type: string
|
|
component_purl:
|
|
type: string
|
|
licenses:
|
|
type: array
|
|
items:
|
|
type: string
|
|
vulnerabilities:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
RekorReceipt:
|
|
type: object
|
|
description: Sigstore Rekor transparency log receipt for offline verification
|
|
required:
|
|
- log_index
|
|
- log_id
|
|
- integrated_time
|
|
properties:
|
|
log_index:
|
|
type: integer
|
|
format: int64
|
|
description: Rekor log index
|
|
log_id:
|
|
type: string
|
|
description: Rekor log ID (base64-encoded SHA-256 of public key)
|
|
integrated_time:
|
|
type: integer
|
|
format: int64
|
|
description: Unix timestamp when entry was integrated
|
|
inclusion_proof:
|
|
$ref: '#/components/schemas/InclusionProof'
|
|
inclusion_promise:
|
|
$ref: '#/components/schemas/SignedEntryTimestamp'
|
|
|
|
InclusionProof:
|
|
type: object
|
|
description: Merkle tree inclusion proof for log entry
|
|
properties:
|
|
log_index:
|
|
type: integer
|
|
format: int64
|
|
root_hash:
|
|
type: string
|
|
format: byte
|
|
tree_size:
|
|
type: integer
|
|
format: int64
|
|
hashes:
|
|
type: array
|
|
items:
|
|
type: string
|
|
format: byte
|
|
|
|
SignedEntryTimestamp:
|
|
type: object
|
|
description: Signed Entry Timestamp (SET) from Rekor
|
|
properties:
|
|
log_id:
|
|
type: string
|
|
format: byte
|
|
integrated_time:
|
|
type: integer
|
|
format: int64
|
|
signature:
|
|
type: string
|
|
format: byte
|