664 lines
20 KiB
YAML
664 lines
20 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: StellaOps ExportCenter API
|
|
version: 1.0.0
|
|
description: >-
|
|
Export profiles, runs, and deterministic bundle downloads for air-gap and offline deployments.
|
|
Supports attestation exports, mirror bundles, bootstrap packs, and portable evidence bundles.
|
|
contact:
|
|
name: StellaOps Exporter Service Guild
|
|
x-stella-oas-revision: '2025-12-07'
|
|
servers:
|
|
- url: https://{env}.export.api.stellaops.local
|
|
description: Default environment-scoped host
|
|
variables:
|
|
env:
|
|
default: prod
|
|
enum: [dev, staging, prod, airgap]
|
|
- url: https://export.{region}.offline.bundle
|
|
description: Offline bundle host for air-gapped deployments
|
|
variables:
|
|
region:
|
|
default: local
|
|
enum: [local]
|
|
security:
|
|
- bearerAuth: []
|
|
- mTLS: []
|
|
paths:
|
|
/.well-known/openapi:
|
|
get:
|
|
summary: OpenAPI discovery endpoint
|
|
operationId: getOpenApiDiscovery
|
|
tags: [discovery]
|
|
security: []
|
|
responses:
|
|
'200':
|
|
description: OpenAPI specification document
|
|
headers:
|
|
ETag:
|
|
description: SHA-256 hash of the OAS document
|
|
schema:
|
|
type: string
|
|
example: '"sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"'
|
|
X-Export-Oas-Version:
|
|
description: OAS version identifier
|
|
schema:
|
|
type: string
|
|
example: 'v1'
|
|
Last-Modified:
|
|
description: OAS document last modification time
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
example: '2025-01-01T00:00:00Z'
|
|
Cache-Control:
|
|
description: Cache directive
|
|
schema:
|
|
type: string
|
|
example: 'private, must-revalidate'
|
|
content:
|
|
application/yaml:
|
|
schema:
|
|
type: string
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
|
|
/v1/exports/profiles:
|
|
get:
|
|
summary: List available export profiles
|
|
operationId: listExportProfiles
|
|
tags: [profiles]
|
|
parameters:
|
|
- name: kind
|
|
in: query
|
|
description: Filter by profile kind
|
|
schema:
|
|
type: string
|
|
enum: [attestation, mirror, bootstrap, airgap-evidence]
|
|
- name: limit
|
|
in: query
|
|
description: Maximum number of profiles to return
|
|
schema:
|
|
type: integer
|
|
default: 50
|
|
maximum: 200
|
|
- name: cursor
|
|
in: query
|
|
description: Pagination cursor from previous response
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: List of export profiles
|
|
headers:
|
|
X-Stella-Quota-Remaining:
|
|
schema:
|
|
type: integer
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ExportProfilePage'
|
|
example:
|
|
profiles:
|
|
- id: 'profile-attestation-v1'
|
|
kind: 'attestation'
|
|
description: 'Export attestation bundles with DSSE envelopes'
|
|
version: 'v1'
|
|
retentionDays: 90
|
|
- id: 'profile-mirror-full'
|
|
kind: 'mirror'
|
|
description: 'Full mirror bundle with all advisories'
|
|
version: 'v1'
|
|
retentionDays: 365
|
|
cursor: null
|
|
hasMore: false
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/v1/exports/runs:
|
|
get:
|
|
summary: List export runs
|
|
operationId: listExportRuns
|
|
tags: [runs]
|
|
parameters:
|
|
- $ref: '#/components/parameters/TenantId'
|
|
- name: profileId
|
|
in: query
|
|
description: Filter by export profile
|
|
schema:
|
|
type: string
|
|
- name: status
|
|
in: query
|
|
description: Filter by status
|
|
schema:
|
|
type: string
|
|
enum: [pending, running, completed, failed]
|
|
- name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 50
|
|
maximum: 200
|
|
- name: cursor
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: List of export runs
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ExportRunPage'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/v1/exports/airgap/evidence/{bundleId}:
|
|
post:
|
|
summary: Create portable evidence export
|
|
operationId: createEvidenceExport
|
|
tags: [evidence]
|
|
parameters:
|
|
- name: bundleId
|
|
in: path
|
|
required: true
|
|
description: Source evidence bundle identifier
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- $ref: '#/components/parameters/TenantId'
|
|
responses:
|
|
'202':
|
|
description: Export request accepted
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ExportStatus'
|
|
example:
|
|
exportId: '01234567-89ab-cdef-0123-456789abcdef'
|
|
profileId: 'profile-airgap-evidence-v1'
|
|
status: 'pending'
|
|
bundleId: 'fedcba98-7654-3210-fedc-ba9876543210'
|
|
createdAt: '2025-01-01T00:00:00Z'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/v1/exports/airgap/evidence/{exportId}:
|
|
get:
|
|
summary: Get evidence export status
|
|
operationId: getEvidenceExportStatus
|
|
tags: [evidence]
|
|
parameters:
|
|
- name: exportId
|
|
in: path
|
|
required: true
|
|
description: Export run identifier
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- $ref: '#/components/parameters/TenantId'
|
|
responses:
|
|
'200':
|
|
description: Export status
|
|
headers:
|
|
ETag:
|
|
description: Status document hash
|
|
schema:
|
|
type: string
|
|
Last-Modified:
|
|
description: Status last update time
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ExportStatus'
|
|
example:
|
|
exportId: '01234567-89ab-cdef-0123-456789abcdef'
|
|
profileId: 'profile-airgap-evidence-v1'
|
|
status: 'completed'
|
|
bundleId: 'fedcba98-7654-3210-fedc-ba9876543210'
|
|
artifactSha256: 'sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
|
|
rootHash: 'sha256:fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210'
|
|
portableVersion: 'v1'
|
|
createdAt: '2025-01-01T00:00:00Z'
|
|
completedAt: '2025-01-01T00:01:00Z'
|
|
downloadUri: '/v1/exports/airgap/evidence/01234567-89ab-cdef-0123-456789abcdef/download'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/v1/exports/airgap/evidence/{exportId}/download:
|
|
get:
|
|
summary: Download evidence export bundle
|
|
operationId: downloadEvidenceExport
|
|
tags: [evidence]
|
|
parameters:
|
|
- name: exportId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- $ref: '#/components/parameters/TenantId'
|
|
responses:
|
|
'200':
|
|
description: Portable evidence bundle archive
|
|
headers:
|
|
ETag:
|
|
description: Archive SHA-256 hash
|
|
schema:
|
|
type: string
|
|
example: '"sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"'
|
|
Last-Modified:
|
|
description: Archive creation time
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
Content-Disposition:
|
|
description: Suggested filename
|
|
schema:
|
|
type: string
|
|
example: 'attachment; filename="export-portable-bundle-v1.tgz"'
|
|
Cache-Control:
|
|
schema:
|
|
type: string
|
|
example: 'private, must-revalidate'
|
|
content:
|
|
application/gzip:
|
|
schema:
|
|
type: string
|
|
format: binary
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/v1/exports/attestations/{attestationId}:
|
|
post:
|
|
summary: Create attestation export
|
|
operationId: createAttestationExport
|
|
tags: [attestations]
|
|
parameters:
|
|
- name: attestationId
|
|
in: path
|
|
required: true
|
|
description: Source attestation identifier
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- $ref: '#/components/parameters/TenantId'
|
|
responses:
|
|
'202':
|
|
description: Export request accepted
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ExportStatus'
|
|
example:
|
|
exportId: '11111111-1111-1111-1111-111111111111'
|
|
profileId: 'profile-attestation-v1'
|
|
status: 'pending'
|
|
attestationId: '22222222-2222-2222-2222-222222222222'
|
|
createdAt: '2025-01-01T00:00:00Z'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/v1/exports/attestations/{exportId}:
|
|
get:
|
|
summary: Get attestation export status
|
|
operationId: getAttestationExportStatus
|
|
tags: [attestations]
|
|
parameters:
|
|
- name: exportId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- $ref: '#/components/parameters/TenantId'
|
|
responses:
|
|
'200':
|
|
description: Export status
|
|
headers:
|
|
ETag:
|
|
schema:
|
|
type: string
|
|
Last-Modified:
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ExportStatus'
|
|
example:
|
|
exportId: '11111111-1111-1111-1111-111111111111'
|
|
profileId: 'profile-attestation-v1'
|
|
status: 'completed'
|
|
attestationId: '22222222-2222-2222-2222-222222222222'
|
|
artifactSha256: 'sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789'
|
|
rootHash: 'sha256:9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba'
|
|
statementDigest: 'sha256:1111111111111111111111111111111111111111111111111111111111111111'
|
|
createdAt: '2025-01-01T00:00:00Z'
|
|
completedAt: '2025-01-01T00:01:00Z'
|
|
downloadUri: '/v1/exports/attestations/11111111-1111-1111-1111-111111111111/download'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/v1/exports/attestations/{exportId}/download:
|
|
get:
|
|
summary: Download attestation export bundle
|
|
operationId: downloadAttestationExport
|
|
tags: [attestations]
|
|
parameters:
|
|
- name: exportId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- $ref: '#/components/parameters/TenantId'
|
|
responses:
|
|
'200':
|
|
description: Attestation bundle archive
|
|
headers:
|
|
ETag:
|
|
description: Archive SHA-256 hash
|
|
schema:
|
|
type: string
|
|
example: '"sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"'
|
|
Last-Modified:
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
Content-Disposition:
|
|
schema:
|
|
type: string
|
|
example: 'attachment; filename="export-attestation-bundle-v1.tgz"'
|
|
Cache-Control:
|
|
schema:
|
|
type: string
|
|
example: 'private, must-revalidate'
|
|
content:
|
|
application/gzip:
|
|
schema:
|
|
type: string
|
|
format: binary
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/v1/exports/runs/{exportId}/events:
|
|
get:
|
|
summary: Get export run events (stub)
|
|
operationId: getExportRunEvents
|
|
tags: [runs]
|
|
x-stub: true
|
|
description: >-
|
|
Timeline/event stream pointer for export run progress. Returns pointer to
|
|
notification/event stream when notifications are enabled. Stub until event
|
|
envelopes fully land.
|
|
parameters:
|
|
- name: exportId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- $ref: '#/components/parameters/TenantId'
|
|
responses:
|
|
'200':
|
|
description: Event stream reference
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
exportId:
|
|
type: string
|
|
format: uuid
|
|
eventStreamUri:
|
|
type: string
|
|
format: uri
|
|
status:
|
|
type: string
|
|
enum: [available, not-configured]
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
components:
|
|
securitySchemes:
|
|
bearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
description: OAuth2 access token with export scopes
|
|
mTLS:
|
|
type: mutualTLS
|
|
description: Mutual TLS client certificate authentication
|
|
|
|
parameters:
|
|
TenantId:
|
|
name: X-Stella-Tenant-Id
|
|
in: header
|
|
required: true
|
|
description: Tenant identifier for multi-tenant scoping
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
|
|
schemas:
|
|
ExportProfile:
|
|
type: object
|
|
required: [id, kind, description, version, retentionDays]
|
|
properties:
|
|
id:
|
|
type: string
|
|
description: Unique profile identifier
|
|
example: 'profile-attestation-v1'
|
|
kind:
|
|
type: string
|
|
enum: [attestation, mirror, bootstrap, airgap-evidence]
|
|
description: Profile type
|
|
description:
|
|
type: string
|
|
description: Human-readable profile description
|
|
version:
|
|
type: string
|
|
description: Profile schema version
|
|
example: 'v1'
|
|
retentionDays:
|
|
type: integer
|
|
description: Number of days exports are retained
|
|
example: 90
|
|
|
|
ExportProfilePage:
|
|
type: object
|
|
required: [profiles, hasMore]
|
|
properties:
|
|
profiles:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/ExportProfile'
|
|
cursor:
|
|
type: string
|
|
nullable: true
|
|
description: Pagination cursor for next page
|
|
hasMore:
|
|
type: boolean
|
|
description: Whether more results are available
|
|
|
|
ExportStatus:
|
|
type: object
|
|
required: [exportId, profileId, status, createdAt]
|
|
properties:
|
|
exportId:
|
|
type: string
|
|
format: uuid
|
|
description: Unique export run identifier
|
|
profileId:
|
|
type: string
|
|
description: Associated export profile
|
|
status:
|
|
type: string
|
|
enum: [pending, running, completed, failed]
|
|
description: Current export status
|
|
artifactSha256:
|
|
type: string
|
|
nullable: true
|
|
description: SHA-256 hash of the exported artifact
|
|
example: 'sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
|
|
rootHash:
|
|
type: string
|
|
nullable: true
|
|
description: Merkle root hash of bundle contents
|
|
example: 'sha256:fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210'
|
|
portableVersion:
|
|
type: string
|
|
nullable: true
|
|
description: Portable bundle format version
|
|
attestationId:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
description: Source attestation identifier (for attestation exports)
|
|
bundleId:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
description: Source bundle identifier (for evidence exports)
|
|
statementDigest:
|
|
type: string
|
|
nullable: true
|
|
description: SHA-256 of in-toto statement (for attestation exports)
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
description: Export creation timestamp (ISO 8601)
|
|
example: '2025-01-01T00:00:00Z'
|
|
completedAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
description: Export completion timestamp (ISO 8601)
|
|
downloadUri:
|
|
type: string
|
|
format: uri
|
|
nullable: true
|
|
description: Relative URI for downloading the export artifact
|
|
|
|
ExportRunPage:
|
|
type: object
|
|
required: [runs, hasMore]
|
|
properties:
|
|
runs:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/ExportStatus'
|
|
cursor:
|
|
type: string
|
|
nullable: true
|
|
hasMore:
|
|
type: boolean
|
|
|
|
ErrorEnvelope:
|
|
type: object
|
|
required: [error]
|
|
properties:
|
|
error:
|
|
type: object
|
|
required: [code, message, correlationId]
|
|
properties:
|
|
code:
|
|
type: string
|
|
description: Machine-readable error code
|
|
example: 'EXPORT_NOT_FOUND'
|
|
message:
|
|
type: string
|
|
description: Human-readable error message
|
|
example: 'Export with the specified ID was not found'
|
|
correlationId:
|
|
type: string
|
|
format: uuid
|
|
description: Request correlation ID for tracing
|
|
retryAfterSeconds:
|
|
type: integer
|
|
nullable: true
|
|
description: Suggested retry delay for rate-limited requests
|
|
|
|
responses:
|
|
Unauthorized:
|
|
description: Authentication required or invalid credentials
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorEnvelope'
|
|
example:
|
|
error:
|
|
code: 'UNAUTHORIZED'
|
|
message: 'Valid authentication credentials required'
|
|
correlationId: '00000000-0000-0000-0000-000000000000'
|
|
|
|
NotFound:
|
|
description: Resource not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorEnvelope'
|
|
example:
|
|
error:
|
|
code: 'NOT_FOUND'
|
|
message: 'The requested resource was not found'
|
|
correlationId: '00000000-0000-0000-0000-000000000000'
|
|
|
|
RateLimited:
|
|
description: Rate limit exceeded
|
|
headers:
|
|
X-Stella-Quota-Remaining:
|
|
schema:
|
|
type: integer
|
|
example: 0
|
|
Retry-After:
|
|
schema:
|
|
type: integer
|
|
example: 60
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorEnvelope'
|
|
example:
|
|
error:
|
|
code: 'RATE_LIMITED'
|
|
message: 'Rate limit exceeded. Please retry after the specified delay.'
|
|
correlationId: '00000000-0000-0000-0000-000000000000'
|
|
retryAfterSeconds: 60
|
|
|
|
tags:
|
|
- name: discovery
|
|
description: OpenAPI discovery and metadata
|
|
- name: profiles
|
|
description: Export profile management
|
|
- name: runs
|
|
description: Export run management and status
|
|
- name: evidence
|
|
description: Portable evidence bundle exports
|
|
- name: attestations
|
|
description: Attestation bundle exports
|