diff --git a/open-api/rest-catalog-open-api.py b/open-api/rest-catalog-open-api.py index 5e3580ae3825..91a52b8d993f 100644 --- a/open-api/rest-catalog-open-api.py +++ b/open-api/rest-catalog-open-api.py @@ -1175,6 +1175,53 @@ class RemoteSignResult(BaseModel): headers: MultiValuedMap +class RemoteSignBatchElement(BaseModel): + """ + The fields of one request in a batch that are not repeated with the other requests. + """ + + uri: str + headers: MultiValuedMap + body: str | None = Field( + None, + description='Optional body of the request to send to the signing API, as in `RemoteSignRequest`.', + ) + + +class CompletedSignResult(RemoteSignResult): + """ + A successfully signed batch element + """ + + index: int = Field( + ..., description='The 0-based position of the element in `requests`', ge=0 + ) + + +class FailedSignResult(BaseModel): + """ + A batch element that could not be signed + """ + + index: int = Field( + ..., description='The 0-based position of the element in `requests`', ge=0 + ) + error: ErrorModel + + +class RemoteSignBatchResponse(BaseModel): + """ + The result of a batch remote request signing operation. + """ + + completed: list[CompletedSignResult] = Field( + ..., description='Elements that were signed' + ) + failed: list[FailedSignResult] = Field( + ..., description='Elements that could not be signed' + ) + + class RemoteSigningConfig(BaseModel): """ Configuration for the remote signer client. @@ -1188,6 +1235,12 @@ class RemoteSigningConfig(BaseModel): None, description='Static headers the signer client MUST include unchanged in every request to the signing endpoint.\n', ) + sign_batch_max_size: int | None = Field( + None, + alias='sign-batch-max-size', + description='The maximum number of elements in one `batchSignRequests` request for this table.', + ge=1, + ) class CreateNamespaceRequest(BaseModel): @@ -1370,6 +1423,22 @@ class FetchScanTasksRequest(BaseModel): plan_task: PlanTask = Field(..., alias='plan-task') +class RemoteSignBatchRequest(BaseModel): + """ + A batch of requests to be signed remotely. `region`, `method`, `provider` and `properties` apply to every element of `requests`. + + """ + + region: str + method: Literal['PUT', 'GET', 'HEAD', 'POST', 'DELETE', 'PATCH', 'OPTIONS'] + provider: str = Field( + ..., + description='The storage provider for every element of the batch. The provider should correspond to the scheme used for a storage native URI. For example `s3` for AWS S3 paths.', + ) + properties: dict[str, str] | None = None + requests: list[RemoteSignBatchElement] = Field(..., min_length=1) + + class Term(RootModel[TermReference | TransformTerm]): root: TermReference | TransformTerm = Field( ..., diff --git a/open-api/rest-catalog-open-api.yaml b/open-api/rest-catalog-open-api.yaml index e9a530a12804..19f8448922d2 100644 --- a/open-api/rest-catalog-open-api.yaml +++ b/open-api/rest-catalog-open-api.yaml @@ -1429,6 +1429,59 @@ paths: 5XX: $ref: '#/components/responses/ServerErrorResponse' + /v1/{prefix}/namespaces/{namespace}/tables/{table}/sign/batch: + parameters: + - $ref: '#/components/parameters/prefix' + - $ref: '#/components/parameters/namespace' + - $ref: '#/components/parameters/table' + - $ref: '#/components/parameters/data-access' + + post: + tags: + - Catalog API + summary: Remotely signs a batch of requests to object storage + operationId: batchSignRequests + description: + Signs a batch of requests to object storage on the client's behalf. + + + A server that supports this operation for a table MUST set `sign-batch-max-size` in the + table's `RemoteSigningConfig`. A client MUST NOT send more elements than that value. A + batch above the server's limit is rejected with 413. + + + A 200 response means the batch was processed. Each element of `requests` is reported once, + by its 0-based index, in either `completed` or `failed`. + + + `X-Iceberg-Access-Delegation` applies to the batch as a whole. + requestBody: + description: The batch of requests to be signed + content: + application/json: + schema: + $ref: '#/components/schemas/RemoteSignBatchRequest' + required: true + responses: + 200: + $ref: '#/components/responses/RemoteSignBatchResponse' + 400: + $ref: '#/components/responses/BadRequestErrorResponse' + 401: + $ref: '#/components/responses/UnauthorizedResponse' + 403: + $ref: '#/components/responses/ForbiddenResponse' + 406: + $ref: '#/components/responses/UnsupportedOperationResponse' + 413: + $ref: '#/components/responses/BatchContentTooLargeResponse' + 419: + $ref: '#/components/responses/AuthenticationTimeoutResponse' + 503: + $ref: '#/components/responses/ServiceUnavailableResponse' + 5XX: + $ref: '#/components/responses/ServerErrorResponse' + /v1/{prefix}/tables/rename: parameters: - $ref: '#/components/parameters/prefix' @@ -5466,6 +5519,96 @@ components: headers: $ref: '#/components/schemas/MultiValuedMap' + RemoteSignBatchRequest: + description: > + A batch of requests to be signed remotely. `region`, `method`, `provider` and + `properties` apply to every element of `requests`. + type: object + required: + - region + - method + - provider + - requests + properties: + region: + type: string + method: + type: string + enum: ["PUT", "GET", "HEAD", "POST", "DELETE", "PATCH", "OPTIONS"] + provider: + type: string + description: The storage provider for every element of the batch. The provider should correspond + to the scheme used for a storage native URI. For example `s3` for AWS S3 paths. + properties: + type: object + additionalProperties: + type: string + requests: + type: array + minItems: 1 + items: + $ref: '#/components/schemas/RemoteSignBatchElement' + + RemoteSignBatchElement: + description: The fields of one request in a batch that are not repeated with the other requests. + type: object + required: + - uri + - headers + properties: + uri: + type: string + headers: + $ref: '#/components/schemas/MultiValuedMap' + body: + type: string + description: Optional body of the request to send to the signing API, as in `RemoteSignRequest`. + + CompletedSignResult: + description: A successfully signed batch element + allOf: + - $ref: '#/components/schemas/RemoteSignResult' + - type: object + required: + - index + properties: + index: + type: integer + minimum: 0 + description: The 0-based position of the element in `requests` + + FailedSignResult: + description: A batch element that could not be signed + type: object + required: + - index + - error + properties: + index: + type: integer + minimum: 0 + description: The 0-based position of the element in `requests` + error: + $ref: '#/components/schemas/ErrorModel' + + RemoteSignBatchResponse: + description: The result of a batch remote request signing operation. + type: object + required: + - completed + - failed + properties: + completed: + description: Elements that were signed + type: array + items: + $ref: '#/components/schemas/CompletedSignResult' + failed: + description: Elements that could not be signed + type: array + items: + $ref: '#/components/schemas/FailedSignResult' + RemoteSigningConfig: description: Configuration for the remote signer client. type: object @@ -5483,6 +5626,10 @@ components: description: > Static headers the signer client MUST include unchanged in every request to the signing endpoint. + sign-batch-max-size: + type: integer + minimum: 1 + description: The maximum number of elements in one `batchSignRequests` request for this table. ############################# # Reusable Response Objects # @@ -5662,6 +5809,21 @@ components: } } + BatchContentTooLargeResponse: + description: + The batch has more elements than the server accepts, as set in `sign-batch-max-size`. + content: + application/json: + schema: + $ref: '#/components/schemas/IcebergErrorResponse' + example: { + "error": { + "message": "Batch exceeds the maximum of 100 elements", + "type": "ContentTooLargeException", + "code": 413 + } + } + ServiceUnavailableResponse: description: The service is not ready to handle the request, request could have been partially processed. @@ -5800,6 +5962,13 @@ components: schema: $ref: '#/components/schemas/RemoteSignResult' + RemoteSignBatchResponse: + description: The outcome of signing each element of a batch. + content: + application/json: + schema: + $ref: '#/components/schemas/RemoteSignBatchResponse' + ####################################### # Common examples of different values # #######################################