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

jerryshao pushed a commit to branch branch-1.3
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/branch-1.3 by this push:
     new 8a811218fa [Cherry-pick to branch-1.3] [#13504] fix(core): Report 
missing securable objects correctly (#13505) (#13536)
8a811218fa is described below

commit 8a811218fa0b3713cbed34c47b6ca82c274a0d68
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Mon Sep 28 19:04:10 2026 +0800

    [Cherry-pick to branch-1.3] [#13504] fix(core): Report missing securable 
objects correctly (#13505) (#13536)
    
    ### What changes were proposed in this pull request?
    
    Cherry-pick #13505 to `branch-1.3`.
    
    Convert `NoSuchEntityException` raised while resolving a role's
    securable object into `NoSuchMetadataObjectException`, while preserving
    the original cause.
    
    Add a regression test that verifies the correct exception and ensures
    the role remains unchanged after the failed update.
    
    The cherry-pick conflicts have been resolved in
    f53cb8a8438db2f454c4eb1599f94efcda878377.
    
    ### Why are the changes needed?
    
    Role privilege updates currently report every missing entity as a
    missing role. When the role exists but its securable object cannot be
    resolved, clients incorrectly receive `NoSuchRoleException`, masking the
    actual failure.
    
    Fix: #13504
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes. When a securable object is missing during a role privilege update,
    clients now receive `NoSuchMetadataObjectException` instead of the
    incorrect `NoSuchRoleException`. Missing roles retain their existing
    behavior.
    
    ### How was this patch tested?
    
    - `./gradlew :core:spotlessApply`
    - `./gradlew :core:test --tests
    org.apache.gravitino.storage.relational.service.TestRoleMetaService`
    - `git diff --check`
    
    ---------
    
    Co-authored-by: roryqi <[email protected]>
    Co-authored-by: roryqi <[email protected]>
---
 .../relational/service/RoleMetaService.java        |  8 +++-
 .../relational/service/TestRoleMetaService.java    | 44 ++++++++++++++++++++++
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/service/RoleMetaService.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/service/RoleMetaService.java
index 803d4949df..38358942e4 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/service/RoleMetaService.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/service/RoleMetaService.java
@@ -41,6 +41,7 @@ import org.apache.gravitino.Namespace;
 import org.apache.gravitino.authorization.AuthorizationUtils;
 import org.apache.gravitino.authorization.SecurableObject;
 import org.apache.gravitino.exceptions.NoSuchEntityException;
+import org.apache.gravitino.exceptions.NoSuchMetadataObjectException;
 import org.apache.gravitino.meta.RoleEntity;
 import org.apache.gravitino.meta.UserEntity;
 import org.apache.gravitino.metrics.Monitored;
@@ -281,7 +282,12 @@ public class RoleMetaService {
       NameIdentifier nameIdentifier = 
MetadataObjectUtil.toEntityIdent(metalake, object);
       Entity.EntityType entityType = 
MetadataObjectUtil.toEntityType(object.type());
 
-      
objectBuilder.withMetadataObjectId(EntityIdService.getEntityId(nameIdentifier, 
entityType));
+      try {
+        
objectBuilder.withMetadataObjectId(EntityIdService.getEntityId(nameIdentifier, 
entityType));
+      } catch (NoSuchEntityException nse) {
+        throw new NoSuchMetadataObjectException(
+            nse, "Metadata object %s type %s doesn't exist", 
object.fullName(), object.type());
+      }
       securableObjectPOs.add(objectBuilder.build());
     }
     return securableObjectPOs;
diff --git 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestRoleMetaService.java
 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestRoleMetaService.java
index 287b346413..3d3f57a069 100644
--- 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestRoleMetaService.java
+++ 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestRoleMetaService.java
@@ -46,6 +46,7 @@ import org.apache.gravitino.authorization.Privileges;
 import org.apache.gravitino.authorization.SecurableObject;
 import org.apache.gravitino.authorization.SecurableObjects;
 import org.apache.gravitino.exceptions.NoSuchEntityException;
+import org.apache.gravitino.exceptions.NoSuchMetadataObjectException;
 import org.apache.gravitino.meta.AuditInfo;
 import org.apache.gravitino.meta.BaseMetalake;
 import org.apache.gravitino.meta.CatalogEntity;
@@ -835,6 +836,49 @@ class TestRoleMetaService extends TestJDBCBackend {
     Assertions.assertTrue(revokeMultipleRole.securableObjects().isEmpty());
   }
 
+  @TestTemplate
+  void testUpdateRoleReportsMissingSecurableObject() throws IOException {
+    createAndInsertMakeLake(METALAKE_NAME);
+    String catalogName = "catalog";
+    createAndInsertCatalog(METALAKE_NAME, catalogName);
+
+    RoleMetaService roleMetaService = RoleMetaService.getInstance();
+    RoleEntity role =
+        createRoleEntity(
+            RandomIdGenerator.INSTANCE.nextId(),
+            AuthorizationUtils.ofRoleNamespace(METALAKE_NAME),
+            "role",
+            AUDIT_INFO,
+            catalogName);
+    roleMetaService.insertRole(role, false);
+
+    String missingCatalog = "missing_catalog";
+    NoSuchMetadataObjectException exception =
+        Assertions.assertThrows(
+            NoSuchMetadataObjectException.class,
+            () ->
+                roleMetaService.updateRole(
+                    role.nameIdentifier(),
+                    (RoleEntity current) ->
+                        RoleEntity.builder()
+                            .withId(current.id())
+                            .withName(current.name())
+                            .withNamespace(current.namespace())
+                            .withProperties(current.properties())
+                            .withSecurableObjects(
+                                Lists.newArrayList(
+                                    SecurableObjects.ofCatalog(
+                                        missingCatalog,
+                                        
Lists.newArrayList(Privileges.UseCatalog.allow()))))
+                            .withAuditInfo(current.auditInfo())
+                            .build()));
+
+    Assertions.assertEquals(
+        "Metadata object missing_catalog type CATALOG doesn't exist", 
exception.getMessage());
+    Assertions.assertInstanceOf(NoSuchEntityException.class, 
exception.getCause());
+    Assertions.assertEquals(role, 
roleMetaService.getRoleByIdentifier(role.nameIdentifier()));
+  }
+
   @TestTemplate
   void testDeleteMetalakeCascade() throws IOException {
     BaseMetalake metalake = createAndInsertMakeLake(METALAKE_NAME);

Reply via email to