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();
}