This is an automated email from the ASF dual-hosted git repository.

JingsongLi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/paimon-rust.git


The following commit(s) were added to refs/heads/main by this push:
     new e1426421 [core] Read s3.session-token with the same precedence as the 
access key (#1156)
e1426421 is described below

commit e14264219ea51c0b07988e1eeabe02c4c693fdf8
Author: ump45nose <[email protected]>
AuthorDate: Mon Oct 19 20:13:52 2026 +0800

    [core] Read s3.session-token with the same precedence as the access key 
(#1156)
---
 crates/paimon/src/io/storage_s3.rs | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/crates/paimon/src/io/storage_s3.rs 
b/crates/paimon/src/io/storage_s3.rs
index 7aaaa0c3..96e4abaf 100644
--- a/crates/paimon/src/io/storage_s3.rs
+++ b/crates/paimon/src/io/storage_s3.rs
@@ -41,6 +41,11 @@ const S3_ACCESS_KEY: &str = "s3.access-key";
 /// Compatible with paimon-java's `s3.secret-key` / `fs.s3a.secret.key`.
 const S3_SECRET_KEY: &str = "s3.secret-key";
 
+/// Configuration key for S3 session token.
+///
+/// Compatible with paimon-java's `s3.session-token` / `fs.s3a.session.token`.
+const S3_SESSION_TOKEN: &str = "s3.session-token";
+
 /// Configuration key for S3 path-style access.
 ///
 /// When set to `true`, uses path-style URLs (`https://s3.endpoint/bucket`)
@@ -69,6 +74,7 @@ const JAVA_CONFIG_PREFIXES: &[&str] = &["fs.s3a.", "s3a.", 
"s3."];
 const KEY_ALIASES: &[(&str, &str)] = &[
     ("s3.access.key", "s3.access-key"),
     ("s3.secret.key", "s3.secret-key"),
+    ("s3.session.token", "s3.session-token"),
     ("s3.path.style.access", "s3.path-style-access"),
 ];
 
@@ -100,7 +106,7 @@ pub(crate) fn s3_config_parse(props: HashMap<String, 
String>) -> Result<S3Config
     cfg.region = normalized.get(S3_REGION).cloned();
 
     // Session / assume-role credentials.
-    cfg.session_token = normalized.get("s3.session.token").cloned();
+    cfg.session_token = normalized.get(S3_SESSION_TOKEN).cloned();
     cfg.role_arn = normalized.get("s3.assumed.role.arn").cloned();
     cfg.external_id = normalized.get("s3.assumed.role.externalId").cloned();
     cfg.role_session_name = 
normalized.get("s3.assumed.role.session.name").cloned();
@@ -280,6 +286,31 @@ mod tests {
         assert_eq!(cfg.external_id.as_deref(), Some("ext-id"));
     }
 
+    #[test]
+    fn test_s3_config_parse_session_token_follows_access_key_precedence() {
+        let props = make_props(&[
+            ("s3.access-key", "AK_A"),
+            ("s3.secret-key", "SK_A"),
+            ("s3.session-token", "TOKEN_A"),
+            ("fs.s3a.access.key", "AK_B"),
+            ("fs.s3a.secret.key", "SK_B"),
+            ("fs.s3a.session.token", "TOKEN_B"),
+        ]);
+
+        let cfg = s3_config_parse(props).unwrap();
+        assert_eq!(cfg.access_key_id.as_deref(), Some("AK_A"));
+        assert_eq!(cfg.secret_access_key.as_deref(), Some("SK_A"));
+        assert_eq!(cfg.session_token.as_deref(), Some("TOKEN_A"));
+    }
+
+    #[test]
+    fn test_s3_config_parse_hadoop_session_token() {
+        let props = make_props(&[("fs.s3a.session.token", "TOKEN")]);
+
+        let cfg = s3_config_parse(props).unwrap();
+        assert_eq!(cfg.session_token.as_deref(), Some("TOKEN"));
+    }
+
     #[test]
     fn test_s3_config_parse_sse() {
         let props = make_props(&[("s3.sse.type", "aws:kms"), ("s3.sse.key", 
"my-kms-key-id")]);

Reply via email to