openapi: 3.0.3 info: title: Stella Ops Artifact Store API description: | Unified artifact storage API with bom-ref support. Sprint: SPRINT_20260118_017_Evidence_artifact_store_unification (AS-005, AS-007) ## Overview The Artifact Store API provides unified storage and retrieval of evidence artifacts (SBOMs, VEX, DSSE envelopes, Rekor proofs) using a bom-ref based path convention. ## Path Convention Artifacts are stored at: `/artifacts/{bom-ref-encoded}/{serialNumber}/{artifactId}.json` Where: - `bom-ref-encoded`: URL-safe base64 encoded PURL - `serialNumber`: CycloneDX serial number (URN UUID) - `artifactId`: Unique artifact identifier version: 1.0.0 contact: name: Stella Ops Team license: name: BUSL-1.1 servers: - url: /api/v1 description: API v1 tags: - name: Artifacts description: Artifact storage and retrieval operations - name: Evidence description: Evidence submission operations paths: /evidence: post: operationId: submitEvidence tags: [Evidence] summary: Submit evidence artifact description: | Ingests DSSE envelopes with SBOM references and stores in unified ArtifactStore. Extracts and validates bom_ref and cyclonedx_serial from the envelope. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EvidenceSubmissionRequest' responses: '201': description: Evidence stored successfully content: application/json: schema: $ref: '#/components/schemas/ArtifactMetadata' '400': description: Invalid request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '409': description: Artifact already exists content: application/json: schema: $ref: '#/components/schemas/ArtifactMetadata' /artifacts: get: operationId: listArtifacts tags: [Artifacts] summary: List artifacts by bom-ref description: | Returns paginated list of artifacts for a given bom-ref. Supports filtering by serial_number and time range. parameters: - name: bom_ref in: query required: true description: Package URL or component reference schema: type: string example: "pkg:docker/acme/api@sha256:abc123" - name: serial_number in: query required: false description: CycloneDX serial number filter schema: type: string example: "urn:uuid:12345678-1234-1234-1234-123456789012" - name: from in: query required: false description: Start date filter (ISO 8601) schema: type: string format: date-time - name: to in: query required: false description: End date filter (ISO 8601) schema: type: string format: date-time - name: limit in: query required: false description: Maximum results per page (default 50, max 1000) schema: type: integer minimum: 1 maximum: 1000 default: 50 - name: continuation_token in: query required: false description: Token for pagination schema: type: string responses: '200': description: Artifacts retrieved successfully content: application/json: schema: $ref: '#/components/schemas/ArtifactListResponse' /artifacts/{artifact_id}: get: operationId: getArtifact tags: [Artifacts] summary: Get artifact by ID description: Returns artifact metadata and optionally content parameters: - name: artifact_id in: path required: true schema: type: string format: uuid - name: include_content in: query required: false description: Include artifact content in response schema: type: boolean default: false responses: '200': description: Artifact retrieved content: application/json: schema: $ref: '#/components/schemas/ArtifactResponse' '404': description: Artifact not found delete: operationId: deleteArtifact tags: [Artifacts] summary: Delete artifact (soft delete) description: Marks artifact as deleted without removing from storage parameters: - name: artifact_id in: path required: true schema: type: string format: uuid responses: '204': description: Artifact deleted '404': description: Artifact not found /artifacts/{artifact_id}/content: get: operationId: getArtifactContent tags: [Artifacts] summary: Get artifact content description: Returns the raw artifact content parameters: - name: artifact_id in: path required: true schema: type: string format: uuid responses: '200': description: Artifact content content: application/octet-stream: schema: type: string format: binary application/json: schema: type: object application/vnd.dsse+json: schema: type: object application/vnd.cyclonedx+json: schema: type: object '404': description: Artifact not found components: schemas: EvidenceSubmissionRequest: type: object required: - bom_ref properties: bom_ref: type: string description: Package URL or component reference example: "pkg:docker/acme/api@sha256:abc123def456" cyclonedx_serial: type: string description: CycloneDX serial number (URN UUID) example: "urn:uuid:12345678-1234-1234-1234-123456789012" dsse_uri: type: string description: URI to DSSE envelope (s3://, file://, https://) example: "s3://evidence-bucket/path/to/envelope.json" rekor_uuid: type: string description: Rekor log entry UUID example: "f1a2b3c4d5e6f7a8" content: type: string format: byte description: Base64-encoded artifact content (alternative to dsse_uri) content_type: type: string description: MIME type of content example: "application/vnd.dsse+json" metadata: type: object additionalProperties: type: string description: Additional metadata key-value pairs ArtifactMetadata: type: object required: - artifact_id - bom_ref - storage_key - sha256 - created_at properties: artifact_id: type: string format: uuid description: Unique artifact identifier bom_ref: type: string description: Package URL or component reference serial_number: type: string nullable: true description: CycloneDX serial number storage_key: type: string description: Storage path for artifact content_type: type: string description: MIME type size_bytes: type: integer format: int64 description: Content size in bytes sha256: type: string description: SHA-256 hash of content created_at: type: string format: date-time description: Creation timestamp rekor_uuid: type: string nullable: true description: Rekor log entry UUID if linked metadata: type: object additionalProperties: type: string description: Additional metadata ArtifactListResponse: type: object required: - artifacts - total properties: artifacts: type: array items: $ref: '#/components/schemas/ArtifactMetadata' total: type: integer description: Total matching artifacts continuation_token: type: string nullable: true description: Token for next page ArtifactResponse: allOf: - $ref: '#/components/schemas/ArtifactMetadata' - type: object properties: content: type: string format: byte nullable: true description: Base64-encoded content (if include_content=true) ErrorResponse: type: object required: - error - message properties: error: type: string description: Error code message: type: string description: Human-readable error message details: type: object additionalProperties: true description: Additional error details