@@ -3109,6 +3109,67 @@ def test_resolve_storage_credentials_empty() -> None:
31093109 assert RestCatalog ._resolve_storage_credentials ([], None ) == {}
31103110
31113111
3112+ def test_resolve_storage_credentials_skips_hadoop_only () -> None :
3113+ from pyiceberg .catalog .rest .scan_planning import StorageCredential
3114+
3115+ # The longer fs.* prefix would win a blind longest-match; the filter drops it.
3116+ credentials = [
3117+ StorageCredential (prefix = "s3://warehouse/jindo" , config = {"fs.s3.access-key" : "hadoop-k" }),
3118+ StorageCredential (prefix = "s3://warehouse" , config = {"s3.access-key-id" : "native-k" }),
3119+ ]
3120+ result = RestCatalog ._resolve_storage_credentials (credentials , "s3://warehouse/jindo/table/data" )
3121+ assert result == {"s3.access-key-id" : "native-k" }
3122+
3123+
3124+ def test_resolve_storage_credentials_mixed_prefix_namespaces_preserved () -> None :
3125+ from pyiceberg .catalog .rest .scan_planning import StorageCredential
3126+
3127+ credentials = [
3128+ StorageCredential (prefix = "gs" , config = {"gs.oauth2.token" : "tok" }),
3129+ StorageCredential (prefix = "s3" , config = {"s3.access-key-id" : "native-k" }),
3130+ ]
3131+ result = RestCatalog ._resolve_storage_credentials (credentials , "gs://bucket/path" )
3132+ assert result == {"gs.oauth2.token" : "tok" }
3133+
3134+
3135+ def test_resolve_storage_credentials_all_hadoop_only_returns_empty () -> None :
3136+ from pyiceberg .catalog .rest .scan_planning import StorageCredential
3137+
3138+ credentials = [
3139+ StorageCredential (prefix = "custom" , config = {"fs.custom.access-key" : "hadoop-k" }),
3140+ ]
3141+ assert RestCatalog ._resolve_storage_credentials (credentials , "custom://bucket/path" ) == {}
3142+
3143+
3144+ def test_resolve_storage_credentials_root_prefix_fallback_for_s3_compatible_scheme () -> None :
3145+ from pyiceberg .catalog .rest .scan_planning import StorageCredential
3146+
3147+ # oss:// is routed through pyarrow's S3FileSystem, so ROOT_PREFIX "s3" applies.
3148+ credentials = [
3149+ StorageCredential (prefix = "s3" , config = {"s3.access-key-id" : "native-k" }),
3150+ ]
3151+ result = RestCatalog ._resolve_storage_credentials (credentials , "oss://bucket/path" )
3152+ assert result == {"s3.access-key-id" : "native-k" }
3153+
3154+
3155+ def test_resolve_storage_credentials_root_prefix_fallback_respects_consumable () -> None :
3156+ from pyiceberg .catalog .rest .scan_planning import StorageCredential
3157+
3158+ credentials = [
3159+ StorageCredential (prefix = "s3" , config = {"fs.s3.access-key" : "hadoop-k" }),
3160+ ]
3161+ assert RestCatalog ._resolve_storage_credentials (credentials , "s3://bucket/path" ) == {}
3162+
3163+
3164+ def test_resolve_storage_credentials_fallback_skipped_for_non_s3_scheme () -> None :
3165+ from pyiceberg .catalog .rest .scan_planning import StorageCredential
3166+
3167+ credentials = [
3168+ StorageCredential (prefix = "s3" , config = {"s3.access-key-id" : "native-k" }),
3169+ ]
3170+ assert RestCatalog ._resolve_storage_credentials (credentials , "gs://bucket/path" ) == {}
3171+
3172+
31123173def test_load_table_with_storage_credentials (rest_mock : Mocker , example_table_metadata_with_snapshot_v1 : dict [str , Any ]) -> None :
31133174 metadata_location = "s3://warehouse/database/table/metadata/00001.metadata.json"
31143175 rest_mock .get (
0 commit comments