From 448c359430e4e7190c7d6714087a660954f5dc5d Mon Sep 17 00:00:00 2001 From: Holger Schmermbeck Date: Sun, 16 Nov 2025 12:47:36 +0100 Subject: [PATCH] docs: add OpenAPI documentation for File Attachments API - POST /secrets/{secret}/attachments (upload) - GET /secrets/{secret}/attachments (list) - GET /attachments/{attachment}/download (download) - DELETE /attachments/{attachment} (delete) - Added SecretAttachment schema - Includes authentication, validation, and error responses Related: #175 --- docs/openapi.yaml | 213 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) diff --git a/docs/openapi.yaml b/docs/openapi.yaml index b9c50da..a5dddca 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -74,6 +74,44 @@ components: description: Timestamp of the health check example: '2025-10-25T19:25:00Z' + SecretAttachment: + type: object + required: + - id + - filename + - file_size + - mime_type + - download_url + - created_at + properties: + id: + type: string + format: uuid + description: Unique attachment identifier + example: '550e8400-e29b-41d4-a716-446655440000' + filename: + type: string + description: Original filename (decrypted) + example: 'confidential-report.pdf' + file_size: + type: integer + description: File size in bytes + example: 102400 + mime_type: + type: string + description: MIME type of the file + example: 'application/pdf' + download_url: + type: string + format: uri + description: URL to download the file + example: 'https://api.secpal.app/v1/attachments/550e8400-e29b-41d4-a716-446655440000/download' + created_at: + type: string + format: date-time + description: Upload timestamp (ISO 8601) + example: '2025-11-16T14:30:00Z' + responses: BadRequest: description: Bad Request - Invalid input parameters @@ -159,3 +197,178 @@ paths: example: message: Service temporarily unavailable code: SERVICE_UNAVAILABLE + + /secrets/{secret}/attachments: + post: + summary: Upload Attachment + description: | + Upload a file attachment to a secret. File is encrypted at rest using tenant DEK. + Maximum file size and allowed MIME types are configurable. + operationId: uploadAttachment + tags: + - Secret Attachments + security: + - BearerAuth: [] + parameters: + - name: secret + in: path + required: true + description: Secret UUID + schema: + type: string + format: uuid + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + required: + - file + properties: + file: + type: string + format: binary + description: File to upload (max 10MB by default) + responses: + '201': + description: Attachment uploaded successfully + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/SecretAttachment' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + message: Validation failed + code: VALIDATION_ERROR + details: + file: ['The file field is required.'] + + get: + summary: List Attachments + description: | + List all attachments for a secret. Returns attachments in descending order by creation date. + operationId: listAttachments + tags: + - Secret Attachments + security: + - BearerAuth: [] + parameters: + - name: secret + in: path + required: true + description: Secret UUID + schema: + type: string + format: uuid + responses: + '200': + description: Attachments retrieved successfully + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/SecretAttachment' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + + /attachments/{attachment}/download: + get: + summary: Download Attachment + description: | + Download and decrypt an attachment file. Returns the file with appropriate Content-Type and Content-Disposition headers. + operationId: downloadAttachment + tags: + - Secret Attachments + security: + - BearerAuth: [] + parameters: + - name: attachment + in: path + required: true + description: Attachment UUID + schema: + type: string + format: uuid + responses: + '200': + description: File downloaded successfully + content: + '*/*': + schema: + type: string + format: binary + headers: + Content-Type: + description: MIME type of the file + schema: + type: string + example: application/pdf + Content-Disposition: + description: Attachment filename + schema: + type: string + example: 'attachment; filename="report.pdf"' + Content-Length: + description: File size in bytes + schema: + type: integer + example: 102400 + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + + /attachments/{attachment}: + delete: + summary: Delete Attachment + description: | + Delete an attachment file and its metadata. File is permanently removed from storage. + operationId: deleteAttachment + tags: + - Secret Attachments + security: + - BearerAuth: [] + parameters: + - name: attachment + in: path + required: true + description: Attachment UUID + schema: + type: string + format: uuid + responses: + '204': + description: Attachment deleted successfully + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound'