mchades commented on code in PR #12718:
URL: https://github.com/apache/gravitino/pull/12718#discussion_r3901367047


##########
core/src/main/java/org/apache/gravitino/policy/PolicyManager.java:
##########
@@ -261,41 +267,49 @@ public MetadataObject[] 
listMetadataObjectsForPolicy(String metalake, String pol
   }
 
   @Override
-  public PolicyEntity[] listPolicyInfosForMetadataObject(
-      String metalake, MetadataObject metadataObject) {
-    NameIdentifier entityIdent = MetadataObjectUtil.toEntityIdent(metalake, 
metadataObject);
-    Entity.EntityType entityType = 
MetadataObjectUtil.toEntityType(metadataObject);
-
-    MetadataObjectUtil.checkMetadataObject(metalake, metadataObject);
+  public RelationalEntity<?>[] listTagAssociationsForPolicy(String metalake, 
String policyName) {
+    NameIdentifier policyIdentifier = NameIdentifierUtil.ofPolicy(metalake, 
policyName);
     checkMetalake(NameIdentifier.of(metalake), entityStore);
-
     return TreeLockUtils.doWithTreeLock(
-        entityIdent,
+        policyIdentifier,
         LockType.READ,
         () -> {
+          getPolicyWithoutLock(metalake, policyName);
           try {
             return entityStore
                 .relationOperations()
-                .listEntitiesByRelation(
-                    SupportsRelationOperations.Type.POLICY_METADATA_OBJECT_REL,
-                    entityIdent,
-                    entityType,
-                    true /* allFields */)
-                .stream()
-                .map(entity -> (PolicyEntity) entity)
-                .toArray(PolicyEntity[]::new);
-          } catch (NoSuchEntityException e) {
-            throw new NoSuchMetadataObjectException(
-                e,
-                "Failed to list policies for metadata object %s due to not 
found",
-                metadataObject);
+                .batchListEntitiesByRelation(
+                    SupportsRelationOperations.Type.POLICY_TAG_REL,
+                    Collections.singletonList(policyIdentifier),
+                    Entity.EntityType.POLICY)
+                .toArray(new RelationalEntity<?>[0]);
           } catch (IOException e) {
-            LOG.error("Failed to list policies for metadata object {}", 
metadataObject, e);
+            LOG.error(
+                "Failed to list tag associations for policy {} under metalake 
{}",
+                policyName,
+                metalake,
+                e);
             throw new RuntimeException(e);
           }
         });
   }
 
+  @Override
+  public PolicyEntity[] listPolicyInfosForMetadataObject(
+      String metalake, MetadataObject metadataObject) {
+    NameIdentifier entityIdent = MetadataObjectUtil.toEntityIdent(metalake, 
metadataObject);
+    Entity.EntityType entityType = 
MetadataObjectUtil.toEntityType(metadataObject);
+    MetadataObjectUtil.checkMetadataObject(metalake, metadataObject);
+    checkMetalake(NameIdentifier.of(metalake), entityStore);
+
+    Map<Long, PolicyEntity> policiesById = new LinkedHashMap<>();
+    Arrays.stream(listDirectPoliciesForMetadataObject(entityIdent, entityType, 
metadataObject))
+        .forEach(policy -> policiesById.putIfAbsent(policy.id(), policy));
+    Arrays.stream(objectPolicyResolver.resolve(metalake, metadataObject))

Review Comment:
   `ObjectPolicyResolver.resolve` already walks the requested object and all 
parents through `EffectiveTagResolver`, while 
[`MetadataObjectPolicyOperations`](https://github.com/apache/gravitino/blob/18ca5608f4a57ebad241fbcde5a881ae8072d167/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectPolicyOperations.java#L182-L211)
 still calls this method once for the object and again for each parent. A child 
override such as `data_domain=risk` over a parent `data_domain=finance` is 
therefore evaluated correctly here, but the later parent call adds a 
`TAG_VALUE("finance")` policy back. Policies selected from inherited tags are 
also returned in the first call and marked `inherited=false` by the REST layer. 
Please resolve tag-derived policies exactly once for the requested object, keep 
any direct-policy compatibility traversal separate, and add an end-to-end 
override regression test.



##########
core/src/main/java/org/apache/gravitino/tag/TagManager.java:
##########
@@ -227,6 +231,109 @@ public MetadataObject[] listMetadataObjectsForTag(String 
metalake, String name)
     return listMetadataObjectsForTag(metalake, name, null);
   }
 
+  @Override
+  public RelationalEntity<?>[] listPolicyAssociationsForTag(String metalake, 
String name) {
+    NameIdentifier tagIdentifier = NameIdentifierUtil.ofTag(metalake, name);
+    checkMetalake(NameIdentifier.of(metalake), entityStore);
+    return TreeLockUtils.doWithTreeLock(
+        tagIdentifier,
+        LockType.READ,
+        () -> {
+          try {
+            return entityStore
+                .relationOperations()
+                .batchListEntitiesByRelation(
+                    SupportsRelationOperations.Type.POLICY_TAG_REL,
+                    Collections.singletonList(tagIdentifier),
+                    Entity.EntityType.TAG)
+                .toArray(new RelationalEntity<?>[0]);
+          } catch (IOException e) {
+            LOG.error(
+                "Failed to list policy associations for tag {} under metalake 
{}",
+                name,
+                metalake,
+                e);
+            throw new RuntimeException(e);
+          }
+        });
+  }
+
+  @Override
+  public void addPolicyForTag(
+      String metalake, String tagName, String policyName, 
PolicyAssociationSelector selector) {
+    NameIdentifier tagIdentifier = NameIdentifierUtil.ofTag(metalake, tagName);
+    NameIdentifier policyIdentifier = NameIdentifierUtil.ofPolicy(metalake, 
policyName);
+    checkMetalake(NameIdentifier.of(metalake), entityStore);
+    TreeLockUtils.doWithTreeLock(
+        tagIdentifier,
+        LockType.WRITE,
+        () -> {
+          RelationUpdate update =
+              RelationUpdate.of(
+                  SupportsRelationOperations.Type.POLICY_TAG_REL,
+                  tagIdentifier,
+                  Entity.EntityType.TAG,
+                  new RelationEdgeTarget[] {
+                    RelationEdgeTarget.of(
+                        policyIdentifier,
+                        Entity.EntityType.POLICY,
+                        PolicyAssociationSelectorSerde.serialize(selector))

Review Comment:
   This method persists the selector without validating it against the tag's 
`TagValueConstraint`. It accepts `TAG_VALUE("engineering")` for an 
`ALLOWED_VALUES("finance", "risk")` tag, or any `TAG_VALUE` for a `NO_VALUE` 
tag, creating an association that can never match. Please load the tag under 
the lock, validate the selector against its constraint, and add negative tests 
for unsupported values and constraint types.



##########
core/src/main/java/org/apache/gravitino/tag/TagDispatcher.java:
##########
@@ -117,6 +119,56 @@ default Tag createTag(
    */
   MetadataObject[] listMetadataObjectsForTag(String metalake, String name);
 
+  /**
+   * List policy names directly associated with the specified tag.
+   *
+   * @param metalake The name of the metalake.
+   * @param name The name of the tag.
+   * @return The directly associated policy names.
+   */
+  default String[] listPoliciesForTag(String metalake, String name) {
+    return Arrays.stream(listPolicyAssociationsForTag(metalake, name))
+        .map(association -> association.targetEntity().name())
+        .toArray(String[]::new);
+  }
+
+  /**
+   * List policy associations, including selectors, for the specified tag.
+   *
+   * @param metalake The name of the metalake.
+   * @param name The name of the tag.
+   * @return The policy-to-tag associations.
+   */
+  default RelationalEntity<?>[] listPolicyAssociationsForTag(String metalake, 
String name) {

Review Comment:
   
[`GravitinoEnv`](https://github.com/apache/gravitino/blob/18ca5608f4a57ebad241fbcde5a881ae8072d167/core/src/main/java/org/apache/gravitino/GravitinoEnv.java#L930-L937)
 exposes `TagHookDispatcher(TagEventDispatcher(TagManager))`, but neither 
wrapper overrides these new default methods, so calls through the production 
dispatcher stop at this `UnsupportedOperationException` instead of reaching 
`TagManager`. `PolicyHookDispatcher`/`PolicyEventDispatcher` have the same gap 
for `listTagAssociationsForPolicy`. Please delegate the new operations through 
both wrapper layers and test the composed runtime chain.



##########
core/src/main/java/org/apache/gravitino/tag/TagManager.java:
##########
@@ -227,6 +231,109 @@ public MetadataObject[] listMetadataObjectsForTag(String 
metalake, String name)
     return listMetadataObjectsForTag(metalake, name, null);
   }
 
+  @Override
+  public RelationalEntity<?>[] listPolicyAssociationsForTag(String metalake, 
String name) {
+    NameIdentifier tagIdentifier = NameIdentifierUtil.ofTag(metalake, name);
+    checkMetalake(NameIdentifier.of(metalake), entityStore);
+    return TreeLockUtils.doWithTreeLock(
+        tagIdentifier,
+        LockType.READ,
+        () -> {
+          try {
+            return entityStore
+                .relationOperations()
+                .batchListEntitiesByRelation(

Review Comment:
   `batchListEntitiesByRelation` returns an empty list when no matching 
relation exists and does not prove that the anchor tag exists. Because this 
method never loads the tag, a nonexistent tag is indistinguishable from an 
existing tag with no policies, so the planned GET endpoint cannot honor its 404 
contract. Please check the tag under the read lock before querying and add a 
missing-tag test.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to