This is an automated email from the ASF dual-hosted git repository. yuzelin pushed a commit to branch release-1.4 in repository https://gitbox.apache.org/repos/asf/paimon.git
commit 861252a7028fce664dc9583beacc6bca6ee94731 Author: XiaoHongbo <[email protected]> AuthorDate: Wed Apr 1 11:10:33 2026 +0800 [python] Fix REST signature mismatch by encoding query param values (#7568) Requests with special characters in query parameters (e.g. functionNamePattern=func%) fail with `401 NotAuthorizedException: "accessKeyId validate failed with error message: current signature xxx not match"`. This PR fixes above issue by encoding query param values --- paimon-python/pypaimon/api/typedef.py | 17 +++++++++++++++-- paimon-python/pypaimon/tests/rest/dlf_signer_test.py | 7 +++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/paimon-python/pypaimon/api/typedef.py b/paimon-python/pypaimon/api/typedef.py index 893b199b4b..3d05cb2fb6 100644 --- a/paimon-python/pypaimon/api/typedef.py +++ b/paimon-python/pypaimon/api/typedef.py @@ -15,15 +15,28 @@ # specific language governing permissions and limitations # under the License. -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import Dict, TypeVar +from urllib.parse import quote T = TypeVar("T") +def _encode_string(value: str) -> str: + if value is None: + return value + return quote(str(value), safe='') + + @dataclass class RESTAuthParameter: method: str path: str data: str - parameters: Dict[str, str] + parameters: Dict[str, str] = field(default_factory=dict) + + def __post_init__(self): + if self.parameters: + self.parameters = { + k: _encode_string(v) for k, v in self.parameters.items() + } diff --git a/paimon-python/pypaimon/tests/rest/dlf_signer_test.py b/paimon-python/pypaimon/tests/rest/dlf_signer_test.py index a2e72f599e..9109f5d619 100644 --- a/paimon-python/pypaimon/tests/rest/dlf_signer_test.py +++ b/paimon-python/pypaimon/tests/rest/dlf_signer_test.py @@ -131,6 +131,13 @@ class DLFSignerTest(unittest.TestCase): self.assertIn("Content-MD5", header) self.assertEqual("UNSIGNED-PAYLOAD", header.get("x-dlf-content-sha256")) + def test_rest_auth_parameter_encodes_values(self): + param = RESTAuthParameter( + method="GET", path="/test", + data="", parameters={"functionNamePattern": "func%"}) + self.assertEqual( + param.parameters["functionNamePattern"], "func%25") + def test_parse_signing_algo_from_uri(self): parse = DLFAuthProviderFactory.parse_signing_algo_from_uri
