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

singhpk234 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 ed2c106f36 Persistence: use correct grant loading method (#3908)
ed2c106f36 is described below

commit ed2c106f3628d00bffec7da71c2ec0731ebb5aa5
Author: Prashant Singh <[email protected]>
AuthorDate: Tue Mar 3 17:44:52 2026 -0800

    Persistence: use correct grant loading method (#3908)
---
 .../nosql/metastore/TestNoSqlMetaStoreManager.java |  4 ++
 .../TransactionalMetaStoreManagerImpl.java         |  2 +-
 .../BasePolarisMetaStoreManagerTest.java           |  6 ++
 .../persistence/PolarisTestMetaStoreManager.java   | 72 ++++++++++++++++++++++
 4 files changed, 83 insertions(+), 1 deletion(-)

diff --git 
a/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/TestNoSqlMetaStoreManager.java
 
b/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/TestNoSqlMetaStoreManager.java
index 1c41980dbb..41499f84f3 100644
--- 
a/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/TestNoSqlMetaStoreManager.java
+++ 
b/persistence/nosql/persistence/metastore/src/test/java/org/apache/polaris/persistence/nosql/metastore/TestNoSqlMetaStoreManager.java
@@ -116,6 +116,10 @@ public class TestNoSqlMetaStoreManager extends 
BasePolarisMetaStoreManagerTest {
         .isInstanceOf(UnsupportedOperationException.class);
   }
 
+  @Override
+  @Disabled("loadResolvedEntities is unsupported in the NoSQL metastore 
implementation")
+  protected void testLoadResolvedEntitiesGranteeVsSecurableRecords() {}
+
   @BeforeEach
   void setup() {
     this.metaStore = polarisTestMetaStoreManager.polarisMetaStoreManager();
diff --git 
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TransactionalMetaStoreManagerImpl.java
 
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TransactionalMetaStoreManagerImpl.java
index a04bc8fffa..96c938f38c 100644
--- 
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TransactionalMetaStoreManagerImpl.java
+++ 
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TransactionalMetaStoreManagerImpl.java
@@ -2256,7 +2256,7 @@ public class TransactionalMetaStoreManagerImpl extends 
BaseMetaStoreManager {
           ms.loadAllGrantRecordsOnSecurableInCurrentTxn(callCtx, 
e.getCatalogId(), e.getId());
       final List<PolarisGrantRecord> grantRecordsAsGrantee =
           e.getType().isGrantee()
-              ? ms.loadAllGrantRecordsOnSecurableInCurrentTxn(callCtx, 
e.getCatalogId(), e.getId())
+              ? ms.loadAllGrantRecordsOnGranteeInCurrentTxn(callCtx, 
e.getCatalogId(), e.getId())
               : List.of();
       return new ResolvedPolarisEntity(
           PolarisEntity.of(e), grantRecordsAsGrantee, grantRecordsAsSecurable);
diff --git 
a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BasePolarisMetaStoreManagerTest.java
 
b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BasePolarisMetaStoreManagerTest.java
index 88242e88dc..726bbfc6f8 100644
--- 
a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BasePolarisMetaStoreManagerTest.java
+++ 
b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BasePolarisMetaStoreManagerTest.java
@@ -283,6 +283,12 @@ public abstract class BasePolarisMetaStoreManagerTest {
     polarisTestMetaStoreManager.testLoadResolvedEntitiesById();
   }
 
+  /** test that grantee and securable grant records are loaded from the 
correct store methods */
+  @Test
+  protected void testLoadResolvedEntitiesGranteeVsSecurableRecords() {
+    
polarisTestMetaStoreManager.testLoadResolvedEntitiesGranteeVsSecurableRecords();
+  }
+
   /** Test the set of functions for the entity cache */
   @Test
   protected void testEntityCache() {
diff --git 
a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/PolarisTestMetaStoreManager.java
 
b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/PolarisTestMetaStoreManager.java
index bf6afcb8b3..9a5b938df3 100644
--- 
a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/PolarisTestMetaStoreManager.java
+++ 
b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/PolarisTestMetaStoreManager.java
@@ -2801,6 +2801,78 @@ public class PolarisTestMetaStoreManager {
         .containsExactly(getEntityCore(N1_N2));
   }
 
+  /**
+   * Verify that loadResolvedEntities returns distinct grantee and securable 
grant records for
+   * entities that are both grantees and securables (e.g. catalog roles).
+   */
+  public void testLoadResolvedEntitiesGranteeVsSecurableRecords() {
+    // create a catalog
+    PolarisBaseEntity catalog =
+        new PolarisBaseEntity(
+            PolarisEntityConstants.getNullId(),
+            
polarisMetaStoreManager.generateNewEntityId(this.polarisCallContext).getId(),
+            PolarisEntityType.CATALOG,
+            PolarisEntitySubType.NULL_SUBTYPE,
+            PolarisEntityConstants.getRootEntityId(),
+            "grantee_test");
+    CreateCatalogResult catalogCreated =
+        polarisMetaStoreManager.createCatalog(this.polarisCallContext, 
catalog, List.of());
+    Assertions.assertThat(catalogCreated).isNotNull();
+    catalog = catalogCreated.getCatalog();
+
+    // create a namespace (securable target for the grant TO the role)
+    PolarisBaseEntity N1 = this.createEntity(List.of(catalog), 
PolarisEntityType.NAMESPACE, "N1");
+
+    // create a catalog role — both a grantee and a securable
+    PolarisBaseEntity R1 =
+        this.createEntity(List.of(catalog), PolarisEntityType.CATALOG_ROLE, 
"R1");
+
+    // grant a privilege TO R1 on N1 (R1 is the grantee)
+    grantPrivilege(R1, List.of(catalog, N1), N1, 
PolarisPrivilege.TABLE_READ_DATA);
+
+    // create a principal role and grant R1 usage to it (R1 is the securable)
+    PolarisBaseEntity PR1 = this.createEntity(null, 
PolarisEntityType.PRINCIPAL_ROLE, "PR1");
+    grantToGrantee(catalog, R1, PR1, PolarisPrivilege.CATALOG_ROLE_USAGE);
+
+    // load R1 via loadResolvedEntities
+    ResolvedEntitiesResult result =
+        polarisMetaStoreManager.loadResolvedEntities(
+            polarisCallContext,
+            PolarisEntityType.CATALOG_ROLE,
+            List.of(new PolarisEntityId(R1.getCatalogId(), R1.getId())));
+    Assertions.assertThat(result)
+        .isNotNull()
+        .returns(BaseResult.ReturnStatus.SUCCESS, 
ResolvedEntitiesResult::getReturnStatus);
+
+    ResolvedPolarisEntity resolved = result.getResolvedEntities().get(0);
+    Assertions.assertThat(resolved).isNotNull();
+
+    // grantee records: R1 was granted TABLE_READ_DATA on N1, so granteeId 
must be R1
+    Assertions.assertThat(resolved.getGrantRecordsAsGrantee())
+        .isNotEmpty()
+        .allSatisfy(
+            g -> {
+              Assertions.assertThat(g.getGranteeId()).isEqualTo(R1.getId());
+              Assertions.assertThat(g.getSecurableId()).isEqualTo(N1.getId());
+              Assertions.assertThat(g.getPrivilegeCode())
+                  .isEqualTo(PolarisPrivilege.TABLE_READ_DATA.getCode());
+            });
+
+    // securable records: PR1 was granted CATALOG_ROLE_USAGE on R1, so 
securableId must be R1
+    Assertions.assertThat(resolved.getGrantRecordsAsSecurable())
+        .isNotEmpty()
+        .allSatisfy(
+            g -> {
+              Assertions.assertThat(g.getSecurableId()).isEqualTo(R1.getId());
+              Assertions.assertThat(g.getGranteeId()).isEqualTo(PR1.getId());
+              Assertions.assertThat(g.getPrivilegeCode())
+                  .isEqualTo(PolarisPrivilege.CATALOG_ROLE_USAGE.getCode());
+            });
+
+    Assertions.assertThat(resolved.getGrantRecordsAsGrantee())
+        .doesNotContainAnyElementsOf(resolved.getGrantRecordsAsSecurable());
+  }
+
   private static PolarisEntityCore getEntityCore(PolarisBaseEntity entity) {
     return new PolarisEntityCore.Builder<>(entity).build();
   }

Reply via email to