sundapeng opened a new pull request, #9941:
URL: https://github.com/apache/paimon/pull/9941
### Purpose
Follow-up to #9918, and an alternative to #9937: both fix the same problem,
and only one of them should be merged.
Some DlfNext POP gateway deployments only route an ACS4 request that names
the API it calls. With `dlf.signing-algorithm=openapi-v4`, the first call a
catalog makes, `GET /v1/config`, is refused:
```
400 MissingHeader: Specified header x-acs-action is mandatory for this
action.
```
The header must be signed (`SignatureDoesNotMatch.HeaderUnsigned` otherwise)
and must match the request (`InvalidAction.Mismatch` otherwise), so a static
`header.x-acs-action` option cannot supply it.
#9937 has the signer work the name out from the method and the path. This PR
has each caller state it instead:
- `RESTApiNames` holds a constant for every API that `RESTApi` calls. Where
DLF OpenAPI (DlfNext `2026-01-18`) registers an API, the constant uses the
registered name. Three of those differ from the operationIds in
`rest-catalog-open-api.yaml`: `RollbackToSnapshot`, `FastForwardBranch` and
`DropTag`. The management APIs follow the registered names too, e.g.
`GrantPermissionAssignment` and `ListPolicies`.
- Every `RESTApi` call passes its name via
`restAuthFunction.withApiName(...)`, 79 call sites in total. `RESTAuthFunction`
records the name on `RESTAuthParameter` (`apiName()`), so the `RESTClient`
interface and `HttpClient` do not change. `RESTAuthParameter.withApiName`
copies the already-encoded parameters rather than encoding them again.
- `DLFRequestSigner` gains `signRequestHeaders(RESTAuthParameter, ...)`,
whose default delegates to `signHeaders(body, ...)`. `DLFAuthProvider` calls
it, and `DLFOpenApiV4Signer` overrides it to send `apiName` as `x-acs-action`,
which is signed like every other `x-acs-*` header.
- The `default` and `openapi` signers are unchanged. pypaimon gets the same
change: `rest_api_names.py`, `RESTAuthFunction.with_api_name`,
`RESTAuthParameter.api_name`, and all 38 calls in `rest_api.py`.
Compared with #9937, there is no path matching, and a name cannot drift from
its path. The cost is a wider diff in `RESTApi`, and a new API has to pass its
name.
APIs that the gateway does not register (such as `ListTablesGlobally` or
`GetTableById`) also get a name. Against a public `dlfnext` endpoint, such
calls return `InvalidAction.NotFound` whether or not `x-acs-action` is sent, so
naming them changes nothing there.
### Tests
- `RESTApiNamesTest` (10 tests): runs every public `RESTApi` method against
a local HTTP server with the `openapi-v4` signer, and asserts the method, path
and `x-acs-action` of each request. The expectations match the registered name
for all 53 registered operations. Changing one call site's name makes it fail.
- `RESTAuthFunctionTest` (3 tests): `withApiName` tags requests without
touching the original function, and the parameter copy does not encode
parameters twice.
- `DLFOpenApiV4SignerTest` (+3 tests): a known-answer signature for a POST
with a body and an API name (the same value #9937 pins, and one computed
independently); no API name means no header; `RESTAuthFunction` +
`DLFAuthProvider` send `x-acs-action` inside `SignedHeaders`.
- `DLFRequestSignerTest` (+1 test): the `default` and `openapi` signers
ignore the name.
- pypaimon:
- `rest_api_names_test.py` covers all 38 `RESTApi` calls the same way
- `dlf_signer_test.py` gains 7 tests, pinning the same known-answer string
- `org.apache.paimon.rest.**` in paimon-api: 162 pass. In paimon-core,
`MockRESTCatalogTest`, `HttpClientTest`, `AuthProviderTest`,
`DLFAuthSignatureTest` and `DLFAuthProviderFactoryTest`: 245 pass. pypaimon
REST tests: 330 pass; the one failure and one error need the optional `lance`
and `ray` modules and fail the same way without this change. Checkstyle,
spotless, flake8 and the license check are clean.
- Against a gateway that requires the header, the Java client ran end to
end: create database, create table, paged list with a `%` pattern, alter table,
write, commit, read back, drop. pypaimon passed the metadata calls, including
`AuthTableQuery`, `ListPartitions`, `ListTags` and `ListBranches`.
- Against a public `dlfnext` endpoint in cn-hangzhou, the same Java
end-to-end run and pypaimon calls pass.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]