Skip to content

Commit cf70efb

Browse files
committed
Hide policy attachment behind a config
1 parent 652bdb3 commit cf70efb

File tree

5 files changed

+64
-11
lines changed

5 files changed

+64
-11
lines changed

polaris-core/src/main/java/org/apache/polaris/core/config/FeatureConfiguration.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,4 +349,15 @@ public static void enforceFeatureEnabledOrThrow(
349349
+ "it is still possible to enforce the uniqueness of table locations within a catalog.")
350350
.defaultValue(false)
351351
.buildFeatureConfiguration();
352+
353+
public static final FeatureConfiguration<Boolean>
354+
ALLOW_ATTACHING_FINE_GRAINED_POLICIES_TO_ENTITIES =
355+
PolarisConfiguration.<Boolean>builder()
356+
.key("ALLOW_ATTACHING_FINE_GRAINED_POLICIES_TO_ENTITIES_ENABLED")
357+
.catalogConfig(
358+
"polaris.config.allow-attaching-fine-grained-policies-to-entities.enabled")
359+
.description(
360+
"If set to true, fine grained access control policies can be attached to entities.")
361+
.defaultValue(false)
362+
.buildFeatureConfiguration();
352363
}

polaris-core/src/main/java/org/apache/polaris/core/policy/validator/PolicyValidators.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
package org.apache.polaris.core.policy.validator;
2020

2121
import com.google.common.base.Preconditions;
22+
import org.apache.polaris.core.config.FeatureConfiguration;
23+
import org.apache.polaris.core.context.CallContext;
2224
import org.apache.polaris.core.entity.PolarisEntity;
2325
import org.apache.polaris.core.policy.PolicyEntity;
2426
import org.apache.polaris.core.policy.PredefinedPolicyTypes;
@@ -84,7 +86,8 @@ public static void validate(PolicyEntity policy) {
8486
* @param targetEntity the target Polaris entity to attach the policy to
8587
* @return {@code true} if the policy is attachable to the target entity; {@code false} otherwise
8688
*/
87-
public static boolean canAttach(PolicyEntity policy, PolarisEntity targetEntity) {
89+
public static boolean canAttach(
90+
CallContext callContext, PolicyEntity policy, PolarisEntity targetEntity) {
8891
Preconditions.checkNotNull(policy, "Policy must not be null");
8992
Preconditions.checkNotNull(targetEntity, "Target entity must not be null");
9093

@@ -103,17 +106,19 @@ public static boolean canAttach(PolicyEntity policy, PolarisEntity targetEntity)
103106
return BaseMaintenancePolicyValidator.INSTANCE.canAttach(entityType, entitySubType);
104107

105108
case ACCESS_CONTROL:
106-
// TODO: Add validator for attaching this only to table
107-
return true;
109+
return callContext
110+
.getRealmConfig()
111+
.getConfig(FeatureConfiguration.ALLOW_ATTACHING_FINE_GRAINED_POLICIES_TO_ENTITIES);
108112

109113
default:
110114
LOGGER.warn("Attachment not supported for policy type: {}", policyType.getName());
111115
return false;
112116
}
113117
}
114118

115-
public static void validateAttach(PolicyEntity policy, PolarisEntity targetEntity) {
116-
if (!canAttach(policy, targetEntity)) {
119+
public static void validateAttach(
120+
CallContext callContext, PolicyEntity policy, PolarisEntity targetEntity) {
121+
if (!canAttach(callContext, policy, targetEntity)) {
117122
throw new PolicyAttachException(
118123
"Cannot attach policy '%s' to target entity '%s'",
119124
policy.getName(), targetEntity.getName());

polaris-core/src/test/java/org/apache/polaris/core/policy/PolicyValidatorsTest.java

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,14 @@
2323
import static org.apache.polaris.core.policy.PredefinedPolicyTypes.DATA_COMPACTION;
2424
import static org.assertj.core.api.Assertions.assertThat;
2525
import static org.assertj.core.api.Assertions.assertThatThrownBy;
26+
import static org.mockito.Mockito.mock;
27+
import static org.mockito.Mockito.when;
2628

2729
import org.apache.iceberg.catalog.Namespace;
2830
import org.apache.iceberg.catalog.TableIdentifier;
31+
import org.apache.polaris.core.config.FeatureConfiguration;
32+
import org.apache.polaris.core.config.RealmConfig;
33+
import org.apache.polaris.core.context.CallContext;
2934
import org.apache.polaris.core.entity.CatalogEntity;
3035
import org.apache.polaris.core.entity.NamespaceEntity;
3136
import org.apache.polaris.core.entity.PrincipalEntity;
@@ -38,6 +43,7 @@ public class PolicyValidatorsTest {
3843
Namespace ns = Namespace.of("NS1");
3944
TableIdentifier tableIdentifier = TableIdentifier.of(ns, "table1");
4045
PolicyEntity policyEntity = new PolicyEntity.Builder(ns, "pn", DATA_COMPACTION).build();
46+
CallContext callContext = mock(CallContext.class);
4147

4248
@Test
4349
public void testInvalidPolicy() {
@@ -92,22 +98,22 @@ public void testValidPolicy() {
9298
@Test
9399
public void testCanAttachReturnsTrueForCatalogType() {
94100
var targetEntity = new CatalogEntity.Builder().build();
95-
var result = PolicyValidators.canAttach(policyEntity, targetEntity);
101+
var result = PolicyValidators.canAttach(callContext, policyEntity, targetEntity);
96102
assertThat(result).isTrue().as("Expected canAttach() to return true for CATALOG type");
97103
}
98104

99105
@Test
100106
public void testCanAttachReturnsTrueForNamespaceType() {
101107
var targetEntity = new NamespaceEntity.Builder(ns).build();
102-
var result = PolicyValidators.canAttach(policyEntity, targetEntity);
108+
var result = PolicyValidators.canAttach(callContext, policyEntity, targetEntity);
103109
assertThat(result).isTrue().as("Expected canAttach() to return true for CATALOG type");
104110
}
105111

106112
@Test
107113
public void testCanAttachReturnsTrueForIcebergTableLikeWithTableSubtype() {
108114
var targetEntity =
109115
new IcebergTableLikeEntity.Builder(tableIdentifier, "").setSubType(ICEBERG_TABLE).build();
110-
var result = PolicyValidators.canAttach(policyEntity, targetEntity);
116+
var result = PolicyValidators.canAttach(callContext, policyEntity, targetEntity);
111117
assertThat(result)
112118
.isTrue()
113119
.as("Expected canAttach() to return true for ICEBERG_TABLE_LIKE with TABLE subtype");
@@ -117,7 +123,7 @@ public void testCanAttachReturnsTrueForIcebergTableLikeWithTableSubtype() {
117123
public void testCanAttachReturnsFalseForIcebergTableLikeWithNonTableSubtype() {
118124
var targetEntity =
119125
new IcebergTableLikeEntity.Builder(tableIdentifier, "").setSubType(ICEBERG_VIEW).build();
120-
var result = PolicyValidators.canAttach(policyEntity, targetEntity);
126+
var result = PolicyValidators.canAttach(callContext, policyEntity, targetEntity);
121127
assertThat(result)
122128
.isFalse()
123129
.as("Expected canAttach() to return false for ICEBERG_TABLE_LIKE with non-TABLE subtype");
@@ -126,7 +132,36 @@ public void testCanAttachReturnsFalseForIcebergTableLikeWithNonTableSubtype() {
126132
@Test
127133
public void testCanAttachReturnsFalseForUnattachableType() {
128134
var targetEntity = new PrincipalEntity.Builder().build();
129-
var result = PolicyValidators.canAttach(policyEntity, targetEntity);
135+
var result = PolicyValidators.canAttach(callContext, policyEntity, targetEntity);
130136
assertThat(result).isFalse().as("Expected canAttach() to return false for null");
131137
}
138+
139+
@Test
140+
public void testCanAttachAccessControlPolicy() {
141+
// Arrange
142+
Namespace ns = Namespace.of("NS1");
143+
TableIdentifier tableId = TableIdentifier.of(ns, "table1");
144+
PolicyEntity policy =
145+
new PolicyEntity.Builder(ns, "acp", PredefinedPolicyTypes.ACCESS_CONTROL)
146+
.setContent("{\"columnProjections\":[\"col1\"],\"rowFilters\":[]}")
147+
.build();
148+
149+
// Mock CallContext and RealmConfiguration
150+
var realmConfig = mock(RealmConfig.class);
151+
when(callContext.getRealmConfig()).thenReturn(realmConfig);
152+
when(realmConfig.getConfig(
153+
FeatureConfiguration.ALLOW_ATTACHING_FINE_GRAINED_POLICIES_TO_ENTITIES))
154+
.thenReturn(true);
155+
156+
// Use a valid table entity
157+
var tableEntity =
158+
new IcebergTableLikeEntity.Builder(tableId, "")
159+
.setSubType(org.apache.polaris.core.entity.PolarisEntitySubType.ICEBERG_TABLE)
160+
.build();
161+
boolean canAttach =
162+
org.apache.polaris.core.policy.validator.PolicyValidators.canAttach(
163+
callContext, policy, tableEntity);
164+
165+
assertThat(canAttach).isTrue();
166+
}
132167
}

runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalog.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ public boolean attachPolicy(
304304
var targetCatalogPath = PolarisEntity.toCoreList(resolvedTargetPath.getRawParentPath());
305305
var targetEntity = resolvedTargetPath.getRawLeafEntity();
306306

307-
PolicyValidators.validateAttach(policyEntity, targetEntity);
307+
PolicyValidators.validateAttach(callContext, policyEntity, targetEntity);
308308

309309
var result =
310310
metaStoreManager.attachPolicyToEntity(

runtime/service/src/test/java/org/apache/polaris/service/catalog/Profiles.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public Map<String, String> getConfigOverrides() {
3838
"polaris.event-listener.type",
3939
"test",
4040
"polaris.readiness.ignore-severe-issues",
41+
"true",
42+
"polaris.features.\"ALLOW_ATTACHING_FINE_GRAINED_POLICIES_TO_ENTITIES_ENABLED\"",
4143
"true");
4244
}
4345
}

0 commit comments

Comments
 (0)