diff --git a/xtable-api/src/main/java/org/apache/xtable/conversion/ExternalCatalogConfig.java b/xtable-api/src/main/java/org/apache/xtable/conversion/ExternalCatalogConfig.java
index b525d8318..6ac9acf0f 100644
--- a/xtable-api/src/main/java/org/apache/xtable/conversion/ExternalCatalogConfig.java
+++ b/xtable-api/src/main/java/org/apache/xtable/conversion/ExternalCatalogConfig.java
@@ -58,6 +58,13 @@ public class ExternalCatalogConfig {
*/
String catalogConversionSourceImpl;
+ /**
+ * (Optional) A fully qualified class name that implements the interface for {@link
+ * org.apache.xtable.spi.sync.CatalogAccessControlPolicySyncClient} it can be used if the
+ * implementation for catalogType doesn't exist in XTable.
+ */
+ String catalogPolicySyncClientImpl;
+
/**
* The properties for this catalog, used for providing any custom behaviour during catalog sync
*/
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalAccessControlPolicySnapshot.java b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalAccessControlPolicySnapshot.java
new file mode 100644
index 000000000..b28bf3038
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalAccessControlPolicySnapshot.java
@@ -0,0 +1,70 @@
+/*
+ * 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.xtable.model.catalog.policy;
+
+import java.time.Instant;
+import java.util.Collections;
+import java.util.Map;
+
+import lombok.Builder;
+import lombok.Value;
+
+/** A snapshot of all access control data at a given point in time. */
+@Value
+@Builder
+public class InternalAccessControlPolicySnapshot {
+ /**
+ * A unique identifier representing this snapshot's version.
+ *
+ *
This could be a UUID, timestamp string, or any value that guarantees uniqueness across
+ * snapshots.
+ */
+ String versionId;
+
+ /**
+ * The moment in time when this snapshot was created.
+ *
+ *
Useful for maintaining an audit trail or comparing how policies have changed over time.
+ */
+ Instant timestamp;
+
+ /**
+ * A map of user names to {@link InternalUser} objects, capturing individual users' details such
+ * as assigned roles, auditing metadata, etc.
+ */
+ @Builder.Default Map usersByName = Collections.emptyMap();
+
+ /**
+ * A map of group names to {@link InternalUserGroup} objects, representing logical groupings of
+ * users for easier role management.
+ */
+ @Builder.Default Map groupsByName = Collections.emptyMap();
+
+ /**
+ * A map of role names to {@link InternalRole} objects, defining the privileges and security rules
+ * each role entails.
+ */
+ @Builder.Default Map rolesByName = Collections.emptyMap();
+
+ /**
+ * A map of additional properties or metadata related to this snapshot. This map provides
+ * flexibility for storing information without modifying the main schema of the snapshot.
+ */
+ @Builder.Default Map properties = Collections.emptyMap();
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalChangeLogInfo.java b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalChangeLogInfo.java
new file mode 100644
index 000000000..505cf7cb1
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalChangeLogInfo.java
@@ -0,0 +1,48 @@
+/*
+ * 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.xtable.model.catalog.policy;
+
+import java.time.Instant;
+
+import lombok.Builder;
+import lombok.Value;
+
+/**
+ * Contains change-log information for roles, users, or user groups, enabling traceability of who
+ * created or last modified them.
+ *
+ * This class is useful for governance and compliance scenarios, where an audit trail is
+ * necessary. It can be extended to include additional fields such as reasonForChange or
+ * changeDescription.
+ */
+@Value
+@Builder
+public class InternalChangeLogInfo {
+ /** The username or identifier of the entity that created this record. */
+ String createdBy;
+
+ /** The username or identifier of the entity that last modified this record. */
+ String lastModifiedBy;
+
+ /** The timestamp when this record was created. */
+ Instant createdAt;
+
+ /** The timestamp when this record was last modified. */
+ Instant lastModifiedAt;
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalPrivilege.java b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalPrivilege.java
new file mode 100644
index 000000000..48650b1df
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalPrivilege.java
@@ -0,0 +1,45 @@
+/*
+ * 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.xtable.model.catalog.policy;
+
+import lombok.Builder;
+import lombok.Value;
+
+/**
+ * Represents a single privilege assignment for a securable object.
+ *
+ *
This defines the kind of operation (e.g., SELECT, CREATE, MODIFY) and whether it is allowed or
+ * denied. Some catalogs may only accept ALLOW rules and treat all other operations as denied by
+ * default.
+ */
+@Value
+@Builder
+public class InternalPrivilege {
+ /**
+ * The type of privilege, such as SELECT, CREATE, or MODIFY. Each implementation can define its
+ * own set of enums.
+ */
+ InternalPrivilegeType privilegeType;
+
+ /**
+ * The decision, typically ALLOW or DENY. Some catalogs may not support DENY explicitly,
+ * defaulting to ALLOW.
+ */
+ String privilegeDecision;
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalPrivilegeType.java b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalPrivilegeType.java
new file mode 100644
index 000000000..bcd5debfb
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalPrivilegeType.java
@@ -0,0 +1,71 @@
+/*
+ * 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.xtable.model.catalog.policy;
+
+/**
+ * Specifies a set of privileges that can be granted or revoked for securable objects.
+ *
+ *
This enum is used to indicate the type of actions that a subject (user, role, group) is
+ * allowed to perform on a given resource, such as a catalog, database, table, or other securable
+ * entity.
+ */
+public enum InternalPrivilegeType {
+
+ /** Grants all available privileges on the resource. */
+ ALL,
+
+ /**
+ * Allows modification of the structure or metadata of the resource. For example, modifying
+ * schemas or properties.
+ */
+ ALTER,
+
+ /**
+ * Allows describing or viewing the metadata of the resource. Typically applies to viewing schemas
+ * or properties of the resource.
+ */
+ DESCRIBE,
+
+ /**
+ * Allows reading or selecting data from the resource. Commonly associated with performing SQL
+ * SELECT statements.
+ */
+ SELECT,
+
+ /**
+ * Allows inserting new data into the resource. Typically granted for operations like SQL INSERT
+ * statements.
+ */
+ INSERT,
+
+ /**
+ * Allows updating existing data within the resource. Typically granted for operations like SQL
+ * UPDATE statements.
+ */
+ UPDATE,
+
+ /** Allows creating new resources within the catalog. */
+ CREATE,
+
+ /** Allows deleting or dropping a resource, such as a database or a table. */
+ DROP,
+
+ /** Allows removing data from the resource, for example using SQL DELETE statements. */
+ DELETE
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalRole.java b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalRole.java
new file mode 100644
index 000000000..76f04605c
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalRole.java
@@ -0,0 +1,51 @@
+/*
+ * 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.xtable.model.catalog.policy;
+
+import java.util.List;
+import java.util.Map;
+
+import lombok.Builder;
+import lombok.Value;
+
+/**
+ * Represents a role within the catalog.
+ *
+ *
A role can be granted access to multiple securable objects, each with its own set of
+ * privileges. Audit info is stored to track the role's creation and modifications, and a properties
+ * map can hold additional metadata.
+ */
+@Value
+@Builder
+public class InternalRole {
+ /** The unique name or identifier for the role. */
+ String name;
+
+ /** The list of securable objects this role can access. */
+ List securableObjects;
+
+ /** Contains information about how and when this role was created and last modified. */
+ InternalChangeLogInfo changeLogInfo;
+
+ /**
+ * A map to store additional metadata or properties related to this role. For example, this might
+ * include a description, usage instructions, or any catalog-specific fields.
+ */
+ Map properties;
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalSecurableObject.java b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalSecurableObject.java
new file mode 100644
index 000000000..0a7c5e913
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalSecurableObject.java
@@ -0,0 +1,45 @@
+/*
+ * 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.xtable.model.catalog.policy;
+
+import java.util.List;
+
+import lombok.Builder;
+import lombok.Value;
+
+/**
+ * Represents a securable object in the catalog, which can be managed by access control.
+ *
+ * Examples of securable objects include catalogs, schemas, tables, views, or any other data
+ * objects that require fine-grained privilege management. Each securable object can have one or
+ * more privileges assigned to it.
+ */
+@Value
+@Builder
+public class InternalSecurableObject {
+ /** The identifier of the securable object. */
+ InternalSecurableObjectIdentifier securableObjectIdentifier;
+ /**
+ * The type of securable object, such as TABLE, VIEW, FUNCTION, etc. Each implementation can
+ * define its own set of enums.
+ */
+ InternalSecurableObjectType securableObjectType;
+ /** The set of privileges assigned to this object. */
+ List privileges;
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalSecurableObjectIdentifier.java b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalSecurableObjectIdentifier.java
new file mode 100644
index 000000000..d13403ae3
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalSecurableObjectIdentifier.java
@@ -0,0 +1,36 @@
+/*
+ * 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.xtable.model.catalog.policy;
+
+/**
+ * Defines a structure for obtaining a unique, canonical identifier for a securable object within
+ * the catalog.
+ *
+ * Implementations of this interface may represent entities such as catalogs, databases, tables,
+ * or any other resource that can be protected or controlled via security policies.
+ */
+public interface InternalSecurableObjectIdentifier {
+
+ /**
+ * Returns the unique identifier of the securable object in a canonical form.
+ *
+ * @return a non-null {@link String} representing the unique identifier of this securable object
+ */
+ String getId();
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalSecurableObjectType.java b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalSecurableObjectType.java
new file mode 100644
index 000000000..13ba7247a
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalSecurableObjectType.java
@@ -0,0 +1,55 @@
+/*
+ * 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.xtable.model.catalog.policy;
+
+/**
+ * Identifies the type of securable object within the catalog.
+ *
+ *
Each attribute in this enum represents a different kind of resource for which permissions may
+ * be managed or enforced.
+ */
+public enum InternalSecurableObjectType {
+
+ /** Represents the root container in which databases and other objects reside. */
+ CATALOG,
+
+ /** Represents a logical grouping of tables and other related objects. */
+ DATABASE,
+
+ /** Represents a table, typically containing rows and columns of data. */
+ TABLE,
+
+ /** Represents a view, which is often a virtual table defined by a query. */
+ VIEW,
+
+ /**
+ * Represents a partition, commonly used to segment table data for performance or organizational
+ * reasons.
+ */
+ PARTITION,
+
+ /** Represents a column, generally a single field within a table or partition. */
+ COLUMN,
+
+ /** Represents a function, such as a user-defined function (UDF) within the database system. */
+ FUNCTION,
+
+ /** Represents an unsupported object type for error handling. */
+ UNSUPPORTED
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalUser.java b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalUser.java
new file mode 100644
index 000000000..f39f8e322
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalUser.java
@@ -0,0 +1,43 @@
+/*
+ * 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.xtable.model.catalog.policy;
+
+import java.util.List;
+
+import lombok.Builder;
+import lombok.Value;
+
+/**
+ * Represents an individual user within the catalog.
+ *
+ *
A user may be assigned multiple roles, and can also belong to a specific user group. Audit
+ * information is stored to allow tracking of who created or last modified the user.
+ */
+@Value
+@Builder
+public class InternalUser {
+ /** The unique name or identifier for the user. */
+ String name;
+
+ /** The list of roles assigned to this user. */
+ List roles;
+
+ /** Contains information about how and when this user was created and last modified. */
+ InternalChangeLogInfo changeLogInfo;
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalUserGroup.java b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalUserGroup.java
new file mode 100644
index 000000000..179f95490
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/catalog/policy/InternalUserGroup.java
@@ -0,0 +1,43 @@
+/*
+ * 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.xtable.model.catalog.policy;
+
+import java.util.List;
+
+import lombok.Builder;
+import lombok.Value;
+
+/**
+ * Represents a user group within the catalog.
+ *
+ * Groups can have multiple roles assigned, and also include audit information to track creation
+ * and modifications.
+ */
+@Value
+@Builder
+public class InternalUserGroup {
+ /** The unique name or identifier for the user group. */
+ String name;
+
+ /** The list of roles assigned to this group. */
+ List roles;
+
+ /** Contains information about how and when this group was created and last modified. */
+ InternalChangeLogInfo changeLogInfo;
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/sync/policy/PolicySyncResult.java b/xtable-api/src/main/java/org/apache/xtable/model/sync/policy/PolicySyncResult.java
new file mode 100644
index 000000000..1e936f5eb
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/sync/policy/PolicySyncResult.java
@@ -0,0 +1,156 @@
+/*
+ * 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.xtable.model.sync.policy;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import lombok.Builder;
+import lombok.Value;
+
+import org.apache.xtable.annotations.Evolving;
+import org.apache.xtable.model.sync.ErrorDetails;
+import org.apache.xtable.model.sync.SyncStatusCode;
+
+/**
+ * Represents the result of a policy sync between catalogs, capturing details of roles, users, and
+ * user groups.
+ */
+@Value
+@Builder
+@Evolving
+public class PolicySyncResult {
+
+ /** List of role sync results. */
+ @Builder.Default List rolesSyncResult = new ArrayList<>();
+
+ /** List of user sync results. */
+ @Builder.Default List usersSyncResult = new ArrayList<>();
+
+ /** List of user group sync results. */
+ @Builder.Default List userGroupsSyncResult = new ArrayList<>();
+
+ /** The start time of the policy sync. */
+ Instant startTime;
+
+ /** The duration of the policy sync. */
+ Duration duration;
+
+ /** Represents the sync result for a specific role, including privileges and status. */
+ @Value
+ public static class RoleSyncResult {
+ /** The name of the role. */
+ String roleName;
+
+ /** Mapping of securable objects to their privilege sync info details. */
+ Map> privilegeSyncInfos;
+
+ /** The status of the role sync (e.g., SUCCESS or ERROR). */
+ SyncStatusCode statusCode;
+
+ /** Details of any errors that occurred during synchronization. */
+ ErrorDetails errorDetails;
+
+ /**
+ * Builds a {@link PolicySyncResult.RoleSyncResult} for a given role.
+ *
+ * @param roleName The name of the role.
+ * @param privilegeSyncInfos A map of privileges associated with the role.
+ * @param errorDetails exception details if an error occurred, otherwise null.
+ * @return A RoleSyncResult object containing the synchronization details.
+ */
+ public static PolicySyncResult.RoleSyncResult create(
+ String roleName,
+ Map> privilegeSyncInfos,
+ ErrorDetails errorDetails) {
+
+ SyncStatusCode statusCode =
+ errorDetails == null ? SyncStatusCode.SUCCESS : SyncStatusCode.ERROR;
+ return new RoleSyncResult(roleName, privilegeSyncInfos, statusCode, errorDetails);
+ }
+ }
+
+ /** Represents the sync result for a specific user. */
+ @Value
+ public static class UserSyncResult {
+ /** The name of the user. */
+ String userName;
+
+ /** List of role grant synchronization details. */
+ List roleGrantSyncInfos;
+
+ /** The status of the user synchronization. */
+ SyncStatusCode statusCode;
+
+ /** Details of any errors that occurred during synchronization. */
+ ErrorDetails errorDetails;
+
+ /**
+ * Builds a {@link PolicySyncResult.UserSyncResult} for a given user.
+ *
+ * @param userName The name of the user.
+ * @param roleGrantSyncInfos List of role grant synchronization information.
+ * @param errorDetails exception details if an error occurred, otherwise null.
+ * @return A UserSyncResult object containing the synchronization details.
+ */
+ public static PolicySyncResult.UserSyncResult create(
+ String userName, List roleGrantSyncInfos, ErrorDetails errorDetails) {
+
+ SyncStatusCode statusCode =
+ errorDetails == null ? SyncStatusCode.SUCCESS : SyncStatusCode.ERROR;
+ return new UserSyncResult(userName, roleGrantSyncInfos, statusCode, errorDetails);
+ }
+ }
+
+ /** Represents the synchronization result for a user group. */
+ @Value
+ public static class UserGroupSyncResult {
+ /** The name of the user group. */
+ String userGroupName;
+
+ /** List of role grant sync details. */
+ List roleGrantSyncInfos;
+
+ /** The status of the user group synchronization. */
+ SyncStatusCode statusCode;
+
+ /** Details of any errors that occurred during synchronization. */
+ ErrorDetails errorDetails;
+
+ /**
+ * Builds a {@link PolicySyncResult.UserGroupSyncResult} for a given user group.
+ *
+ * @param groupName The name of the user group.
+ * @param roleGrantSyncInfos List of role grant synchronization information.
+ * @param errorDetails exception details if an error occurred, otherwise null.
+ * @return A UserGroupSyncResult object containing the synchronization details.
+ */
+ public static PolicySyncResult.UserGroupSyncResult create(
+ String groupName, List roleGrantSyncInfos, ErrorDetails errorDetails) {
+
+ SyncStatusCode statusCode =
+ errorDetails == null ? SyncStatusCode.SUCCESS : SyncStatusCode.ERROR;
+ return new UserGroupSyncResult(groupName, roleGrantSyncInfos, statusCode, errorDetails);
+ }
+ }
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/sync/policy/PrivilegeSyncInfo.java b/xtable-api/src/main/java/org/apache/xtable/model/sync/policy/PrivilegeSyncInfo.java
new file mode 100644
index 000000000..4a559e4fc
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/sync/policy/PrivilegeSyncInfo.java
@@ -0,0 +1,52 @@
+/*
+ * 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.xtable.model.sync.policy;
+
+import lombok.Value;
+
+import org.apache.xtable.annotations.Evolving;
+import org.apache.xtable.model.catalog.policy.InternalPrivilegeType;
+import org.apache.xtable.model.sync.ErrorDetails;
+import org.apache.xtable.model.sync.SyncStatusCode;
+
+/**
+ * Represents the synchronization details of a specific privilege, including its type, status, and
+ * any associated errors.
+ */
+@Value
+@Evolving
+public class PrivilegeSyncInfo {
+
+ /** The type of privilege (e.g., SELECT, INSERT, DELETE). */
+ String privilegeType;
+
+ /** The status of the privilege sync (e.g., SUCCESS, ERROR). */
+ SyncStatusCode statusCode;
+
+ /** Details of any errors that occurred during synchronization. */
+ ErrorDetails errorDetails;
+
+ public static PrivilegeSyncInfo create(
+ InternalPrivilegeType internalPrivilegeType, ErrorDetails errorDetails) {
+
+ SyncStatusCode statusCode =
+ errorDetails == null ? SyncStatusCode.SUCCESS : SyncStatusCode.ERROR;
+ return new PrivilegeSyncInfo(internalPrivilegeType.name(), statusCode, errorDetails);
+ }
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/sync/policy/RoleGrantSyncInfo.java b/xtable-api/src/main/java/org/apache/xtable/model/sync/policy/RoleGrantSyncInfo.java
new file mode 100644
index 000000000..561964004
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/sync/policy/RoleGrantSyncInfo.java
@@ -0,0 +1,53 @@
+/*
+ * 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.xtable.model.sync.policy;
+
+import lombok.Value;
+
+import org.apache.xtable.annotations.Evolving;
+import org.apache.xtable.model.sync.ErrorDetails;
+import org.apache.xtable.model.sync.SyncStatusCode;
+
+/** Represents the synchronization result of a role grant operation, */
+@Value
+@Evolving
+public class RoleGrantSyncInfo {
+
+ /** The name of the role being granted. */
+ String roleName;
+
+ /** The status of the role grant synchronization (e.g., SUCCESS, ERROR). */
+ SyncStatusCode status;
+
+ /** Details of any errors that occurred during the synchronization. */
+ ErrorDetails errorDetails;
+
+ /**
+ * Builds a {@link RoleGrantSyncInfo} object for a given role.
+ *
+ * @param roleName The name of the role.
+ * @param errorDetails exception details if an error occurred, otherwise null.
+ * @return A RoleGrantSyncInfo object.
+ */
+ public static RoleGrantSyncInfo create(String roleName, ErrorDetails errorDetails) {
+ SyncStatusCode statusCode =
+ errorDetails == null ? SyncStatusCode.SUCCESS : SyncStatusCode.ERROR;
+ return new RoleGrantSyncInfo(roleName, statusCode, errorDetails);
+ }
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/model/sync/policy/SecurableObjectInfo.java b/xtable-api/src/main/java/org/apache/xtable/model/sync/policy/SecurableObjectInfo.java
new file mode 100644
index 000000000..d7974cefc
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/model/sync/policy/SecurableObjectInfo.java
@@ -0,0 +1,50 @@
+/*
+ * 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.xtable.model.sync.policy;
+
+import lombok.Value;
+
+import org.apache.xtable.annotations.Evolving;
+import org.apache.xtable.model.catalog.policy.InternalSecurableObject;
+
+/**
+ * Represents metadata about a securable object, such as a database, table. This class holds basic
+ * identification details like the object's name and type.
+ */
+@Value
+@Evolving
+public class SecurableObjectInfo {
+ /** The name of the securable object. */
+ String name;
+
+ /** The type of the securable object (e.g., "DATABASE", "TABLE", "VIEW"). */
+ String objectType;
+
+ /**
+ * Builds a {@link SecurableObjectInfo} object from an {@link InternalSecurableObject}.
+ *
+ * @param securableObject The internal securable object.
+ * @return A SecurableObjectInfo object.
+ */
+ public static SecurableObjectInfo create(InternalSecurableObject securableObject) {
+ return new SecurableObjectInfo(
+ securableObject.getSecurableObjectIdentifier().getId(),
+ securableObject.getSecurableObjectType().name());
+ }
+}
diff --git a/xtable-api/src/main/java/org/apache/xtable/spi/sync/CatalogAccessControlPolicySyncClient.java b/xtable-api/src/main/java/org/apache/xtable/spi/sync/CatalogAccessControlPolicySyncClient.java
new file mode 100644
index 000000000..1478a0d43
--- /dev/null
+++ b/xtable-api/src/main/java/org/apache/xtable/spi/sync/CatalogAccessControlPolicySyncClient.java
@@ -0,0 +1,70 @@
+/*
+ * 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.xtable.spi.sync;
+
+import org.apache.xtable.annotations.Evolving;
+import org.apache.xtable.model.catalog.policy.InternalAccessControlPolicySnapshot;
+import org.apache.xtable.model.sync.SyncResult;
+import org.apache.xtable.model.sync.policy.PolicySyncResult;
+
+/**
+ * Defines the contract for synchronizing access control policies between a specific catalog and the
+ * internal canonical model.
+ *
+ * Implementations of this interface are responsible for:
+ *
+ *
+ * - Fetching the catalog’s native policy definitions and converting them into the canonical
+ * model.
+ *
- Converting the canonical model back into the catalog’s format and updating the catalog
+ * accordingly.
+ *
+ */
+@Evolving
+public interface CatalogAccessControlPolicySyncClient {
+ /**
+ * Fetches the current policies from the catalog, converting them into the internal canonical
+ * model.
+ *
+ * This method allows you to pull in the catalog’s native policy definitions (e.g., roles,
+ * privileges, user/groups) and map them into a {@link InternalAccessControlPolicySnapshot} so
+ * that they can be managed or merged with your centralized policy framework.
+ *
+ * @return A {@code CatalogAccessControlPolicySnapshot} containing the catalog’s current policies.
+ */
+ InternalAccessControlPolicySnapshot fetchPolicies();
+
+ /**
+ * Pushes the canonical policy snapshot into the target catalog, converting it into the catalog’s
+ * native policy definitions and applying any necessary updates.
+ *
+ *
This method typically performs the following steps:
+ *
+ *
+ * - Transforms the given {@code InternalAccessControlPolicySnapshot} into the catalog’s
+ * native format (roles, privileges, etc.).
+ *
- Applies the resulting policy definitions to the catalog, potentially overwriting or
+ * merging existing policies.
+ *
- Returns a {@link SyncResult} detailing the success or failure of the operation.
+ *
+ *
+ * @param snapshot The access control policy snapshot to be synchronized with the catalog.
+ */
+ PolicySyncResult pushPolicies(InternalAccessControlPolicySnapshot snapshot);
+}
diff --git a/xtable-core/src/main/java/org/apache/xtable/catalog/CatalogConversionFactory.java b/xtable-core/src/main/java/org/apache/xtable/catalog/CatalogConversionFactory.java
index 777811bef..371db0325 100644
--- a/xtable-core/src/main/java/org/apache/xtable/catalog/CatalogConversionFactory.java
+++ b/xtable-core/src/main/java/org/apache/xtable/catalog/CatalogConversionFactory.java
@@ -31,6 +31,7 @@
import org.apache.xtable.exception.NotSupportedException;
import org.apache.xtable.reflection.ReflectionUtils;
import org.apache.xtable.spi.extractor.CatalogConversionSource;
+import org.apache.xtable.spi.sync.CatalogAccessControlPolicySyncClient;
import org.apache.xtable.spi.sync.CatalogSyncClient;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@@ -88,6 +89,19 @@ public CatalogSyncClient createCatalogSyncClient(
configuration);
}
+ /**
+ * Returns an implementation class for {@link CatalogAccessControlPolicySyncClient} that'll be
+ * used for fetching / syncing policies from / to catalog
+ *
+ * @param catalogConfig configuration for the catalog
+ * @param configuration hadoop configuration
+ */
+ public CatalogAccessControlPolicySyncClient createCatalogPolicySyncClient(
+ ExternalCatalogConfig catalogConfig, Configuration configuration) {
+ return ReflectionUtils.createInstanceOfClass(
+ catalogConfig.getCatalogPolicySyncClientImpl(), catalogConfig, configuration);
+ }
+
private static T findInstanceByCatalogType(
Class serviceClass, String catalogType, Function catalogTypeExtractor) {
ServiceLoader loader = ServiceLoader.load(serviceClass);
diff --git a/xtable-core/src/test/java/org/apache/xtable/catalog/TestCatalogConversionFactory.java b/xtable-core/src/test/java/org/apache/xtable/catalog/TestCatalogConversionFactory.java
index 1d05666b8..9f5801168 100644
--- a/xtable-core/src/test/java/org/apache/xtable/catalog/TestCatalogConversionFactory.java
+++ b/xtable-core/src/test/java/org/apache/xtable/catalog/TestCatalogConversionFactory.java
@@ -29,8 +29,10 @@
import org.apache.xtable.conversion.TargetCatalogConfig;
import org.apache.xtable.model.catalog.ThreePartHierarchicalTableIdentifier;
import org.apache.xtable.spi.extractor.CatalogConversionSource;
+import org.apache.xtable.spi.sync.CatalogAccessControlPolicySyncClient;
import org.apache.xtable.spi.sync.CatalogSyncClient;
import org.apache.xtable.testutil.ITTestUtils;
+import org.apache.xtable.testutil.ITTestUtils.TestCatalogAccessControlPolicySyncClientImpl;
import org.apache.xtable.testutil.ITTestUtils.TestCatalogConversionSourceImpl;
import org.apache.xtable.testutil.ITTestUtils.TestCatalogSyncImpl;
@@ -105,4 +107,21 @@ void createCatalogSyncClientForCatalogType() {
targetCatalogConfig.getCatalogConfig(), "TABLE_FORMAT", new Configuration());
assertEquals(catalogSyncClient.getClass().getName(), TestCatalogSyncImpl.class.getName());
}
+
+ @Test
+ void createCatalogPolicySyncClient() {
+ ExternalCatalogConfig externalCatalogConfig =
+ ExternalCatalogConfig.builder()
+ .catalogId("catalogId")
+ .catalogPolicySyncClientImpl(
+ TestCatalogAccessControlPolicySyncClientImpl.class.getName())
+ .catalogProperties(Collections.emptyMap())
+ .build();
+ CatalogAccessControlPolicySyncClient catalogSyncClient =
+ CatalogConversionFactory.getInstance()
+ .createCatalogPolicySyncClient(externalCatalogConfig, new Configuration());
+ assertEquals(
+ catalogSyncClient.getClass().getName(),
+ TestCatalogAccessControlPolicySyncClientImpl.class.getName());
+ }
}
diff --git a/xtable-core/src/test/java/org/apache/xtable/testutil/ITTestUtils.java b/xtable-core/src/test/java/org/apache/xtable/testutil/ITTestUtils.java
index 75c3833ad..3c4f38417 100644
--- a/xtable-core/src/test/java/org/apache/xtable/testutil/ITTestUtils.java
+++ b/xtable-core/src/test/java/org/apache/xtable/testutil/ITTestUtils.java
@@ -30,10 +30,13 @@
import org.apache.xtable.conversion.SourceTable;
import org.apache.xtable.model.InternalTable;
import org.apache.xtable.model.catalog.CatalogTableIdentifier;
+import org.apache.xtable.model.catalog.policy.InternalAccessControlPolicySnapshot;
import org.apache.xtable.model.schema.InternalPartitionField;
import org.apache.xtable.model.schema.InternalSchema;
import org.apache.xtable.model.storage.DataLayoutStrategy;
+import org.apache.xtable.model.sync.policy.PolicySyncResult;
import org.apache.xtable.spi.extractor.CatalogConversionSource;
+import org.apache.xtable.spi.sync.CatalogAccessControlPolicySyncClient;
import org.apache.xtable.spi.sync.CatalogSyncClient;
public class ITTestUtils {
@@ -161,4 +164,21 @@ public String getCatalogType() {
@Override
public void init(ExternalCatalogConfig catalogConfig, Configuration configuration) {}
}
+
+ public static class TestCatalogAccessControlPolicySyncClientImpl
+ implements CatalogAccessControlPolicySyncClient {
+
+ public TestCatalogAccessControlPolicySyncClientImpl(
+ ExternalCatalogConfig catalogConfig, Configuration hadoopConf) {}
+
+ @Override
+ public InternalAccessControlPolicySnapshot fetchPolicies() {
+ return InternalAccessControlPolicySnapshot.builder().build();
+ }
+
+ @Override
+ public PolicySyncResult pushPolicies(InternalAccessControlPolicySnapshot snapshot) {
+ return PolicySyncResult.builder().build();
+ }
+ }
}