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

honahx pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git


The following commit(s) were added to refs/heads/main by this push:
     new 04a99509c [Catalog Federation] Enable Credential Vending for 
Passthrough Facade Catalog (#2784)
04a99509c is described below

commit 04a99509c024a9cc88bba386f1a1012a0c034ee8
Author: Honah (Jonas) J. <[email protected]>
AuthorDate: Fri Oct 10 12:25:05 2025 -0500

    [Catalog Federation] Enable Credential Vending for Passthrough Facade 
Catalog (#2784)
    
    This PR introduces credential vending support for passthrough-facade 
catalogs.
    
    When creating a passthrough-facade catalog, the configuration currently 
requires two components:
    
    StorageConfig – specifies the storage info for the remote catalog.
    ConnectionInfo – defines connection parameters for the underlying remote 
catalog.
    
    With this change, the StorageConfig is now also used to vend temporary 
credentials for user requests.
    Credential vending honors table-level RBAC policies to determine whether to 
issue read-only or read-write credentials, ensuring access control consistency 
with Polaris authorization semantics.
    
    A new test case validates the credential vending workflow, verifying both 
read and write credential vending.
    
    Note: the remote catalog referenced by the passthrough-facade does not need 
to support IRC
---
 CHANGELOG.md                                       |   2 +
 integration-tests/build.gradle.kts                 |   1 +
 .../it/test/CatalogFederationIntegrationTest.java  | 114 ++++++++++++++++++---
 .../polaris/core/config/FeatureConfiguration.java  |   9 ++
 .../catalog/iceberg/IcebergCatalogHandler.java     |  78 +++++++++-----
 .../service/spark/it/CatalogFederationIT.java      |  24 +++--
 6 files changed, 178 insertions(+), 50 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 995f9891b..257fbedb7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -35,6 +35,8 @@ request adding CHANGELOG notes for breaking (!) changes and 
possibly other secti
 
 ### New Features
 
+- Support credential vending for federated catalogs. 
`ALLOW_FEDERATED_CATALOGS_CREDENTIAL_VENDING` (default: true) was added to 
toggle this feature.
+
 ### Changes
 
 ### Deprecations
diff --git a/integration-tests/build.gradle.kts 
b/integration-tests/build.gradle.kts
index 6c48edae6..7429c5371 100644
--- a/integration-tests/build.gradle.kts
+++ b/integration-tests/build.gradle.kts
@@ -67,6 +67,7 @@ dependencies {
   implementation(libs.awaitility)
   implementation(libs.s3mock.testcontainers)
   implementation(project(":polaris-runtime-test-common"))
+  implementation(project(":polaris-minio-testcontainer"))
 }
 
 copiedCodeChecks {
diff --git 
a/integration-tests/src/main/java/org/apache/polaris/service/it/test/CatalogFederationIntegrationTest.java
 
b/integration-tests/src/main/java/org/apache/polaris/service/it/test/CatalogFederationIntegrationTest.java
index 42032dc7f..af9937b3d 100644
--- 
a/integration-tests/src/main/java/org/apache/polaris/service/it/test/CatalogFederationIntegrationTest.java
+++ 
b/integration-tests/src/main/java/org/apache/polaris/service/it/test/CatalogFederationIntegrationTest.java
@@ -27,6 +27,7 @@ import java.util.List;
 import java.util.UUID;
 import org.apache.iceberg.exceptions.ForbiddenException;
 import org.apache.polaris.core.admin.model.AuthenticationParameters;
+import org.apache.polaris.core.admin.model.AwsStorageConfigInfo;
 import org.apache.polaris.core.admin.model.Catalog;
 import org.apache.polaris.core.admin.model.CatalogGrant;
 import org.apache.polaris.core.admin.model.CatalogPrivilege;
@@ -34,7 +35,6 @@ import org.apache.polaris.core.admin.model.CatalogProperties;
 import org.apache.polaris.core.admin.model.CatalogRole;
 import org.apache.polaris.core.admin.model.ConnectionConfigInfo;
 import org.apache.polaris.core.admin.model.ExternalCatalog;
-import org.apache.polaris.core.admin.model.FileStorageConfigInfo;
 import org.apache.polaris.core.admin.model.GrantResource;
 import org.apache.polaris.core.admin.model.IcebergRestConnectionConfigInfo;
 import org.apache.polaris.core.admin.model.NamespaceGrant;
@@ -52,6 +52,9 @@ import org.apache.polaris.service.it.env.PolarisApiEndpoints;
 import org.apache.polaris.service.it.env.PolarisClient;
 import org.apache.polaris.service.it.ext.PolarisIntegrationTestExtension;
 import org.apache.polaris.service.it.ext.SparkSessionBuilder;
+import org.apache.polaris.test.minio.Minio;
+import org.apache.polaris.test.minio.MinioAccess;
+import org.apache.polaris.test.minio.MinioExtension;
 import org.apache.spark.sql.Row;
 import org.apache.spark.sql.SparkSession;
 import org.junit.jupiter.api.AfterAll;
@@ -66,9 +69,14 @@ import org.junit.jupiter.api.io.TempDir;
  * Integration test for catalog federation functionality. This test verifies 
that an external
  * catalog can be created that federates with an internal catalog.
  */
+@ExtendWith(MinioExtension.class)
 @ExtendWith(PolarisIntegrationTestExtension.class)
 public class CatalogFederationIntegrationTest {
 
+  public static final String BUCKET_URI_PREFIX = 
"/minio-test-catalog-federation";
+  public static final String MINIO_ACCESS_KEY = 
"test-ak-123-catalog-federation";
+  public static final String MINIO_SECRET_KEY = 
"test-sk-123-catalog-federation";
+
   private static PolarisClient client;
   private static CatalogApi catalogApi;
   private static ManagementApi managementApi;
@@ -78,6 +86,8 @@ public class CatalogFederationIntegrationTest {
   private static String federatedCatalogName;
   private static String localCatalogRoleName;
   private static String federatedCatalogRoleName;
+  private static URI storageBase;
+  private static String endpoint;
 
   private static final String PRINCIPAL_NAME = "test-catalog-federation-user";
   private static final String PRINCIPAL_ROLE_NAME = 
"test-catalog-federation-user-role";
@@ -93,12 +103,17 @@ public class CatalogFederationIntegrationTest {
   private PrincipalWithCredentials newUserCredentials;
 
   @BeforeAll
-  static void setup(PolarisApiEndpoints apiEndpoints, ClientCredentials 
credentials) {
+  static void setup(
+      PolarisApiEndpoints apiEndpoints,
+      ClientCredentials credentials,
+      @Minio(accessKey = MINIO_ACCESS_KEY, secretKey = MINIO_SECRET_KEY) 
MinioAccess minioAccess) {
     endpoints = apiEndpoints;
     client = polarisClient(endpoints);
     String adminToken = client.obtainToken(credentials);
     managementApi = client.managementApi(adminToken);
     catalogApi = client.catalogApi(adminToken);
+    storageBase = minioAccess.s3BucketUri(BUCKET_URI_PREFIX);
+    endpoint = minioAccess.s3endpoint();
   }
 
   @AfterAll
@@ -129,12 +144,14 @@ public class CatalogFederationIntegrationTest {
   }
 
   private void setupCatalogs() {
-    baseLocation = URI.create("file:///tmp/warehouse");
+    baseLocation = storageBase;
     newUserCredentials = managementApi.createPrincipalWithRole(PRINCIPAL_NAME, 
PRINCIPAL_ROLE_NAME);
 
-    FileStorageConfigInfo storageConfig =
-        FileStorageConfigInfo.builder()
-            .setStorageType(StorageConfigInfo.StorageTypeEnum.FILE)
+    AwsStorageConfigInfo storageConfig =
+        AwsStorageConfigInfo.builder()
+            .setStorageType(StorageConfigInfo.StorageTypeEnum.S3)
+            .setPathStyleAccess(true)
+            .setEndpoint(endpoint)
             .setAllowedLocations(List.of(baseLocation.toString()))
             .build();
 
@@ -197,6 +214,14 @@ public class CatalogFederationIntegrationTest {
     spark =
         SparkSessionBuilder.buildWithTestDefaults()
             .withWarehouse(warehouseDir.toUri())
+            .withConfig(
+                "spark.sql.catalog." + localCatalogName + 
".header.X-Iceberg-Access-Delegation",
+                "vended-credentials")
+            .withConfig(
+                "spark.sql.catalog." + federatedCatalogName + 
".header.X-Iceberg-Access-Delegation",
+                "vended-credentials")
+            .withConfig("spark.sql.catalog." + localCatalogName + 
".cache-enabled", "false")
+            .withConfig("spark.sql.catalog." + federatedCatalogName + 
".cache-enabled", "false")
             .addCatalog(
                 localCatalogName, "org.apache.iceberg.spark.SparkCatalog", 
endpoints, sparkToken)
             .addCatalog(
@@ -296,10 +321,6 @@ public class CatalogFederationIntegrationTest {
             .sql("SELECT * FROM " + localCatalogName + ".ns2.test_table ORDER 
BY id")
             .collectAsList();
     assertThat(localNs2Data).hasSize(2);
-
-    // Restore the grant
-    managementApi.revokeGrant(federatedCatalogName, federatedCatalogRoleName, 
namespaceGrant);
-    managementApi.addGrant(federatedCatalogName, federatedCatalogRoleName, 
defaultCatalogGrant);
   }
 
   @Test
@@ -335,9 +356,76 @@ public class CatalogFederationIntegrationTest {
             .sql("SELECT * FROM " + localCatalogName + ".ns2.test_table ORDER 
BY id")
             .collectAsList();
     assertThat(localNs2Data).hasSize(2);
+  }
 
-    // Restore the grant
-    managementApi.revokeGrant(federatedCatalogName, federatedCatalogRoleName, 
tableGrant);
-    managementApi.addGrant(federatedCatalogName, federatedCatalogRoleName, 
defaultCatalogGrant);
+  @Test
+  void testFederatedCatalogWithCredentialVending() {
+    managementApi.revokeGrant(federatedCatalogName, federatedCatalogRoleName, 
defaultCatalogGrant);
+
+    // Case 1: Only have TABLE_READ_PROPERTIES privilege, should not be able 
to read data
+    TableGrant tablePropertiesGrant =
+        TableGrant.builder()
+            .setType(GrantResource.TypeEnum.TABLE)
+            .setPrivilege(TablePrivilege.TABLE_READ_PROPERTIES)
+            .setNamespace(List.of("ns1"))
+            .setTableName("test_table")
+            .build();
+    managementApi.addGrant(federatedCatalogName, federatedCatalogRoleName, 
tablePropertiesGrant);
+    spark.sql("USE " + federatedCatalogName);
+
+    // Read table data should fail since TABLE_READ_PROPERTIES does not allow 
reading data
+    assertThatThrownBy(() -> spark.sql("SELECT * FROM ns1.test_table ORDER BY 
id"))
+        .isInstanceOf(ForbiddenException.class);
+
+    // Case 2: Only have TABLE_READ_DATA privilege, should be able to read 
data but not write
+    managementApi.revokeGrant(federatedCatalogName, federatedCatalogRoleName, 
tablePropertiesGrant);
+    TableGrant tableReadDataGrant =
+        TableGrant.builder()
+            .setType(GrantResource.TypeEnum.TABLE)
+            .setPrivilege(TablePrivilege.TABLE_READ_DATA)
+            .setNamespace(List.of("ns1"))
+            .setTableName("test_table")
+            .build();
+    managementApi.addGrant(federatedCatalogName, federatedCatalogRoleName, 
tableReadDataGrant);
+
+    // Verify that the vended credential allows reading the data
+    List<Row> ns1Data = spark.sql("SELECT * FROM ns1.test_table ORDER BY 
id").collectAsList();
+    assertThat(ns1Data).hasSize(2);
+    assertThat(ns1Data.get(0).getInt(0)).isEqualTo(1);
+    assertThat(ns1Data.get(0).getString(1)).isEqualTo("Alice");
+
+    // Verify that write is blocked since the vended credential should only 
have read permission
+    assertThatThrownBy(() -> spark.sql("INSERT INTO ns1.test_table VALUES (3, 
'Charlie')"))
+        .hasMessageContaining(
+            "software.amazon.awssdk.services.s3.model.S3Exception: Access 
Denied. (Service: S3, Status Code: 403,");
+
+    // Case 3: TABLE_WRITE_DATA should
+    managementApi.revokeGrant(federatedCatalogName, federatedCatalogRoleName, 
tableReadDataGrant);
+    TableGrant tableWriteDataGrant =
+        TableGrant.builder()
+            .setType(GrantResource.TypeEnum.TABLE)
+            .setPrivilege(TablePrivilege.TABLE_WRITE_DATA)
+            .setNamespace(List.of("ns1"))
+            .setTableName("test_table")
+            .build();
+    managementApi.addGrant(federatedCatalogName, federatedCatalogRoleName, 
tableWriteDataGrant);
+
+    spark.sql("INSERT INTO ns1.test_table VALUES (3, 'Charlie')");
+
+    // Verify the write was successful by reading back
+    List<Row> updatedData = spark.sql("SELECT * FROM ns1.test_table ORDER BY 
id").collectAsList();
+    assertThat(updatedData).hasSize(3);
+    assertThat(updatedData.get(2).getInt(0)).isEqualTo(3);
+    assertThat(updatedData.get(2).getString(1)).isEqualTo("Charlie");
+
+    // Verify the data is also visible from the local catalog (both point to 
same storage)
+    spark.sql(String.format("REFRESH TABLE %s.ns1.test_table", 
localCatalogName));
+    List<Row> localData =
+        spark
+            .sql(String.format("SELECT * FROM %s.ns1.test_table ORDER BY id", 
localCatalogName))
+            .collectAsList();
+    assertThat(localData).hasSize(3);
+    assertThat(localData.get(2).getInt(0)).isEqualTo(3);
+    assertThat(localData.get(2).getString(1)).isEqualTo("Charlie");
   }
 }
diff --git 
a/polaris-core/src/main/java/org/apache/polaris/core/config/FeatureConfiguration.java
 
b/polaris-core/src/main/java/org/apache/polaris/core/config/FeatureConfiguration.java
index 5d81c79f1..1772f4725 100644
--- 
a/polaris-core/src/main/java/org/apache/polaris/core/config/FeatureConfiguration.java
+++ 
b/polaris-core/src/main/java/org/apache/polaris/core/config/FeatureConfiguration.java
@@ -429,4 +429,13 @@ public class FeatureConfiguration<T> extends 
PolarisConfiguration<T> {
               "When true, enables finer grained update table privileges which 
are passed to the authorizer for update table operations")
           .defaultValue(true)
           .buildFeatureConfiguration();
+
+  public static final FeatureConfiguration<Boolean> 
ALLOW_FEDERATED_CATALOGS_CREDENTIAL_VENDING =
+      PolarisConfiguration.<Boolean>builder()
+          .key("ALLOW_FEDERATED_CATALOGS_CREDENTIAL_VENDING")
+          
.catalogConfig("polaris.config.allow-federated-catalogs-credential-vending")
+          .description(
+              "If set to true (default), allow credential vending for external 
catalogs. Note this requires ALLOW_EXTERNAL_CATALOG_CREDENTIAL_VENDING to be 
true first.")
+          .defaultValue(true)
+          .buildFeatureConfiguration();
 }
diff --git 
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
 
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
index 280c98d46..833c0ab11 100644
--- 
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
+++ 
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
@@ -18,6 +18,7 @@
  */
 package org.apache.polaris.service.catalog.iceberg;
 
+import static 
org.apache.polaris.core.config.FeatureConfiguration.ALLOW_FEDERATED_CATALOGS_CREDENTIAL_VENDING;
 import static 
org.apache.polaris.core.config.FeatureConfiguration.LIST_PAGINATION_ENABLED;
 import static 
org.apache.polaris.service.catalog.AccessDelegationMode.VENDED_CREDENTIALS;
 
@@ -265,6 +266,10 @@ public class IcebergCatalogHandler extends CatalogHandler 
implements AutoCloseab
         throw new UnsupportedOperationException(
             "External catalog factory for type '" + connectionType + "' is 
unavailable.");
       }
+      // TODO: if the remote catalog is not RestCatalog, the corresponding 
table operation will use
+      // environment to load the table metadata, the env may not contain 
credentials to access the
+      // storage. In the future, we could leverage PolarisCredentialManager to 
inject storage
+      // credentials for non-rest remote catalog
       this.baseCatalog = federatedCatalog;
     } else {
       LOGGER.atInfo().log("Initializing non-federated catalog");
@@ -421,6 +426,12 @@ public class IcebergCatalogHandler extends CatalogHandler 
implements AutoCloseab
           
PolarisAuthorizableOperation.CREATE_TABLE_DIRECT_WITH_WRITE_DELEGATION,
           TableIdentifier.of(namespace, request.name()));
     }
+
+    CatalogEntity catalog = getResolvedCatalogEntity();
+    if (catalog.isStaticFacade()) {
+      throw new BadRequestException("Cannot create table on static-facade 
external catalogs.");
+    }
+    checkAllowExternalCatalogCredentialVending(delegationModes);
   }
 
   public LoadTableResponse createTableDirect(
@@ -431,10 +442,6 @@ public class IcebergCatalogHandler extends CatalogHandler 
implements AutoCloseab
 
     authorizeCreateTableDirect(namespace, request, delegationModes);
 
-    CatalogEntity catalog = getResolvedCatalogEntity();
-    if (catalog.isStaticFacade()) {
-      throw new BadRequestException("Cannot create table on static-facade 
external catalogs.");
-    }
     request.validate();
 
     TableIdentifier tableIdentifier = TableIdentifier.of(namespace, 
request.name());
@@ -545,6 +552,12 @@ public class IcebergCatalogHandler extends CatalogHandler 
implements AutoCloseab
           
PolarisAuthorizableOperation.CREATE_TABLE_STAGED_WITH_WRITE_DELEGATION,
           TableIdentifier.of(namespace, request.name()));
     }
+
+    CatalogEntity catalog = getResolvedCatalogEntity();
+    if (catalog.isStaticFacade()) {
+      throw new BadRequestException("Cannot create table on static-facade 
external catalogs.");
+    }
+    checkAllowExternalCatalogCredentialVending(delegationModes);
   }
 
   public LoadTableResponse createTableStaged(
@@ -555,10 +568,6 @@ public class IcebergCatalogHandler extends CatalogHandler 
implements AutoCloseab
 
     authorizeCreateTableStaged(namespace, request, delegationModes);
 
-    CatalogEntity catalog = getResolvedCatalogEntity();
-    if (catalog.isStaticFacade()) {
-      throw new BadRequestException("Cannot create table on static-facade 
external catalogs.");
-    }
     TableIdentifier ident = TableIdentifier.of(namespace, request.name());
     TableMetadata metadata = stageTableCreateHelper(namespace, request);
 
@@ -723,23 +732,7 @@ public class IcebergCatalogHandler extends CatalogHandler 
implements AutoCloseab
           read, PolarisEntitySubType.ICEBERG_TABLE, tableIdentifier);
     }
 
-    CatalogEntity catalogEntity = getResolvedCatalogEntity();
-
-    LOGGER.info("Catalog type: {}", catalogEntity.getCatalogType());
-    LOGGER.info(
-        "allow external catalog credential vending: {}",
-        realmConfig.getConfig(
-            FeatureConfiguration.ALLOW_EXTERNAL_CATALOG_CREDENTIAL_VENDING, 
catalogEntity));
-    if (catalogEntity
-            .getCatalogType()
-            
.equals(org.apache.polaris.core.admin.model.Catalog.TypeEnum.EXTERNAL)
-        && !realmConfig.getConfig(
-            FeatureConfiguration.ALLOW_EXTERNAL_CATALOG_CREDENTIAL_VENDING, 
catalogEntity)) {
-      throw new ForbiddenException(
-          "Access Delegation is not enabled for this catalog. Please consult 
applicable "
-              + "documentation for the catalog config property '%s' to enable 
this feature",
-          
FeatureConfiguration.ALLOW_EXTERNAL_CATALOG_CREDENTIAL_VENDING.catalogConfig());
-    }
+    checkAllowExternalCatalogCredentialVending(delegationModes);
 
     return actionsRequested;
   }
@@ -808,8 +801,15 @@ public class IcebergCatalogHandler extends CatalogHandler 
implements AutoCloseab
     PolarisResolvedPathWrapper resolvedStoragePath =
         CatalogUtils.findResolvedStorageEntity(resolutionManifest, 
tableIdentifier);
 
-    if (baseCatalog instanceof IcebergCatalog && resolvedStoragePath != null) {
+    if (resolvedStoragePath == null) {
+      LOGGER.debug(
+          "Unable to find storage configuration information for table {}", 
tableIdentifier);
+      return responseBuilder;
+    }
 
+    if (baseCatalog instanceof IcebergCatalog
+        || realmConfig.getConfig(
+            ALLOW_FEDERATED_CATALOGS_CREDENTIAL_VENDING, 
getResolvedCatalogEntity())) {
       AccessConfig accessConfig =
           accessConfigProvider.getAccessConfig(
               callContext,
@@ -838,6 +838,7 @@ public class IcebergCatalogHandler extends CatalogHandler 
implements AutoCloseab
       }
       responseBuilder.addAllConfig(accessConfig.extraProperties());
     }
+
     return responseBuilder;
   }
 
@@ -1211,6 +1212,31 @@ public class IcebergCatalogHandler extends 
CatalogHandler implements AutoCloseab
     }
   }
 
+  private void checkAllowExternalCatalogCredentialVending(
+      EnumSet<AccessDelegationMode> delegationModes) {
+
+    if (delegationModes.isEmpty()) {
+      return;
+    }
+    CatalogEntity catalogEntity = getResolvedCatalogEntity();
+
+    LOGGER.info("Catalog type: {}", catalogEntity.getCatalogType());
+    LOGGER.info(
+        "allow external catalog credential vending: {}",
+        realmConfig.getConfig(
+            FeatureConfiguration.ALLOW_EXTERNAL_CATALOG_CREDENTIAL_VENDING, 
catalogEntity));
+    if (catalogEntity
+            .getCatalogType()
+            
.equals(org.apache.polaris.core.admin.model.Catalog.TypeEnum.EXTERNAL)
+        && !realmConfig.getConfig(
+            FeatureConfiguration.ALLOW_EXTERNAL_CATALOG_CREDENTIAL_VENDING, 
catalogEntity)) {
+      throw new ForbiddenException(
+          "Access Delegation is not enabled for this catalog. Please consult 
applicable "
+              + "documentation for the catalog config property '%s' to enable 
this feature",
+          
FeatureConfiguration.ALLOW_EXTERNAL_CATALOG_CREDENTIAL_VENDING.catalogConfig());
+    }
+  }
+
   @Override
   public void close() throws Exception {
     if (baseCatalog instanceof Closeable closeable) {
diff --git 
a/runtime/spark-tests/src/intTest/java/org/apache/polaris/service/spark/it/CatalogFederationIT.java
 
b/runtime/spark-tests/src/intTest/java/org/apache/polaris/service/spark/it/CatalogFederationIT.java
index cdd9a2a90..60e01f9a0 100644
--- 
a/runtime/spark-tests/src/intTest/java/org/apache/polaris/service/spark/it/CatalogFederationIT.java
+++ 
b/runtime/spark-tests/src/intTest/java/org/apache/polaris/service/spark/it/CatalogFederationIT.java
@@ -18,6 +18,7 @@
  */
 package org.apache.polaris.service.spark.it;
 
+import com.google.common.collect.ImmutableMap;
 import io.quarkus.test.junit.QuarkusIntegrationTest;
 import io.quarkus.test.junit.QuarkusTestProfile;
 import io.quarkus.test.junit.TestProfile;
@@ -31,17 +32,18 @@ public class CatalogFederationIT extends 
CatalogFederationIntegrationTest {
   public static class CatalogFederationProfile implements QuarkusTestProfile {
     @Override
     public Map<String, String> getConfigOverrides() {
-      return Map.of(
-          "polaris.features.\"ENABLE_CATALOG_FEDERATION\"",
-          "true",
-          "polaris.features.\"SUPPORTED_CATALOG_CONNECTION_TYPES\"",
-          "[\"ICEBERG_REST\"]",
-          "polaris.features.\"ALLOW_OVERLAPPING_CATALOG_URLS\"",
-          "true",
-          
"polaris.features.\"ENABLE_SUB_CATALOG_RBAC_FOR_FEDERATED_CATALOGS\"",
-          "true",
-          
"polaris.features.\"ALLOW_DROPPING_NON_EMPTY_PASSTHROUGH_FACADE_CATALOG\"",
-          "true");
+      return ImmutableMap.<String, String>builder()
+          .put("polaris.features.\"ENABLE_CATALOG_FEDERATION\"", "true")
+          .put("polaris.features.\"SUPPORTED_CATALOG_CONNECTION_TYPES\"", 
"[\"ICEBERG_REST\"]")
+          .put("polaris.features.\"ALLOW_OVERLAPPING_CATALOG_URLS\"", "true")
+          
.put("polaris.features.\"ENABLE_SUB_CATALOG_RBAC_FOR_FEDERATED_CATALOGS\"", 
"true")
+          
.put("polaris.features.\"ALLOW_DROPPING_NON_EMPTY_PASSTHROUGH_FACADE_CATALOG\"",
 "true")
+          .put("polaris.features.\"SKIP_CREDENTIAL_SUBSCOPING_INDIRECTION\"", 
"false")
+          
.put("polaris.features.\"ALLOW_EXTERNAL_CATALOG_CREDENTIAL_VENDING\"", "true")
+          
.put("polaris.features.\"ALLOW_FEDERATED_CATALOGS_CREDENTIAL_VENDING\"", "true")
+          .put("polaris.storage.aws.access-key", 
CatalogFederationIntegrationTest.MINIO_ACCESS_KEY)
+          .put("polaris.storage.aws.secret-key", 
CatalogFederationIntegrationTest.MINIO_SECRET_KEY)
+          .build();
     }
   }
 }

Reply via email to