dennishuo commented on code in PR #1805:
URL: https://github.com/apache/polaris/pull/1805#discussion_r2136169734


##########
polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TransactionalMetaStoreManagerImpl.java:
##########
@@ -473,6 +475,12 @@ private void revokeGrantRecord(
 
     ms.persistStorageIntegrationIfNeededInCurrentTxn(callCtx, catalog, 
integration);
 
+    // CATALOG_PRE_PERSIST mutation point
+    EntityMutationEngine entityMutationEngine = 
callCtx.getEntityMutationEngine();
+    if (entityMutationEngine != null) {
+      entityMutationEngine.applyMutations(MutationPoint.CATALOG_PRE_PERSIST, 
catalog);

Review Comment:
   Does this need to be:
   
         catalog = 
entityMutationEngine.applyMutations(MutationPoint.CATALOG_PRE_PERSIST, catalog);
   
   ?



##########
polaris-core/src/main/java/org/apache/polaris/core/identity/mutation/EntityMutationEngine.java:
##########
@@ -0,0 +1,42 @@
+/*
+ * 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.polaris.core.identity.mutation;
+
+import org.apache.polaris.core.entity.PolarisBaseEntity;
+
+/**
+ * Engine responsible for applying a sequence of {@link EntityMutator} 
transformations to a {@link
+ * PolarisBaseEntity}.
+ *
+ * <p>This abstraction allows Polaris to customize or enrich entities during 
runtime or persistence,
+ * based on configured or contextual logic (e.g., injecting service identity 
info, computing derived
+ * fields).
+ */
+public interface EntityMutationEngine {
+  /**
+   * Applies all registered entity mutators to the provided entity, in order.
+   *
+   * @param mutationPoint The point in the entity lifecycle where mutations 
should be applied.
+   * @param entity The original Polaris entity to mutate.

Review Comment:
   It's too bad we don't have a way to express C++-style `const` correctness as 
we move towards immutable PolarisBaseEntity, but maybe we can at least mention 
here that the intention is that implementations should *not* mutate the input 
entity, but instead only create the new transformed entity.



##########
polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TransactionalMetaStoreManagerImpl.java:
##########
@@ -473,6 +475,12 @@ private void revokeGrantRecord(
 
     ms.persistStorageIntegrationIfNeededInCurrentTxn(callCtx, catalog, 
integration);
 
+    // CATALOG_PRE_PERSIST mutation point

Review Comment:
   For now, unfortunately we didn't quite manage to refactor all of the shared 
logic nryerrn `AtomicOperationMetaStoreManager` and 
`TransactionalMetaStoreManagerImpl` into a base class yet; the best we have is 
the `prepareToPersistNewEntity` hook defined in `BaseMetaStoreManager`.
   
   This means either this logic needs to be added in both the 
`AtomicOperationMetaStoreManager` and `TransactionalMetaStoreManagerImpl`, or 
needs to be abstracted into `BaseMetaStoreManager` somehow while making sure 
both of those impls invoke the shared logic. `persistNewEntity` isn't specific 
to catalog-creation so you'd need an enum on entityType there if you just put 
this logic in there.



##########
polaris-core/src/main/java/org/apache/polaris/core/identity/mutation/EntityMutationEngine.java:
##########
@@ -0,0 +1,42 @@
+/*
+ * 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.polaris.core.identity.mutation;
+
+import org.apache.polaris.core.entity.PolarisBaseEntity;
+
+/**
+ * Engine responsible for applying a sequence of {@link EntityMutator} 
transformations to a {@link
+ * PolarisBaseEntity}.
+ *
+ * <p>This abstraction allows Polaris to customize or enrich entities during 
runtime or persistence,
+ * based on configured or contextual logic (e.g., injecting service identity 
info, computing derived
+ * fields).
+ */
+public interface EntityMutationEngine {

Review Comment:
   It's unfortunate that we haven't had a chance yet to make 
`PolarisBaseEntity` immutable, but maybe our naming for this set of classes 
should be something that more strongly implies producing a "new transformed 
copy of the entity" rather than make it tempting for anyone to try mutating 
them in-place.
   
   What does everyone think of naming these instead:
   
   - EntityTransformationEngine/EntityTransformer/TransformationPoint
   - EntityDecorationEngine/EntityDecorator/DecorationPoint
   
   ?



##########
quarkus/service/src/main/java/org/apache/polaris/service/quarkus/identity/mutation/CatalogEntityConnectionConfigMutator.java:
##########
@@ -0,0 +1,86 @@
+/*
+ * 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.polaris.service.quarkus.identity.mutation;
+
+import io.smallrye.common.annotation.Identifier;
+import jakarta.enterprise.context.RequestScoped;
+import jakarta.inject.Inject;
+import org.apache.polaris.core.connection.AuthenticationParametersDpo;
+import org.apache.polaris.core.connection.AuthenticationType;
+import org.apache.polaris.core.connection.ConnectionConfigInfoDpo;
+import org.apache.polaris.core.entity.CatalogEntity;
+import org.apache.polaris.core.entity.PolarisBaseEntity;
+import org.apache.polaris.core.identity.ServiceIdentityType;
+import org.apache.polaris.core.identity.dpo.ServiceIdentityInfoDpo;
+import org.apache.polaris.service.identity.mutation.AppliesTo;
+import org.apache.polaris.core.identity.mutation.EntityMutator;
+import org.apache.polaris.core.identity.mutation.MutationPoint;
+import org.apache.polaris.core.identity.registry.ServiceIdentityRegistry;
+
+/**
+ * Entity mutator that injects a {@link ServiceIdentityInfoDpo} into a 
passthrough {@link
+ * CatalogEntity}, allowing the Polaris service identity to be surfaced to 
Polaris users.
+ *
+ * <p>This is necessary for authentication mechanisms such as SigV4, where 
Polaris users must
+ * explicitly allowlist the service identity that Polaris uses to access their 
services.
+ */
+@RequestScoped
+@Identifier("catalog-connection-config")
+@AppliesTo(MutationPoint.CATALOG_PRE_PERSIST)
+public class CatalogEntityConnectionConfigMutator implements EntityMutator {
+
+  private final ServiceIdentityRegistry serviceIdentityRegistry;
+
+  @Inject
+  CatalogEntityConnectionConfigMutator(ServiceIdentityRegistry 
serviceIdentityRegistry) {
+    this.serviceIdentityRegistry = serviceIdentityRegistry;
+  }
+
+  /**
+   * If the entity is a passthrough {@link CatalogEntity} and its connection 
uses AWS SIGV4
+   * authentication, this method injects a service identity into its 
connection configuration.
+   *
+   * @param entity the original Polaris entity
+   * @return the mutated entity with service identity injected, or the 
original if no change is
+   *     needed
+   */
+  @Override
+  public PolarisBaseEntity apply(PolarisBaseEntity entity) {
+    if (!(entity instanceof CatalogEntity catalogEntity) || 
!catalogEntity.isPassthroughFacade()) {
+      return entity;
+    }
+
+    ConnectionConfigInfoDpo connectionConfigInfoDpo = 
catalogEntity.getConnectionConfigInfoDpo();
+    AuthenticationParametersDpo authenticationParameters =
+        connectionConfigInfoDpo.getAuthenticationParameters();
+
+    if (authenticationParameters.getAuthenticationType() == 
AuthenticationType.SIGV4) {
+      CatalogEntity.Builder builder = new CatalogEntity.Builder(catalogEntity);
+      ConnectionConfigInfoDpo injectedConnectionConfigInfoDpo =
+          connectionConfigInfoDpo.withServiceIdentity(
+              
serviceIdentityRegistry.assignServiceIdentity(ServiceIdentityType.AWS_IAM));
+      builder.setConnectionConfigInfoDpo(injectedConnectionConfigInfoDpo);
+      builder.setEntityVersion(entity.getEntityVersion() + 1);

Review Comment:
   Normally we should only increment the entityVersion if the intermediate 
version is possibly visible to the outside world. It may or may not end up 
being harmless to modify the version multiple times during construction of the 
entity, but this would be inconsistent with other steps of the entity-building 
process.
   
   On the other side, it's true that it might be nice to have something that 
represents the complete entity contents as a version or hashCode so that we can 
compare across different transformations.
   
   For now, we should probably avoid incrementing the entityVersion here for 
consistency with how other things also still construct parts of the entity 
during creation/updates without incrementing the version for every intermediate 
state.



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

To unsubscribe, e-mail: [email protected]

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

Reply via email to