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: AGPL-3.0-or-later url: https://www.gnu.org/licenses/agpl-3.0.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