This is an automated email from the ASF dual-hosted git repository.
roryqi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 95ce9f5a23 [#13859] fix(authz): expose inaccessible object tag and
policy associations (#13863)
95ce9f5a23 is described below
commit 95ce9f5a230decdfabb5249c0d7910543a32402c
Author: roryqi <[email protected]>
AuthorDate: Fri Oct 16 15:41:26 2026 +0800
[#13859] fix(authz): expose inaccessible object tag and policy associations
(#13863)
### What changes were proposed in this pull request?
Add authorization-filtering indicators to metadata object tag and policy
list responses:
- `hasInaccessibleTags`
- `hasInaccessiblePolicies`
The indicators are included in both name and detailed responses. Tag and
policy associations are aggregated before authorization filtering so
direct and inherited associations follow the same behavior.
### Why are the changes needed?
When all associated tags or policies are inaccessible, the APIs
currently return an empty list indistinguishable from an object with no
associations.
The new fields indicate whether associations were omitted without
exposing their names, count, details, or inheritance source.
Fix: #13859
### Does this PR introduce _any_ user-facing change?
Yes. The metadata object tag and policy list APIs add boolean fields
indicating whether inaccessible associations were omitted.
### How was this patch tested?
- Common response DTO unit tests
- Metadata object tag and policy REST tests
- Tag and policy Docker authorization integration tests
- `./gradlew :docs:build`
- Spotless checks
---
.../org/apache/gravitino/policy/PolicyList.java | 61 +++++++++++++++
.../apache/gravitino/policy/SupportsPolicies.java | 27 +++++++
.../org/apache/gravitino/tag/SupportsTags.java | 26 +++++++
.../java/org/apache/gravitino/tag/TagList.java | 61 +++++++++++++++
.../apache/gravitino/client/BaseSchemaCatalog.java | 22 ++++++
.../org/apache/gravitino/client/GenericColumn.java | 11 +++
.../apache/gravitino/client/GenericFileset.java | 22 ++++++
.../apache/gravitino/client/GenericFunction.java | 11 +++
.../org/apache/gravitino/client/GenericModel.java | 22 ++++++
.../org/apache/gravitino/client/GenericSchema.java | 22 ++++++
.../gravitino/client/GenericSemanticModel.java | 26 +++++++
.../org/apache/gravitino/client/GenericTopic.java | 22 ++++++
.../org/apache/gravitino/client/GenericView.java | 11 +++
.../client/MetadataObjectPolicyOperations.java | 31 +++++---
.../client/MetadataObjectTagOperations.java | 32 +++++---
.../apache/gravitino/client/RelationalTable.java | 22 ++++++
.../gravitino/client/TestSupportPolicies.java | 23 +++---
.../apache/gravitino/client/TestSupportTags.java | 21 +++--
.../test/authorization/PolicyAuthorizationIT.java | 89 ++++++++++++++++++++++
.../TagOperationsAuthorizationIT.java | 61 +++++++++++++++
.../client-python/gravitino/api/tag/__init__.py | 2 +
.../gravitino/api/tag/supports_tags.py | 17 +++++
.../gravitino/api/tag/{__init__.py => tag_list.py} | 24 ++++--
.../gravitino/client/base_schema_catalog.py | 7 ++
.../gravitino/client/generic_column.py | 7 ++
.../gravitino/client/generic_fileset.py | 9 ++-
.../gravitino/client/generic_function.py | 9 +++
.../gravitino/client/generic_model.py | 8 +-
.../gravitino/client/generic_schema.py | 7 ++
.../gravitino/client/generic_semantic_model.py | 7 ++
.../client-python/gravitino/client/generic_view.py | 7 ++
.../client/metadata_object_tag_operations.py | 30 +++++---
.../gravitino/client/relational_table.py | 7 ++
.../gravitino/dto/responses/tag_response.py | 13 +++-
clients/client-python/tests/unittests/mock_base.py | 4 +-
.../client-python/tests/unittests/test_tag_api.py | 54 +++++++++++--
....java => MetadataObjectPolicyListResponse.java} | 51 +++++--------
...nse.java => MetadataObjectTagListResponse.java} | 46 +++++------
.../gravitino/dto/responses/NameListResponse.java | 2 +
.../dto/responses/PolicyListResponse.java | 2 +
...stResponse.java => PolicyNameListResponse.java} | 47 +++++-------
.../gravitino/dto/responses/TagListResponse.java | 2 +
...gListResponse.java => TagNameListResponse.java} | 47 +++++-------
.../gravitino/dto/responses/TestResponses.java | 78 +++++++++++++++++++
docs/manage-policies-in-gravitino.md | 35 ++++++++-
docs/manage-tags-in-gravitino.md | 48 ++++++++++--
docs/open-api/policies.yaml | 50 ++++++++++--
docs/open-api/tags.yaml | 50 ++++++++++--
.../web/rest/MetadataObjectPolicyOperations.java | 11 ++-
.../web/rest/MetadataObjectTagOperations.java | 37 +++++----
.../rest/TestMetadataObjectPolicyOperations.java | 19 +++--
.../web/rest/TestMetadataObjectTagOperations.java | 9 ++-
52 files changed, 1148 insertions(+), 221 deletions(-)
diff --git a/api/src/main/java/org/apache/gravitino/policy/PolicyList.java
b/api/src/main/java/org/apache/gravitino/policy/PolicyList.java
new file mode 100644
index 0000000000..11281e61b7
--- /dev/null
+++ b/api/src/main/java/org/apache/gravitino/policy/PolicyList.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.policy;
+
+import com.google.common.base.Preconditions;
+import org.apache.gravitino.annotation.Evolving;
+
+/**
+ * A list of visible policies and whether authorization filtering omitted
other policies.
+ *
+ * @param <T> The type of the returned policy names or policy objects.
+ */
+@Evolving
+public final class PolicyList<T> {
+
+ private final T[] policies;
+ private final boolean hasInaccessiblePolicies;
+
+ /**
+ * Creates a policy list.
+ *
+ * @param policies The visible policy names or policy objects.
+ * @param hasInaccessiblePolicies Whether one or more inaccessible policies
were omitted.
+ */
+ public PolicyList(T[] policies, boolean hasInaccessiblePolicies) {
+ Preconditions.checkArgument(policies != null, "Policies must not be null");
+ this.policies = policies.clone();
+ this.hasInaccessiblePolicies = hasInaccessiblePolicies;
+ }
+
+ /**
+ * @return The visible policy names or policy objects.
+ */
+ public T[] policies() {
+ return policies.clone();
+ }
+
+ /**
+ * @return True if one or more inaccessible policies were omitted, false
otherwise.
+ */
+ public boolean hasInaccessiblePolicies() {
+ return hasInaccessiblePolicies;
+ }
+}
diff --git
a/api/src/main/java/org/apache/gravitino/policy/SupportsPolicies.java
b/api/src/main/java/org/apache/gravitino/policy/SupportsPolicies.java
index af0ed772c6..21651678f0 100644
--- a/api/src/main/java/org/apache/gravitino/policy/SupportsPolicies.java
+++ b/api/src/main/java/org/apache/gravitino/policy/SupportsPolicies.java
@@ -33,8 +33,35 @@ public interface SupportsPolicies {
*/
String[] listPolicies();
+ /**
+ * List the visible policy names and whether authorization filtering omitted
other policies.
+ *
+ * <p>The default implementation preserves compatibility with existing
implementations but cannot
+ * detect omitted policies. Implementations that support authorization
filtering should override
+ * this method.
+ *
+ * @return The visible policy names and authorization-filtering status.
+ */
+ default PolicyList<String> listPoliciesWithVisibility() {
+ return new PolicyList<>(listPolicies(), false);
+ }
+
/**
* @return The policies that apply to the metadata object.
*/
Policy[] listPolicyInfos();
+
+ /**
+ * List the visible policies with details and whether authorization
filtering omitted other
+ * policies.
+ *
+ * <p>The default implementation preserves compatibility with existing
implementations but cannot
+ * detect omitted policies. Implementations that support authorization
filtering should override
+ * this method.
+ *
+ * @return The visible policies and authorization-filtering status.
+ */
+ default PolicyList<Policy> listPolicyInfosWithVisibility() {
+ return new PolicyList<>(listPolicyInfos(), false);
+ }
}
diff --git a/api/src/main/java/org/apache/gravitino/tag/SupportsTags.java
b/api/src/main/java/org/apache/gravitino/tag/SupportsTags.java
index 67805d1782..21184fc431 100644
--- a/api/src/main/java/org/apache/gravitino/tag/SupportsTags.java
+++ b/api/src/main/java/org/apache/gravitino/tag/SupportsTags.java
@@ -37,6 +37,19 @@ public interface SupportsTags {
*/
String[] listTags();
+ /**
+ * List the visible tag names and whether authorization filtering omitted
other tags.
+ *
+ * <p>The default implementation preserves compatibility with existing
implementations but cannot
+ * detect omitted tags. Implementations that support authorization filtering
should override this
+ * method.
+ *
+ * @return The visible tag names and authorization-filtering status.
+ */
+ default TagList<String> listTagsWithVisibility() {
+ return new TagList<>(listTags(), false);
+ }
+
/**
* List all the tags with details for the specific object.
*
@@ -44,6 +57,19 @@ public interface SupportsTags {
*/
Tag[] listTagsInfo();
+ /**
+ * List the visible tags with details and whether authorization filtering
omitted other tags.
+ *
+ * <p>The default implementation preserves compatibility with existing
implementations but cannot
+ * detect omitted tags. Implementations that support authorization filtering
should override this
+ * method.
+ *
+ * @return The visible tags and authorization-filtering status.
+ */
+ default TagList<Tag> listTagsInfoWithVisibility() {
+ return new TagList<>(listTagsInfo(), false);
+ }
+
/**
* Get a tag by its name for the specific object.
*
diff --git a/api/src/main/java/org/apache/gravitino/tag/TagList.java
b/api/src/main/java/org/apache/gravitino/tag/TagList.java
new file mode 100644
index 0000000000..1eea86680f
--- /dev/null
+++ b/api/src/main/java/org/apache/gravitino/tag/TagList.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.tag;
+
+import com.google.common.base.Preconditions;
+import org.apache.gravitino.annotation.Evolving;
+
+/**
+ * A list of visible tags and whether authorization filtering omitted other
tags.
+ *
+ * @param <T> The type of the returned tag names or tag objects.
+ */
+@Evolving
+public final class TagList<T> {
+
+ private final T[] tags;
+ private final boolean hasInaccessibleTags;
+
+ /**
+ * Creates a tag list.
+ *
+ * @param tags The visible tag names or tag objects.
+ * @param hasInaccessibleTags Whether one or more inaccessible tags were
omitted.
+ */
+ public TagList(T[] tags, boolean hasInaccessibleTags) {
+ Preconditions.checkArgument(tags != null, "Tags must not be null");
+ this.tags = tags.clone();
+ this.hasInaccessibleTags = hasInaccessibleTags;
+ }
+
+ /**
+ * @return The visible tag names or tag objects.
+ */
+ public T[] tags() {
+ return tags.clone();
+ }
+
+ /**
+ * @return True if one or more inaccessible tags were omitted, false
otherwise.
+ */
+ public boolean hasInaccessibleTags() {
+ return hasInaccessibleTags;
+ }
+}
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/BaseSchemaCatalog.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/BaseSchemaCatalog.java
index ca4b17ce0c..5fc840852f 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/BaseSchemaCatalog.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/BaseSchemaCatalog.java
@@ -54,12 +54,14 @@ import org.apache.gravitino.function.FunctionChange;
import org.apache.gravitino.function.FunctionDefinition;
import org.apache.gravitino.function.FunctionType;
import org.apache.gravitino.policy.Policy;
+import org.apache.gravitino.policy.PolicyList;
import org.apache.gravitino.policy.SupportsPolicies;
import org.apache.gravitino.rest.RESTUtils;
import org.apache.gravitino.secret.SecretBinding;
import org.apache.gravitino.secret.SecretReference;
import org.apache.gravitino.tag.SupportsTags;
import org.apache.gravitino.tag.Tag;
+import org.apache.gravitino.tag.TagList;
import org.apache.gravitino.tag.TagValue;
/**
@@ -311,11 +313,21 @@ abstract class BaseSchemaCatalog extends CatalogDTO
return objectTagOperations.listTags();
}
+ @Override
+ public TagList<String> listTagsWithVisibility() {
+ return objectTagOperations.listTagsWithVisibility();
+ }
+
@Override
public Tag[] listTagsInfo() {
return objectTagOperations.listTagsInfo();
}
+ @Override
+ public TagList<Tag> listTagsInfoWithVisibility() {
+ return objectTagOperations.listTagsInfoWithVisibility();
+ }
+
@Override
public Tag getTag(String name) {
return objectTagOperations.getTag(name);
@@ -336,11 +348,21 @@ abstract class BaseSchemaCatalog extends CatalogDTO
return objectPolicyOperations.listPolicies();
}
+ @Override
+ public PolicyList<String> listPoliciesWithVisibility() {
+ return objectPolicyOperations.listPoliciesWithVisibility();
+ }
+
@Override
public Policy[] listPolicyInfos() {
return objectPolicyOperations.listPolicyInfos();
}
+ @Override
+ public PolicyList<Policy> listPolicyInfosWithVisibility() {
+ return objectPolicyOperations.listPolicyInfosWithVisibility();
+ }
+
@Override
public String[] listBindingRoleNames() {
return objectRoleOperations.listBindingRoleNames();
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericColumn.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericColumn.java
index c7845db865..70994dcfd3 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericColumn.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericColumn.java
@@ -29,6 +29,7 @@ import org.apache.gravitino.rel.expressions.Expression;
import org.apache.gravitino.rel.types.Type;
import org.apache.gravitino.tag.SupportsTags;
import org.apache.gravitino.tag.Tag;
+import org.apache.gravitino.tag.TagList;
import org.apache.gravitino.tag.TagValue;
/** Represents a generic column. */
@@ -63,11 +64,21 @@ public class GenericColumn implements Column, SupportsTags {
return objectTagOperations.listTags();
}
+ @Override
+ public TagList<String> listTagsWithVisibility() {
+ return objectTagOperations.listTagsWithVisibility();
+ }
+
@Override
public Tag[] listTagsInfo() {
return objectTagOperations.listTagsInfo();
}
+ @Override
+ public TagList<Tag> listTagsInfoWithVisibility() {
+ return objectTagOperations.listTagsInfoWithVisibility();
+ }
+
@Override
public Tag getTag(String name) throws NoSuchTagException {
return objectTagOperations.getTag(name);
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericFileset.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericFileset.java
index 844621573d..c442ceb514 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericFileset.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericFileset.java
@@ -33,10 +33,12 @@ import org.apache.gravitino.dto.file.FilesetDTO;
import org.apache.gravitino.exceptions.NoSuchTagException;
import org.apache.gravitino.file.Fileset;
import org.apache.gravitino.policy.Policy;
+import org.apache.gravitino.policy.PolicyList;
import org.apache.gravitino.policy.SupportsPolicies;
import org.apache.gravitino.secret.SupportsSecrets;
import org.apache.gravitino.tag.SupportsTags;
import org.apache.gravitino.tag.Tag;
+import org.apache.gravitino.tag.TagList;
import org.apache.gravitino.tag.TagValue;
/** Represents a generic fileset. */
@@ -134,11 +136,21 @@ class GenericFileset
return objectTagOperations.listTags();
}
+ @Override
+ public TagList<String> listTagsWithVisibility() {
+ return objectTagOperations.listTagsWithVisibility();
+ }
+
@Override
public Tag[] listTagsInfo() {
return objectTagOperations.listTagsInfo();
}
+ @Override
+ public TagList<Tag> listTagsInfoWithVisibility() {
+ return objectTagOperations.listTagsInfoWithVisibility();
+ }
+
@Override
public Tag getTag(String name) throws NoSuchTagException {
return objectTagOperations.getTag(name);
@@ -159,11 +171,21 @@ class GenericFileset
return objectPolicyOperations.listPolicies();
}
+ @Override
+ public PolicyList<String> listPoliciesWithVisibility() {
+ return objectPolicyOperations.listPoliciesWithVisibility();
+ }
+
@Override
public Policy[] listPolicyInfos() {
return objectPolicyOperations.listPolicyInfos();
}
+ @Override
+ public PolicyList<Policy> listPolicyInfosWithVisibility() {
+ return objectPolicyOperations.listPolicyInfosWithVisibility();
+ }
+
@Override
public String[] listBindingRoleNames() {
return objectRoleOperations.listBindingRoleNames();
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericFunction.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericFunction.java
index 2bb58b7ec3..a2f6eb1e7f 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericFunction.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericFunction.java
@@ -32,6 +32,7 @@ import org.apache.gravitino.function.FunctionDefinition;
import org.apache.gravitino.function.FunctionType;
import org.apache.gravitino.tag.SupportsTags;
import org.apache.gravitino.tag.Tag;
+import org.apache.gravitino.tag.TagList;
import org.apache.gravitino.tag.TagValue;
/** Represents a generic function. */
@@ -91,11 +92,21 @@ class GenericFunction implements Function, SupportsTags {
return objectTagOperations.listTags();
}
+ @Override
+ public TagList<String> listTagsWithVisibility() {
+ return objectTagOperations.listTagsWithVisibility();
+ }
+
@Override
public Tag[] listTagsInfo() {
return objectTagOperations.listTagsInfo();
}
+ @Override
+ public TagList<Tag> listTagsInfoWithVisibility() {
+ return objectTagOperations.listTagsInfoWithVisibility();
+ }
+
@Override
public Tag getTag(String name) throws NoSuchTagException {
return objectTagOperations.getTag(name);
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModel.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModel.java
index f12177af4d..1967661785 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModel.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModel.java
@@ -31,10 +31,12 @@ import org.apache.gravitino.exceptions.NoSuchTagException;
import org.apache.gravitino.exceptions.TagAlreadyAssociatedException;
import org.apache.gravitino.model.Model;
import org.apache.gravitino.policy.Policy;
+import org.apache.gravitino.policy.PolicyList;
import org.apache.gravitino.policy.SupportsPolicies;
import org.apache.gravitino.secret.SupportsSecrets;
import org.apache.gravitino.tag.SupportsTags;
import org.apache.gravitino.tag.Tag;
+import org.apache.gravitino.tag.TagList;
import org.apache.gravitino.tag.TagValue;
/** Represents a generic model. */
@@ -132,11 +134,21 @@ class GenericModel implements Model, SupportsTags,
SupportsPolicies, SupportsSec
return objectTagOperations.listTags();
}
+ @Override
+ public TagList<String> listTagsWithVisibility() {
+ return objectTagOperations.listTagsWithVisibility();
+ }
+
@Override
public Tag[] listTagsInfo() {
return objectTagOperations.listTagsInfo();
}
+ @Override
+ public TagList<Tag> listTagsInfoWithVisibility() {
+ return objectTagOperations.listTagsInfoWithVisibility();
+ }
+
@Override
public Tag getTag(String name) throws NoSuchTagException {
return objectTagOperations.getTag(name);
@@ -158,8 +170,18 @@ class GenericModel implements Model, SupportsTags,
SupportsPolicies, SupportsSec
return objectPolicyOperations.listPolicies();
}
+ @Override
+ public PolicyList<String> listPoliciesWithVisibility() {
+ return objectPolicyOperations.listPoliciesWithVisibility();
+ }
+
@Override
public Policy[] listPolicyInfos() {
return objectPolicyOperations.listPolicyInfos();
}
+
+ @Override
+ public PolicyList<Policy> listPolicyInfosWithVisibility() {
+ return objectPolicyOperations.listPolicyInfosWithVisibility();
+ }
}
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericSchema.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericSchema.java
index 756e0640ab..348df64662 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericSchema.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericSchema.java
@@ -28,10 +28,12 @@ import org.apache.gravitino.authorization.SupportsRoles;
import org.apache.gravitino.dto.SchemaDTO;
import org.apache.gravitino.exceptions.NoSuchTagException;
import org.apache.gravitino.policy.Policy;
+import org.apache.gravitino.policy.PolicyList;
import org.apache.gravitino.policy.SupportsPolicies;
import org.apache.gravitino.secret.SupportsSecrets;
import org.apache.gravitino.tag.SupportsTags;
import org.apache.gravitino.tag.Tag;
+import org.apache.gravitino.tag.TagList;
import org.apache.gravitino.tag.TagValue;
/** Represents a generic schema. */
@@ -108,11 +110,21 @@ class GenericSchema
return objectTagOperations.listTags();
}
+ @Override
+ public TagList<String> listTagsWithVisibility() {
+ return objectTagOperations.listTagsWithVisibility();
+ }
+
@Override
public Tag[] listTagsInfo() {
return objectTagOperations.listTagsInfo();
}
+ @Override
+ public TagList<Tag> listTagsInfoWithVisibility() {
+ return objectTagOperations.listTagsInfoWithVisibility();
+ }
+
@Override
public Tag getTag(String name) throws NoSuchTagException {
return objectTagOperations.getTag(name);
@@ -133,11 +145,21 @@ class GenericSchema
return objectPolicyOperations.listPolicies();
}
+ @Override
+ public PolicyList<String> listPoliciesWithVisibility() {
+ return objectPolicyOperations.listPoliciesWithVisibility();
+ }
+
@Override
public Policy[] listPolicyInfos() {
return objectPolicyOperations.listPolicyInfos();
}
+ @Override
+ public PolicyList<Policy> listPolicyInfosWithVisibility() {
+ return objectPolicyOperations.listPolicyInfosWithVisibility();
+ }
+
@Override
public String[] listBindingRoleNames() {
return objectRoleOperations.listBindingRoleNames();
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericSemanticModel.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericSemanticModel.java
index e64d1483fc..f5074a30dc 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericSemanticModel.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericSemanticModel.java
@@ -29,11 +29,13 @@ import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.MetadataObjects;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.policy.Policy;
+import org.apache.gravitino.policy.PolicyList;
import org.apache.gravitino.policy.SupportsPolicies;
import org.apache.gravitino.semantic.SemanticModel;
import org.apache.gravitino.semantic.SemanticModelDefinition;
import org.apache.gravitino.tag.SupportsTags;
import org.apache.gravitino.tag.Tag;
+import org.apache.gravitino.tag.TagList;
import org.apache.gravitino.tag.TagValue;
/** An immutable client-side Semantic Model returned by the Gravitino REST
API. */
@@ -120,12 +122,24 @@ class GenericSemanticModel implements SemanticModel,
SupportsTags, SupportsPolic
return objectTagOperations.listTags();
}
+ /** {@inheritDoc} */
+ @Override
+ public TagList<String> listTagsWithVisibility() {
+ return objectTagOperations.listTagsWithVisibility();
+ }
+
/** {@inheritDoc} */
@Override
public Tag[] listTagsInfo() {
return objectTagOperations.listTagsInfo();
}
+ /** {@inheritDoc} */
+ @Override
+ public TagList<Tag> listTagsInfoWithVisibility() {
+ return objectTagOperations.listTagsInfoWithVisibility();
+ }
+
/** {@inheritDoc} */
@Override
public Tag getTag(String name) {
@@ -150,12 +164,24 @@ class GenericSemanticModel implements SemanticModel,
SupportsTags, SupportsPolic
return objectPolicyOperations.listPolicies();
}
+ /** {@inheritDoc} */
+ @Override
+ public PolicyList<String> listPoliciesWithVisibility() {
+ return objectPolicyOperations.listPoliciesWithVisibility();
+ }
+
/** {@inheritDoc} */
@Override
public Policy[] listPolicyInfos() {
return objectPolicyOperations.listPolicyInfos();
}
+ /** {@inheritDoc} */
+ @Override
+ public PolicyList<Policy> listPolicyInfosWithVisibility() {
+ return objectPolicyOperations.listPolicyInfosWithVisibility();
+ }
+
/** {@inheritDoc} */
@Override
public boolean equals(Object other) {
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericTopic.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericTopic.java
index 6ed87337eb..c8b3a80bac 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericTopic.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericTopic.java
@@ -30,10 +30,12 @@ import org.apache.gravitino.dto.messaging.TopicDTO;
import org.apache.gravitino.exceptions.NoSuchTagException;
import org.apache.gravitino.messaging.Topic;
import org.apache.gravitino.policy.Policy;
+import org.apache.gravitino.policy.PolicyList;
import org.apache.gravitino.policy.SupportsPolicies;
import org.apache.gravitino.secret.SupportsSecrets;
import org.apache.gravitino.tag.SupportsTags;
import org.apache.gravitino.tag.Tag;
+import org.apache.gravitino.tag.TagList;
import org.apache.gravitino.tag.TagValue;
/** Represents a generic topic. */
@@ -112,11 +114,21 @@ class GenericTopic
return objectTagOperations.listTags();
}
+ @Override
+ public TagList<String> listTagsWithVisibility() {
+ return objectTagOperations.listTagsWithVisibility();
+ }
+
@Override
public Tag[] listTagsInfo() {
return objectTagOperations.listTagsInfo();
}
+ @Override
+ public TagList<Tag> listTagsInfoWithVisibility() {
+ return objectTagOperations.listTagsInfoWithVisibility();
+ }
+
@Override
public Tag getTag(String name) throws NoSuchTagException {
return objectTagOperations.getTag(name);
@@ -137,11 +149,21 @@ class GenericTopic
return objectPolicyOperations.listPolicies();
}
+ @Override
+ public PolicyList<String> listPoliciesWithVisibility() {
+ return objectPolicyOperations.listPoliciesWithVisibility();
+ }
+
@Override
public Policy[] listPolicyInfos() {
return objectPolicyOperations.listPolicyInfos();
}
+ @Override
+ public PolicyList<Policy> listPolicyInfosWithVisibility() {
+ return objectPolicyOperations.listPolicyInfosWithVisibility();
+ }
+
@Override
public String[] listBindingRoleNames() {
return objectRoleOperations.listBindingRoleNames();
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericView.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericView.java
index 7b0a0b6921..f4b1e9e935 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericView.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericView.java
@@ -34,6 +34,7 @@ import org.apache.gravitino.rel.View;
import org.apache.gravitino.secret.SupportsSecrets;
import org.apache.gravitino.tag.SupportsTags;
import org.apache.gravitino.tag.Tag;
+import org.apache.gravitino.tag.TagList;
import org.apache.gravitino.tag.TagValue;
/** Represents a generic view. */
@@ -115,11 +116,21 @@ class GenericView implements View, SupportsTags,
SupportsSecrets {
return objectTagOperations.listTags();
}
+ @Override
+ public TagList<String> listTagsWithVisibility() {
+ return objectTagOperations.listTagsWithVisibility();
+ }
+
@Override
public Tag[] listTagsInfo() {
return objectTagOperations.listTagsInfo();
}
+ @Override
+ public TagList<Tag> listTagsInfoWithVisibility() {
+ return objectTagOperations.listTagsInfoWithVisibility();
+ }
+
@Override
public Tag getTag(String name) throws NoSuchTagException {
return objectTagOperations.getTag(name);
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/MetadataObjectPolicyOperations.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/MetadataObjectPolicyOperations.java
index 79292cee44..6028b3005d 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/MetadataObjectPolicyOperations.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/MetadataObjectPolicyOperations.java
@@ -23,9 +23,10 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Locale;
import org.apache.gravitino.MetadataObject;
-import org.apache.gravitino.dto.responses.NameListResponse;
-import org.apache.gravitino.dto.responses.PolicyListResponse;
+import org.apache.gravitino.dto.responses.MetadataObjectPolicyListResponse;
+import org.apache.gravitino.dto.responses.PolicyNameListResponse;
import org.apache.gravitino.policy.Policy;
+import org.apache.gravitino.policy.PolicyList;
import org.apache.gravitino.policy.SupportsPolicies;
import org.apache.gravitino.rest.RESTUtils;
@@ -52,30 +53,40 @@ class MetadataObjectPolicyOperations implements
SupportsPolicies {
@Override
public String[] listPolicies() {
- NameListResponse resp =
+ return listPoliciesWithVisibility().policies();
+ }
+
+ @Override
+ public PolicyList<String> listPoliciesWithVisibility() {
+ PolicyNameListResponse resp =
restClient.get(
policyRequestPath,
- NameListResponse.class,
+ PolicyNameListResponse.class,
Collections.emptyMap(),
ErrorHandlers.policyErrorHandler());
resp.validate();
- return resp.getNames();
+ return new PolicyList<>(resp.getNames(), resp.hasInaccessiblePolicies());
}
@Override
public Policy[] listPolicyInfos() {
- PolicyListResponse resp =
+ return listPolicyInfosWithVisibility().policies();
+ }
+
+ @Override
+ public PolicyList<Policy> listPolicyInfosWithVisibility() {
+ MetadataObjectPolicyListResponse resp =
restClient.get(
policyRequestPath,
ImmutableMap.of("details", "true"),
- PolicyListResponse.class,
+ MetadataObjectPolicyListResponse.class,
Collections.emptyMap(),
ErrorHandlers.policyErrorHandler());
resp.validate();
- return Arrays.stream(resp.getPolicies())
- .map(policyDTO -> new GenericPolicy(policyDTO))
- .toArray(Policy[]::new);
+ Policy[] policies =
+
Arrays.stream(resp.getPolicies()).map(GenericPolicy::new).toArray(Policy[]::new);
+ return new PolicyList<>(policies, resp.hasInaccessiblePolicies());
}
}
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/MetadataObjectTagOperations.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/MetadataObjectTagOperations.java
index c504c9a212..d29a82c4e7 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/MetadataObjectTagOperations.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/MetadataObjectTagOperations.java
@@ -27,13 +27,15 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.dto.requests.TagValuesAssociateRequest;
import org.apache.gravitino.dto.requests.TagsAssociateRequest;
+import org.apache.gravitino.dto.responses.MetadataObjectTagListResponse;
import org.apache.gravitino.dto.responses.NameListResponse;
-import org.apache.gravitino.dto.responses.TagListResponse;
+import org.apache.gravitino.dto.responses.TagNameListResponse;
import org.apache.gravitino.dto.responses.TagResponse;
import org.apache.gravitino.exceptions.NoSuchTagException;
import org.apache.gravitino.rest.RESTUtils;
import org.apache.gravitino.tag.SupportsTags;
import org.apache.gravitino.tag.Tag;
+import org.apache.gravitino.tag.TagList;
import org.apache.gravitino.tag.TagValue;
import org.apache.hc.core5.http.HttpHeaders;
@@ -65,31 +67,43 @@ class MetadataObjectTagOperations implements SupportsTags {
@Override
public String[] listTags() {
- NameListResponse resp =
+ return listTagsWithVisibility().tags();
+ }
+
+ @Override
+ public TagList<String> listTagsWithVisibility() {
+ TagNameListResponse resp =
restClient.get(
tagRequestPath,
- NameListResponse.class,
+ TagNameListResponse.class,
Collections.emptyMap(),
ErrorHandlers.tagErrorHandler());
resp.validate();
- return resp.getNames();
+ return new TagList<>(resp.getNames(), resp.hasInaccessibleTags());
}
@Override
public Tag[] listTagsInfo() {
- TagListResponse resp =
+ return listTagsInfoWithVisibility().tags();
+ }
+
+ @Override
+ public TagList<Tag> listTagsInfoWithVisibility() {
+ MetadataObjectTagListResponse resp =
restClient.get(
tagRequestPath,
ImmutableMap.of("details", "true"),
- TagListResponse.class,
+ MetadataObjectTagListResponse.class,
Collections.emptyMap(),
ErrorHandlers.tagErrorHandler());
resp.validate();
- return Arrays.stream(resp.getTags())
- .map(tagDTO -> new GenericTag(tagDTO, restClient, metalakeName))
- .toArray(Tag[]::new);
+ Tag[] tags =
+ Arrays.stream(resp.getTags())
+ .map(tagDTO -> new GenericTag(tagDTO, restClient, metalakeName))
+ .toArray(Tag[]::new);
+ return new TagList<>(tags, resp.hasInaccessibleTags());
}
@Override
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/RelationalTable.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/RelationalTable.java
index 36348080e2..b2eb7b627c 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/RelationalTable.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/RelationalTable.java
@@ -47,6 +47,7 @@ import org.apache.gravitino.exceptions.NoSuchTagException;
import org.apache.gravitino.exceptions.PartitionAlreadyExistsException;
import org.apache.gravitino.exceptions.UnmodifiableStatisticException;
import org.apache.gravitino.policy.Policy;
+import org.apache.gravitino.policy.PolicyList;
import org.apache.gravitino.policy.SupportsPolicies;
import org.apache.gravitino.rel.Column;
import org.apache.gravitino.rel.SupportsPartitions;
@@ -68,6 +69,7 @@ import org.apache.gravitino.stats.SupportsPartitionStatistics;
import org.apache.gravitino.stats.SupportsStatistics;
import org.apache.gravitino.tag.SupportsTags;
import org.apache.gravitino.tag.Tag;
+import org.apache.gravitino.tag.TagList;
import org.apache.gravitino.tag.TagValue;
/** Represents a relational table. */
@@ -391,11 +393,21 @@ class RelationalTable
return objectTagOperations.listTags();
}
+ @Override
+ public TagList<String> listTagsWithVisibility() {
+ return objectTagOperations.listTagsWithVisibility();
+ }
+
@Override
public Tag[] listTagsInfo() {
return objectTagOperations.listTagsInfo();
}
+ @Override
+ public TagList<Tag> listTagsInfoWithVisibility() {
+ return objectTagOperations.listTagsInfoWithVisibility();
+ }
+
@Override
public Tag getTag(String name) throws NoSuchTagException {
return objectTagOperations.getTag(name);
@@ -416,11 +428,21 @@ class RelationalTable
return objectPolicyOperations.listPolicies();
}
+ @Override
+ public PolicyList<String> listPoliciesWithVisibility() {
+ return objectPolicyOperations.listPoliciesWithVisibility();
+ }
+
@Override
public Policy[] listPolicyInfos() {
return objectPolicyOperations.listPolicyInfos();
}
+ @Override
+ public PolicyList<Policy> listPolicyInfosWithVisibility() {
+ return objectPolicyOperations.listPolicyInfosWithVisibility();
+ }
+
@Override
public String[] listBindingRoleNames() {
return objectRoleOperations.listBindingRoleNames();
diff --git
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestSupportPolicies.java
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestSupportPolicies.java
index a2033f306f..2e05dac76e 100644
---
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestSupportPolicies.java
+++
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestSupportPolicies.java
@@ -44,14 +44,15 @@ import org.apache.gravitino.dto.policy.PolicyDTO;
import org.apache.gravitino.dto.rel.ColumnDTO;
import org.apache.gravitino.dto.rel.TableDTO;
import org.apache.gravitino.dto.responses.ErrorResponse;
-import org.apache.gravitino.dto.responses.NameListResponse;
-import org.apache.gravitino.dto.responses.PolicyListResponse;
+import org.apache.gravitino.dto.responses.MetadataObjectPolicyListResponse;
+import org.apache.gravitino.dto.responses.PolicyNameListResponse;
import org.apache.gravitino.dto.semantic.SemanticModelDTO;
import org.apache.gravitino.dto.semantic.SemanticModelDefinitionDTO;
import org.apache.gravitino.exceptions.NotFoundException;
import org.apache.gravitino.file.Fileset;
import org.apache.gravitino.messaging.Topic;
import org.apache.gravitino.policy.Policy;
+import org.apache.gravitino.policy.PolicyList;
import org.apache.gravitino.policy.SupportsPolicies;
import org.apache.gravitino.rel.Table;
import org.apache.gravitino.rel.types.Types;
@@ -320,14 +321,15 @@ public class TestSupportPolicies extends TestBase {
+ "/policies";
String[] policies = new String[] {"policy1", "policy2"};
- NameListResponse resp = new NameListResponse(policies);
+ PolicyNameListResponse resp = new PolicyNameListResponse(policies, true);
buildMockResource(Method.GET, path, null, resp, SC_OK);
- String[] actualPolicies = supportsPolicies.listPolicies();
- Assertions.assertArrayEquals(policies, actualPolicies);
+ PolicyList<String> policyList =
supportsPolicies.listPoliciesWithVisibility();
+ Assertions.assertArrayEquals(policies, policyList.policies());
+ Assertions.assertTrue(policyList.hasInaccessiblePolicies());
// Return empty list
- NameListResponse resp1 = new NameListResponse(new String[0]);
+ PolicyNameListResponse resp1 = new PolicyNameListResponse(new String[0],
false);
buildMockResource(Method.GET, path, null, resp1, SC_OK);
String[] actualPolicies1 = supportsPolicies.listPolicies();
@@ -378,19 +380,22 @@ public class TestSupportPolicies extends TestBase {
.withAudit(AuditDTO.builder().withCreator("test").build())
.build();
PolicyDTO[] policies = new PolicyDTO[] {policy1, policy2};
- PolicyListResponse resp = new PolicyListResponse(policies);
+ MetadataObjectPolicyListResponse resp = new
MetadataObjectPolicyListResponse(policies, true);
buildMockResource(
Method.GET, path, Collections.singletonMap("details", "true"), null,
resp, SC_OK);
- Policy[] actualPolicies = supportsPolicies.listPolicyInfos();
+ PolicyList<Policy> policyList =
supportsPolicies.listPolicyInfosWithVisibility();
+ Policy[] actualPolicies = policyList.policies();
Assertions.assertEquals(2, actualPolicies.length);
Assertions.assertEquals("policy1", actualPolicies[0].name());
Assertions.assertEquals("policy2", actualPolicies[1].name());
Assertions.assertFalse(actualPolicies[0].inherited().orElseThrow());
Assertions.assertTrue(actualPolicies[1].inherited().orElseThrow());
+ Assertions.assertTrue(policyList.hasInaccessiblePolicies());
// Return empty list
- PolicyListResponse resp1 = new PolicyListResponse(new PolicyDTO[0]);
+ MetadataObjectPolicyListResponse resp1 =
+ new MetadataObjectPolicyListResponse(new PolicyDTO[0], false);
buildMockResource(
Method.GET, path, Collections.singletonMap("details", "true"), null,
resp1, SC_OK);
diff --git
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestSupportTags.java
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestSupportTags.java
index 446fd2bf61..a2c2811106 100644
---
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestSupportTags.java
+++
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestSupportTags.java
@@ -46,8 +46,9 @@ import org.apache.gravitino.dto.rel.ViewDTO;
import org.apache.gravitino.dto.requests.TagValuesAssociateRequest;
import org.apache.gravitino.dto.requests.TagsAssociateRequest;
import org.apache.gravitino.dto.responses.ErrorResponse;
+import org.apache.gravitino.dto.responses.MetadataObjectTagListResponse;
import org.apache.gravitino.dto.responses.NameListResponse;
-import org.apache.gravitino.dto.responses.TagListResponse;
+import org.apache.gravitino.dto.responses.TagNameListResponse;
import org.apache.gravitino.dto.responses.TagResponse;
import org.apache.gravitino.dto.semantic.SemanticModelDTO;
import org.apache.gravitino.dto.semantic.SemanticModelDefinitionDTO;
@@ -68,6 +69,7 @@ import org.apache.gravitino.semantic.SemanticModel;
import org.apache.gravitino.semantic.SemanticModelDefinition;
import org.apache.gravitino.tag.SupportsTags;
import org.apache.gravitino.tag.Tag;
+import org.apache.gravitino.tag.TagList;
import org.apache.gravitino.tag.TagValue;
import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.Method;
@@ -582,14 +584,15 @@ public class TestSupportTags extends TestBase {
+ "/tags";
String[] tags = new String[] {"tag1", "tag2"};
- NameListResponse resp = new NameListResponse(tags);
+ TagNameListResponse resp = new TagNameListResponse(tags, true);
buildMockResource(Method.GET, path, null, resp, SC_OK);
- String[] actualTags = supportsTags.listTags();
- Assertions.assertArrayEquals(tags, actualTags);
+ TagList<String> tagList = supportsTags.listTagsWithVisibility();
+ Assertions.assertArrayEquals(tags, tagList.tags());
+ Assertions.assertTrue(tagList.hasInaccessibleTags());
// Return empty list
- NameListResponse resp1 = new NameListResponse(new String[0]);
+ TagNameListResponse resp1 = new TagNameListResponse(new String[0], false);
buildMockResource(Method.GET, path, null, resp1, SC_OK);
String[] actualTags1 = supportsTags.listTags();
@@ -633,16 +636,18 @@ public class TestSupportTags extends TestBase {
.withAudit(AuditDTO.builder().withCreator("test").build())
.build();
TagDTO[] tags = new TagDTO[] {tag1, tag2};
- TagListResponse resp = new TagListResponse(tags);
+ MetadataObjectTagListResponse resp = new
MetadataObjectTagListResponse(tags, true);
buildMockResource(Method.GET, path, null, resp, SC_OK);
- Tag[] actualTags = supportsTags.listTagsInfo();
+ TagList<Tag> tagList = supportsTags.listTagsInfoWithVisibility();
+ Tag[] actualTags = tagList.tags();
Assertions.assertEquals(2, actualTags.length);
Assertions.assertEquals("tag1", actualTags[0].name());
Assertions.assertEquals("tag2", actualTags[1].name());
+ Assertions.assertTrue(tagList.hasInaccessibleTags());
// Return empty list
- TagListResponse resp1 = new TagListResponse(new TagDTO[0]);
+ MetadataObjectTagListResponse resp1 = new
MetadataObjectTagListResponse(new TagDTO[0], false);
buildMockResource(Method.GET, path, null, resp1, SC_OK);
Tag[] actualTags1 = supportsTags.listTagsInfo();
diff --git
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/PolicyAuthorizationIT.java
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/PolicyAuthorizationIT.java
index dc8ec96d0b..754b975cb7 100644
---
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/PolicyAuthorizationIT.java
+++
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/PolicyAuthorizationIT.java
@@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -42,6 +43,8 @@ import
org.apache.gravitino.integration.test.container.ContainerSuite;
import org.apache.gravitino.integration.test.container.HiveContainer;
import org.apache.gravitino.policy.PolicyChange;
import org.apache.gravitino.policy.PolicyContents;
+import org.apache.gravitino.policy.PolicyList;
+import org.apache.gravitino.policy.SupportsPolicies;
import org.apache.gravitino.rel.Column;
import org.apache.gravitino.rel.TableCatalog;
import org.apache.gravitino.rel.types.Types;
@@ -212,6 +215,73 @@ public class PolicyAuthorizationIT extends
BaseRestApiAuthorizationIT {
metalakeLoadByNormalUser.alterPolicy("policy2",
PolicyChange.updateComment("222"));
}
+ @Test
+ @Order(5)
+ public void testListPoliciesByMetadataObjectVisibility() throws Exception {
+ String hiddenTag = "hidden_policy_tag";
+ String visibleTag = "visible_policy_tag";
+ String allHiddenTable = "all_hidden_policy_table";
+ GravitinoMetalake gravitinoMetalake = client.loadMetalake(METALAKE);
+ TableCatalog tableCatalog =
gravitinoMetalake.loadCatalog(CATALOG).asTableCatalog();
+
+ gravitinoMetalake.grantPrivilegesToRole(
+ role,
+ MetadataObjects.of(ImmutableList.of(CATALOG, SCHEMA),
MetadataObject.Type.SCHEMA),
+ ImmutableList.of(Privileges.SelectTable.allow(),
Privileges.UseSchema.allow()));
+ tableCatalog.createTable(
+ NameIdentifier.of(SCHEMA, allHiddenTable),
+ createColumns(),
+ "test policy visibility indicators",
+ new HashMap<>());
+ gravitinoMetalake.createTag(hiddenTag, "hidden policy tag", Map.of());
+ gravitinoMetalake.createTag(visibleTag, "visible policy tag", Map.of());
+ gravitinoMetalake.addPolicyForTag(hiddenTag, "policy1");
+ gravitinoMetalake.addPolicyForTag(visibleTag, "policy2");
+
+ try {
+ tableCatalog
+ .loadTable(NameIdentifier.of(SCHEMA, allHiddenTable))
+ .supportsTags()
+ .associateTags(new String[] {hiddenTag}, null);
+ tableCatalog
+ .loadTable(NameIdentifier.of(SCHEMA, "table1"))
+ .supportsTags()
+ .associateTags(new String[] {hiddenTag, visibleTag}, null);
+
+ SupportsPolicies allHiddenPolicies =
+ normalUserClient
+ .loadMetalake(METALAKE)
+ .loadCatalog(CATALOG)
+ .asTableCatalog()
+ .loadTable(NameIdentifier.of(SCHEMA, allHiddenTable))
+ .supportsPolicies();
+ assertPolicyList(allHiddenPolicies, new String[0], true);
+
+ SupportsPolicies mixedPolicies =
+ normalUserClient
+ .loadMetalake(METALAKE)
+ .loadCatalog(CATALOG)
+ .asTableCatalog()
+ .loadTable(NameIdentifier.of(SCHEMA, "table1"))
+ .supportsPolicies();
+ assertPolicyList(mixedPolicies, new String[] {"policy2"}, true);
+ } finally {
+ tableCatalog
+ .loadTable(NameIdentifier.of(SCHEMA, allHiddenTable))
+ .supportsTags()
+ .associateTags(null, new String[] {hiddenTag});
+ tableCatalog
+ .loadTable(NameIdentifier.of(SCHEMA, "table1"))
+ .supportsTags()
+ .associateTags(null, new String[] {hiddenTag, visibleTag});
+ gravitinoMetalake.removePolicyFromTag(hiddenTag, "policy1");
+ gravitinoMetalake.removePolicyFromTag(visibleTag, "policy2");
+ gravitinoMetalake.deleteTag(hiddenTag);
+ gravitinoMetalake.deleteTag(visibleTag);
+ tableCatalog.dropTable(NameIdentifier.of(SCHEMA, allHiddenTable));
+ }
+ }
+
@Test
@Order(10)
public void testDropPolicy() {
@@ -226,4 +296,23 @@ public class PolicyAuthorizationIT extends
BaseRestApiAuthorizationIT {
gravitinoMetalake.deletePolicy("policy1");
metalakeLoadByNormalUser.deletePolicy("policy2");
}
+
+ private void assertPolicyList(
+ SupportsPolicies supportsPolicies,
+ String[] expectedPolicyNames,
+ boolean hasInaccessiblePolicies) {
+ PolicyList<String> nameResult =
supportsPolicies.listPoliciesWithVisibility();
+ String[] actualPolicyNames = nameResult.policies();
+ Arrays.sort(actualPolicyNames);
+ Arrays.sort(expectedPolicyNames);
+ Assertions.assertArrayEquals(expectedPolicyNames, actualPolicyNames);
+ Assertions.assertEquals(hasInaccessiblePolicies,
nameResult.hasInaccessiblePolicies());
+
+ var detailsResult = supportsPolicies.listPolicyInfosWithVisibility();
+ String[] actualDetailNames =
+ Arrays.stream(detailsResult.policies()).map(policy ->
policy.name()).toArray(String[]::new);
+ Arrays.sort(actualDetailNames);
+ Assertions.assertArrayEquals(expectedPolicyNames, actualDetailNames);
+ Assertions.assertEquals(hasInaccessiblePolicies,
detailsResult.hasInaccessiblePolicies());
+ }
}
diff --git
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/TagOperationsAuthorizationIT.java
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/TagOperationsAuthorizationIT.java
index 01780d8bee..6c76d0fdd9 100644
---
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/TagOperationsAuthorizationIT.java
+++
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/TagOperationsAuthorizationIT.java
@@ -48,6 +48,7 @@ import org.apache.gravitino.rel.TableCatalog;
import org.apache.gravitino.rel.types.Types;
import org.apache.gravitino.tag.SupportsTags;
import org.apache.gravitino.tag.TagChange;
+import org.apache.gravitino.tag.TagList;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
@@ -281,6 +282,49 @@ public class TagOperationsAuthorizationIT extends
BaseRestApiAuthorizationIT {
String[] tagsLoadByNormalUser = tableSupportTagByNormalUser.listTags();
Arrays.sort(tagsLoadByNormalUser);
assertArrayEquals(new String[] {"tag2", "tag3"}, tagsLoadByNormalUser);
+
+ TagList<String> nameResult =
tableSupportTagByNormalUser.listTagsWithVisibility();
+ Assertions.assertEquals(2, nameResult.tags().length);
+ Assertions.assertTrue(nameResult.hasInaccessibleTags());
+
+ var detailsResult =
tableSupportTagByNormalUser.listTagsInfoWithVisibility();
+ Assertions.assertEquals(2, detailsResult.tags().length);
+ Assertions.assertTrue(detailsResult.hasInaccessibleTags());
+
+ String untaggedCatalog = "untagged_catalog";
+ Map<String, String> properties = Maps.newHashMap();
+ properties.put("metastore.uris", hmsUri);
+ gravitinoMetalake.createCatalog(
+ untaggedCatalog, Catalog.Type.RELATIONAL, "hive", "untagged catalog",
properties);
+ gravitinoMetalake.grantPrivilegesToRole(
+ role,
+ MetadataObjects.of(ImmutableList.of(untaggedCatalog),
MetadataObject.Type.CATALOG),
+ ImmutableList.of(Privileges.UseCatalog.allow()));
+
+ String tableWithOnlyInheritedHiddenTag =
"table_with_only_inherited_hidden_tag";
+ TableCatalog tableCatalog =
gravitinoMetalake.loadCatalog(CATALOG).asTableCatalog();
+ tableCatalog.createTable(
+ NameIdentifier.of(SCHEMA, tableWithOnlyInheritedHiddenTag),
+ createColumns(),
+ "test visibility indicators",
+ new HashMap<>());
+ try {
+ SupportsTags untaggedCatalogTags =
+
normalUserClient.loadMetalake(METALAKE).loadCatalog(untaggedCatalog).supportsTags();
+ assertTagList(untaggedCatalogTags, new String[0], false);
+
+ SupportsTags inheritedHiddenTags =
+ normalUserClient
+ .loadMetalake(METALAKE)
+ .loadCatalog(CATALOG)
+ .asTableCatalog()
+ .loadTable(NameIdentifier.of(SCHEMA,
tableWithOnlyInheritedHiddenTag))
+ .supportsTags();
+ assertTagList(inheritedHiddenTags, new String[0], true);
+ } finally {
+ tableCatalog.dropTable(NameIdentifier.of(SCHEMA,
tableWithOnlyInheritedHiddenTag));
+ gravitinoMetalake.dropCatalog(untaggedCatalog, true);
+ }
}
@Test
@@ -467,4 +511,21 @@ public class TagOperationsAuthorizationIT extends
BaseRestApiAuthorizationIT {
private Column[] createColumns() {
return new Column[] {Column.of("col1", Types.StringType.get())};
}
+
+ private void assertTagList(
+ SupportsTags supportsTags, String[] expectedTagNames, boolean
hasInaccessibleTags) {
+ TagList<String> nameResult = supportsTags.listTagsWithVisibility();
+ String[] actualTagNames = nameResult.tags();
+ Arrays.sort(actualTagNames);
+ Arrays.sort(expectedTagNames);
+ Assertions.assertArrayEquals(expectedTagNames, actualTagNames);
+ Assertions.assertEquals(hasInaccessibleTags,
nameResult.hasInaccessibleTags());
+
+ var detailsResult = supportsTags.listTagsInfoWithVisibility();
+ String[] actualDetailNames =
+ Arrays.stream(detailsResult.tags()).map(tag ->
tag.name()).toArray(String[]::new);
+ Arrays.sort(actualDetailNames);
+ Assertions.assertArrayEquals(expectedTagNames, actualDetailNames);
+ Assertions.assertEquals(hasInaccessibleTags,
detailsResult.hasInaccessibleTags());
+ }
}
diff --git a/clients/client-python/gravitino/api/tag/__init__.py
b/clients/client-python/gravitino/api/tag/__init__.py
index 28b1469c2f..f464455d71 100644
--- a/clients/client-python/gravitino/api/tag/__init__.py
+++ b/clients/client-python/gravitino/api/tag/__init__.py
@@ -19,8 +19,10 @@ from __future__ import annotations
from gravitino.api.tag.tag import Tag
from gravitino.api.tag.tag_change import TagChange
+from gravitino.api.tag.tag_list import TagList
__all__ = [
"Tag",
"TagChange",
+ "TagList",
]
diff --git a/clients/client-python/gravitino/api/tag/supports_tags.py
b/clients/client-python/gravitino/api/tag/supports_tags.py
index 2e926fe1eb..e8d32474b3 100644
--- a/clients/client-python/gravitino/api/tag/supports_tags.py
+++ b/clients/client-python/gravitino/api/tag/supports_tags.py
@@ -20,6 +20,7 @@ from __future__ import annotations
from abc import ABC, abstractmethod
from gravitino.api.tag.tag import Tag
+from gravitino.api.tag.tag_list import TagList
from gravitino.exceptions.base import UnsupportedOperationException
@@ -38,6 +39,14 @@ class SupportsTags(ABC):
"""
pass
+ def list_tags_with_visibility(self) -> TagList[str]:
+ """List visible tag names and report whether inaccessible tags were
omitted.
+
+ The compatibility default cannot detect omitted tags. Implementations
backed by
+ authorization-aware APIs should override this method.
+ """
+ return TagList(self.list_tags(), False)
+
@abstractmethod
def list_tags_info(self) -> list[Tag]:
"""List all the tags with details for the specific object.
@@ -47,6 +56,14 @@ class SupportsTags(ABC):
"""
pass
+ def list_tags_info_with_visibility(self) -> TagList[Tag]:
+ """List visible tag details and report whether inaccessible tags were
omitted.
+
+ The compatibility default cannot detect omitted tags. Implementations
backed by
+ authorization-aware APIs should override this method.
+ """
+ return TagList(self.list_tags_info(), False)
+
@abstractmethod
def get_tag(self, name: str) -> Tag:
"""Get a tag by its name for the specific object.
diff --git a/clients/client-python/gravitino/api/tag/__init__.py
b/clients/client-python/gravitino/api/tag/tag_list.py
similarity index 56%
copy from clients/client-python/gravitino/api/tag/__init__.py
copy to clients/client-python/gravitino/api/tag/tag_list.py
index 28b1469c2f..e7ed58ac17 100644
--- a/clients/client-python/gravitino/api/tag/__init__.py
+++ b/clients/client-python/gravitino/api/tag/tag_list.py
@@ -17,10 +17,22 @@
from __future__ import annotations
-from gravitino.api.tag.tag import Tag
-from gravitino.api.tag.tag_change import TagChange
+from typing import Generic, TypeVar
-__all__ = [
- "Tag",
- "TagChange",
-]
+T = TypeVar("T")
+
+
+class TagList(Generic[T]):
+ """A list of visible tags and whether authorization filtering omitted
others."""
+
+ def __init__(self, tags: list[T], has_inaccessible_tags: bool):
+ self._tags = list(tags)
+ self._has_inaccessible_tags = has_inaccessible_tags
+
+ def tags(self) -> list[T]:
+ """Return a copy of the visible tag names or tag objects."""
+ return list(self._tags)
+
+ def has_inaccessible_tags(self) -> bool:
+ """Return whether one or more inaccessible tags were omitted."""
+ return self._has_inaccessible_tags
diff --git a/clients/client-python/gravitino/client/base_schema_catalog.py
b/clients/client-python/gravitino/client/base_schema_catalog.py
index 66483a3dac..39fe4fa1fe 100644
--- a/clients/client-python/gravitino/client/base_schema_catalog.py
+++ b/clients/client-python/gravitino/client/base_schema_catalog.py
@@ -34,6 +34,7 @@ from gravitino.api.secret import SecretBinding,
SecretReference
from gravitino.api.supports_schemas import SupportsSchemas
from gravitino.api.tag.supports_tags import SupportsTags
from gravitino.api.tag.tag import Tag
+from gravitino.api.tag.tag_list import TagList
from gravitino.client.function_catalog_operations import
FunctionCatalogOperations
from gravitino.client.generic_schema import GenericSchema
from gravitino.client.metadata_object_credential_operations import (
@@ -402,9 +403,15 @@ class BaseSchemaCatalog(
def list_tags(self) -> List[str]:
return self._object_tag_operations.list_tags()
+ def list_tags_with_visibility(self) -> TagList[str]:
+ return self._object_tag_operations.list_tags_with_visibility()
+
def list_tags_info(self) -> List[Tag]:
return self._object_tag_operations.list_tags_info()
+ def list_tags_info_with_visibility(self) -> TagList[Tag]:
+ return self._object_tag_operations.list_tags_info_with_visibility()
+
def get_tag(self, name: str) -> Tag:
return self._object_tag_operations.get_tag(name)
diff --git a/clients/client-python/gravitino/client/generic_column.py
b/clients/client-python/gravitino/client/generic_column.py
index 79ea04020f..96995238c2 100644
--- a/clients/client-python/gravitino/client/generic_column.py
+++ b/clients/client-python/gravitino/client/generic_column.py
@@ -24,6 +24,7 @@ from gravitino.api.rel.expressions.expression import
Expression
from gravitino.api.rel.types.type import Type
from gravitino.api.tag.supports_tags import SupportsTags
from gravitino.api.tag.tag import Tag
+from gravitino.api.tag.tag_list import TagList
from gravitino.client.metadata_object_tag_operations import
MetadataObjectTagOperations
from gravitino.utils import HTTPClient
@@ -84,9 +85,15 @@ class GenericColumn(Column, SupportsTags):
def list_tags(self) -> list[str]:
return self._object_tag_operations.list_tags()
+ def list_tags_with_visibility(self) -> TagList[str]:
+ return self._object_tag_operations.list_tags_with_visibility()
+
def list_tags_info(self) -> list[Tag]:
return self._object_tag_operations.list_tags_info()
+ def list_tags_info_with_visibility(self) -> TagList[Tag]:
+ return self._object_tag_operations.list_tags_info_with_visibility()
+
def get_tag(self, name: str) -> Tag:
return self._object_tag_operations.get_tag(name)
diff --git a/clients/client-python/gravitino/client/generic_fileset.py
b/clients/client-python/gravitino/client/generic_fileset.py
index 750627288e..c4ed5569b2 100644
--- a/clients/client-python/gravitino/client/generic_fileset.py
+++ b/clients/client-python/gravitino/client/generic_fileset.py
@@ -19,12 +19,13 @@ from typing import Dict, List, Optional
from gravitino.api.authorization.supports_roles import SupportsRoles
from gravitino.api.credential.credential import Credential
from gravitino.api.credential.supports_credentials import SupportsCredentials
-from gravitino.api.secret.supports_secrets import SupportsSecrets
from gravitino.api.file.fileset import Fileset
from gravitino.api.metadata_object import MetadataObject
from gravitino.api.metadata_objects import MetadataObjects
+from gravitino.api.secret.supports_secrets import SupportsSecrets
from gravitino.api.tag.supports_tags import SupportsTags
from gravitino.api.tag.tag import Tag
+from gravitino.api.tag.tag_list import TagList
from gravitino.client.metadata_object_credential_operations import (
MetadataObjectCredentialOperations,
)
@@ -120,9 +121,15 @@ class GenericFileset(
def list_tags(self) -> List[str]:
return self._object_tag_operations.list_tags()
+ def list_tags_with_visibility(self) -> TagList[str]:
+ return self._object_tag_operations.list_tags_with_visibility()
+
def list_tags_info(self) -> List[Tag]:
return self._object_tag_operations.list_tags_info()
+ def list_tags_info_with_visibility(self) -> TagList[Tag]:
+ return self._object_tag_operations.list_tags_info_with_visibility()
+
def get_tag(self, name: str) -> Tag:
return self._object_tag_operations.get_tag(name)
diff --git a/clients/client-python/gravitino/client/generic_function.py
b/clients/client-python/gravitino/client/generic_function.py
index 66faaa939f..5230640859 100644
--- a/clients/client-python/gravitino/client/generic_function.py
+++ b/clients/client-python/gravitino/client/generic_function.py
@@ -24,6 +24,7 @@ from gravitino.api.metadata_object import MetadataObject
from gravitino.api.metadata_objects import MetadataObjects
from gravitino.api.tag.supports_tags import SupportsTags
from gravitino.api.tag.tag import Tag
+from gravitino.api.tag.tag_list import TagList
from gravitino.client.metadata_object_tag_operations import
MetadataObjectTagOperations
from gravitino.dto.audit_dto import AuditDTO
from gravitino.dto.function.function_dto import FunctionDTO
@@ -90,10 +91,18 @@ class GenericFunction(Function, SupportsTags):
"""List the tag names associated with the function."""
return self._object_tag_operations.list_tags()
+ def list_tags_with_visibility(self) -> TagList[str]:
+ """List visible tag names and authorization-filtering status."""
+ return self._object_tag_operations.list_tags_with_visibility()
+
def list_tags_info(self) -> list[Tag]:
"""List the tags associated with the function."""
return self._object_tag_operations.list_tags_info()
+ def list_tags_info_with_visibility(self) -> TagList[Tag]:
+ """List visible tag details and authorization-filtering status."""
+ return self._object_tag_operations.list_tags_info_with_visibility()
+
def get_tag(self, name: str) -> Tag:
"""Get an associated tag by name."""
return self._object_tag_operations.get_tag(name)
diff --git a/clients/client-python/gravitino/client/generic_model.py
b/clients/client-python/gravitino/client/generic_model.py
index 9a99e21bc6..9ca708eb20 100644
--- a/clients/client-python/gravitino/client/generic_model.py
+++ b/clients/client-python/gravitino/client/generic_model.py
@@ -24,7 +24,7 @@ from gravitino.api.metadata_object import MetadataObject
from gravitino.api.metadata_objects import MetadataObjects
from gravitino.api.model.model import Model
from gravitino.api.secret.supports_secrets import SupportsSecrets
-from gravitino.api.tag import Tag
+from gravitino.api.tag import Tag, TagList
from gravitino.api.tag.supports_tags import SupportsTags
from gravitino.client.metadata_object_secret_operations import (
MetadataObjectSecretOperations,
@@ -83,9 +83,15 @@ class GenericModel(Model, SupportsTags, SupportsSecrets):
def list_tags(self) -> list[str]:
return self._model_tag_operations.list_tags()
+ def list_tags_with_visibility(self) -> TagList[str]:
+ return self._model_tag_operations.list_tags_with_visibility()
+
def list_tags_info(self) -> list[Tag]:
return self._model_tag_operations.list_tags_info()
+ def list_tags_info_with_visibility(self) -> TagList[Tag]:
+ return self._model_tag_operations.list_tags_info_with_visibility()
+
def get_tag(self, name: str) -> Tag:
return self._model_tag_operations.get_tag(name)
diff --git a/clients/client-python/gravitino/client/generic_schema.py
b/clients/client-python/gravitino/client/generic_schema.py
index a14944d29a..e3cd6b45bb 100644
--- a/clients/client-python/gravitino/client/generic_schema.py
+++ b/clients/client-python/gravitino/client/generic_schema.py
@@ -27,6 +27,7 @@ from gravitino.api.schema import Schema
from gravitino.api.secret.supports_secrets import SupportsSecrets
from gravitino.api.tag.supports_tags import SupportsTags
from gravitino.api.tag.tag import Tag
+from gravitino.api.tag.tag_list import TagList
from gravitino.client.metadata_object_role_operations import (
MetadataObjectRoleOperations,
)
@@ -99,9 +100,15 @@ class GenericSchema(
def list_tags(self) -> list[str]:
return self._metadata_object_tag_operations.list_tags()
+ def list_tags_with_visibility(self) -> TagList[str]:
+ return self._metadata_object_tag_operations.list_tags_with_visibility()
+
def list_tags_info(self) -> list[Tag]:
return self._metadata_object_tag_operations.list_tags_info()
+ def list_tags_info_with_visibility(self) -> TagList[Tag]:
+ return
self._metadata_object_tag_operations.list_tags_info_with_visibility()
+
def get_tag(self, name: str) -> Tag:
return self._metadata_object_tag_operations.get_tag(name)
diff --git a/clients/client-python/gravitino/client/generic_semantic_model.py
b/clients/client-python/gravitino/client/generic_semantic_model.py
index 950618d5c6..08251dacea 100644
--- a/clients/client-python/gravitino/client/generic_semantic_model.py
+++ b/clients/client-python/gravitino/client/generic_semantic_model.py
@@ -24,6 +24,7 @@ from gravitino.api.semantic.semantic_model import
SemanticModel
from gravitino.api.semantic.semantic_model_definition import
SemanticModelDefinition
from gravitino.api.tag.supports_tags import SupportsTags
from gravitino.api.tag.tag import Tag
+from gravitino.api.tag.tag_list import TagList
from gravitino.client.metadata_object_tag_operations import
MetadataObjectTagOperations
from gravitino.dto.semantic.semantic_model_dto import SemanticModelDTO
from gravitino.namespace import Namespace
@@ -101,9 +102,15 @@ class GenericSemanticModel(SemanticModel, SupportsTags):
def list_tags(self) -> list[str]:
return self._model_tag_operations.list_tags()
+ def list_tags_with_visibility(self) -> TagList[str]:
+ return self._model_tag_operations.list_tags_with_visibility()
+
def list_tags_info(self) -> list[Tag]:
return self._model_tag_operations.list_tags_info()
+ def list_tags_info_with_visibility(self) -> TagList[Tag]:
+ return self._model_tag_operations.list_tags_info_with_visibility()
+
def get_tag(self, name: str) -> Tag:
return self._model_tag_operations.get_tag(name)
diff --git a/clients/client-python/gravitino/client/generic_view.py
b/clients/client-python/gravitino/client/generic_view.py
index 88a25a671e..0802b6f041 100644
--- a/clients/client-python/gravitino/client/generic_view.py
+++ b/clients/client-python/gravitino/client/generic_view.py
@@ -26,6 +26,7 @@ from gravitino.api.rel.view import View
from gravitino.api.secret.supports_secrets import SupportsSecrets
from gravitino.api.tag.supports_tags import SupportsTags
from gravitino.api.tag.tag import Tag
+from gravitino.api.tag.tag_list import TagList
from gravitino.client.metadata_object_secret_operations import (
MetadataObjectSecretOperations,
)
@@ -98,9 +99,15 @@ class GenericView(View, SupportsTags, SupportsSecrets):
def list_tags(self) -> list[str]:
return self._object_tag_operations.list_tags()
+ def list_tags_with_visibility(self) -> TagList[str]:
+ return self._object_tag_operations.list_tags_with_visibility()
+
def list_tags_info(self) -> list[Tag]:
return self._object_tag_operations.list_tags_info()
+ def list_tags_info_with_visibility(self) -> TagList[Tag]:
+ return self._object_tag_operations.list_tags_info_with_visibility()
+
def get_tag(self, name: str) -> Tag:
return self._object_tag_operations.get_tag(name)
diff --git
a/clients/client-python/gravitino/client/metadata_object_tag_operations.py
b/clients/client-python/gravitino/client/metadata_object_tag_operations.py
index d0883bbc05..76a64bfc60 100644
--- a/clients/client-python/gravitino/client/metadata_object_tag_operations.py
+++ b/clients/client-python/gravitino/client/metadata_object_tag_operations.py
@@ -20,6 +20,7 @@ from __future__ import annotations
from gravitino.api.metadata_object import MetadataObject
from gravitino.api.tag.supports_tags import SupportsTags
from gravitino.api.tag.tag import Tag
+from gravitino.api.tag.tag_list import TagList
from gravitino.client.generic_tag import GenericTag
from gravitino.dto.requests.tag_associate_request import (
TagsAssociateRequest,
@@ -68,6 +69,9 @@ class MetadataObjectTagOperations(SupportsTags):
)
def list_tags(self) -> list[str]:
+ return self.list_tags_with_visibility().tags()
+
+ def list_tags_with_visibility(self) -> TagList[str]:
response = self.rest_client.get(
self.tag_request_path,
params={},
@@ -78,9 +82,14 @@ class MetadataObjectTagOperations(SupportsTags):
)
list_tags_resp.validate()
- return list_tags_resp.tag_names()
+ return TagList(
+ list_tags_resp.tag_names(), list_tags_resp.has_inaccessible_tags()
+ )
def list_tags_info(self) -> list[Tag]:
+ return self.list_tags_info_with_visibility().tags()
+
+ def list_tags_info_with_visibility(self) -> TagList[Tag]:
response = self.rest_client.get(
self.tag_request_path,
params={"details": "true"},
@@ -90,14 +99,17 @@ class MetadataObjectTagOperations(SupportsTags):
list_info_resp = TagListResponse.from_json(response.body,
infer_missing=True)
list_info_resp.validate()
- return [
- GenericTag(
- self.metalake_name,
- tag_dto,
- self.rest_client,
- )
- for tag_dto in list_info_resp.tags()
- ]
+ return TagList(
+ [
+ GenericTag(
+ self.metalake_name,
+ tag_dto,
+ self.rest_client,
+ )
+ for tag_dto in list_info_resp.tags()
+ ],
+ list_info_resp.has_inaccessible_tags(),
+ )
def get_tag(self, name: str) -> Tag:
Precondition.check_argument(
diff --git a/clients/client-python/gravitino/client/relational_table.py
b/clients/client-python/gravitino/client/relational_table.py
index 8b81413a51..0ba96431ef 100644
--- a/clients/client-python/gravitino/client/relational_table.py
+++ b/clients/client-python/gravitino/client/relational_table.py
@@ -34,6 +34,7 @@ from gravitino.api.stats.statistic_value import StatisticValue
from gravitino.api.stats.supports_statistics import SupportsStatistics
from gravitino.api.tag.supports_tags import SupportsTags
from gravitino.api.tag.tag import Tag
+from gravitino.api.tag.tag_list import TagList
from gravitino.client.generic_column import GenericColumn
from gravitino.client.metadata_object_role_operations import (
MetadataObjectRoleOperations,
@@ -262,9 +263,15 @@ class RelationalTable(
def list_tags(self) -> list[str]:
return self._object_tag_operations.list_tags()
+ def list_tags_with_visibility(self) -> TagList[str]:
+ return self._object_tag_operations.list_tags_with_visibility()
+
def list_tags_info(self) -> list[Tag]:
return self._object_tag_operations.list_tags_info()
+ def list_tags_info_with_visibility(self) -> TagList[Tag]:
+ return self._object_tag_operations.list_tags_info_with_visibility()
+
def get_tag(self, name: str) -> Tag:
return self._object_tag_operations.get_tag(name)
diff --git a/clients/client-python/gravitino/dto/responses/tag_response.py
b/clients/client-python/gravitino/dto/responses/tag_response.py
index e0dea09e71..d72e9c27e2 100644
--- a/clients/client-python/gravitino/dto/responses/tag_response.py
+++ b/clients/client-python/gravitino/dto/responses/tag_response.py
@@ -20,7 +20,6 @@ from __future__ import annotations
from dataclasses import dataclass, field
from dataclasses_json import config, dataclass_json
-
from gravitino.dto.responses.base_response import BaseResponse
from gravitino.dto.tag_dto import TagDTO
from gravitino.utils.precondition import Precondition
@@ -32,10 +31,16 @@ class TagNamesListResponse(BaseResponse):
"""Represents a response for a Tag Names List request."""
_tags: list[str] = field(default_factory=list,
metadata=config(field_name="names"))
+ _has_inaccessible_tags: bool = field(
+ default=False, metadata=config(field_name="hasInaccessibleTags")
+ )
def tag_names(self) -> list[str]:
return self._tags
+ def has_inaccessible_tags(self) -> bool:
+ return self._has_inaccessible_tags
+
def validate(self) -> None:
Precondition.check_argument(
self._tags is not None, "Tag Names List response should have tags"
@@ -55,10 +60,16 @@ class TagListResponse(BaseResponse):
_tags: list[TagDTO] = field(
default_factory=list, metadata=config(field_name="tags")
)
+ _has_inaccessible_tags: bool = field(
+ default=False, metadata=config(field_name="hasInaccessibleTags")
+ )
def tags(self) -> list[TagDTO]:
return self._tags
+ def has_inaccessible_tags(self) -> bool:
+ return self._has_inaccessible_tags
+
@dataclass_json
@dataclass
diff --git a/clients/client-python/tests/unittests/mock_base.py
b/clients/client-python/tests/unittests/mock_base.py
index ca247d3170..28648f04d6 100644
--- a/clients/client-python/tests/unittests/mock_base.py
+++ b/clients/client-python/tests/unittests/mock_base.py
@@ -213,7 +213,9 @@ def mock_load_fileset(name: str, location: str):
_audit=audit_dto,
)
return GenericFileset(
- fileset, None, Namespace.of("metalake_demo", "fileset_catalog", "tmp")
+ fileset,
+ HTTPClient("http://localhost:9090", is_debug=True),
+ Namespace.of("metalake_demo", "fileset_catalog", "tmp"),
)
diff --git a/clients/client-python/tests/unittests/test_tag_api.py
b/clients/client-python/tests/unittests/test_tag_api.py
index 5b24f3452b..889ad86f17 100644
--- a/clients/client-python/tests/unittests/test_tag_api.py
+++ b/clients/client-python/tests/unittests/test_tag_api.py
@@ -25,17 +25,17 @@ from gravitino.api.tag import Tag
from gravitino.api.tag.supports_tags import SupportsTags
from gravitino.api.tag.tag_change import TagChange
from gravitino.client.generic_tag import GenericTag
-from gravitino.exceptions.base import (
- IllegalArgumentException,
- UnsupportedOperationException,
-)
from gravitino.dto.responses.drop_response import DropResponse
-from gravitino.name_identifier import NameIdentifier
from gravitino.dto.responses.tag_response import (
TagListResponse,
TagNamesListResponse,
TagResponse,
)
+from gravitino.exceptions.base import (
+ IllegalArgumentException,
+ UnsupportedOperationException,
+)
+from gravitino.name_identifier import NameIdentifier
from tests.unittests import mock_base
@@ -80,6 +80,14 @@ class TestTagAPI(unittest.TestCase):
self.assertIsNone(tag.assignment_values())
supports_tags = LegacySupportsTags()
+ self.assertEqual([], supports_tags.list_tags_with_visibility().tags())
+ self.assertFalse(
+ supports_tags.list_tags_with_visibility().has_inaccessible_tags()
+ )
+ self.assertEqual([],
supports_tags.list_tags_info_with_visibility().tags())
+ self.assertFalse(
+
supports_tags.list_tags_info_with_visibility().has_inaccessible_tags()
+ )
with self.assertRaises(UnsupportedOperationException):
supports_tags.assign_tags([], [])
@@ -590,6 +598,24 @@ class TestObjectTagAPI(unittest.TestCase):
self.assertIn("tagA", tags)
self.assertIn("tagB", tags)
+ def test_fileset_list_tags_with_visibility(self, *mock_method) -> None:
+ """Test listing visible tag names and authorization-filtering
status."""
+ client = GravitinoClient(
+ uri="http://localhost:8090",
+ metalake_name=self._metalake_name,
+ check_version=False,
+ )
+ fileset = self._load_fileset(client)
+ response = TagNamesListResponse(0, ["tagA"], True)
+
+ with patch(
+ "gravitino.utils.http_client.HTTPClient.get",
+ return_value=mock_base.mock_http_response(response.to_json()),
+ ):
+ tag_list = fileset.list_tags_with_visibility()
+ self.assertEqual(["tagA"], tag_list.tags())
+ self.assertTrue(tag_list.has_inaccessible_tags())
+
def test_fileset_list_tags_info(self, *mock_method) -> None:
"""Test listing tags with details on a fileset via REST API."""
tag_dto = mock_base.build_tag_dto("tagA", "comment A")
@@ -612,6 +638,24 @@ class TestObjectTagAPI(unittest.TestCase):
self.assertEqual("tagA", tags[0].name())
self.assertEqual("comment A", tags[0].comment())
+ def test_fileset_list_tags_info_with_visibility(self, *mock_method) ->
None:
+ """Test listing visible tag details and authorization-filtering
status."""
+ client = GravitinoClient(
+ uri="http://localhost:8090",
+ metalake_name=self._metalake_name,
+ check_version=False,
+ )
+ fileset = self._load_fileset(client)
+ response = TagListResponse(0, [mock_base.build_tag_dto("tagA")], True)
+
+ with patch(
+ "gravitino.utils.http_client.HTTPClient.get",
+ return_value=mock_base.mock_http_response(response.to_json()),
+ ):
+ tag_list = fileset.list_tags_info_with_visibility()
+ self.assertEqual(["tagA"], [tag.name() for tag in tag_list.tags()])
+ self.assertTrue(tag_list.has_inaccessible_tags())
+
def test_fileset_get_tag(self, *mock_method) -> None:
"""Test getting a specific tag on a fileset via REST API."""
tag_dto = mock_base.build_tag_dto("tagA", "comment A")
diff --git
a/common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
b/common/src/main/java/org/apache/gravitino/dto/responses/MetadataObjectPolicyListResponse.java
similarity index 50%
copy from
common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
copy to
common/src/main/java/org/apache/gravitino/dto/responses/MetadataObjectPolicyListResponse.java
index a260171c79..c4e402bd9d 100644
---
a/common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
+++
b/common/src/main/java/org/apache/gravitino/dto/responses/MetadataObjectPolicyListResponse.java
@@ -19,52 +19,41 @@
package org.apache.gravitino.dto.responses;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Preconditions;
-import java.util.Arrays;
import lombok.EqualsAndHashCode;
-import lombok.Getter;
import lombok.ToString;
import org.apache.gravitino.dto.policy.PolicyDTO;
-/** Represents a response for a list of policies. */
-@Getter
+/** Represents a response for policies associated with a metadata object. */
@ToString
@EqualsAndHashCode(callSuper = true)
-public class PolicyListResponse extends BaseResponse {
+public class MetadataObjectPolicyListResponse extends PolicyListResponse {
- @JsonProperty("policies")
- private final PolicyDTO[] policies;
+ @JsonProperty("hasInaccessiblePolicies")
+ private final boolean hasInaccessiblePolicies;
/**
- * Creates a new PolicyListResponse.
+ * Creates a new MetadataObjectPolicyListResponse.
*
- * @param policies The list of policies.
+ * @param policies The list of accessible policies.
+ * @param hasInaccessiblePolicies Whether inaccessible policies were omitted
from the response.
*/
- public PolicyListResponse(PolicyDTO[] policies) {
- super(0);
- this.policies = policies;
+ public MetadataObjectPolicyListResponse(PolicyDTO[] policies, boolean
hasInaccessiblePolicies) {
+ super(policies);
+ this.hasInaccessiblePolicies = hasInaccessiblePolicies;
}
- /**
- * This is the constructor that is used by Jackson deserializer to create an
instance of
- * PolicyListResponse.
- */
- public PolicyListResponse() {
+ /** Constructor used by Jackson deserializer. */
+ public MetadataObjectPolicyListResponse() {
super();
- this.policies = null;
+ this.hasInaccessiblePolicies = false;
}
- @Override
- public void validate() throws IllegalArgumentException {
- super.validate();
-
- Preconditions.checkArgument(policies != null, "\"policies\" must not be
null");
- Arrays.stream(policies)
- .forEach(
- t -> {
- Preconditions.checkArgument(t != null, "policy must not be
null");
- Preconditions.checkArgument(t.content() != null, "policy content
must not be null");
- t.content().validate();
- });
+ /**
+ * Returns whether inaccessible policies were omitted from the response.
+ *
+ * @return true if at least one inaccessible policy was omitted, false
otherwise
+ */
+ public boolean hasInaccessiblePolicies() {
+ return hasInaccessiblePolicies;
}
}
diff --git
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
b/common/src/main/java/org/apache/gravitino/dto/responses/MetadataObjectTagListResponse.java
similarity index 54%
copy from
common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
copy to
common/src/main/java/org/apache/gravitino/dto/responses/MetadataObjectTagListResponse.java
index 93c324dfe4..f8dce56b20 100644
---
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
+++
b/common/src/main/java/org/apache/gravitino/dto/responses/MetadataObjectTagListResponse.java
@@ -19,47 +19,41 @@
package org.apache.gravitino.dto.responses;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Preconditions;
-import java.util.Arrays;
import lombok.EqualsAndHashCode;
-import lombok.Getter;
import lombok.ToString;
import org.apache.gravitino.dto.tag.TagDTO;
-/** Represents a response for a list of tags. */
-@Getter
+/** Represents a response for tags associated with a metadata object. */
@ToString
@EqualsAndHashCode(callSuper = true)
-public class TagListResponse extends BaseResponse {
+public class MetadataObjectTagListResponse extends TagListResponse {
- @JsonProperty("tags")
- private final TagDTO[] tags;
+ @JsonProperty("hasInaccessibleTags")
+ private final boolean hasInaccessibleTags;
/**
- * Creates a new TagListResponse.
+ * Creates a new MetadataObjectTagListResponse.
*
- * @param tags The list of tags.
+ * @param tags The list of accessible tags.
+ * @param hasInaccessibleTags Whether inaccessible tags were omitted from
the response.
*/
- public TagListResponse(TagDTO[] tags) {
- super(0);
- this.tags = tags;
+ public MetadataObjectTagListResponse(TagDTO[] tags, boolean
hasInaccessibleTags) {
+ super(tags);
+ this.hasInaccessibleTags = hasInaccessibleTags;
}
- /**
- * This is the constructor that is used by Jackson deserializer to create an
instance of
- * TagListResponse.
- */
- public TagListResponse() {
+ /** Constructor used by Jackson deserializer. */
+ public MetadataObjectTagListResponse() {
super();
- this.tags = null;
+ this.hasInaccessibleTags = false;
}
- @Override
- public void validate() throws IllegalArgumentException {
- super.validate();
-
- Preconditions.checkArgument(tags != null, "\"tags\" must not be null");
- Arrays.stream(tags)
- .forEach(t -> Preconditions.checkArgument(t != null, "tag must not be
null"));
+ /**
+ * Returns whether inaccessible tags were omitted from the response.
+ *
+ * @return true if at least one inaccessible tag was omitted, false otherwise
+ */
+ public boolean hasInaccessibleTags() {
+ return hasInaccessibleTags;
}
}
diff --git
a/common/src/main/java/org/apache/gravitino/dto/responses/NameListResponse.java
b/common/src/main/java/org/apache/gravitino/dto/responses/NameListResponse.java
index 0728165c5e..f6128b6b28 100644
---
a/common/src/main/java/org/apache/gravitino/dto/responses/NameListResponse.java
+++
b/common/src/main/java/org/apache/gravitino/dto/responses/NameListResponse.java
@@ -18,6 +18,7 @@
*/
package org.apache.gravitino.dto.responses;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
import java.util.Arrays;
@@ -27,6 +28,7 @@ import lombok.ToString;
import org.apache.commons.lang3.StringUtils;
/** Represents a response for a list of entity names. */
+@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
@ToString
@EqualsAndHashCode(callSuper = true)
diff --git
a/common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
b/common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
index a260171c79..6d754e8216 100644
---
a/common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
+++
b/common/src/main/java/org/apache/gravitino/dto/responses/PolicyListResponse.java
@@ -18,6 +18,7 @@
*/
package org.apache.gravitino.dto.responses;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
import java.util.Arrays;
@@ -27,6 +28,7 @@ import lombok.ToString;
import org.apache.gravitino.dto.policy.PolicyDTO;
/** Represents a response for a list of policies. */
+@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
@ToString
@EqualsAndHashCode(callSuper = true)
diff --git
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
b/common/src/main/java/org/apache/gravitino/dto/responses/PolicyNameListResponse.java
similarity index 53%
copy from
common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
copy to
common/src/main/java/org/apache/gravitino/dto/responses/PolicyNameListResponse.java
index 93c324dfe4..351c9bb99a 100644
---
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
+++
b/common/src/main/java/org/apache/gravitino/dto/responses/PolicyNameListResponse.java
@@ -19,47 +19,40 @@
package org.apache.gravitino.dto.responses;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Preconditions;
-import java.util.Arrays;
import lombok.EqualsAndHashCode;
-import lombok.Getter;
import lombok.ToString;
-import org.apache.gravitino.dto.tag.TagDTO;
-/** Represents a response for a list of tags. */
-@Getter
+/** Represents a response for a list of policy names. */
@ToString
@EqualsAndHashCode(callSuper = true)
-public class TagListResponse extends BaseResponse {
+public class PolicyNameListResponse extends NameListResponse {
- @JsonProperty("tags")
- private final TagDTO[] tags;
+ @JsonProperty("hasInaccessiblePolicies")
+ private final boolean hasInaccessiblePolicies;
/**
- * Creates a new TagListResponse.
+ * Creates a new PolicyNameListResponse.
*
- * @param tags The list of tags.
+ * @param names The list of accessible policy names.
+ * @param hasInaccessiblePolicies Whether inaccessible policies were omitted
from the response.
*/
- public TagListResponse(TagDTO[] tags) {
- super(0);
- this.tags = tags;
+ public PolicyNameListResponse(String[] names, boolean
hasInaccessiblePolicies) {
+ super(names);
+ this.hasInaccessiblePolicies = hasInaccessiblePolicies;
}
- /**
- * This is the constructor that is used by Jackson deserializer to create an
instance of
- * TagListResponse.
- */
- public TagListResponse() {
+ /** Constructor used by Jackson deserializer. */
+ public PolicyNameListResponse() {
super();
- this.tags = null;
+ this.hasInaccessiblePolicies = false;
}
- @Override
- public void validate() throws IllegalArgumentException {
- super.validate();
-
- Preconditions.checkArgument(tags != null, "\"tags\" must not be null");
- Arrays.stream(tags)
- .forEach(t -> Preconditions.checkArgument(t != null, "tag must not be
null"));
+ /**
+ * Returns whether inaccessible policies were omitted from the response.
+ *
+ * @return true if at least one inaccessible policy was omitted, false
otherwise
+ */
+ public boolean hasInaccessiblePolicies() {
+ return hasInaccessiblePolicies;
}
}
diff --git
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
b/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
index 93c324dfe4..1546cef918 100644
---
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
+++
b/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
@@ -18,6 +18,7 @@
*/
package org.apache.gravitino.dto.responses;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
import java.util.Arrays;
@@ -27,6 +28,7 @@ import lombok.ToString;
import org.apache.gravitino.dto.tag.TagDTO;
/** Represents a response for a list of tags. */
+@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
@ToString
@EqualsAndHashCode(callSuper = true)
diff --git
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
b/common/src/main/java/org/apache/gravitino/dto/responses/TagNameListResponse.java
similarity index 54%
copy from
common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
copy to
common/src/main/java/org/apache/gravitino/dto/responses/TagNameListResponse.java
index 93c324dfe4..20c01b8955 100644
---
a/common/src/main/java/org/apache/gravitino/dto/responses/TagListResponse.java
+++
b/common/src/main/java/org/apache/gravitino/dto/responses/TagNameListResponse.java
@@ -19,47 +19,40 @@
package org.apache.gravitino.dto.responses;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Preconditions;
-import java.util.Arrays;
import lombok.EqualsAndHashCode;
-import lombok.Getter;
import lombok.ToString;
-import org.apache.gravitino.dto.tag.TagDTO;
-/** Represents a response for a list of tags. */
-@Getter
+/** Represents a response for a list of tag names. */
@ToString
@EqualsAndHashCode(callSuper = true)
-public class TagListResponse extends BaseResponse {
+public class TagNameListResponse extends NameListResponse {
- @JsonProperty("tags")
- private final TagDTO[] tags;
+ @JsonProperty("hasInaccessibleTags")
+ private final boolean hasInaccessibleTags;
/**
- * Creates a new TagListResponse.
+ * Creates a new TagNameListResponse.
*
- * @param tags The list of tags.
+ * @param names The list of accessible tag names.
+ * @param hasInaccessibleTags Whether inaccessible tags were omitted from
the response.
*/
- public TagListResponse(TagDTO[] tags) {
- super(0);
- this.tags = tags;
+ public TagNameListResponse(String[] names, boolean hasInaccessibleTags) {
+ super(names);
+ this.hasInaccessibleTags = hasInaccessibleTags;
}
- /**
- * This is the constructor that is used by Jackson deserializer to create an
instance of
- * TagListResponse.
- */
- public TagListResponse() {
+ /** Constructor used by Jackson deserializer. */
+ public TagNameListResponse() {
super();
- this.tags = null;
+ this.hasInaccessibleTags = false;
}
- @Override
- public void validate() throws IllegalArgumentException {
- super.validate();
-
- Preconditions.checkArgument(tags != null, "\"tags\" must not be null");
- Arrays.stream(tags)
- .forEach(t -> Preconditions.checkArgument(t != null, "tag must not be
null"));
+ /**
+ * Returns whether inaccessible tags were omitted from the response.
+ *
+ * @return true if at least one inaccessible tag was omitted, false otherwise
+ */
+ public boolean hasInaccessibleTags() {
+ return hasInaccessibleTags;
}
}
diff --git
a/common/src/test/java/org/apache/gravitino/dto/responses/TestResponses.java
b/common/src/test/java/org/apache/gravitino/dto/responses/TestResponses.java
index 2c5ab6bcb0..ec58f95593 100644
--- a/common/src/test/java/org/apache/gravitino/dto/responses/TestResponses.java
+++ b/common/src/test/java/org/apache/gravitino/dto/responses/TestResponses.java
@@ -48,6 +48,7 @@ import
org.apache.gravitino.dto.authorization.SecurableObjectDTO;
import org.apache.gravitino.dto.authorization.UserDTO;
import org.apache.gravitino.dto.model.ModelDTO;
import org.apache.gravitino.dto.model.ModelVersionDTO;
+import org.apache.gravitino.dto.policy.PolicyDTO;
import org.apache.gravitino.dto.rel.ColumnDTO;
import org.apache.gravitino.dto.rel.TableDTO;
import org.apache.gravitino.dto.rel.partitioning.Partitioning;
@@ -390,6 +391,46 @@ public class TestResponses {
assertEquals("\"names\" must not be null", e.getMessage());
}
+ @Test
+ void testTagNameListResponse() throws JsonProcessingException {
+ String[] names = new String[] {"tag1", "tag2"};
+ TagNameListResponse response = new TagNameListResponse(names, true);
+ assertDoesNotThrow(response::validate);
+
+ String serJson = JsonUtils.objectMapper().writeValueAsString(response);
+ TagNameListResponse deserResponse =
+ JsonUtils.objectMapper().readValue(serJson, TagNameListResponse.class);
+ assertEquals(response, deserResponse);
+ assertArrayEquals(names, deserResponse.getNames());
+ assertTrue(deserResponse.hasInaccessibleTags());
+
+ NameListResponse backwardCompatibleResponse =
+ JsonUtils.objectMapper().readValue(serJson, NameListResponse.class);
+ assertArrayEquals(names, backwardCompatibleResponse.getNames());
+
+ assertFalse(new TagNameListResponse(new String[0],
false).hasInaccessibleTags());
+ }
+
+ @Test
+ void testPolicyNameListResponse() throws JsonProcessingException {
+ String[] names = new String[] {"policy1", "policy2"};
+ PolicyNameListResponse response = new PolicyNameListResponse(names, true);
+ assertDoesNotThrow(response::validate);
+
+ String serJson = JsonUtils.objectMapper().writeValueAsString(response);
+ PolicyNameListResponse deserResponse =
+ JsonUtils.objectMapper().readValue(serJson,
PolicyNameListResponse.class);
+ assertEquals(response, deserResponse);
+ assertArrayEquals(names, deserResponse.getNames());
+ assertTrue(deserResponse.hasInaccessiblePolicies());
+
+ NameListResponse backwardCompatibleResponse =
+ JsonUtils.objectMapper().readValue(serJson, NameListResponse.class);
+ assertArrayEquals(names, backwardCompatibleResponse.getNames());
+
+ assertFalse(new PolicyNameListResponse(new String[0],
false).hasInaccessiblePolicies());
+ }
+
@Test
void testTagListResponse() throws JsonProcessingException {
TagDTO tag1 =
TagDTO.builder().withName("tag1").withComment("comment1").build();
@@ -409,6 +450,43 @@ public class TestResponses {
assertEquals("\"tags\" must not be null", e.getMessage());
}
+ @Test
+ void testMetadataObjectTagListResponse() throws JsonProcessingException {
+ TagDTO tag = TagDTO.builder().withName("tag1").build();
+ MetadataObjectTagListResponse response =
+ new MetadataObjectTagListResponse(new TagDTO[] {tag}, true);
+ assertDoesNotThrow(response::validate);
+
+ String serJson = JsonUtils.objectMapper().writeValueAsString(response);
+ MetadataObjectTagListResponse deserResponse =
+ JsonUtils.objectMapper().readValue(serJson,
MetadataObjectTagListResponse.class);
+ assertEquals(response, deserResponse);
+ assertArrayEquals(new TagDTO[] {tag}, deserResponse.getTags());
+ assertTrue(deserResponse.hasInaccessibleTags());
+
+ TagListResponse backwardCompatibleResponse =
+ JsonUtils.objectMapper().readValue(serJson, TagListResponse.class);
+ assertArrayEquals(new TagDTO[] {tag},
backwardCompatibleResponse.getTags());
+ }
+
+ @Test
+ void testMetadataObjectPolicyListResponse() throws JsonProcessingException {
+ MetadataObjectPolicyListResponse response =
+ new MetadataObjectPolicyListResponse(new PolicyDTO[0], true);
+ assertDoesNotThrow(response::validate);
+
+ String serJson = JsonUtils.objectMapper().writeValueAsString(response);
+ MetadataObjectPolicyListResponse deserResponse =
+ JsonUtils.objectMapper().readValue(serJson,
MetadataObjectPolicyListResponse.class);
+ assertEquals(response, deserResponse);
+ assertArrayEquals(new PolicyDTO[0], deserResponse.getPolicies());
+ assertTrue(deserResponse.hasInaccessiblePolicies());
+
+ PolicyListResponse backwardCompatibleResponse =
+ JsonUtils.objectMapper().readValue(serJson, PolicyListResponse.class);
+ assertArrayEquals(new PolicyDTO[0],
backwardCompatibleResponse.getPolicies());
+ }
+
@Test
void testTagResponse() throws JsonProcessingException {
TagDTO tag =
TagDTO.builder().withName("tag1").withComment("comment1").build();
diff --git a/docs/manage-policies-in-gravitino.md
b/docs/manage-policies-in-gravitino.md
index 110f9498db..9b1becb4ff 100644
--- a/docs/manage-policies-in-gravitino.md
+++ b/docs/manage-policies-in-gravitino.md
@@ -343,6 +343,10 @@ The response includes policies derived from effective tags
assigned to the objec
With `details=true`, the response returns full policy objects instead of
policy names.
Each policy includes an `inherited` field, which is `true` when it matches
only through a tag
assigned to an ancestor of the object. Disabled policies do not appear in this
result.
+Both response modes include `hasInaccessiblePolicies`. Gravitino resolves
policies from direct and
+inherited tag assignments before authorization filtering, so the flag also
covers policies omitted
+from inherited associations. The flag reveals only that at least one policy
was omitted; it does not
+reveal the policy's name, count, details, or inheritance source.
<Tabs groupId='language' queryString>
<TabItem value="shell" label="REST">
@@ -352,6 +356,16 @@ curl -X GET -H "Accept: application/vnd.gravitino.v1+json"
\
"http://localhost:8090/api/metalakes/test/objects/table/catalog1.schema1.customers/policies?details=true"
```
+If every applicable policy is inaccessible, the response contains an empty
list and sets the flag:
+
+```json
+{
+ "code": 0,
+ "policies": [],
+ "hasInaccessiblePolicies": true
+}
+```
+
</TabItem>
<TabItem value="java" label="Java">
@@ -360,9 +374,26 @@ Table customers =
client.loadCatalog("catalog1")
.asTableCatalog()
.loadTable(NameIdentifier.of("schema1", "customers"));
-String[] policyNames = customers.supportsPolicies().listPolicies();
-Policy[] policies = customers.supportsPolicies().listPolicyInfos();
+PolicyList<String> nameList =
customers.supportsPolicies().listPoliciesWithVisibility();
+String[] policyNames = nameList.policies();
+boolean omittedPolicies = nameList.hasInaccessiblePolicies();
+
+PolicyList<Policy> detailList =
customers.supportsPolicies().listPolicyInfosWithVisibility();
+Policy[] policies = detailList.policies();
+boolean omittedPolicyDetails = detailList.hasInaccessiblePolicies();
```
+The existing `listPolicies()` and `listPolicyInfos()` methods continue to
return only the visible
+arrays.
+
</TabItem>
</Tabs>
+
+Interpret the visible list and `hasInaccessiblePolicies` together:
+
+| Visible list | `hasInaccessiblePolicies` | Meaning |
+|---|---:|---|
+| Empty | `false` | No enabled policy applies to the object. |
+| Empty | `true` | All applicable policies are inaccessible. |
+| Non-empty | `true` | The response includes visible policies and omits at
least one inaccessible policy. |
+| Non-empty | `false` | All applicable policies are visible. |
diff --git a/docs/manage-tags-in-gravitino.md b/docs/manage-tags-in-gravitino.md
index 5254582a1e..528c9dd18c 100644
--- a/docs/manage-tags-in-gravitino.md
+++ b/docs/manage-tags-in-gravitino.md
@@ -357,6 +357,10 @@ The response includes tags inherited from ancestors. With
`details=true` each ta
`inherited` field and its `assignmentValues`, which a plain name listing does
not. An empty
`assignmentValues` array means the tag is assigned without a value.
`allowedValues` is null for an
unrestricted tag, empty for a valueless-only tag, and otherwise contains the
tag's allowed values.
+Both response modes include `hasInaccessibleTags`. Gravitino resolves direct
and inherited tag
+assignments before authorization filtering, so the flag also covers
inaccessible inherited tags.
+The flag reveals only that at least one tag was omitted; it does not reveal
the tag's name, count,
+details, or inheritance source.
<Tabs groupId='language' queryString>
<TabItem value="shell" label="REST">
@@ -380,7 +384,18 @@ The response includes each tag's definition and assignment
details:
"assignmentValues": ["finance", "risk"],
"inherited": false
}
- ]
+ ],
+ "hasInaccessibleTags": false
+}
+```
+
+If every effective tag is inaccessible, the response contains an empty list
and sets the flag:
+
+```json
+{
+ "code": 0,
+ "tags": [],
+ "hasInaccessibleTags": true
}
```
@@ -389,25 +404,48 @@ The response includes each tag's definition and
assignment details:
```java
Table customers = ...
-String[] tagNames = customers.supportsTags().listTags();
-Tag[] tags = customers.supportsTags().listTagsInfo();
+TagList<String> nameList = customers.supportsTags().listTagsWithVisibility();
+String[] tagNames = nameList.tags();
+boolean omittedTags = nameList.hasInaccessibleTags();
+
+TagList<Tag> detailList =
customers.supportsTags().listTagsInfoWithVisibility();
+Tag[] tags = detailList.tags();
+boolean omittedTagDetails = detailList.hasInaccessibleTags();
String[] values =
tags[0].assignment().map(assignment -> assignment.values()).orElse(new
String[0]);
```
+The existing `listTags()` and `listTagsInfo()` methods continue to return only
the visible arrays.
+
</TabItem>
<TabItem value="python" label="Python">
```python
customers = ...
-tag_names = customers.supports_tags().list_tags()
-tags = customers.supports_tags().list_tags_info()
+name_list = customers.supports_tags().list_tags_with_visibility()
+tag_names = name_list.tags()
+omitted_tags = name_list.has_inaccessible_tags()
+
+detail_list = customers.supports_tags().list_tags_info_with_visibility()
+tags = detail_list.tags()
+omitted_tag_details = detail_list.has_inaccessible_tags()
values = tags[0].assignment_values()
```
+The existing `list_tags()` and `list_tags_info()` methods continue to return
only the visible lists.
+
</TabItem>
</Tabs>
+Interpret the visible list and `hasInaccessibleTags` together:
+
+| Visible list | `hasInaccessibleTags` | Meaning |
+|---|---:|---|
+| Empty | `false` | The object has no effective tag assignments. |
+| Empty | `true` | All effective tag assignments are inaccessible. |
+| Non-empty | `true` | The response includes visible tags and omits at least
one inaccessible tag. |
+| Non-empty | `false` | All effective tag assignments are visible. |
+
### Get One Tag on an Object
<Tabs groupId='language' queryString>
diff --git a/docs/open-api/policies.yaml b/docs/open-api/policies.yaml
index e2310534b0..659a3313d2 100644
--- a/docs/open-api/policies.yaml
+++ b/docs/open-api/policies.yaml
@@ -224,13 +224,13 @@ paths:
application/vnd.gravitino.v1+json:
schema:
oneOf:
- - $ref: "./openapi.yaml#/components/schemas/NameListResponse"
- - $ref: "#/components/schemas/PolicyListResponse"
+ - $ref: "#/components/schemas/PolicyNameListResponse"
+ - $ref:
"#/components/schemas/MetadataObjectPolicyListResponse"
examples:
- NameListResponse:
- $ref: "#/components/examples/NameListResponse"
- PolicyListResponse:
- $ref: "#/components/examples/PolicyListResponse"
+ PolicyNameListResponse:
+ $ref: "#/components/examples/PolicyNameListResponse"
+ MetadataObjectPolicyListResponse:
+ $ref:
"#/components/examples/MetadataObjectPolicyListResponse"
"400":
$ref: "./openapi.yaml#/components/responses/BadRequestErrorResponse"
"404":
@@ -711,6 +711,30 @@ components:
items:
$ref: "#/components/schemas/Policy"
+ PolicyNameListResponse:
+ allOf:
+ - $ref: "./openapi.yaml#/components/schemas/NameListResponse"
+ - type: object
+ required:
+ - names
+ - hasInaccessiblePolicies
+ properties:
+ hasInaccessiblePolicies:
+ type: boolean
+ description: Whether one or more inaccessible policies were
omitted from the response
+
+ MetadataObjectPolicyListResponse:
+ allOf:
+ - $ref: "#/components/schemas/PolicyListResponse"
+ - type: object
+ required:
+ - policies
+ - hasInaccessiblePolicies
+ properties:
+ hasInaccessiblePolicies:
+ type: boolean
+ description: Whether one or more inaccessible policies were
omitted from the response
+
MetadataObject:
type: object
description: A metadata object
@@ -1006,6 +1030,13 @@ components:
$ref: "#/components/schemas/Policy"
examples:
+ PolicyNameListResponse:
+ value: {
+ "code": 0,
+ "names": ["my_policy1"],
+ "hasInaccessiblePolicies": true
+ }
+
NameListResponse:
value: {
"code": 0,
@@ -1046,6 +1077,13 @@ components:
]
}
+ MetadataObjectPolicyListResponse:
+ value: {
+ "code": 0,
+ "policies": [],
+ "hasInaccessiblePolicies": true
+ }
+
PolicyCreate:
value: {
"name": "my_policy1",
diff --git a/docs/open-api/tags.yaml b/docs/open-api/tags.yaml
index 33fa7dd56a..0d66d12ec5 100644
--- a/docs/open-api/tags.yaml
+++ b/docs/open-api/tags.yaml
@@ -197,13 +197,13 @@ paths:
application/vnd.gravitino.v1+json:
schema:
oneOf:
- - $ref: "./openapi.yaml#/components/schemas/NameListResponse"
- - $ref: "#/components/responses/TagListResponse"
+ - $ref: "#/components/responses/TagNameListResponse"
+ - $ref:
"#/components/responses/MetadataObjectTagListResponse"
examples:
- NameListResponse:
- $ref: "#/components/examples/NameListResponse"
- TagListResponse:
- $ref: "#/components/examples/TagListResponse"
+ TagNameListResponse:
+ $ref: "#/components/examples/TagNameListResponse"
+ MetadataObjectTagListResponse:
+ $ref: "#/components/examples/MetadataObjectTagListResponse"
"400":
$ref: "./openapi.yaml#/components/responses/BadRequestErrorResponse"
"404":
@@ -781,6 +781,18 @@ components:
selector:
$ref: "./policies.yaml#/components/schemas/PolicyAssociationSelector"
+ TagNameListResponse:
+ allOf:
+ - $ref: "./openapi.yaml#/components/schemas/NameListResponse"
+ - type: object
+ required:
+ - names
+ - hasInaccessibleTags
+ properties:
+ hasInaccessibleTags:
+ type: boolean
+ description: Whether one or more inaccessible tags were omitted
from the response
+
TagListResponse:
type: object
properties:
@@ -796,6 +808,18 @@ components:
items:
$ref: "#/components/schemas/Tag"
+ MetadataObjectTagListResponse:
+ allOf:
+ - $ref: "#/components/responses/TagListResponse"
+ - type: object
+ required:
+ - tags
+ - hasInaccessibleTags
+ properties:
+ hasInaccessibleTags:
+ type: boolean
+ description: Whether one or more inaccessible tags were omitted
from the response
+
TagResponse:
type: object
properties:
@@ -824,6 +848,13 @@ components:
$ref: "#/components/schemas/MetadataObject"
examples:
+ TagNameListResponse:
+ value: {
+ "code": 0,
+ "names": ["my_tag1"],
+ "hasInaccessibleTags": true
+ }
+
NameListResponse:
value: {
"code": 0,
@@ -862,6 +893,13 @@ components:
]
}
+ MetadataObjectTagListResponse:
+ value: {
+ "code": 0,
+ "tags": [],
+ "hasInaccessibleTags": true
+ }
+
TagCreate:
value: {
"name": "my_tag1",
diff --git
a/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectPolicyOperations.java
b/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectPolicyOperations.java
index 0788720b4d..9b533071aa 100644
---
a/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectPolicyOperations.java
+++
b/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectPolicyOperations.java
@@ -39,8 +39,8 @@ import org.apache.gravitino.Entity;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.MetadataObjects;
import org.apache.gravitino.dto.policy.PolicyDTO;
-import org.apache.gravitino.dto.responses.NameListResponse;
-import org.apache.gravitino.dto.responses.PolicyListResponse;
+import org.apache.gravitino.dto.responses.MetadataObjectPolicyListResponse;
+import org.apache.gravitino.dto.responses.PolicyNameListResponse;
import org.apache.gravitino.meta.PolicyEntity;
import org.apache.gravitino.metrics.MetricNames;
import org.apache.gravitino.policy.PolicyDispatcher;
@@ -96,6 +96,7 @@ public class MetadataObjectPolicyOperations {
PolicyEntity[] policies =
policyDispatcher.listPolicyInfosForMetadataObject(metalake,
object);
+ int policyCount = policies.length;
policies =
MetadataAuthzHelper.filterByExpression(
metalake,
@@ -103,6 +104,7 @@ public class MetadataObjectPolicyOperations {
Entity.EntityType.POLICY,
policies,
policy -> NameIdentifierUtil.ofPolicy(metalake,
policy.name()));
+ boolean hasInaccessiblePolicies = policies.length < policyCount;
PolicyDTO[] policyDTOs =
Arrays.stream(policies)
@@ -119,7 +121,8 @@ public class MetadataObjectPolicyOperations {
type,
fullName,
metalake);
- return Utils.ok(new PolicyListResponse(policyDTOs));
+ return Utils.ok(
+ new MetadataObjectPolicyListResponse(policyDTOs,
hasInaccessiblePolicies));
} else {
String[] policyNames =
@@ -131,7 +134,7 @@ public class MetadataObjectPolicyOperations {
type,
fullName,
metalake);
- return Utils.ok(new NameListResponse(policyNames));
+ return Utils.ok(new PolicyNameListResponse(policyNames,
hasInaccessiblePolicies));
}
});
diff --git
a/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectTagOperations.java
b/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectTagOperations.java
index 66ac0fc8ab..c550b0c5b7 100644
---
a/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectTagOperations.java
+++
b/server/src/main/java/org/apache/gravitino/server/web/rest/MetadataObjectTagOperations.java
@@ -46,8 +46,9 @@ import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.MetadataObjects;
import org.apache.gravitino.dto.requests.TagValuesAssociateRequest;
import org.apache.gravitino.dto.requests.TagsAssociateRequest;
+import org.apache.gravitino.dto.responses.MetadataObjectTagListResponse;
import org.apache.gravitino.dto.responses.NameListResponse;
-import org.apache.gravitino.dto.responses.TagListResponse;
+import org.apache.gravitino.dto.responses.TagNameListResponse;
import org.apache.gravitino.dto.responses.TagResponse;
import org.apache.gravitino.dto.tag.TagDTO;
import org.apache.gravitino.dto.util.DTOConverters;
@@ -206,39 +207,35 @@ public class MetadataObjectTagOperations {
}
}
+ TagDTO[] tagDTOs = tags.values().toArray(new TagDTO[0]);
+ int tagCount = tagDTOs.length;
+ tagDTOs =
+ MetadataAuthzHelper.filterByExpression(
+ metalake,
+
AuthorizationExpressionConstants.LOAD_TAG_AUTHORIZATION_EXPRESSION,
+ Entity.EntityType.TAG,
+ tagDTOs,
+ tagDTO -> NameIdentifierUtil.ofTag(metalake,
tagDTO.name()));
+ boolean hasInaccessibleTags = tagDTOs.length < tagCount;
+
if (verbose) {
LOG.info(
"List {} tags info for object type: {}, full name: {} under
metalake: {}",
- tags.size(),
+ tagDTOs.length,
type,
fullName,
metalake);
- TagDTO[] tagDTOS = tags.values().toArray(new TagDTO[0]);
- tagDTOS =
- MetadataAuthzHelper.filterByExpression(
- metalake,
-
AuthorizationExpressionConstants.LOAD_TAG_AUTHORIZATION_EXPRESSION,
- Entity.EntityType.TAG,
- tagDTOS,
- tagDTO -> NameIdentifierUtil.ofTag(metalake,
tagDTO.name()));
- return Utils.ok(new TagListResponse(tagDTOS));
+ return Utils.ok(new MetadataObjectTagListResponse(tagDTOs,
hasInaccessibleTags));
} else {
- String[] tagNames = tags.keySet().toArray(new String[0]);
- tagNames =
- MetadataAuthzHelper.filterByExpression(
- metalake,
-
AuthorizationExpressionConstants.LOAD_TAG_AUTHORIZATION_EXPRESSION,
- Entity.EntityType.TAG,
- tagNames,
- tagName -> NameIdentifierUtil.ofTag(metalake, tagName));
+ String[] tagNames =
Arrays.stream(tagDTOs).map(TagDTO::name).toArray(String[]::new);
LOG.info(
"List {} tags for object type: {}, full name: {} under
metalake: {}",
tagNames.length,
type,
fullName,
metalake);
- return Utils.ok(new NameListResponse(tagNames));
+ return Utils.ok(new TagNameListResponse(tagNames,
hasInaccessibleTags));
}
});
diff --git
a/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectPolicyOperations.java
b/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectPolicyOperations.java
index e7703609d8..1d546ab84e 100644
---
a/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectPolicyOperations.java
+++
b/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectPolicyOperations.java
@@ -42,8 +42,10 @@ import org.apache.gravitino.Config;
import org.apache.gravitino.GravitinoEnv;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.MetadataObjects;
+import org.apache.gravitino.dto.responses.MetadataObjectPolicyListResponse;
import org.apache.gravitino.dto.responses.NameListResponse;
import org.apache.gravitino.dto.responses.PolicyListResponse;
+import org.apache.gravitino.dto.responses.PolicyNameListResponse;
import org.apache.gravitino.meta.AuditInfo;
import org.apache.gravitino.meta.PolicyEntity;
import org.apache.gravitino.policy.Policy;
@@ -150,8 +152,10 @@ public class TestMetadataObjectPolicyOperations extends
BaseOperationsTest {
Assertions.assertEquals(Response.Status.OK.getStatusCode(),
response.getStatus());
- PolicyListResponse policyListResponse =
response.readEntity(PolicyListResponse.class);
+ MetadataObjectPolicyListResponse policyListResponse =
+ response.readEntity(MetadataObjectPolicyListResponse.class);
Assertions.assertEquals(0, policyListResponse.getCode());
+ Assertions.assertFalse(policyListResponse.hasInaccessiblePolicies());
Assertions.assertEquals(catalogPolicyInfos.length,
policyListResponse.getPolicies().length);
Map<String, Policy> resultPolicies =
@@ -172,8 +176,9 @@ public class TestMetadataObjectPolicyOperations extends
BaseOperationsTest {
Assertions.assertEquals(Response.Status.OK.getStatusCode(),
response1.getStatus());
- NameListResponse nameListResponse =
response1.readEntity(NameListResponse.class);
+ PolicyNameListResponse nameListResponse =
response1.readEntity(PolicyNameListResponse.class);
Assertions.assertEquals(0, nameListResponse.getCode());
+ Assertions.assertFalse(nameListResponse.hasInaccessiblePolicies());
Assertions.assertEquals(catalogPolicyInfos.length,
nameListResponse.getNames().length);
Assertions.assertArrayEquals(
Arrays.stream(catalogPolicyInfos).map(PolicyEntity::name).toArray(String[]::new),
@@ -390,14 +395,18 @@ public class TestMetadataObjectPolicyOperations extends
BaseOperationsTest {
operations.listPoliciesForMetadataObject(
metalake, table.type().toString(), table.fullName(), true);
Assertions.assertEquals(Response.Status.OK.getStatusCode(),
detailsResponse.getStatus());
- Assertions.assertEquals(
- 0, ((PolicyListResponse)
detailsResponse.getEntity()).getPolicies().length);
+ MetadataObjectPolicyListResponse details =
+ (MetadataObjectPolicyListResponse) detailsResponse.getEntity();
+ Assertions.assertEquals(0, details.getPolicies().length);
+ Assertions.assertTrue(details.hasInaccessiblePolicies());
Response namesResponse =
operations.listPoliciesForMetadataObject(
metalake, table.type().toString(), table.fullName(), false);
Assertions.assertEquals(Response.Status.OK.getStatusCode(),
namesResponse.getStatus());
- Assertions.assertEquals(0, ((NameListResponse)
namesResponse.getEntity()).getNames().length);
+ PolicyNameListResponse names = (PolicyNameListResponse)
namesResponse.getEntity();
+ Assertions.assertEquals(0, names.getNames().length);
+ Assertions.assertTrue(names.hasInaccessiblePolicies());
}
Mockito.verify(policyManager, Mockito.never())
.listPolicyInfosForMetadataObject(metalake, schema);
diff --git
a/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectTagOperations.java
b/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectTagOperations.java
index 02f9853063..188ec374fd 100644
---
a/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectTagOperations.java
+++
b/server/src/test/java/org/apache/gravitino/server/web/rest/TestMetadataObjectTagOperations.java
@@ -42,8 +42,10 @@ import
org.apache.gravitino.dto.requests.TagValuesAssociateRequest;
import org.apache.gravitino.dto.requests.TagsAssociateRequest;
import org.apache.gravitino.dto.responses.ErrorConstants;
import org.apache.gravitino.dto.responses.ErrorResponse;
+import org.apache.gravitino.dto.responses.MetadataObjectTagListResponse;
import org.apache.gravitino.dto.responses.NameListResponse;
import org.apache.gravitino.dto.responses.TagListResponse;
+import org.apache.gravitino.dto.responses.TagNameListResponse;
import org.apache.gravitino.dto.responses.TagResponse;
import org.apache.gravitino.exceptions.NoSuchTagException;
import org.apache.gravitino.exceptions.TagAlreadyAssociatedException;
@@ -164,9 +166,11 @@ public class TestMetadataObjectTagOperations extends
BaseOperationsTest {
Assertions.assertEquals(Response.Status.OK.getStatusCode(),
response.getStatus());
- TagListResponse tagListResponse =
response.readEntity(TagListResponse.class);
+ MetadataObjectTagListResponse tagListResponse =
+ response.readEntity(MetadataObjectTagListResponse.class);
Assertions.assertEquals(0, tagListResponse.getCode());
Assertions.assertEquals(catalogTagInfos.length,
tagListResponse.getTags().length);
+ Assertions.assertFalse(tagListResponse.hasInaccessibleTags());
Map<String, Tag> resultTags =
Arrays.stream(tagListResponse.getTags())
@@ -186,9 +190,10 @@ public class TestMetadataObjectTagOperations extends
BaseOperationsTest {
Assertions.assertEquals(Response.Status.OK.getStatusCode(),
response1.getStatus());
- NameListResponse nameListResponse =
response1.readEntity(NameListResponse.class);
+ TagNameListResponse nameListResponse =
response1.readEntity(TagNameListResponse.class);
Assertions.assertEquals(0, nameListResponse.getCode());
Assertions.assertEquals(catalogTagInfos.length,
nameListResponse.getNames().length);
+ Assertions.assertFalse(nameListResponse.hasInaccessibleTags());
Assertions.assertArrayEquals(
Arrays.stream(catalogTagInfos).map(Tag::name).toArray(String[]::new),
nameListResponse.getNames());