You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polaris.apache.org by ad...@apache.org on 2026/04/30 20:09:09 UTC

(polaris) branch main updated: Source RootCredentialsSet from Quarkus config (#4319)

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

adutra 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 67c9964b34 Source RootCredentialsSet from Quarkus config (#4319)
67c9964b34 is described below

commit 67c9964b34f10e7ed1a06cce5e9ff90d3a46b7da
Author: Alexandre Dutra <ad...@apache.org>
AuthorDate: Thu Apr 30 22:09:04 2026 +0200

    Source RootCredentialsSet from Quarkus config (#4319)
    
    This change makes it possible to source root credentials for bootstrapping from any valid Quarkus/SmallRye configuration source, and not only environment variables or system properties.
    
    While storing root credentials in `application.properties` might not be very convenient, if for nothing else this change makes tests easier to write, cf. `RealmContextFilterTest`.
---
 .../polaris/service/config/ServiceProducers.java   | 36 +++++++++---------
 ...moryAtomicOperationMetaStoreManagerFactory.java |  8 ++--
 .../InMemoryPolarisMetaStoreManagerFactory.java    | 16 ++++----
 .../service/context/RealmContextFilterTest.java    | 43 ++--------------------
 .../org/apache/polaris/service/TestServices.java   |  3 +-
 5 files changed, 36 insertions(+), 70 deletions(-)

diff --git a/runtime/service/src/main/java/org/apache/polaris/service/config/ServiceProducers.java b/runtime/service/src/main/java/org/apache/polaris/service/config/ServiceProducers.java
index 3e636a4822..a99736801c 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/config/ServiceProducers.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/config/ServiceProducers.java
@@ -31,6 +31,7 @@ import jakarta.enterprise.inject.Instance;
 import jakarta.enterprise.inject.Produces;
 import jakarta.inject.Singleton;
 import java.time.Clock;
+import java.util.Optional;
 import java.util.stream.Collectors;
 import org.apache.polaris.core.PolarisCallContext;
 import org.apache.polaris.core.PolarisDefaultDiagServiceImpl;
@@ -86,6 +87,7 @@ import org.apache.polaris.service.storage.aws.S3AccessConfig;
 import org.apache.polaris.service.storage.aws.StsClientsPool;
 import org.apache.polaris.service.task.TaskHandlerConfiguration;
 import org.apache.polaris.service.tracing.RequestIdFilter;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.eclipse.microprofile.context.ManagedExecutor;
 import org.eclipse.microprofile.context.ThreadContext;
 import org.jboss.resteasy.reactive.server.core.CurrentRequestManager;
@@ -119,6 +121,13 @@ public class ServiceProducers {
     return new PolarisDefaultDiagServiceImpl();
   }
 
+  @Produces
+  @ApplicationScoped
+  public RootCredentialsSet rootCredentialsSet(
+      @ConfigProperty(name = RootCredentialsSet.SYSTEM_PROPERTY) Optional<String> credentials) {
+    return credentials.map(RootCredentialsSet::fromString).orElse(RootCredentialsSet.EMPTY);
+  }
+
   // Polaris core beans - request scope
 
   @Produces
@@ -272,16 +281,15 @@ public class ServiceProducers {
       @Observes Startup event,
       Bootstrapper bootstrapper,
       PersistenceConfiguration config,
-      RealmContextConfiguration realmContextConfiguration) {
-    var rootCredentialsSet = RootCredentialsSet.fromEnvironment();
+      RealmContextConfiguration realmContextConfiguration,
+      RootCredentialsSet rootCredentialsSet) {
     var rootCredentials = rootCredentialsSet.credentials();
     if (config.isAutoBootstrap()) {
       var realmIds = realmContextConfiguration.realms();
 
       LOGGER.info(
-          "Bootstrapping realm(s) {}, if necessary, from root credentials set provided via the environment variable {} or Java system property {} ...",
+          "Bootstrapping realm(s) {}, if necessary, from root credentials set provided via the {} configuration property ...",
           realmIds.stream().map(r -> "'" + r + "'").collect(Collectors.joining(", ")),
-          RootCredentialsSet.ENVIRONMENT_VARIABLE,
           RootCredentialsSet.SYSTEM_PROPERTY);
 
       var result = bootstrapper.bootstrapRealms(realmIds, rootCredentialsSet);
@@ -291,17 +299,13 @@ public class ServiceProducers {
             var principalSecrets = secrets.getPrincipalSecrets();
 
             var log =
-                LOGGER
-                    .atInfo()
-                    .addArgument(realm)
-                    .addArgument(RootCredentialsSet.ENVIRONMENT_VARIABLE)
-                    .addArgument(RootCredentialsSet.SYSTEM_PROPERTY);
+                LOGGER.atInfo().addArgument(realm).addArgument(RootCredentialsSet.SYSTEM_PROPERTY);
             if (rootCredentials.containsKey(realm)) {
               log.log(
-                  "Realm '{}' automatically bootstrapped, credentials taken from root credentials set provided via the environment variable {} or Java system property {}, not printed to stdout.");
+                  "Realm '{}' automatically bootstrapped, credentials taken from root credentials set provided via the {} configuration property, not printed to stdout.");
             } else {
               log.log(
-                  "Realm '{}' automatically bootstrapped, credentials were not present in root credentials set provided via the environment variable {} or Java system property {}, see separate message printed to stdout.");
+                  "Realm '{}' automatically bootstrapped, credentials were not present in root credentials set provided via the {} configuration property, see separate message printed to stdout.");
               String msg =
                   String.format(
                       "realm: %1s root principal credentials: %2s:%3s",
@@ -321,19 +325,17 @@ public class ServiceProducers {
       if (!unusedRealmSecrets.isEmpty()) {
         // This is intentionally an error to highlight the importance of the situation.
         LOGGER.error(
-            "The realms {} are already fully bootstrapped but the secrets are still available via the environment variable {} or Java system property {}. "
-                + "Remove this security sensitive information from the environment / Java system properties!",
+            "The realms {} are already fully bootstrapped but the secrets are still available via the {} configuration property. "
+                + "Remove this security sensitive information from the application configuration!",
             unusedRealmSecrets,
-            RootCredentialsSet.ENVIRONMENT_VARIABLE,
             RootCredentialsSet.SYSTEM_PROPERTY);
       }
     } else if (!rootCredentials.isEmpty()) {
       // This is intentionally an error to highlight the importance of the situation.
       LOGGER.error(
-          "Secrets for the realms {} are available via the environment variable {} or Java system property {}. "
-              + "Remove this security sensitive information from the environment / Java system properties!",
+          "Secrets for the realms {} are available via the {} configuration property. "
+              + "Remove this security sensitive information from the application configuration!",
           rootCredentials.keySet(),
-          RootCredentialsSet.ENVIRONMENT_VARIABLE,
           RootCredentialsSet.SYSTEM_PROPERTY);
     }
   }
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/persistence/InMemoryAtomicOperationMetaStoreManagerFactory.java b/runtime/service/src/main/java/org/apache/polaris/service/persistence/InMemoryAtomicOperationMetaStoreManagerFactory.java
index fb45bc6c00..662b735785 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/persistence/InMemoryAtomicOperationMetaStoreManagerFactory.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/persistence/InMemoryAtomicOperationMetaStoreManagerFactory.java
@@ -25,6 +25,7 @@ import java.time.Clock;
 import org.apache.polaris.core.PolarisDiagnostics;
 import org.apache.polaris.core.persistence.AtomicOperationMetaStoreManager;
 import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
+import org.apache.polaris.core.persistence.bootstrap.RootCredentialsSet;
 import org.apache.polaris.core.storage.PolarisStorageIntegrationProvider;
 
 /**
@@ -38,15 +39,16 @@ public class InMemoryAtomicOperationMetaStoreManagerFactory
 
   @SuppressWarnings("unused") // Required by CDI
   protected InMemoryAtomicOperationMetaStoreManagerFactory() {
-    this(null, null, null);
+    this(null, null, null, null);
   }
 
   @Inject
   public InMemoryAtomicOperationMetaStoreManagerFactory(
       Clock clock,
       PolarisDiagnostics diagnostics,
-      PolarisStorageIntegrationProvider storageIntegration) {
-    super(clock, diagnostics, storageIntegration);
+      PolarisStorageIntegrationProvider storageIntegration,
+      RootCredentialsSet rootCredentialsSet) {
+    super(clock, diagnostics, storageIntegration, rootCredentialsSet);
   }
 
   @Override
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/persistence/InMemoryPolarisMetaStoreManagerFactory.java b/runtime/service/src/main/java/org/apache/polaris/service/persistence/InMemoryPolarisMetaStoreManagerFactory.java
index 3e8b6e538b..e08fd12082 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/persistence/InMemoryPolarisMetaStoreManagerFactory.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/persistence/InMemoryPolarisMetaStoreManagerFactory.java
@@ -45,20 +45,23 @@ public class InMemoryPolarisMetaStoreManagerFactory
     extends LocalPolarisMetaStoreManagerFactory<TreeMapMetaStore> {
 
   private final PolarisStorageIntegrationProvider storageIntegration;
+  private final RootCredentialsSet rootCredentialsSet;
   private final Set<String> bootstrappedRealms = new HashSet<>();
 
   @SuppressWarnings("unused") // Required by CDI
   protected InMemoryPolarisMetaStoreManagerFactory() {
-    this(null, null, null);
+    this(null, null, null, null);
   }
 
   @Inject
   public InMemoryPolarisMetaStoreManagerFactory(
       Clock clock,
       PolarisDiagnostics diagnostics,
-      PolarisStorageIntegrationProvider storageIntegration) {
+      PolarisStorageIntegrationProvider storageIntegration,
+      RootCredentialsSet rootCredentialsSet) {
     super(clock, diagnostics);
     this.storageIntegration = storageIntegration;
+    this.rootCredentialsSet = rootCredentialsSet;
   }
 
   @Override
@@ -81,7 +84,7 @@ public class InMemoryPolarisMetaStoreManagerFactory
       RealmContext realmContext) {
     String realmId = realmContext.getRealmIdentifier();
     if (!bootstrappedRealms.contains(realmId)) {
-      bootstrapRealmsFromEnvironment(List.of(realmId));
+      bootstrapRealms(List.of(realmId), rootCredentialsSet);
     }
     return super.getOrCreateMetaStoreManager(realmContext);
   }
@@ -90,16 +93,11 @@ public class InMemoryPolarisMetaStoreManagerFactory
   public synchronized TransactionalPersistence getOrCreateSession(RealmContext realmContext) {
     String realmId = realmContext.getRealmIdentifier();
     if (!bootstrappedRealms.contains(realmId)) {
-      bootstrapRealmsFromEnvironment(List.of(realmId));
+      bootstrapRealms(List.of(realmId), rootCredentialsSet);
     }
     return super.getOrCreateSession(realmContext);
   }
 
-  private void bootstrapRealmsFromEnvironment(List<String> realms) {
-    RootCredentialsSet rootCredentialsSet = RootCredentialsSet.fromEnvironment();
-    this.bootstrapRealms(realms, rootCredentialsSet);
-  }
-
   @Override
   public Map<String, PrincipalSecretsResult> bootstrapRealms(
       Iterable<String> realms, RootCredentialsSet rootCredentialsSet) {
diff --git a/runtime/service/src/test/java/org/apache/polaris/service/context/RealmContextFilterTest.java b/runtime/service/src/test/java/org/apache/polaris/service/context/RealmContextFilterTest.java
index 39d54a6bc3..71f34a8a02 100644
--- a/runtime/service/src/test/java/org/apache/polaris/service/context/RealmContextFilterTest.java
+++ b/runtime/service/src/test/java/org/apache/polaris/service/context/RealmContextFilterTest.java
@@ -22,7 +22,6 @@ package org.apache.polaris.service.context;
 import static io.restassured.RestAssured.given;
 import static org.hamcrest.CoreMatchers.is;
 
-import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
 import io.quarkus.test.common.http.TestHTTPEndpoint;
 import io.quarkus.test.junit.QuarkusTest;
 import io.quarkus.test.junit.QuarkusTestProfile;
@@ -30,7 +29,6 @@ import io.quarkus.test.junit.TestProfile;
 import io.restassured.http.ContentType;
 import io.restassured.specification.RequestSpecification;
 import jakarta.ws.rs.core.Response;
-import java.util.List;
 import java.util.Map;
 import org.apache.polaris.service.catalog.api.IcebergRestOAuth2Api;
 import org.junit.jupiter.api.Test;
@@ -48,44 +46,9 @@ class RealmContextFilterTest {
           "polaris.realm-context.header-name",
           REALM_HEADER,
           "polaris.realm-context.realms",
-          "realm1,realm2");
-    }
-
-    @Override
-    public List<TestResourceEntry> testResources() {
-      // `org.apache.polaris.core.persistence.bootstrap.RootCredentialsSet` retrieves the
-      // environmental provides values from, 1st, a system property and, if not present, from an
-      // environment variable. But `RootCredentialsSet` does not query the configuration backend.
-      //
-      // The fact that `RootCredentialsSet` could retrieve 'polaris.bootstrap.credentials' for this
-      // test via system properties was leveraging an implementation detail in Quarkus.
-      // Configs do no longer become system properties in Quarkus/smallrye-config.
-      //
-      // The test-profile effectively ensures that this test runs "alone", so updating and restoring
-      // the relevant system property for `RootCredentialsSet` is safe.
-      return List.of(new TestResourceEntry(RealmContextFilterTestResource.class));
-    }
-  }
-
-  public static class RealmContextFilterTestResource
-      implements QuarkusTestResourceLifecycleManager {
-    private String oldProperty;
-
-    @Override
-    public Map<String, String> start() {
-      oldProperty = System.getProperty("polaris.bootstrap.credentials");
-      System.setProperty(
-          "polaris.bootstrap.credentials", "realm1,client1,secret1;realm2,client2,secret2");
-      return Map.of();
-    }
-
-    @Override
-    public void stop() {
-      if (oldProperty == null) {
-        System.clearProperty("polaris.bootstrap.credentials");
-      } else {
-        System.setProperty("polaris.bootstrap.credentials", oldProperty);
-      }
+          "realm1,realm2",
+          "polaris.bootstrap.credentials",
+          "realm1,client1,secret1;realm2,client2,secret2");
     }
   }
 
diff --git a/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java b/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java
index 1bd6997a21..3cac9befee 100644
--- a/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java
+++ b/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java
@@ -51,6 +51,7 @@ import org.apache.polaris.core.identity.provider.ServiceIdentityProvider;
 import org.apache.polaris.core.persistence.BasePersistence;
 import org.apache.polaris.core.persistence.MetaStoreManagerFactory;
 import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
+import org.apache.polaris.core.persistence.bootstrap.RootCredentialsSet;
 import org.apache.polaris.core.persistence.cache.EntityCache;
 import org.apache.polaris.core.persistence.dao.entity.CreatePrincipalResult;
 import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
@@ -206,7 +207,7 @@ public record TestServices(
               () -> GoogleCredentials.create(new AccessToken(GCP_ACCESS_TOKEN, new Date())));
       InMemoryPolarisMetaStoreManagerFactory metaStoreManagerFactory =
           new InMemoryPolarisMetaStoreManagerFactory(
-              clock, diagnostics, storageIntegrationProvider);
+              clock, diagnostics, storageIntegrationProvider, RootCredentialsSet.EMPTY);
 
       StorageCredentialCacheConfig storageCredentialCacheConfig = () -> 10_000;
       StorageCredentialCache storageCredentialCache =