From 534df91349710aa7e20a858ddd68a71ae6450995 Mon Sep 17 00:00:00 2001
From: adishaa <adishaa@amazon.com>
Date: Fri, 16 Jan 2026 07:00:13 -0800
Subject: [PATCH 01/22] feat: Add Feature Store Support to V3

---
 .../sagemaker/mlops/feature_store/__init__.py | 129 ++++
 .../mlops/feature_store/athena_query.py       | 112 +++
 .../mlops/feature_store/dataset_builder.py    | 725 ++++++++++++++++++
 .../mlops/feature_store/feature_definition.py | 107 +++
 .../mlops/feature_store/feature_utils.py      | 488 ++++++++++++
 .../feature_store/ingestion_manager_pandas.py | 321 ++++++++
 .../sagemaker/mlops/feature_store/inputs.py   |  60 ++
 7 files changed, 1942 insertions(+)
 create mode 100644 sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
 create mode 100644 sagemaker-mlops/src/sagemaker/mlops/feature_store/athena_query.py
 create mode 100644 sagemaker-mlops/src/sagemaker/mlops/feature_store/dataset_builder.py
 create mode 100644 sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_definition.py
 create mode 100644 sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py
 create mode 100644 sagemaker-mlops/src/sagemaker/mlops/feature_store/ingestion_manager_pandas.py
 create mode 100644 sagemaker-mlops/src/sagemaker/mlops/feature_store/inputs.py

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
new file mode 100644
index 0000000000..ee8cd7d1a3
--- /dev/null
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
@@ -0,0 +1,129 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
+"""SageMaker FeatureStore V3 - powered by sagemaker-core."""
+
+# Resources from core
+from sagemaker_core.main.resources import FeatureGroup, FeatureMetadata
+from sagemaker_core.main.resources import FeatureStore
+
+# Shapes from core (Pydantic - no to_dict() needed)
+from sagemaker_core.main.shapes import (
+    DataCatalogConfig,
+    FeatureParameter,
+    FeatureValue,
+    Filter,
+    OfflineStoreConfig,
+    OnlineStoreConfig,
+    OnlineStoreSecurityConfig,
+    S3StorageConfig,
+    SearchExpression,
+    ThroughputConfig,
+    TtlDuration,
+)
+
+# Enums (local - core uses strings)
+from sagemaker.mlops.feature_store.inputs import (
+    DeletionModeEnum,
+    ExpirationTimeResponseEnum,
+    FilterOperatorEnum,
+    OnlineStoreStorageTypeEnum,
+    ResourceEnum,
+    SearchOperatorEnum,
+    SortOrderEnum,
+    TableFormatEnum,
+    TargetStoreEnum,
+    ThroughputModeEnum,
+)
+
+# Feature Definition helpers (local)
+from sagemaker.mlops.feature_store.feature_definition import (
+    FeatureDefinition,
+    FeatureTypeEnum,
+    CollectionTypeEnum,
+    FractionalFeatureDefinition,
+    IntegralFeatureDefinition,
+    StringFeatureDefinition,
+    ListCollectionType,
+    SetCollectionType,
+    VectorCollectionType,
+)
+
+# Utility functions (local)
+from sagemaker.mlops.feature_store.feature_utils import (
+    as_hive_ddl,
+    create_athena_query,
+    create_dataset,
+    get_session_from_role,
+    ingest_dataframe,
+    load_feature_definitions_from_dataframe,
+)
+
+# Classes (local)
+from sagemaker.mlops.feature_store.athena_query import AthenaQuery
+from sagemaker.mlops.feature_store.dataset_builder import (
+    DatasetBuilder,
+    FeatureGroupToBeMerged,
+    JoinComparatorEnum,
+    JoinTypeEnum,
+    TableType,
+)
+from sagemaker.mlops.feature_store.ingestion_manager_pandas import (
+    IngestionError,
+    IngestionManagerPandas,
+)
+
+__all__ = [
+    # Resources
+    "FeatureGroup",
+    "FeatureMetadata",
+    "FeatureStore",
+    # Shapes
+    "DataCatalogConfig",
+    "FeatureParameter",
+    "FeatureValue",
+    "Filter",
+    "OfflineStoreConfig",
+    "OnlineStoreConfig",
+    "OnlineStoreSecurityConfig",
+    "S3StorageConfig",
+    "SearchExpression",
+    "ThroughputConfig",
+    "TtlDuration",
+    # Enums
+    "DeletionModeEnum",
+    "ExpirationTimeResponseEnum",
+    "FilterOperatorEnum",
+    "OnlineStoreStorageTypeEnum",
+    "ResourceEnum",
+    "SearchOperatorEnum",
+    "SortOrderEnum",
+    "TableFormatEnum",
+    "TargetStoreEnum",
+    "ThroughputModeEnum",
+    # Feature Definitions
+    "FeatureDefinition",
+    "FeatureTypeEnum",
+    "CollectionTypeEnum",
+    "FractionalFeatureDefinition",
+    "IntegralFeatureDefinition",
+    "StringFeatureDefinition",
+    "ListCollectionType",
+    "SetCollectionType",
+    "VectorCollectionType",
+    # Utility functions
+    "as_hive_ddl",
+    "create_athena_query",
+    "create_dataset",
+    "get_session_from_role",
+    "ingest_dataframe",
+    "load_feature_definitions_from_dataframe",
+    # Classes
+    "AthenaQuery",
+    "DatasetBuilder",
+    "FeatureGroupToBeMerged",
+    "IngestionError",
+    "IngestionManagerPandas",
+    "JoinComparatorEnum",
+    "JoinTypeEnum",
+    "TableType",
+]
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/athena_query.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/athena_query.py
new file mode 100644
index 0000000000..123b3c4305
--- /dev/null
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/athena_query.py
@@ -0,0 +1,112 @@
+import os
+import tempfile
+from dataclasses import dataclass, field
+from typing import Any, Dict
+from urllib.parse import urlparse
+import pandas as pd
+from pandas import DataFrame
+
+from sagemaker.mlops.feature_store.feature_utils import (
+    start_query_execution,
+    get_query_execution,
+    wait_for_athena_query,
+    download_athena_query_result,
+)
+
+from sagemaker.core.helper.session_helper import Session
+
+@dataclass
+class AthenaQuery:
+    """Class to manage querying of feature store data with AWS Athena.
+
+    This class instantiates a AthenaQuery object that is used to retrieve data from feature store
+    via standard SQL queries.
+
+    Attributes:
+        catalog (str): name of the data catalog.
+        database (str): name of the database.
+        table_name (str): name of the table.
+        sagemaker_session (Session): instance of the Session class to perform boto calls.
+    """
+
+    catalog: str
+    database: str
+    table_name: str
+    sagemaker_session: Session
+    _current_query_execution_id: str = field(default=None, init=False)
+    _result_bucket: str = field(default=None, init=False)
+    _result_file_prefix: str = field(default=None, init=False)
+
+    def run(
+        self, query_string: str, output_location: str, kms_key: str = None, workgroup: str = None
+    ) -> str:
+        """Execute a SQL query given a query string, output location and kms key.
+
+        This method executes the SQL query using Athena and outputs the results to output_location
+        and returns the execution id of the query.
+
+        Args:
+            query_string: SQL query string.
+            output_location: S3 URI of the query result.
+            kms_key: KMS key id. If set, will be used to encrypt the query result file.
+            workgroup (str): The name of the workgroup in which the query is being started.
+
+        Returns:
+            Execution id of the query.
+        """
+        response = start_query_execution(
+            session=self.sagemaker_session,
+            catalog=self.catalog,
+            database=self.database,
+            query_string=query_string,
+            output_location=output_location,
+            kms_key=kms_key,
+            workgroup=workgroup,
+        )
+
+        self._current_query_execution_id = response["QueryExecutionId"]
+        parsed_result = urlparse(output_location, allow_fragments=False)
+        self._result_bucket = parsed_result.netloc
+        self._result_file_prefix = parsed_result.path.strip("/")
+        return self._current_query_execution_id
+
+    def wait(self):
+        """Wait for the current query to finish."""
+        wait_for_athena_query(self.sagemaker_session, self._current_query_execution_id)
+
+    def get_query_execution(self) -> Dict[str, Any]:
+        """Get execution status of the current query.
+
+        Returns:
+            Response dict from Athena.
+        """
+        return get_query_execution(self.sagemaker_session, self._current_query_execution_id)
+
+    def as_dataframe(self, **kwargs) -> DataFrame:
+        """Download the result of the current query and load it into a DataFrame.
+
+        Args:
+            **kwargs (object): key arguments used for the method pandas.read_csv to be able to
+                    have a better tuning on data. For more info read:
+                    https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html
+
+        Returns:
+            A pandas DataFrame contains the query result.
+        """
+        state = self.get_query_execution()["QueryExecution"]["Status"]["State"]
+        if state != "SUCCEEDED":
+            if state in ("QUEUED", "RUNNING"):
+                raise RuntimeError(f"Query {self._current_query_execution_id} still executing.")
+            raise RuntimeError(f"Query {self._current_query_execution_id} failed.")
+
+        output_file = os.path.join(tempfile.gettempdir(), f"{self._current_query_execution_id}.csv")
+        download_athena_query_result(
+            session=self.sagemaker_session,
+            bucket=self._result_bucket,
+            prefix=self._result_file_prefix,
+            query_execution_id=self._current_query_execution_id,
+            filename=output_file,
+        )
+        kwargs.pop("delimiter", None)
+        return pd.read_csv(output_file, delimiter=",", **kwargs)
+
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/dataset_builder.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/dataset_builder.py
new file mode 100644
index 0000000000..f5450663a6
--- /dev/null
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/dataset_builder.py
@@ -0,0 +1,725 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
+"""Dataset Builder for FeatureStore."""
+from dataclasses import dataclass, field
+from enum import Enum
+from typing import Any, Dict, List, Union
+import datetime
+
+import pandas as pd
+
+from sagemaker.core.helper.session_helper import Session
+from sagemaker.mlops.feature_store import FeatureGroup
+from sagemaker.mlops.feature_store.feature_definition import FeatureDefinition, FeatureTypeEnum
+from sagemaker.mlops.feature_store.feature_utils import (
+    upload_dataframe_to_s3,
+    download_csv_from_s3,
+    run_athena_query,
+)
+
+_DEFAULT_CATALOG = "AwsDataCatalog"
+_DEFAULT_DATABASE = "sagemaker_featurestore"
+
+_DTYPE_TO_FEATURE_TYPE = {
+    "object": "String", "string": "String",
+    "int64": "Integral", "int32": "Integral",
+    "float64": "Fractional", "float32": "Fractional",
+}
+
+_DTYPE_TO_ATHENA_TYPE = {
+    "object": "STRING", "int64": "INT", "float64": "DOUBLE",
+    "bool": "BOOLEAN", "datetime64[ns]": "TIMESTAMP",
+}
+
+
+class TableType(Enum):
+    FEATURE_GROUP = "FeatureGroup"
+    DATA_FRAME = "DataFrame"
+
+
+class JoinTypeEnum(Enum):
+    INNER_JOIN = "JOIN"
+    LEFT_JOIN = "LEFT JOIN"
+    RIGHT_JOIN = "RIGHT JOIN"
+    FULL_JOIN = "FULL JOIN"
+    CROSS_JOIN = "CROSS JOIN"
+
+
+class JoinComparatorEnum(Enum):
+    EQUALS = "="
+    GREATER_THAN = ">"
+    GREATER_THAN_OR_EQUAL_TO = ">="
+    LESS_THAN = "<"
+    LESS_THAN_OR_EQUAL_TO = "<="
+    NOT_EQUAL_TO = "<>"
+
+
+@dataclass
+class FeatureGroupToBeMerged:
+    """FeatureGroup metadata which will be used for SQL join.
+
+    This class instantiates a FeatureGroupToBeMerged object that comprises a list of feature names,
+    a list of feature names which will be included in SQL query, a database, an Athena table name,
+    a feature name of record identifier, a feature name of event time identifier and a feature name
+    of base which is the target join key.
+
+    Attributes:
+        features (List[str]): A list of strings representing feature names of this FeatureGroup.
+        included_feature_names (List[str]): A list of strings representing features to be
+            included in the SQL join.
+        projected_feature_names (List[str]): A list of strings representing features to be
+            included for final projection in output.
+        catalog (str): A string representing the catalog.
+        database (str): A string representing the database.
+        table_name (str): A string representing the Athena table name of this FeatureGroup.
+        record_identifier_feature_name (str): A string representing the record identifier feature.
+        event_time_identifier_feature (FeatureDefinition): A FeatureDefinition representing the
+            event time identifier feature.
+        target_feature_name_in_base (str): A string representing the feature name in base which will
+            be used as target join key (default: None).
+        table_type (TableType): A TableType representing the type of table if it is Feature Group or
+            Panda Data Frame (default: None).
+        feature_name_in_target (str): A string representing the feature name in the target feature
+            group that will be compared to the target feature in the base feature group.
+            If None is provided, the record identifier feature will be used in the
+            SQL join. (default: None).
+        join_comparator (JoinComparatorEnum): A JoinComparatorEnum representing the comparator
+            used when joining the target feature in the base feature group and the feature
+            in the target feature group. (default: JoinComparatorEnum.EQUALS).
+        join_type (JoinTypeEnum): A JoinTypeEnum representing the type of join between
+            the base and target feature groups. (default: JoinTypeEnum.INNER_JOIN).
+    """
+    features: List[str]
+    included_feature_names: List[str]
+    projected_feature_names: List[str]
+    catalog: str
+    database: str
+    table_name: str
+    record_identifier_feature_name: str
+    event_time_identifier_feature: FeatureDefinition
+    target_feature_name_in_base: str = None
+    table_type: TableType = None
+    feature_name_in_target: str = None
+    join_comparator: JoinComparatorEnum = JoinComparatorEnum.EQUALS
+    join_type: JoinTypeEnum = JoinTypeEnum.INNER_JOIN
+
+
+def construct_feature_group_to_be_merged(
+    target_feature_group: FeatureGroup,
+    included_feature_names: List[str],
+    target_feature_name_in_base: str = None,
+    feature_name_in_target: str = None,
+    join_comparator: JoinComparatorEnum = JoinComparatorEnum.EQUALS,
+    join_type: JoinTypeEnum = JoinTypeEnum.INNER_JOIN,
+) -> FeatureGroupToBeMerged:
+    """Construct a FeatureGroupToBeMerged object by provided parameters.
+
+    Args:
+        target_feature_group (FeatureGroup): A FeatureGroup object.
+        included_feature_names (List[str]): A list of strings representing features to be
+            included in the output.
+        target_feature_name_in_base (str): A string representing the feature name in base which
+            will be used as target join key (default: None).
+        feature_name_in_target (str): A string representing the feature name in the target feature
+            group that will be compared to the target feature in the base feature group.
+            If None is provided, the record identifier feature will be used in the
+            SQL join. (default: None).
+        join_comparator (JoinComparatorEnum): A JoinComparatorEnum representing the comparator
+            used when joining the target feature in the base feature group and the feature
+            in the target feature group. (default: JoinComparatorEnum.EQUALS).
+        join_type (JoinTypeEnum): A JoinTypeEnum representing the type of join between
+            the base and target feature groups. (default: JoinTypeEnum.INNER_JOIN).
+
+    Returns:
+        A FeatureGroupToBeMerged object.
+
+    Raises:
+        RuntimeError: No metastore is configured with the FeatureGroup.
+        ValueError: Invalid feature name(s) in included_feature_names.
+    """
+    fg = FeatureGroup.get(feature_group_name=target_feature_group.feature_group_name)
+
+    if not fg.offline_store_config or not fg.offline_store_config.data_catalog_config:
+        raise RuntimeError(f"No metastore configured for FeatureGroup {fg.feature_group_name}.")
+
+    catalog_config = fg.offline_store_config.data_catalog_config
+    disable_glue = catalog_config.disable_glue_table_creation or False
+
+    features = [fd.feature_name for fd in fg.feature_definitions]
+    record_id = fg.record_identifier_feature_name
+    event_time_name = fg.event_time_feature_name
+    event_time_type = next(
+        (fd.feature_type for fd in fg.feature_definitions if fd.feature_name == event_time_name),
+        None
+    )
+
+    if feature_name_in_target and feature_name_in_target not in features:
+        raise ValueError(f"Feature {feature_name_in_target} not found in {fg.feature_group_name}")
+
+    for feat in included_feature_names or []:
+        if feat not in features:
+            raise ValueError(f"Feature {feat} not found in {fg.feature_group_name}")
+
+    if not included_feature_names:
+        included_feature_names = features.copy()
+        projected_feature_names = features.copy()
+    else:
+        projected_feature_names = included_feature_names.copy()
+        if record_id not in included_feature_names:
+            included_feature_names.append(record_id)
+        if event_time_name not in included_feature_names:
+            included_feature_names.append(event_time_name)
+
+    return FeatureGroupToBeMerged(
+        features=features,
+        included_feature_names=included_feature_names,
+        projected_feature_names=projected_feature_names,
+        catalog=catalog_config.catalog if disable_glue else _DEFAULT_CATALOG,
+        database=catalog_config.database,
+        table_name=catalog_config.table_name,
+        record_identifier_feature_name=record_id,
+        event_time_identifier_feature=FeatureDefinition(event_time_name, FeatureTypeEnum(event_time_type)),
+        target_feature_name_in_base=target_feature_name_in_base,
+        table_type=TableType.FEATURE_GROUP,
+        feature_name_in_target=feature_name_in_target,
+        join_comparator=join_comparator,
+        join_type=join_type,
+    )
+
+
+@dataclass
+class DatasetBuilder:
+    """DatasetBuilder definition.
+
+    This class instantiates a DatasetBuilder object that comprises a base, a list of feature names,
+    an output path and a KMS key ID.
+
+    Attributes:
+        _sagemaker_session (Session): Session instance to perform boto calls.
+        _base (Union[FeatureGroup, DataFrame]): A base which can be either a FeatureGroup or a
+            pandas.DataFrame and will be used to merge other FeatureGroups and generate a Dataset.
+        _output_path (str): An S3 URI which stores the output .csv file.
+        _record_identifier_feature_name (str): A string representing the record identifier feature
+            if base is a DataFrame (default: None).
+        _event_time_identifier_feature_name (str): A string representing the event time identifier
+            feature if base is a DataFrame (default: None).
+        _included_feature_names (List[str]): A list of strings representing features to be
+            included in the output. If not set, all features will be included in the output.
+            (default: None).
+        _kms_key_id (str): A KMS key id. If set, will be used to encrypt the result file
+            (default: None).
+        _point_in_time_accurate_join (bool): A boolean representing if point-in-time join
+            is applied to the resulting dataframe when calling "to_dataframe".
+            When set to True, users can retrieve data using "row-level time travel"
+            according to the event times provided to the DatasetBuilder. This requires that the
+            entity dataframe with event times is submitted as the base in the constructor
+            (default: False).
+        _include_duplicated_records (bool): A boolean representing whether the resulting dataframe
+            when calling "to_dataframe" should include duplicated records (default: False).
+        _include_deleted_records (bool): A boolean representing whether the resulting
+            dataframe when calling "to_dataframe" should include deleted records (default: False).
+        _number_of_recent_records (int): An integer representing how many records will be
+            returned for each record identifier (default: 1).
+        _number_of_records (int): An integer representing the number of records that should be
+            returned in the resulting dataframe when calling "to_dataframe" (default: None).
+        _write_time_ending_timestamp (datetime.datetime): A datetime that represents the latest
+            write time for a record to be included in the resulting dataset. Records with a
+            newer write time will be omitted from the resulting dataset. (default: None).
+        _event_time_starting_timestamp (datetime.datetime): A datetime that represents the earliest
+            event time for a record to be included in the resulting dataset. Records
+            with an older event time will be omitted from the resulting dataset. (default: None).
+        _event_time_ending_timestamp (datetime.datetime): A datetime that represents the latest
+            event time for a record to be included in the resulting dataset. Records
+            with a newer event time will be omitted from the resulting dataset. (default: None).
+        _feature_groups_to_be_merged (List[FeatureGroupToBeMerged]): A list of
+            FeatureGroupToBeMerged which will be joined to base (default: []).
+        _event_time_identifier_feature_type (FeatureTypeEnum): A FeatureTypeEnum representing the
+            type of event time identifier feature (default: None).
+    """
+
+    _sagemaker_session: Session
+    _base: Union[FeatureGroup, pd.DataFrame]
+    _output_path: str
+    _record_identifier_feature_name: str = None
+    _event_time_identifier_feature_name: str = None
+    _included_feature_names: List[str] = None
+    _kms_key_id: str = None
+    _event_time_identifier_feature_type: FeatureTypeEnum = None
+
+    _point_in_time_accurate_join: bool = field(default=False, init=False)
+    _include_duplicated_records: bool = field(default=False, init=False)
+    _include_deleted_records: bool = field(default=False, init=False)
+    _number_of_recent_records: int = field(default=None, init=False)
+    _number_of_records: int = field(default=None, init=False)
+    _write_time_ending_timestamp: datetime.datetime = field(default=None, init=False)
+    _event_time_starting_timestamp: datetime.datetime = field(default=None, init=False)
+    _event_time_ending_timestamp: datetime.datetime = field(default=None, init=False)
+    _feature_groups_to_be_merged: List[FeatureGroupToBeMerged] = field(default_factory=list, init=False)
+
+    def with_feature_group(
+        self,
+        feature_group: FeatureGroup,
+        target_feature_name_in_base: str = None,
+        included_feature_names: List[str] = None,
+        feature_name_in_target: str = None,
+        join_comparator: JoinComparatorEnum = JoinComparatorEnum.EQUALS,
+        join_type: JoinTypeEnum = JoinTypeEnum.INNER_JOIN,
+    ) -> "DatasetBuilder":
+        """Join FeatureGroup with base.
+
+        Args:
+            feature_group (FeatureGroup): A target FeatureGroup which will be joined to base.
+            target_feature_name_in_base (str): A string representing the feature name in base which
+                will be used as a join key (default: None).
+            included_feature_names (List[str]): A list of strings representing features to be
+                included in the output (default: None).
+            feature_name_in_target (str): A string representing the feature name in the target
+                feature group that will be compared to the target feature in the base feature group.
+                If None is provided, the record identifier feature will be used in the
+                SQL join. (default: None).
+            join_comparator (JoinComparatorEnum): A JoinComparatorEnum representing the comparator
+                used when joining the target feature in the base feature group and the feature
+                in the target feature group. (default: JoinComparatorEnum.EQUALS).
+            join_type (JoinTypeEnum): A JoinTypeEnum representing the type of join between
+                the base and target feature groups. (default: JoinTypeEnum.INNER_JOIN).
+
+        Returns:
+            This DatasetBuilder object.
+        """
+        self._feature_groups_to_be_merged.append(
+            construct_feature_group_to_be_merged(
+                feature_group, included_feature_names, target_feature_name_in_base,
+                feature_name_in_target, join_comparator, join_type,
+            )
+        )
+        return self
+
+    def point_in_time_accurate_join(self) -> "DatasetBuilder":
+        """Enable point-in-time accurate join.
+
+        Returns:
+            This DatasetBuilder object.
+        """
+        self._point_in_time_accurate_join = True
+        return self
+
+    def include_duplicated_records(self) -> "DatasetBuilder":
+        """Include duplicated records in dataset.
+
+        Returns:
+            This DatasetBuilder object.
+        """
+        self._include_duplicated_records = True
+        return self
+
+    def include_deleted_records(self) -> "DatasetBuilder":
+        """Include deleted records in dataset.
+
+        Returns:
+            This DatasetBuilder object.
+        """
+        self._include_deleted_records = True
+        return self
+
+    def with_number_of_recent_records_by_record_identifier(self, n: int) -> "DatasetBuilder":
+        """Set number_of_recent_records field with provided input.
+
+        Args:
+            n (int): An int that how many recent records will be returned for
+                each record identifier.
+
+        Returns:
+            This DatasetBuilder object.
+        """
+        self._number_of_recent_records = n
+        return self
+
+    def with_number_of_records_from_query_results(self, n: int) -> "DatasetBuilder":
+        """Set number_of_records field with provided input.
+
+        Args:
+            n (int): An int that how many records will be returned.
+
+        Returns:
+            This DatasetBuilder object.
+        """
+        self._number_of_records = n
+        return self
+
+    def as_of(self, timestamp: datetime.datetime) -> "DatasetBuilder":
+        """Set write_time_ending_timestamp field with provided input.
+
+        Args:
+            timestamp (datetime.datetime): A datetime that all records' write time in dataset will
+                be before it.
+
+        Returns:
+            This DatasetBuilder object.
+        """
+        self._write_time_ending_timestamp = timestamp
+        return self
+
+    def with_event_time_range(
+        self,
+        starting_timestamp: datetime.datetime = None,
+        ending_timestamp: datetime.datetime = None,
+    ) -> "DatasetBuilder":
+        """Set event_time_starting_timestamp and event_time_ending_timestamp with provided inputs.
+
+        Args:
+            starting_timestamp (datetime.datetime): A datetime that all records' event time in
+                dataset will be after it (default: None).
+            ending_timestamp (datetime.datetime): A datetime that all records' event time in dataset
+                will be before it (default: None).
+
+        Returns:
+            This DatasetBuilder object.
+        """
+        self._event_time_starting_timestamp = starting_timestamp
+        self._event_time_ending_timestamp = ending_timestamp
+        return self
+
+    def to_csv_file(self) -> tuple[str, str]:
+        """Get query string and result in .csv format file.
+
+        Returns:
+            The S3 path of the .csv file.
+            The query string executed.
+        """
+        if isinstance(self._base, pd.DataFrame):
+            return self._to_csv_from_dataframe()
+        if isinstance(self._base, FeatureGroup):
+            return self._to_csv_from_feature_group()
+        raise ValueError("Base must be either a FeatureGroup or a DataFrame.")
+
+    def to_dataframe(self) -> tuple[pd.DataFrame, str]:
+        """Get query string and result in pandas.DataFrame.
+
+        Returns:
+            The pandas.DataFrame object.
+            The query string executed.
+        """
+        csv_file, query_string = self.to_csv_file()
+        df = download_csv_from_s3(csv_file, self._sagemaker_session, self._kms_key_id)
+        if "row_recent" in df.columns:
+            df = df.drop("row_recent", axis="columns")
+        return df, query_string
+
+
+    def _to_csv_from_dataframe(self) -> tuple[str, str]:
+        s3_folder, temp_table_name = upload_dataframe_to_s3(
+            self._base, self._output_path, self._sagemaker_session, self._kms_key_id
+        )
+        self._create_temp_table(temp_table_name, s3_folder)
+
+        base_features = list(self._base.columns)
+        event_time_dtype = str(self._base[self._event_time_identifier_feature_name].dtypes)
+        self._event_time_identifier_feature_type = FeatureTypeEnum(
+            _DTYPE_TO_FEATURE_TYPE.get(event_time_dtype, "String")
+        )
+
+        included = self._included_feature_names or base_features
+        fg_to_merge = FeatureGroupToBeMerged(
+            features=base_features,
+            included_feature_names=included,
+            projected_feature_names=included,
+            catalog=_DEFAULT_CATALOG,
+            database=_DEFAULT_DATABASE,
+            table_name=temp_table_name,
+            record_identifier_feature_name=self._record_identifier_feature_name,
+            event_time_identifier_feature=FeatureDefinition(
+                self._event_time_identifier_feature_name,
+                self._event_time_identifier_feature_type,
+            ),
+            table_type=TableType.DATA_FRAME,
+        )
+
+        query_string = self._construct_query_string(fg_to_merge)
+        result = self._run_query(query_string, _DEFAULT_CATALOG, _DEFAULT_DATABASE)
+        return self._extract_result(result)
+
+    def _to_csv_from_feature_group(self) -> tuple[str, str]:
+        base_fg = construct_feature_group_to_be_merged(self._base, self._included_feature_names)
+        self._record_identifier_feature_name = base_fg.record_identifier_feature_name
+        self._event_time_identifier_feature_name = base_fg.event_time_identifier_feature.feature_name
+        self._event_time_identifier_feature_type = base_fg.event_time_identifier_feature.feature_type
+
+        query_string = self._construct_query_string(base_fg)
+        result = self._run_query(query_string, base_fg.catalog, base_fg.database)
+        return self._extract_result(result)
+
+    def _extract_result(self, query_result: dict) -> tuple[str, str]:
+        execution = query_result.get("QueryExecution", {})
+        return (
+            execution.get("ResultConfiguration", {}).get("OutputLocation"),
+            execution.get("Query"),
+        )
+
+    def _run_query(self, query_string: str, catalog: str, database: str) -> Dict[str, Any]:
+        return run_athena_query(
+            session=self._sagemaker_session,
+            catalog=catalog,
+            database=database,
+            query_string=query_string,
+            output_location=self._output_path,
+            kms_key=self._kms_key_id,
+        )
+
+    def _create_temp_table(self, temp_table_name: str, s3_folder: str):
+        columns = ", ".join(
+            f"{col} {_DTYPE_TO_ATHENA_TYPE.get(str(self._base[col].dtypes), 'STRING')}"
+            for col in self._base.columns
+        )
+        serde = '"separatorChar" = ",", "quoteChar" = "`", "escapeChar" = "\\\\"'
+        query = (
+            f"CREATE EXTERNAL TABLE {temp_table_name} ({columns}) "
+            f"ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde' "
+            f"WITH SERDEPROPERTIES ({serde}) LOCATION '{s3_folder}';"
+        )
+        self._run_query(query, _DEFAULT_CATALOG, _DEFAULT_DATABASE)
+
+
+    def _construct_query_string(self, base: FeatureGroupToBeMerged) -> str:
+        base_query = self._construct_table_query(base, "base")
+        query = f"WITH fg_base AS ({base_query})"
+
+        for i, fg in enumerate(self._feature_groups_to_be_merged):
+            fg_query = self._construct_table_query(fg, str(i))
+            query += f",\nfg_{i} AS ({fg_query})"
+
+        selected = ", ".join(f"fg_base.{f}" for f in base.projected_feature_names)
+        selected_final = ", ".join(base.projected_feature_names)
+
+        for i, fg in enumerate(self._feature_groups_to_be_merged):
+            selected += ", " + ", ".join(
+                f'fg_{i}."{f}" as "{f}.{i+1}"' for f in fg.projected_feature_names
+            )
+            selected_final += ", " + ", ".join(
+                f'"{f}.{i+1}"' for f in fg.projected_feature_names
+            )
+
+        query += (
+            f"\nSELECT {selected_final}\nFROM (\n"
+            f"SELECT {selected}, row_number() OVER (\n"
+            f'PARTITION BY fg_base."{base.record_identifier_feature_name}"\n'
+            f'ORDER BY fg_base."{base.event_time_identifier_feature.feature_name}" DESC'
+        )
+
+        join_strings = []
+        for i, fg in enumerate(self._feature_groups_to_be_merged):
+            if not fg.target_feature_name_in_base:
+                fg.target_feature_name_in_base = self._record_identifier_feature_name
+            elif fg.target_feature_name_in_base not in base.features:
+                raise ValueError(f"Feature {fg.target_feature_name_in_base} not found in base")
+            query += f', fg_{i}."{fg.event_time_identifier_feature.feature_name}" DESC'
+            join_strings.append(self._construct_join_condition(fg, str(i)))
+
+        recent_where = ""
+        if self._number_of_recent_records is not None and self._number_of_recent_records >= 0:
+            recent_where = f"WHERE row_recent <= {self._number_of_recent_records}"
+
+        query += f"\n) AS row_recent\nFROM fg_base{''.join(join_strings)}\n)\n{recent_where}"
+
+        if self._number_of_records is not None and self._number_of_records >= 0:
+            query += f"\nLIMIT {self._number_of_records}"
+
+        return query
+
+    def _construct_table_query(self, fg: FeatureGroupToBeMerged, suffix: str) -> str:
+        included = ", ".join(f'table_{suffix}."{f}"' for f in fg.included_feature_names)
+        included_with_write = included
+        if fg.table_type is TableType.FEATURE_GROUP:
+            included_with_write += f', table_{suffix}."write_time"'
+
+        record_id = fg.record_identifier_feature_name
+        event_time = fg.event_time_identifier_feature.feature_name
+
+        if self._include_duplicated_records and self._include_deleted_records:
+            return (
+                f"SELECT {included}\n"
+                f'FROM "{fg.database}"."{fg.table_name}" table_{suffix}\n'
+                + self._construct_where_query_string(suffix, fg.event_time_identifier_feature, ["NOT is_deleted"])
+            )
+
+        if fg.table_type is TableType.FEATURE_GROUP and self._include_deleted_records:
+            rank = f'ORDER BY origin_{suffix}."api_invocation_time" DESC, origin_{suffix}."write_time" DESC\n'
+            return (
+                f"SELECT {included}\nFROM (\n"
+                f"SELECT *, row_number() OVER (\n"
+                f'PARTITION BY origin_{suffix}."{record_id}", origin_{suffix}."{event_time}"\n'
+                f"{rank}) AS row_{suffix}\n"
+                f'FROM "{fg.database}"."{fg.table_name}" origin_{suffix}\n'
+                f"WHERE NOT is_deleted) AS table_{suffix}\n"
+                + self._construct_where_query_string(suffix, fg.event_time_identifier_feature, [f"row_{suffix} = 1"])
+            )
+
+        if fg.table_type is TableType.FEATURE_GROUP:
+            dedup = self._construct_dedup_query(fg, suffix)
+            deleted = self._construct_deleted_query(fg, suffix)
+            rank_cond = (
+                f'OR (table_{suffix}."{event_time}" = deleted_{suffix}."{event_time}" '
+                f'AND table_{suffix}."api_invocation_time" > deleted_{suffix}."api_invocation_time")\n'
+                f'OR (table_{suffix}."{event_time}" = deleted_{suffix}."{event_time}" '
+                f'AND table_{suffix}."api_invocation_time" = deleted_{suffix}."api_invocation_time" '
+                f'AND table_{suffix}."write_time" > deleted_{suffix}."write_time")\n'
+            )
+
+            if self._include_duplicated_records:
+                return (
+                    f"WITH {deleted}\n"
+                    f"SELECT {included}\nFROM (\n"
+                    f"SELECT {included_with_write}\n"
+                    f'FROM "{fg.database}"."{fg.table_name}" table_{suffix}\n'
+                    f"LEFT JOIN deleted_{suffix} ON table_{suffix}.\"{record_id}\" = deleted_{suffix}.\"{record_id}\"\n"
+                    f'WHERE deleted_{suffix}."{record_id}" IS NULL\n'
+                    f"UNION ALL\n"
+                    f"SELECT {included_with_write}\nFROM deleted_{suffix}\n"
+                    f'JOIN "{fg.database}"."{fg.table_name}" table_{suffix}\n'
+                    f'ON table_{suffix}."{record_id}" = deleted_{suffix}."{record_id}"\n'
+                    f'AND (table_{suffix}."{event_time}" > deleted_{suffix}."{event_time}"\n{rank_cond})\n'
+                    f") AS table_{suffix}\n"
+                    + self._construct_where_query_string(suffix, fg.event_time_identifier_feature, [])
+                )
+
+            return (
+                f"WITH {dedup},\n{deleted}\n"
+                f"SELECT {included}\nFROM (\n"
+                f"SELECT {included_with_write}\nFROM table_{suffix}\n"
+                f"LEFT JOIN deleted_{suffix} ON table_{suffix}.\"{record_id}\" = deleted_{suffix}.\"{record_id}\"\n"
+                f'WHERE deleted_{suffix}."{record_id}" IS NULL\n'
+                f"UNION ALL\n"
+                f"SELECT {included_with_write}\nFROM deleted_{suffix}\n"
+                f"JOIN table_{suffix} ON table_{suffix}.\"{record_id}\" = deleted_{suffix}.\"{record_id}\"\n"
+                f'AND (table_{suffix}."{event_time}" > deleted_{suffix}."{event_time}"\n{rank_cond})\n'
+                f") AS table_{suffix}\n"
+                + self._construct_where_query_string(suffix, fg.event_time_identifier_feature, [])
+            )
+
+        dedup = self._construct_dedup_query(fg, suffix)
+        return (
+            f"WITH {dedup}\n"
+            f"SELECT {included}\nFROM (\n"
+            f"SELECT {included_with_write}\nFROM table_{suffix}\n"
+            f") AS table_{suffix}\n"
+            + self._construct_where_query_string(suffix, fg.event_time_identifier_feature, [])
+        )
+
+    def _construct_dedup_query(self, fg: FeatureGroupToBeMerged, suffix: str) -> str:
+        record_id = fg.record_identifier_feature_name
+        event_time = fg.event_time_identifier_feature.feature_name
+        rank = ""
+        is_fg = fg.table_type is TableType.FEATURE_GROUP
+
+        if is_fg:
+            rank = f'ORDER BY origin_{suffix}."api_invocation_time" DESC, origin_{suffix}."write_time" DESC\n'
+
+        where_conds = []
+        if is_fg and self._write_time_ending_timestamp:
+            where_conds.append(self._construct_write_time_condition(f"origin_{suffix}"))
+        where_conds.extend(self._construct_event_time_conditions(f"origin_{suffix}", fg.event_time_identifier_feature))
+        where_str = f"WHERE {' AND '.join(where_conds)}\n" if where_conds else ""
+
+        dedup_where = f"WHERE dedup_row_{suffix} = 1\n" if is_fg else ""
+
+        return (
+            f"table_{suffix} AS (\n"
+            f"SELECT *\nFROM (\n"
+            f"SELECT *, row_number() OVER (\n"
+            f'PARTITION BY origin_{suffix}."{record_id}", origin_{suffix}."{event_time}"\n'
+            f"{rank}) AS dedup_row_{suffix}\n"
+            f'FROM "{fg.database}"."{fg.table_name}" origin_{suffix}\n'
+            f"{where_str})\n{dedup_where})"
+        )
+
+    def _construct_deleted_query(self, fg: FeatureGroupToBeMerged, suffix: str) -> str:
+        record_id = fg.record_identifier_feature_name
+        event_time = fg.event_time_identifier_feature.feature_name
+        rank = f'ORDER BY origin_{suffix}."{event_time}" DESC'
+
+        if fg.table_type is TableType.FEATURE_GROUP:
+            rank += f', origin_{suffix}."api_invocation_time" DESC, origin_{suffix}."write_time" DESC\n'
+
+        write_cond = ""
+        if fg.table_type is TableType.FEATURE_GROUP and self._write_time_ending_timestamp:
+            write_cond = f" AND {self._construct_write_time_condition(f'origin_{suffix}')}\n"
+
+        event_conds = ""
+        if self._event_time_starting_timestamp and self._event_time_ending_timestamp:
+            conds = self._construct_event_time_conditions(f"origin_{suffix}", fg.event_time_identifier_feature)
+            event_conds = "".join(f"AND {c}\n" for c in conds)
+
+        return (
+            f"deleted_{suffix} AS (\n"
+            f"SELECT *\nFROM (\n"
+            f"SELECT *, row_number() OVER (\n"
+            f'PARTITION BY origin_{suffix}."{record_id}"\n'
+            f"{rank}) AS deleted_row_{suffix}\n"
+            f'FROM "{fg.database}"."{fg.table_name}" origin_{suffix}\n'
+            f"WHERE is_deleted{write_cond}{event_conds})\n"
+            f"WHERE deleted_row_{suffix} = 1\n)"
+        )
+
+    def _construct_where_query_string(
+        self, suffix: str, event_time_feature: FeatureDefinition, conditions: List[str]
+    ) -> str:
+        self._validate_options()
+
+        if isinstance(self._base, FeatureGroup) and self._write_time_ending_timestamp:
+            conditions.append(self._construct_write_time_condition(f"table_{suffix}"))
+
+        conditions.extend(self._construct_event_time_conditions(f"table_{suffix}", event_time_feature))
+        return f"WHERE {' AND '.join(conditions)}" if conditions else ""
+
+    def _validate_options(self):
+        is_df_base = isinstance(self._base, pd.DataFrame)
+        no_joins = len(self._feature_groups_to_be_merged) == 0
+
+        if self._number_of_recent_records is not None and self._number_of_recent_records < 0:
+            raise ValueError("number_of_recent_records must be non-negative.")
+        if self._number_of_records is not None and self._number_of_records < 0:
+            raise ValueError("number_of_records must be non-negative.")
+        if is_df_base and no_joins:
+            if self._include_deleted_records:
+                raise ValueError("include_deleted_records() only works for FeatureGroup if no join.")
+            if self._include_duplicated_records:
+                raise ValueError("include_duplicated_records() only works for FeatureGroup if no join.")
+            if self._write_time_ending_timestamp:
+                raise ValueError("as_of() only works for FeatureGroup if no join.")
+        if self._point_in_time_accurate_join and no_joins:
+            raise ValueError("point_in_time_accurate_join() requires at least one join.")
+
+    def _construct_event_time_conditions(self, table: str, event_time_feature: FeatureDefinition) -> List[str]:
+        cast_fn = "from_iso8601_timestamp" if event_time_feature.feature_type == FeatureTypeEnum.STRING else "from_unixtime"
+        conditions = []
+        if self._event_time_starting_timestamp:
+            conditions.append(
+                f'{cast_fn}({table}."{event_time_feature.feature_name}") >= '
+                f"from_unixtime({self._event_time_starting_timestamp.timestamp()})"
+            )
+        if self._event_time_ending_timestamp:
+            conditions.append(
+                f'{cast_fn}({table}."{event_time_feature.feature_name}") <= '
+                f"from_unixtime({self._event_time_ending_timestamp.timestamp()})"
+            )
+        return conditions
+
+    def _construct_write_time_condition(self, table: str) -> str:
+        ts = self._write_time_ending_timestamp.replace(microsecond=0)
+        return f'{table}."write_time" <= to_timestamp(\'{ts}\', \'yyyy-mm-dd hh24:mi:ss\')'
+
+    def _construct_join_condition(self, fg: FeatureGroupToBeMerged, suffix: str) -> str:
+        target_feature = fg.feature_name_in_target or fg.record_identifier_feature_name
+        join = (
+            f"\n{fg.join_type.value} fg_{suffix}\n"
+            f'ON fg_base."{fg.target_feature_name_in_base}" {fg.join_comparator.value} fg_{suffix}."{target_feature}"'
+        )
+
+        if self._point_in_time_accurate_join:
+            base_cast = "from_iso8601_timestamp" if self._event_time_identifier_feature_type == FeatureTypeEnum.STRING else "from_unixtime"
+            fg_cast = "from_iso8601_timestamp" if fg.event_time_identifier_feature.feature_type == FeatureTypeEnum.STRING else "from_unixtime"
+            join += (
+                f'\nAND {base_cast}(fg_base."{self._event_time_identifier_feature_name}") >= '
+                f'{fg_cast}(fg_{suffix}."{fg.event_time_identifier_feature.feature_name}")'
+            )
+
+        return join
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_definition.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_definition.py
new file mode 100644
index 0000000000..32408e5585
--- /dev/null
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_definition.py
@@ -0,0 +1,107 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"). You
+# may not use this file except in compliance with the License. A copy of
+# the License is located at
+#
+#     http://aws.amazon.com/apache2.0/
+#
+# or in the "license" file accompanying this file. This file 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.
+"""Feature Definitions for FeatureStore."""
+from __future__ import absolute_import
+
+from enum import Enum
+from typing import Optional, Union
+
+from sagemaker.core.shapes import (
+    FeatureDefinition,
+    CollectionConfig,
+    VectorConfig,
+)
+
+class FeatureTypeEnum(Enum):
+    """Feature data types: Fractional, Integral, or String."""
+
+    FRACTIONAL = "Fractional"
+    INTEGRAL = "Integral"
+    STRING = "String"
+
+class CollectionTypeEnum(Enum):
+    """Collection types: List, Set, or Vector."""
+
+    LIST = "List"
+    SET = "Set"
+    VECTOR = "Vector"
+
+class ListCollectionType:
+    """List collection type."""
+
+    collection_type = CollectionTypeEnum.LIST.value
+    collection_config = None
+
+class SetCollectionType:
+    """Set collection type."""
+
+    collection_type = CollectionTypeEnum.SET.value
+    collection_config = None
+
+class VectorCollectionType:
+    """Vector collection type with dimension."""
+
+    collection_type = CollectionTypeEnum.VECTOR.value
+
+    def __init__(self, dimension: int):
+        self.collection_config = CollectionConfig(
+            vector_config=VectorConfig(dimension=dimension)
+        )
+
+CollectionType = Union[ListCollectionType, SetCollectionType, VectorCollectionType]
+
+def _create_feature_definition(
+        feature_name: str,
+        feature_type: FeatureTypeEnum,
+        collection_type: Optional[CollectionType] = None,
+) -> FeatureDefinition:
+    """Internal helper to create FeatureDefinition from collection type."""
+    return FeatureDefinition(
+        feature_name=feature_name,
+        feature_type=feature_type.value,
+        collection_type=collection_type.collection_type if collection_type else None,
+        collection_config=collection_type.collection_config if collection_type else None,
+    )
+
+def FractionalFeatureDefinition(
+        feature_name: str,
+        collection_type: Optional[CollectionType] = None,
+) -> FeatureDefinition:
+    """Create a feature definition with Fractional type."""
+    return _create_feature_definition(feature_name, FeatureTypeEnum.FRACTIONAL, collection_type)
+
+def IntegralFeatureDefinition(
+        feature_name: str,
+        collection_type: Optional[CollectionType] = None,
+) -> FeatureDefinition:
+    """Create a feature definition with Integral type."""
+    return _create_feature_definition(feature_name, FeatureTypeEnum.INTEGRAL, collection_type)
+
+def StringFeatureDefinition(
+        feature_name: str,
+        collection_type: Optional[CollectionType] = None,
+) -> FeatureDefinition:
+    """Create a feature definition with String type."""
+    return _create_feature_definition(feature_name, FeatureTypeEnum.STRING, collection_type)
+
+__all__ = [
+    "FeatureDefinition",
+    "FeatureTypeEnum",
+    "CollectionTypeEnum",
+    "ListCollectionType",
+    "SetCollectionType",
+    "VectorCollectionType",
+    "FractionalFeatureDefinition",
+    "IntegralFeatureDefinition",
+    "StringFeatureDefinition",
+]
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py
new file mode 100644
index 0000000000..f7f6523b8d
--- /dev/null
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py
@@ -0,0 +1,488 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
+"""Utilities for working with FeatureGroups and FeatureStores."""
+import logging
+import os
+import time
+from typing import Any, Dict, Sequence, Union
+
+import boto3
+import pandas as pd
+from pandas import DataFrame, Series
+
+from sagemaker.mlops.feature_store import FeatureGroup as CoreFeatureGroup, FeatureGroup
+from sagemaker.core.helper.session_helper import Session
+from sagemaker.core.s3.client import S3Uploader, S3Downloader
+from sagemaker.mlops.feature_store.dataset_builder import DatasetBuilder
+from sagemaker.mlops.feature_store.feature_definition import (
+    FeatureDefinition,
+    FractionalFeatureDefinition,
+    IntegralFeatureDefinition,
+    ListCollectionType,
+    StringFeatureDefinition,
+)
+from sagemaker.mlops.feature_store.ingestion_manager_pandas import IngestionManagerPandas
+
+from sagemaker import utils
+
+
+logger = logging.getLogger(__name__)
+
+# --- Constants ---
+
+_FEATURE_TYPE_TO_DDL_DATA_TYPE_MAP = {
+    "Integral": "INT",
+    "Fractional": "FLOAT",
+    "String": "STRING",
+}
+
+_DTYPE_TO_FEATURE_TYPE_MAP = {
+    "object": "String",
+    "string": "String",
+    "int64": "Integral",
+    "float64": "Fractional",
+}
+
+_INTEGER_TYPES = {"int_", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64"}
+_FLOAT_TYPES = {"float_", "float16", "float32", "float64"}
+
+
+def _get_athena_client(session: Session):
+    """Get Athena client from session."""
+    return session.boto_session.client("athena", region_name=session.boto_region_name)
+
+
+def _get_s3_client(session: Session):
+    """Get S3 client from session."""
+    return session.boto_session.client("s3", region_name=session.boto_region_name)
+
+
+def start_query_execution(
+    session: Session,
+    catalog: str,
+    database: str,
+    query_string: str,
+    output_location: str,
+    kms_key: str = None,
+    workgroup: str = None,
+) -> Dict[str, str]:
+    """Start Athena query execution.
+
+    Args:
+        session: Session instance for boto calls.
+        catalog: Name of the data catalog.
+        database: Name of the database.
+        query_string: SQL query string.
+        output_location: S3 URI for query results.
+        kms_key: KMS key for encryption (default: None).
+        workgroup: Athena workgroup name (default: None).
+
+    Returns:
+        Response dict with QueryExecutionId.
+    """
+    kwargs = {
+        "QueryString": query_string,
+        "QueryExecutionContext": {"Catalog": catalog, "Database": database},
+        "ResultConfiguration": {"OutputLocation": output_location},
+    }
+    if kms_key:
+        kwargs["ResultConfiguration"]["EncryptionConfiguration"] = {
+            "EncryptionOption": "SSE_KMS",
+            "KmsKey": kms_key,
+        }
+    if workgroup:
+        kwargs["WorkGroup"] = workgroup
+    return _get_athena_client(session).start_query_execution(**kwargs)
+
+
+def get_query_execution(session: Session, query_execution_id: str) -> Dict[str, Any]:
+    """Get execution status of an Athena query.
+
+    Args:
+        session: Session instance for boto calls.
+        query_execution_id: The query execution ID.
+
+    Returns:
+        Response dict from Athena.
+    """
+    return _get_athena_client(session).get_query_execution(QueryExecutionId=query_execution_id)
+
+
+def wait_for_athena_query(session: Session, query_execution_id: str, poll: int = 5):
+    """Wait for Athena query to finish.
+
+    Args:
+        session: Session instance for boto calls.
+        query_execution_id: The query execution ID.
+        poll: Polling interval in seconds (default: 5).
+    """
+    while True:
+        state = get_query_execution(session, query_execution_id)["QueryExecution"]["Status"]["State"]
+        if state in ("SUCCEEDED", "FAILED"):
+            logger.info("Query %s %s.", query_execution_id, state.lower())
+            break
+        logger.info("Query %s is being executed.", query_execution_id)
+        time.sleep(poll)
+
+
+def run_athena_query(
+    session: Session,
+    catalog: str,
+    database: str,
+    query_string: str,
+    output_location: str,
+    kms_key: str = None,
+) -> Dict[str, Any]:
+    """Execute Athena query, wait for completion, and return result.
+
+    Args:
+        session: Session instance for boto calls.
+        catalog: Name of the data catalog.
+        database: Name of the database.
+        query_string: SQL query string.
+        output_location: S3 URI for query results.
+        kms_key: KMS key for encryption (default: None).
+
+    Returns:
+        Query execution result dict.
+
+    Raises:
+        RuntimeError: If query fails.
+    """
+    response = start_query_execution(
+        session=session,
+        catalog=catalog,
+        database=database,
+        query_string=query_string,
+        output_location=output_location,
+        kms_key=kms_key,
+    )
+    query_id = response["QueryExecutionId"]
+    wait_for_athena_query(session, query_id)
+
+    result = get_query_execution(session, query_id)
+    if result["QueryExecution"]["Status"]["State"] != "SUCCEEDED":
+        raise RuntimeError(f"Athena query {query_id} failed.")
+    return result
+
+
+def download_athena_query_result(
+    session: Session,
+    bucket: str,
+    prefix: str,
+    query_execution_id: str,
+    filename: str,
+):
+    """Download query result file from S3.
+
+    Args:
+        session: Session instance for boto calls.
+        bucket: S3 bucket name.
+        prefix: S3 key prefix.
+        query_execution_id: The query execution ID.
+        filename: Local filename to save to.
+    """
+    _get_s3_client(session).download_file(
+        Bucket=bucket,
+        Key=f"{prefix}/{query_execution_id}.csv",
+        Filename=filename,
+    )
+
+
+def upload_dataframe_to_s3(
+    data_frame: DataFrame,
+    output_path: str,
+    session: Session,
+    kms_key: str = None,
+) -> tuple[str, str]:
+    """Upload DataFrame to S3 as CSV.
+
+    Args:
+        data_frame: DataFrame to upload.
+        output_path: S3 URI base path.
+        session: Session instance for boto calls.
+        kms_key: KMS key for encryption (default: None).
+
+    Returns:
+        Tuple of (s3_folder, temp_table_name).
+    """
+
+    temp_id = utils.unique_name_from_base("dataframe-base")
+    local_file = f"{temp_id}.csv"
+    s3_folder = os.path.join(output_path, temp_id)
+
+    data_frame.to_csv(local_file, index=False, header=False)
+    S3Uploader.upload(
+        local_path=local_file,
+        desired_s3_uri=s3_folder,
+        sagemaker_session=session,
+        kms_key=kms_key,
+    )
+    os.remove(local_file)
+
+    table_name = f'dataframe_{temp_id.replace("-", "_")}'
+    return s3_folder, table_name
+
+
+def download_csv_from_s3(
+    s3_uri: str,
+    session: Session,
+    kms_key: str = None,
+) -> DataFrame:
+    """Download CSV from S3 and return as DataFrame.
+
+    Args:
+        s3_uri: S3 URI of the CSV file.
+        session: Session instance for boto calls.
+        kms_key: KMS key for decryption (default: None).
+
+    Returns:
+        DataFrame with CSV contents.
+    """
+
+    S3Downloader.download(
+        s3_uri=s3_uri,
+        local_path="./",
+        kms_key=kms_key,
+        sagemaker_session=session,
+    )
+
+    local_file = s3_uri.split("/")[-1]
+    df = pd.read_csv(local_file)
+    os.remove(local_file)
+
+    metadata_file = f"{local_file}.metadata"
+    if os.path.exists(metadata_file):
+        os.remove(metadata_file)
+
+    return df
+
+
+def get_session_from_role(region: str, assume_role: str = None) -> Session:
+    """Get a Session from a region and optional IAM role.
+
+    Args:
+        region: AWS region name.
+        assume_role: IAM role ARN to assume (default: None).
+
+    Returns:
+        Session instance.
+    """
+    boto_session = boto3.Session(region_name=region)
+
+    if assume_role:
+        sts = boto_session.client("sts", region_name=region)
+        credentials = sts.assume_role(
+            RoleArn=assume_role,
+            RoleSessionName="SagemakerExecution",
+        )["Credentials"]
+
+        boto_session = boto3.Session(
+            region_name=region,
+            aws_access_key_id=credentials["AccessKeyId"],
+            aws_secret_access_key=credentials["SecretAccessKey"],
+            aws_session_token=credentials["SessionToken"],
+        )
+
+    return Session(
+        boto_session=boto_session,
+        sagemaker_client=boto_session.client("sagemaker"),
+        sagemaker_runtime_client=boto_session.client("sagemaker-runtime"),
+        sagemaker_featurestore_runtime_client=boto_session.client("sagemaker-featurestore-runtime"),
+    )
+
+
+# --- FeatureDefinition Functions ---
+
+def _is_collection_column(series: Series, sample_size: int = 1000) -> bool:
+    """Check if column contains list/set values."""
+    sample = series.head(sample_size).dropna()
+    return sample.apply(lambda x: isinstance(x, (list, set))).any()
+
+
+def _generate_feature_definition(
+    series: Series,
+    online_storage_type: str = None,
+) -> FeatureDefinition:
+    """Generate a FeatureDefinition from a pandas Series."""
+    dtype = str(series.dtype)
+    collection_type = None
+
+    if online_storage_type == "InMemory" and _is_collection_column(series):
+        collection_type = ListCollectionType()
+
+    if dtype in _INTEGER_TYPES:
+        return IntegralFeatureDefinition(series.name, collection_type)
+    if dtype in _FLOAT_TYPES:
+        return FractionalFeatureDefinition(series.name, collection_type)
+    return StringFeatureDefinition(series.name, collection_type)
+
+
+def load_feature_definitions_from_dataframe(
+    data_frame: DataFrame,
+    online_storage_type: str = None,
+) -> Sequence[FeatureDefinition]:
+    """Infer FeatureDefinitions from DataFrame dtypes.
+
+    Column name is used as feature name. Feature type is inferred from the dtype
+    of the column. Integer dtypes are mapped to Integral feature type. Float dtypes
+    are mapped to Fractional feature type. All other dtypes are mapped to String.
+
+    For IN_MEMORY online_storage_type, collection type columns within DataFrame
+    will be inferred as List instead of String.
+
+    Args:
+        data_frame: DataFrame to infer features from.
+        online_storage_type: "Standard" or "InMemory" (default: None).
+
+    Returns:
+        List of FeatureDefinition objects.
+    """
+    return [
+        _generate_feature_definition(data_frame[col], online_storage_type)
+        for col in data_frame.columns
+    ]
+
+
+# --- FeatureGroup Functions ---
+
+def create_athena_query(feature_group_name: str, session: Session):
+    """Create an AthenaQuery for a FeatureGroup.
+
+    Args:
+        feature_group_name: Name of the FeatureGroup.
+        session: Session instance for Athena boto calls.
+
+    Returns:
+        AthenaQuery initialized with data catalog config.
+
+    Raises:
+        RuntimeError: If no metastore is configured.
+    """
+    from sagemaker.mlops.feature_store.athena_query import AthenaQuery
+
+    fg = CoreFeatureGroup.get(feature_group_name=feature_group_name)
+
+    if not fg.offline_store_config or not fg.offline_store_config.data_catalog_config:
+        raise RuntimeError("No metastore is configured with this feature group.")
+
+    catalog_config = fg.offline_store_config.data_catalog_config
+    disable_glue = catalog_config.disable_glue_table_creation or False
+
+    return AthenaQuery(
+        catalog=catalog_config.catalog if disable_glue else "AwsDataCatalog",
+        database=catalog_config.database,
+        table_name=catalog_config.table_name,
+        sagemaker_session=session,
+    )
+
+
+def as_hive_ddl(
+    feature_group_name: str,
+    database: str = "sagemaker_featurestore",
+    table_name: str = None,
+) -> str:
+    """Generate Hive DDL for a FeatureGroup's offline store table.
+
+    Schema of the table is generated based on the feature definitions. Columns are named
+    after feature name and data-type are inferred based on feature type. Integral feature
+    type is mapped to INT data-type. Fractional feature type is mapped to FLOAT data-type.
+    String feature type is mapped to STRING data-type.
+
+    Args:
+        feature_group_name: Name of the FeatureGroup.
+        database: Hive database name (default: "sagemaker_featurestore").
+        table_name: Hive table name (default: feature_group_name).
+
+    Returns:
+        CREATE EXTERNAL TABLE DDL string.
+    """
+    fg = CoreFeatureGroup.get(feature_group_name=feature_group_name)
+    table_name = table_name or feature_group_name
+    resolved_output_s3_uri = fg.offline_store_config.s3_storage_config.resolved_output_s3_uri
+
+    ddl = f"CREATE EXTERNAL TABLE IF NOT EXISTS {database}.{table_name} (\n"
+    for fd in fg.feature_definitions:
+        ddl += f"  {fd.feature_name} {_FEATURE_TYPE_TO_DDL_DATA_TYPE_MAP.get(fd.feature_type)}\n"
+    ddl += "  write_time TIMESTAMP\n"
+    ddl += "  event_time TIMESTAMP\n"
+    ddl += "  is_deleted BOOLEAN\n"
+    ddl += ")\n"
+    ddl += (
+        "ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'\n"
+        "  STORED AS\n"
+        "  INPUTFORMAT 'parquet.hive.DeprecatedParquetInputFormat'\n"
+        "  OUTPUTFORMAT 'parquet.hive.DeprecatedParquetOutputFormat'\n"
+        f"LOCATION '{resolved_output_s3_uri}'"
+    )
+    return ddl
+
+
+def ingest_dataframe(
+    feature_group_name: str,
+    data_frame: DataFrame,
+    max_workers: int = 1,
+    max_processes: int = 1,
+    wait: bool = True,
+    timeout: Union[int, float] = None,
+):
+    """Ingest a pandas DataFrame to a FeatureGroup.
+
+    Args:
+        feature_group_name: Name of the FeatureGroup.
+        data_frame: DataFrame to ingest.
+        max_workers: Threads per process (default: 1).
+        max_processes: Number of processes (default: 1).
+        wait: Wait for ingestion to complete (default: True).
+        timeout: Timeout in seconds (default: None).
+
+    Returns:
+        IngestionManagerPandas instance.
+
+    Raises:
+        ValueError: If max_workers or max_processes <= 0.
+    """
+    
+    if max_processes <= 0:
+        raise ValueError("max_processes must be greater than 0.")
+    if max_workers <= 0:
+        raise ValueError("max_workers must be greater than 0.")
+
+    fg = CoreFeatureGroup.get(feature_group_name=feature_group_name)
+    feature_definitions = {fd.feature_name: fd.feature_type for fd in fg.feature_definitions}
+
+    manager = IngestionManagerPandas(
+        feature_group_name=feature_group_name,
+        feature_definitions=feature_definitions,
+        max_workers=max_workers,
+        max_processes=max_processes,
+    )
+    manager.run(data_frame=data_frame, wait=wait, timeout=timeout)
+    return manager
+
+def create_dataset(
+    base: Union[FeatureGroup, pd.DataFrame],
+    output_path: str,
+    session: Session,
+    record_identifier_feature_name: str = None,
+    event_time_identifier_feature_name: str = None,
+    included_feature_names: Sequence[str] = None,
+    kms_key_id: str = None,
+) -> DatasetBuilder:
+    """Create a DatasetBuilder for generating a Dataset."""
+    if isinstance(base, pd.DataFrame):
+        if not record_identifier_feature_name or not event_time_identifier_feature_name:
+            raise ValueError(
+                "record_identifier_feature_name and event_time_identifier_feature_name "
+                "are required when base is a DataFrame."
+            )
+    return DatasetBuilder(
+        _sagemaker_session=session,
+        _base=base,
+        _output_path=output_path,
+        _record_identifier_feature_name=record_identifier_feature_name,
+        _event_time_identifier_feature_name=event_time_identifier_feature_name,
+        _included_feature_names=included_feature_names,
+        _kms_key_id=kms_key_id,
+    )
+
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/ingestion_manager_pandas.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/ingestion_manager_pandas.py
new file mode 100644
index 0000000000..60d022dab1
--- /dev/null
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/ingestion_manager_pandas.py
@@ -0,0 +1,321 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
+"""Multi-threaded data ingestion for FeatureStore using SageMaker Core."""
+import logging
+import math
+import signal
+from concurrent.futures import ThreadPoolExecutor, as_completed
+from dataclasses import dataclass, field
+from multiprocessing.pool import AsyncResult
+from typing import Any, Dict, Iterable, List, Sequence, Union
+
+import pandas as pd
+from pandas import DataFrame
+from pandas.api.types import is_list_like
+from pathos.multiprocessing import ProcessingPool
+
+from sagemaker.core.resources import FeatureGroup as CoreFeatureGroup
+from sagemaker.core.shapes import FeatureValue
+
+logger = logging.getLogger(__name__)
+
+
+class IngestionError(Exception):
+    """Exception raised for errors during ingestion.
+
+    Attributes:
+        failed_rows: List of row indices that failed to ingest.
+        message: Error message.
+    """
+
+    def __init__(self, failed_rows: List[int], message: str):
+        self.failed_rows = failed_rows
+        self.message = message
+        super().__init__(self.message)
+
+
+@dataclass
+class IngestionManagerPandas:
+    """Class to manage the multi-threaded data ingestion process.
+
+    This class will manage the data ingestion process which is multi-threaded.
+
+    Attributes:
+        feature_group_name (str): name of the Feature Group.
+        feature_definitions (Dict[str, Dict[Any, Any]]): dictionary of feature definitions
+            where the key is the feature name and the value is the FeatureDefinition.
+            The FeatureDefinition contains the data type of the feature.
+        max_workers (int): number of threads to create.
+        max_processes (int): number of processes to create. Each process spawns
+            ``max_workers`` threads.
+    """
+
+    feature_group_name: str
+    feature_definitions: Dict[str, Dict[Any, Any]]
+    max_workers: int = 1
+    max_processes: int = 1
+    _async_result: AsyncResult = field(default=None, init=False)
+    _processing_pool: ProcessingPool = field(default=None, init=False)
+    _failed_indices: List[int] = field(default_factory=list, init=False)
+
+    @property
+    def failed_rows(self) -> List[int]:
+        """Get rows that failed to ingest.
+
+        Returns:
+            List of row indices that failed to be ingested.
+        """
+        return self._failed_indices
+
+    def run(
+        self,
+        data_frame: DataFrame,
+        target_stores: List[str] = None,
+        wait: bool = True,
+        timeout: Union[int, float] = None,
+    ):
+        """Start the ingestion process.
+
+        Args:
+            data_frame (DataFrame): source DataFrame to be ingested.
+            target_stores (List[str]): list of target stores ("OnlineStore", "OfflineStore").
+                If None, the default target store is used.
+            wait (bool): whether to wait for the ingestion to finish or not.
+            timeout (Union[int, float]): ``concurrent.futures.TimeoutError`` will be raised
+                if timeout is reached.
+        """
+        if self.max_workers == 1 and self.max_processes == 1:
+            self._run_single_process_single_thread(data_frame=data_frame, target_stores=target_stores)
+        else:
+            self._run_multi_process(data_frame=data_frame, target_stores=target_stores, wait=wait, timeout=timeout)
+
+    def wait(self, timeout: Union[int, float] = None):
+        """Wait for the ingestion process to finish.
+
+        Args:
+            timeout (Union[int, float]): ``concurrent.futures.TimeoutError`` will be raised
+                if timeout is reached.
+        """
+        try:
+            results = self._async_result.get(timeout=timeout)
+        except KeyboardInterrupt as e:
+            self._processing_pool.terminate()
+            self._processing_pool.close()
+            self._processing_pool.clear()
+            raise e
+        else:
+            self._processing_pool.close()
+            self._processing_pool.clear()
+
+        self._failed_indices = [idx for failed in results for idx in failed]
+
+        if self._failed_indices:
+            raise IngestionError(
+                self._failed_indices,
+                f"Failed to ingest some data into FeatureGroup {self.feature_group_name}",
+            )
+
+    def _run_single_process_single_thread(
+        self,
+        data_frame: DataFrame,
+        target_stores: List[str] = None,
+    ):
+        """Ingest utilizing a single process and a single thread."""
+        logger.info("Started single-threaded ingestion for %d rows", len(data_frame))
+        failed_rows = []
+
+        fg = CoreFeatureGroup(feature_group_name=self.feature_group_name)
+
+        for row in data_frame.itertuples():
+            self._ingest_row(
+                data_frame=data_frame,
+                row=row,
+                feature_group=fg,
+                feature_definitions=self.feature_definitions,
+                failed_rows=failed_rows,
+                target_stores=target_stores,
+            )
+
+        self._failed_indices = failed_rows
+        if self._failed_indices:
+            raise IngestionError(
+                self._failed_indices,
+                f"Failed to ingest some data into FeatureGroup {self.feature_group_name}",
+            )
+
+    def _run_multi_process(
+        self,
+        data_frame: DataFrame,
+        target_stores: List[str] = None,
+        wait: bool = True,
+        timeout: Union[int, float] = None,
+    ):
+        """Start the ingestion process with the specified number of processes."""
+        batch_size = math.ceil(data_frame.shape[0] / self.max_processes)
+
+        args = []
+        for i in range(self.max_processes):
+            start_index = min(i * batch_size, data_frame.shape[0])
+            end_index = min(i * batch_size + batch_size, data_frame.shape[0])
+            args.append((
+                self.max_workers,
+                self.feature_group_name,
+                self.feature_definitions,
+                data_frame[start_index:end_index],
+                target_stores,
+                start_index,
+                timeout,
+            ))
+
+        def init_worker():
+            signal.signal(signal.SIGINT, signal.SIG_IGN)
+
+        self._processing_pool = ProcessingPool(self.max_processes, init_worker)
+        self._processing_pool.restart(force=True)
+
+        self._async_result = self._processing_pool.amap(
+            lambda x: IngestionManagerPandas._run_multi_threaded(*x),
+            args,
+        )
+
+        if wait:
+            self.wait(timeout=timeout)
+
+    @staticmethod
+    def _run_multi_threaded(
+        max_workers: int,
+        feature_group_name: str,
+        feature_definitions: Dict[str, Dict[Any, Any]],
+        data_frame: DataFrame,
+        target_stores: List[str] = None,
+        row_offset: int = 0,
+        timeout: Union[int, float] = None,
+    ) -> List[int]:
+        """Start multi-threaded ingestion within a single process."""
+        executor = ThreadPoolExecutor(max_workers=max_workers)
+        batch_size = math.ceil(data_frame.shape[0] / max_workers)
+
+        futures = {}
+        for i in range(max_workers):
+            start_index = min(i * batch_size, data_frame.shape[0])
+            end_index = min(i * batch_size + batch_size, data_frame.shape[0])
+            future = executor.submit(
+                IngestionManagerPandas._ingest_single_batch,
+                data_frame=data_frame,
+                feature_group_name=feature_group_name,
+                feature_definitions=feature_definitions,
+                start_index=start_index,
+                end_index=end_index,
+                target_stores=target_stores,
+            )
+            futures[future] = (start_index + row_offset, end_index + row_offset)
+
+        failed_indices = []
+        for future in as_completed(futures, timeout=timeout):
+            start, end = futures[future]
+            failed_rows = future.result()
+            if not failed_rows:
+                logger.info("Successfully ingested row %d to %d", start, end)
+            failed_indices.extend(failed_rows)
+
+        executor.shutdown(wait=False)
+        return failed_indices
+
+    @staticmethod
+    def _ingest_single_batch(
+        data_frame: DataFrame,
+        feature_group_name: str,
+        feature_definitions: Dict[str, Dict[Any, Any]],
+        start_index: int,
+        end_index: int,
+        target_stores: List[str] = None,
+    ) -> List[int]:
+        """Ingest a single batch of DataFrame rows into FeatureStore."""
+        logger.info("Started ingesting index %d to %d", start_index, end_index)
+        failed_rows = []
+
+        fg = CoreFeatureGroup(feature_group_name=feature_group_name)
+
+        for row in data_frame[start_index:end_index].itertuples():
+            IngestionManagerPandas._ingest_row(
+                data_frame=data_frame,
+                row=row,
+                feature_group=fg,
+                feature_definitions=feature_definitions,
+                failed_rows=failed_rows,
+                target_stores=target_stores,
+            )
+
+        return failed_rows
+
+    @staticmethod
+    def _ingest_row(
+        data_frame: DataFrame,
+        row: Iterable,
+        feature_group: CoreFeatureGroup,
+        feature_definitions: Dict[str, Dict[Any, Any]],
+        failed_rows: List[int],
+        target_stores: List[str] = None,
+    ):
+        """Ingest a single DataFrame row into FeatureStore using SageMaker Core."""
+        try:
+            record = []
+            for index in range(1, len(row)):
+                feature_name = data_frame.columns[index - 1]
+                feature_value = row[index]
+
+                if not IngestionManagerPandas._feature_value_is_not_none(feature_value):
+                    continue
+
+                if IngestionManagerPandas._is_feature_collection_type(feature_name, feature_definitions):
+                    record.append(FeatureValue(
+                        feature_name=feature_name,
+                        value_as_string_list=IngestionManagerPandas._convert_to_string_list(feature_value),
+                    ))
+                else:
+                    record.append(FeatureValue(
+                        feature_name=feature_name,
+                        value_as_string=str(feature_value),
+                    ))
+
+            # Use SageMaker Core's put_record directly
+            feature_group.put_record(
+                record=record,
+                target_stores=target_stores,
+            )
+
+        except Exception as e:
+            logger.error("Failed to ingest row %d: %s", row[0], e)
+            failed_rows.append(row[0])
+
+    @staticmethod
+    def _is_feature_collection_type(
+        feature_name: str,
+        feature_definitions: Dict[str, Dict[Any, Any]],
+    ) -> bool:
+        """Check if the feature is a collection type."""
+        feature_def = feature_definitions.get(feature_name)
+        if feature_def:
+            return feature_def.get("CollectionType") is not None
+        return False
+
+    @staticmethod
+    def _feature_value_is_not_none(feature_value: Any) -> bool:
+        """Check if the feature value is not None.
+
+        For Collection Type features, we check if the value is not None.
+        For Scalar values, we use pd.notna() to keep the behavior same.
+        """
+        if not is_list_like(feature_value):
+            return pd.notna(feature_value)
+        return feature_value is not None
+
+    @staticmethod
+    def _convert_to_string_list(feature_value: List[Any]) -> List[str]:
+        """Convert a list of feature values to a list of strings."""
+        if not is_list_like(feature_value):
+            raise ValueError(
+                f"Invalid feature value: {feature_value} for a collection type feature "
+                f"must be an Array, but was {type(feature_value)}"
+            )
+        return [str(v) if v is not None else None for v in feature_value]
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/inputs.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/inputs.py
new file mode 100644
index 0000000000..f264059eb3
--- /dev/null
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/inputs.py
@@ -0,0 +1,60 @@
+"""Enums for FeatureStore operations."""
+from enum import Enum
+
+class TargetStoreEnum(Enum):
+    """Store types for put_record."""
+    ONLINE_STORE = "OnlineStore"
+    OFFLINE_STORE = "OfflineStore"
+
+class OnlineStoreStorageTypeEnum(Enum):
+    """Storage types for online store."""
+    STANDARD = "Standard"
+    IN_MEMORY = "InMemory"
+
+class TableFormatEnum(Enum):
+    """Offline store table formats."""
+    GLUE = "Glue"
+    ICEBERG = "Iceberg"
+
+class ResourceEnum(Enum):
+    """Resource types for search."""
+    FEATURE_GROUP = "FeatureGroup"
+    FEATURE_METADATA = "FeatureMetadata"
+
+class SearchOperatorEnum(Enum):
+    """Search operators."""
+    AND = "And"
+    OR = "Or"
+
+class SortOrderEnum(Enum):
+    """Sort orders."""
+    ASCENDING = "Ascending"
+    DESCENDING = "Descending"
+
+class FilterOperatorEnum(Enum):
+    """Filter operators."""
+    EQUALS = "Equals"
+    NOT_EQUALS = "NotEquals"
+    GREATER_THAN = "GreaterThan"
+    GREATER_THAN_OR_EQUAL_TO = "GreaterThanOrEqualTo"
+    LESS_THAN = "LessThan"
+    LESS_THAN_OR_EQUAL_TO = "LessThanOrEqualTo"
+    CONTAINS = "Contains"
+    EXISTS = "Exists"
+    NOT_EXISTS = "NotExists"
+    IN = "In"
+
+class DeletionModeEnum(Enum):
+    """Deletion modes for delete_record."""
+    SOFT_DELETE = "SoftDelete"
+    HARD_DELETE = "HardDelete"
+
+class ExpirationTimeResponseEnum(Enum):
+    """ExpiresAt response toggle."""
+    DISABLED = "Disabled"
+    ENABLED = "Enabled"
+
+class ThroughputModeEnum(Enum):
+    """Throughput modes for feature group."""
+    ON_DEMAND = "OnDemand"
+    PROVISIONED = "Provisioned"
\ No newline at end of file

From 193d16fa2c61440ed1cd4d906e64e2726229ce6e Mon Sep 17 00:00:00 2001
From: adishaa <adishaa@amazon.com>
Date: Fri, 16 Jan 2026 11:34:01 -0800
Subject: [PATCH 02/22] Add feature store tests

---
 .../mlops/feature_store/MIGRATION_GUIDE.md    | 513 ++++++++++++++++++
 .../sagemaker/mlops/feature_store/__init__.py |   8 +-
 .../mlops/feature_store/dataset_builder.py    |  45 +-
 .../mlops/feature_store/feature_utils.py      |  31 +-
 .../feature_store/ingestion_manager_pandas.py |  19 +-
 sagemaker-mlops/tests/__init__.py             |   0
 sagemaker-mlops/tests/unit/__init__.py        |   0
 .../tests/unit/sagemaker/__init__.py          |   0
 .../tests/unit/sagemaker/mlops/__init__.py    |   0
 .../sagemaker/mlops/feature_store/__init__.py |   2 +
 .../sagemaker/mlops/feature_store/conftest.py |  80 +++
 .../mlops/feature_store/test_athena_query.py  | 113 ++++
 .../feature_store/test_dataset_builder.py     | 345 ++++++++++++
 .../feature_store/test_feature_definition.py  | 126 +++++
 .../mlops/feature_store/test_feature_utils.py | 202 +++++++
 .../test_ingestion_manager_pandas.py          | 256 +++++++++
 .../mlops/feature_store/test_inputs.py        | 109 ++++
 17 files changed, 1802 insertions(+), 47 deletions(-)
 create mode 100644 sagemaker-mlops/src/sagemaker/mlops/feature_store/MIGRATION_GUIDE.md
 create mode 100644 sagemaker-mlops/tests/__init__.py
 create mode 100644 sagemaker-mlops/tests/unit/__init__.py
 create mode 100644 sagemaker-mlops/tests/unit/sagemaker/__init__.py
 create mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/__init__.py
 create mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/__init__.py
 create mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/conftest.py
 create mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_athena_query.py
 create mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_dataset_builder.py
 create mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_feature_definition.py
 create mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_feature_utils.py
 create mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_ingestion_manager_pandas.py
 create mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_inputs.py

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/MIGRATION_GUIDE.md b/sagemaker-mlops/src/sagemaker/mlops/feature_store/MIGRATION_GUIDE.md
new file mode 100644
index 0000000000..40942fa6f3
--- /dev/null
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/MIGRATION_GUIDE.md
@@ -0,0 +1,513 @@
+# SageMaker FeatureStore V2 to V3 Migration Guide
+
+## Overview
+
+V3 uses **sagemaker-core** as the foundation, which provides:
+- Pydantic-based shapes with automatic serialization
+- Resource classes that manage boto clients internally
+- No need for explicit Session management in most cases
+
+## File Mapping
+
+| V2 File | V3 File | Notes |
+|---------|---------|-------|
+| `feature_group.py` | Re-exported from `sagemaker_core.main.resources` | No wrapper class needed |
+| `feature_store.py` | Re-exported from `sagemaker_core.main.resources` | `FeatureStore.search()` available |
+| `feature_definition.py` | `feature_definition.py` | Helper factories retained |
+| `feature_utils.py` | `feature_utils.py` | Standalone functions |
+| `inputs.py` | `inputs.py` | Enums only (shapes from core) |
+| `dataset_builder.py` | `dataset_builder.py` | Converted to dataclass |
+| N/A | `athena_query.py` | Extracted from feature_group.py |
+| N/A | `ingestion_manager_pandas.py` | Extracted from feature_group.py |
+
+---
+
+## FeatureGroup Operations
+
+### Create FeatureGroup
+
+**V2:**
+```python
+from sagemaker.feature_store.feature_group import FeatureGroup
+from sagemaker.session import Session
+
+session = Session()
+fg = FeatureGroup(name="my-fg", sagemaker_session=session)
+fg.load_feature_definitions(data_frame=df)
+fg.create(
+    s3_uri="s3://bucket/prefix",
+    record_identifier_name="id",
+    event_time_feature_name="ts",
+    role_arn=role,
+    enable_online_store=True,
+)
+```
+
+**V3:**
+```python
+from sagemaker.mlops.feature_store import (
+    FeatureGroup,
+    OnlineStoreConfig,
+    OfflineStoreConfig,
+    S3StorageConfig,
+    load_feature_definitions_from_dataframe,
+)
+
+feature_defs = load_feature_definitions_from_dataframe(df)
+
+FeatureGroup.create(
+    feature_group_name="my-fg",
+    feature_definitions=feature_defs,
+    record_identifier_feature_name="id",
+    event_time_feature_name="ts",
+    role_arn=role,
+    online_store_config=OnlineStoreConfig(enable_online_store=True),
+    offline_store_config=OfflineStoreConfig(
+        s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/prefix")
+    ),
+)
+```
+
+### Get/Describe FeatureGroup
+
+**V2:**
+```python
+fg = FeatureGroup(name="my-fg", sagemaker_session=session)
+response = fg.describe()
+```
+
+**V3:**
+```python
+from sagemaker.mlops.feature_store import FeatureGroup
+
+fg = FeatureGroup.get(feature_group_name="my-fg")
+# fg is now a typed object with attributes:
+# fg.feature_group_name, fg.feature_definitions, fg.offline_store_config, etc.
+```
+
+### Delete FeatureGroup
+
+**V2:**
+```python
+fg.delete()
+```
+
+**V3:**
+```python
+FeatureGroup(feature_group_name="my-fg").delete()
+# or
+fg = FeatureGroup.get(feature_group_name="my-fg")
+fg.delete()
+```
+
+### Update FeatureGroup
+
+**V2:**
+```python
+fg.update(
+    feature_additions=[FeatureDefinition("new_col", FeatureTypeEnum.STRING)],
+    throughput_config=ThroughputConfigUpdate(mode=ThroughputModeEnum.ON_DEMAND),
+)
+```
+
+**V3:**
+```python
+from sagemaker.mlops.feature_store import FeatureGroup, ThroughputConfig
+
+fg = FeatureGroup.get(feature_group_name="my-fg")
+fg.update(
+    feature_additions=[{"FeatureName": "new_col", "FeatureType": "String"}],
+    throughput_config=ThroughputConfig(throughput_mode="OnDemand"),
+)
+```
+
+---
+
+## Record Operations
+
+### Put Record
+
+**V2:**
+```python
+from sagemaker.feature_store.inputs import FeatureValue
+
+fg.put_record(
+    record=[
+        FeatureValue(feature_name="id", value_as_string="123"),
+        FeatureValue(feature_name="name", value_as_string="John"),
+    ],
+    target_stores=[TargetStoreEnum.ONLINE_STORE],
+)
+```
+
+**V3:**
+```python
+from sagemaker.mlops.feature_store import FeatureGroup, FeatureValue
+
+FeatureGroup(feature_group_name="my-fg").put_record(
+    record=[
+        FeatureValue(feature_name="id", value_as_string="123"),
+        FeatureValue(feature_name="name", value_as_string="John"),
+    ],
+    target_stores=["OnlineStore"],  # strings, not enums
+)
+```
+
+### Get Record
+
+**V2:**
+```python
+response = fg.get_record(record_identifier_value_as_string="123")
+```
+
+**V3:**
+```python
+response = FeatureGroup(feature_group_name="my-fg").get_record(
+    record_identifier_value_as_string="123"
+)
+```
+
+### Delete Record
+
+**V2:**
+```python
+fg.delete_record(
+    record_identifier_value_as_string="123",
+    event_time="2024-01-15T00:00:00Z",
+    deletion_mode=DeletionModeEnum.SOFT_DELETE,
+)
+```
+
+**V3:**
+```python
+FeatureGroup(feature_group_name="my-fg").delete_record(
+    record_identifier_value_as_string="123",
+    event_time="2024-01-15T00:00:00Z",
+    deletion_mode="SoftDelete",  # string, not enum
+)
+```
+
+### Batch Get Record
+
+**V2:**
+```python
+from sagemaker.feature_store.feature_store import FeatureStore
+from sagemaker.feature_store.inputs import Identifier
+
+fs = FeatureStore(sagemaker_session=session)
+response = fs.batch_get_record(
+    identifiers=[
+        Identifier(feature_group_name="my-fg", record_identifiers_value_as_string=["123", "456"])
+    ]
+)
+```
+
+**V3:**
+```python
+from sagemaker.mlops.feature_store import FeatureGroup
+
+response = FeatureGroup(feature_group_name="my-fg").batch_get_record(
+    identifiers=[
+        {"FeatureGroupName": "my-fg", "RecordIdentifiersValueAsString": ["123", "456"]}
+    ]
+)
+```
+
+---
+
+## DataFrame Ingestion
+
+**V2:**
+```python
+fg.ingest(data_frame=df, max_workers=4, max_processes=2, wait=True)
+```
+
+**V3:**
+```python
+from sagemaker.mlops.feature_store import ingest_dataframe
+
+manager = ingest_dataframe(
+    feature_group_name="my-fg",
+    data_frame=df,
+    max_workers=4,
+    max_processes=2,
+    wait=True,
+)
+# Access failed rows: manager.failed_rows
+```
+
+---
+
+## Athena Query
+
+**V2:**
+```python
+query = fg.athena_query()
+query.run(query_string="SELECT * FROM ...", output_location="s3://...")
+query.wait()
+df = query.as_dataframe()
+```
+
+**V3:**
+```python
+from sagemaker.mlops.feature_store import create_athena_query
+
+query = create_athena_query("my-fg", session)
+query.run(query_string="SELECT * FROM ...", output_location="s3://...")
+query.wait()
+df = query.as_dataframe()
+```
+
+---
+
+## Hive DDL Generation
+
+**V2:**
+```python
+ddl = fg.as_hive_ddl(database="mydb", table_name="mytable")
+```
+
+**V3:**
+```python
+from sagemaker.mlops.feature_store import as_hive_ddl
+
+ddl = as_hive_ddl("my-fg", database="mydb", table_name="mytable")
+```
+
+---
+
+## Feature Definitions
+
+**V2:**
+```python
+fg.load_feature_definitions(data_frame=df)
+# Modifies fg.feature_definitions in place
+```
+
+**V3:**
+```python
+from sagemaker.mlops.feature_store import load_feature_definitions_from_dataframe
+
+defs = load_feature_definitions_from_dataframe(df)
+# Returns list, doesn't modify any object
+```
+
+### Using Helper Factories
+
+**V2 & V3 (same):**
+```python
+from sagemaker.mlops.feature_store import (
+    FractionalFeatureDefinition,
+    IntegralFeatureDefinition,
+    StringFeatureDefinition,
+    VectorCollectionType,
+)
+
+defs = [
+    IntegralFeatureDefinition("id"),
+    StringFeatureDefinition("name"),
+    FractionalFeatureDefinition("embedding", VectorCollectionType(128)),
+]
+```
+
+---
+
+## Search
+
+**V2:**
+```python
+from sagemaker.feature_store.feature_store import FeatureStore
+from sagemaker.feature_store.inputs import Filter, ResourceEnum
+
+fs = FeatureStore(sagemaker_session=session)
+response = fs.search(
+    resource=ResourceEnum.FEATURE_GROUP,
+    filters=[Filter(name="FeatureGroupName", value="my-prefix", operator=FilterOperatorEnum.CONTAINS)],
+)
+```
+
+**V3:**
+```python
+from sagemaker.mlops.feature_store import FeatureStore, Filter, SearchExpression
+
+response = FeatureStore.search(
+    resource="FeatureGroup",
+    search_expression=SearchExpression(
+        filters=[Filter(name="FeatureGroupName", value="my-prefix", operator="Contains")]
+    ),
+)
+```
+
+---
+
+## Feature Metadata
+
+**V2:**
+```python
+fg.describe_feature_metadata(feature_name="my-feature")
+fg.update_feature_metadata(feature_name="my-feature", description="Updated desc")
+fg.list_parameters_for_feature_metadata(feature_name="my-feature")
+```
+
+**V3:**
+```python
+from sagemaker.mlops.feature_store import FeatureMetadata
+
+# Get metadata
+metadata = FeatureMetadata.get(feature_group_name="my-fg", feature_name="my-feature")
+print(metadata.description)
+print(metadata.parameters)
+
+# Update metadata
+metadata.update(description="Updated desc")
+```
+
+---
+
+## Dataset Builder
+
+**V2:**
+```python
+from sagemaker.feature_store.feature_store import FeatureStore
+
+fs = FeatureStore(sagemaker_session=session)
+builder = fs.create_dataset(
+    base=fg,
+    output_path="s3://bucket/output",
+)
+builder.with_feature_group(other_fg, target_feature_name_in_base="id")
+builder.point_in_time_accurate_join()
+df, query = builder.to_dataframe()
+```
+
+**V3:**
+```python
+from sagemaker.mlops.feature_store import create_dataset, FeatureGroup
+
+fg = FeatureGroup.get(feature_group_name="my-fg")
+other_fg = FeatureGroup.get(feature_group_name="other-fg")
+
+builder = create_dataset(
+    base=fg,
+    output_path="s3://bucket/output",
+    session=session,
+)
+builder.with_feature_group(other_fg, target_feature_name_in_base="id")
+builder.point_in_time_accurate_join()
+df, query = builder.to_dataframe()
+```
+
+---
+
+## Config Objects (Shapes)
+
+**V2:**
+```python
+from sagemaker.feature_store.inputs import (
+    OnlineStoreConfig,
+    OfflineStoreConfig,
+    S3StorageConfig,
+    TtlDuration,
+)
+
+config = OnlineStoreConfig(enable_online_store=True, ttl_duration=TtlDuration(unit="Hours", value=24))
+config.to_dict()  # Manual serialization required
+```
+
+**V3:**
+```python
+from sagemaker.mlops.feature_store import (
+    OnlineStoreConfig,
+    OfflineStoreConfig,
+    S3StorageConfig,
+    TtlDuration,
+)
+
+config = OnlineStoreConfig(enable_online_store=True, ttl_duration=TtlDuration(unit="Hours", value=24))
+# No to_dict() needed - Pydantic handles serialization automatically
+```
+
+---
+
+## Key Differences Summary
+
+| Aspect | V2 | V3 |
+|--------|----|----|
+| **Session** | Required for most operations | Optional - core manages clients |
+| **FeatureGroup** | Wrapper class with session | Direct core resource class |
+| **Shapes** | `@attr.s` with `to_dict()` | Pydantic with auto-serialization |
+| **Enums** | `TargetStoreEnum.ONLINE_STORE.value` | Just use strings: `"OnlineStore"` |
+| **Methods** | Instance methods on FeatureGroup | Standalone functions + core methods |
+| **Ingestion** | `fg.ingest(df)` | `ingest_dataframe(name, df)` |
+| **Athena** | `fg.athena_query()` | `create_athena_query(name, session)` |
+| **DDL** | `fg.as_hive_ddl()` | `as_hive_ddl(name)` |
+| **Feature Defs** | `fg.load_feature_definitions(df)` | `load_feature_definitions_from_dataframe(df)` |
+| **Imports** | Multiple modules | Single `__init__.py` re-exports all |
+
+---
+
+## Missing in V3 (Intentionally)
+
+These V2 features are **not wrapped** because core provides them directly:
+
+- `FeatureGroup.create()` - use `FeatureGroup.create()` from core
+- `FeatureGroup.delete()` - use `FeatureGroup(...).delete()` from core
+- `FeatureGroup.describe()` - use `FeatureGroup.get()` from core (returns typed object)
+- `FeatureGroup.update()` - use `FeatureGroup(...).update()` from core
+- `FeatureGroup.put_record()` - use `FeatureGroup(...).put_record()` from core
+- `FeatureGroup.get_record()` - use `FeatureGroup(...).get_record()` from core
+- `FeatureGroup.delete_record()` - use `FeatureGroup(...).delete_record()` from core
+- `FeatureGroup.batch_get_record()` - use `FeatureGroup(...).batch_get_record()` from core
+- `FeatureStore.search()` - use `FeatureStore.search()` from core
+- `FeatureStore.list_feature_groups()` - use `FeatureGroup.get_all()` from core
+- All config shapes (`OnlineStoreConfig`, etc.) - re-exported from core
+
+---
+
+## Import Cheatsheet
+
+```python
+# V3 - Everything from one place
+from sagemaker.mlops.feature_store import (
+    # Resources (from core)
+    FeatureGroup,
+    FeatureStore,
+    FeatureMetadata,
+    
+    # Shapes (from core)
+    OnlineStoreConfig,
+    OfflineStoreConfig,
+    S3StorageConfig,
+    DataCatalogConfig,
+    TtlDuration,
+    FeatureValue,
+    FeatureParameter,
+    ThroughputConfig,
+    Filter,
+    SearchExpression,
+    
+    # Enums (local)
+    TargetStoreEnum,
+    OnlineStoreStorageTypeEnum,
+    TableFormatEnum,
+    DeletionModeEnum,
+    ThroughputModeEnum,
+    
+    # Feature Definition helpers (local)
+    FeatureDefinition,
+    FractionalFeatureDefinition,
+    IntegralFeatureDefinition,
+    StringFeatureDefinition,
+    VectorCollectionType,
+    
+    # Utility functions (local)
+    create_athena_query,
+    as_hive_ddl,
+    load_feature_definitions_from_dataframe,
+    ingest_dataframe,
+    create_dataset,
+    
+    # Classes (local)
+    DatasetBuilder,
+)
+```
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
index ee8cd7d1a3..f15d6d3845 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
@@ -3,11 +3,10 @@
 """SageMaker FeatureStore V3 - powered by sagemaker-core."""
 
 # Resources from core
-from sagemaker_core.main.resources import FeatureGroup, FeatureMetadata
-from sagemaker_core.main.resources import FeatureStore
+from sagemaker.core.resources import FeatureGroup, FeatureMetadata
 
 # Shapes from core (Pydantic - no to_dict() needed)
-from sagemaker_core.main.shapes import (
+from sagemaker.core.shapes import (
     DataCatalogConfig,
     FeatureParameter,
     FeatureValue,
@@ -52,7 +51,6 @@
 from sagemaker.mlops.feature_store.feature_utils import (
     as_hive_ddl,
     create_athena_query,
-    create_dataset,
     get_session_from_role,
     ingest_dataframe,
     load_feature_definitions_from_dataframe,
@@ -76,7 +74,6 @@
     # Resources
     "FeatureGroup",
     "FeatureMetadata",
-    "FeatureStore",
     # Shapes
     "DataCatalogConfig",
     "FeatureParameter",
@@ -113,7 +110,6 @@
     # Utility functions
     "as_hive_ddl",
     "create_athena_query",
-    "create_dataset",
     "get_session_from_role",
     "ingest_dataframe",
     "load_feature_definitions_from_dataframe",
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/dataset_builder.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/dataset_builder.py
index f5450663a6..72e9535320 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/dataset_builder.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/dataset_builder.py
@@ -178,7 +178,9 @@ def construct_feature_group_to_be_merged(
         database=catalog_config.database,
         table_name=catalog_config.table_name,
         record_identifier_feature_name=record_id,
-        event_time_identifier_feature=FeatureDefinition(event_time_name, FeatureTypeEnum(event_time_type)),
+        event_time_identifier_feature=FeatureDefinition(
+            feature_name=event_time_name, feature_type=FeatureTypeEnum(event_time_type).value
+        ),
         target_feature_name_in_base=target_feature_name_in_base,
         table_type=TableType.FEATURE_GROUP,
         feature_name_in_target=feature_name_in_target,
@@ -256,6 +258,47 @@ class DatasetBuilder:
     _event_time_ending_timestamp: datetime.datetime = field(default=None, init=False)
     _feature_groups_to_be_merged: List[FeatureGroupToBeMerged] = field(default_factory=list, init=False)
 
+    @classmethod
+    def create(
+        cls,
+        base: Union[FeatureGroup, pd.DataFrame],
+        output_path: str,
+        session: Session,
+        record_identifier_feature_name: str = None,
+        event_time_identifier_feature_name: str = None,
+        included_feature_names: List[str] = None,
+        kms_key_id: str = None,
+    ) -> "DatasetBuilder":
+        """Create a DatasetBuilder for generating a Dataset.
+
+        Args:
+            base: A FeatureGroup or DataFrame to use as the base.
+            output_path: S3 URI for output.
+            session: SageMaker session.
+            record_identifier_feature_name: Required if base is DataFrame.
+            event_time_identifier_feature_name: Required if base is DataFrame.
+            included_feature_names: Features to include in output.
+            kms_key_id: KMS key for encryption.
+
+        Returns:
+            DatasetBuilder instance.
+        """
+        if isinstance(base, pd.DataFrame):
+            if not record_identifier_feature_name or not event_time_identifier_feature_name:
+                raise ValueError(
+                    "record_identifier_feature_name and event_time_identifier_feature_name "
+                    "are required when base is a DataFrame."
+                )
+        return cls(
+            _sagemaker_session=session,
+            _base=base,
+            _output_path=output_path,
+            _record_identifier_feature_name=record_identifier_feature_name,
+            _event_time_identifier_feature_name=event_time_identifier_feature_name,
+            _included_feature_names=included_feature_names,
+            _kms_key_id=kms_key_id,
+        )
+
     def with_feature_group(
         self,
         feature_group: FeatureGroup,
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py
index f7f6523b8d..0b7c747515 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py
@@ -13,7 +13,6 @@
 from sagemaker.mlops.feature_store import FeatureGroup as CoreFeatureGroup, FeatureGroup
 from sagemaker.core.helper.session_helper import Session
 from sagemaker.core.s3.client import S3Uploader, S3Downloader
-from sagemaker.mlops.feature_store.dataset_builder import DatasetBuilder
 from sagemaker.mlops.feature_store.feature_definition import (
     FeatureDefinition,
     FractionalFeatureDefinition,
@@ -23,7 +22,7 @@
 )
 from sagemaker.mlops.feature_store.ingestion_manager_pandas import IngestionManagerPandas
 
-from sagemaker import utils
+from sagemaker.core.utils import unique_name_from_base
 
 
 logger = logging.getLogger(__name__)
@@ -207,7 +206,7 @@ def upload_dataframe_to_s3(
         Tuple of (s3_folder, temp_table_name).
     """
 
-    temp_id = utils.unique_name_from_base("dataframe-base")
+    temp_id = unique_name_from_base("dataframe-base")
     local_file = f"{temp_id}.csv"
     s3_folder = os.path.join(output_path, temp_id)
 
@@ -460,29 +459,3 @@ def ingest_dataframe(
     manager.run(data_frame=data_frame, wait=wait, timeout=timeout)
     return manager
 
-def create_dataset(
-    base: Union[FeatureGroup, pd.DataFrame],
-    output_path: str,
-    session: Session,
-    record_identifier_feature_name: str = None,
-    event_time_identifier_feature_name: str = None,
-    included_feature_names: Sequence[str] = None,
-    kms_key_id: str = None,
-) -> DatasetBuilder:
-    """Create a DatasetBuilder for generating a Dataset."""
-    if isinstance(base, pd.DataFrame):
-        if not record_identifier_feature_name or not event_time_identifier_feature_name:
-            raise ValueError(
-                "record_identifier_feature_name and event_time_identifier_feature_name "
-                "are required when base is a DataFrame."
-            )
-    return DatasetBuilder(
-        _sagemaker_session=session,
-        _base=base,
-        _output_path=output_path,
-        _record_identifier_feature_name=record_identifier_feature_name,
-        _event_time_identifier_feature_name=event_time_identifier_feature_name,
-        _included_feature_names=included_feature_names,
-        _kms_key_id=kms_key_id,
-    )
-
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/ingestion_manager_pandas.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/ingestion_manager_pandas.py
index 60d022dab1..4d7b4e5375 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/ingestion_manager_pandas.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/ingestion_manager_pandas.py
@@ -6,13 +6,12 @@
 import signal
 from concurrent.futures import ThreadPoolExecutor, as_completed
 from dataclasses import dataclass, field
-from multiprocessing.pool import AsyncResult
+from multiprocessing import Pool
 from typing import Any, Dict, Iterable, List, Sequence, Union
 
 import pandas as pd
 from pandas import DataFrame
 from pandas.api.types import is_list_like
-from pathos.multiprocessing import ProcessingPool
 
 from sagemaker.core.resources import FeatureGroup as CoreFeatureGroup
 from sagemaker.core.shapes import FeatureValue
@@ -54,8 +53,8 @@ class IngestionManagerPandas:
     feature_definitions: Dict[str, Dict[Any, Any]]
     max_workers: int = 1
     max_processes: int = 1
-    _async_result: AsyncResult = field(default=None, init=False)
-    _processing_pool: ProcessingPool = field(default=None, init=False)
+    _async_result: Any = field(default=None, init=False)
+    _processing_pool: Pool = field(default=None, init=False)
     _failed_indices: List[int] = field(default_factory=list, init=False)
 
     @property
@@ -100,12 +99,11 @@ def wait(self, timeout: Union[int, float] = None):
             results = self._async_result.get(timeout=timeout)
         except KeyboardInterrupt as e:
             self._processing_pool.terminate()
-            self._processing_pool.close()
-            self._processing_pool.clear()
+            self._processing_pool.join()
             raise e
         else:
             self._processing_pool.close()
-            self._processing_pool.clear()
+            self._processing_pool.join()
 
         self._failed_indices = [idx for failed in results for idx in failed]
 
@@ -170,11 +168,10 @@ def _run_multi_process(
         def init_worker():
             signal.signal(signal.SIGINT, signal.SIG_IGN)
 
-        self._processing_pool = ProcessingPool(self.max_processes, init_worker)
-        self._processing_pool.restart(force=True)
+        self._processing_pool = Pool(self.max_processes, init_worker)
 
-        self._async_result = self._processing_pool.amap(
-            lambda x: IngestionManagerPandas._run_multi_threaded(*x),
+        self._async_result = self._processing_pool.starmap_async(
+            IngestionManagerPandas._run_multi_threaded,
             args,
         )
 
diff --git a/sagemaker-mlops/tests/__init__.py b/sagemaker-mlops/tests/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/sagemaker-mlops/tests/unit/__init__.py b/sagemaker-mlops/tests/unit/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/sagemaker-mlops/tests/unit/sagemaker/__init__.py b/sagemaker-mlops/tests/unit/sagemaker/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/__init__.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/__init__.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/__init__.py
new file mode 100644
index 0000000000..f34bf7d447
--- /dev/null
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/__init__.py
@@ -0,0 +1,2 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/conftest.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/conftest.py
new file mode 100644
index 0000000000..9b2ec55895
--- /dev/null
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/conftest.py
@@ -0,0 +1,80 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
+"""Conftest for feature_store tests."""
+import pytest
+from unittest.mock import Mock, MagicMock
+import pandas as pd
+import numpy as np
+
+
+@pytest.fixture
+def mock_session():
+    """Create a mock Session."""
+    session = Mock()
+    session.boto_session = Mock()
+    session.boto_region_name = "us-west-2"
+    session.sagemaker_client = Mock()
+    session.sagemaker_runtime_client = Mock()
+    session.sagemaker_featurestore_runtime_client = Mock()
+    return session
+
+
+@pytest.fixture
+def sample_dataframe():
+    """Create a sample DataFrame for testing."""
+    return pd.DataFrame({
+        "id": pd.Series([1, 2, 3, 4, 5], dtype="int64"),
+        "value": pd.Series([1.1, 2.2, 3.3, 4.4, 5.5], dtype="float64"),
+        "name": pd.Series(["a", "b", "c", "d", "e"], dtype="string"),
+        "event_time": pd.Series(
+            ["2024-01-01T00:00:00Z"] * 5,
+            dtype="string"
+        ),
+    })
+
+
+@pytest.fixture
+def dataframe_with_collections():
+    """Create a DataFrame with collection type columns."""
+    return pd.DataFrame({
+        "id": pd.Series([1, 2, 3], dtype="int64"),
+        "tags": pd.Series([["a", "b"], ["c"], ["d", "e", "f"]], dtype="object"),
+        "scores": pd.Series([[1.0, 2.0], [3.0], [4.0, 5.0]], dtype="object"),
+        "event_time": pd.Series(["2024-01-01"] * 3, dtype="string"),
+    })
+
+
+@pytest.fixture
+def feature_definitions_dict():
+    """Create a feature definitions dictionary."""
+    return {
+        "id": {"FeatureName": "id", "FeatureType": "Integral"},
+        "value": {"FeatureName": "value", "FeatureType": "Fractional"},
+        "name": {"FeatureName": "name", "FeatureType": "String"},
+        "event_time": {"FeatureName": "event_time", "FeatureType": "String"},
+    }
+
+
+@pytest.fixture
+def mock_feature_group():
+    """Create a mock FeatureGroup from core."""
+    fg = MagicMock()
+    fg.feature_group_name = "test-feature-group"
+    fg.record_identifier_feature_name = "id"
+    fg.event_time_feature_name = "event_time"
+    fg.feature_definitions = [
+        MagicMock(feature_name="id", feature_type="Integral"),
+        MagicMock(feature_name="value", feature_type="Fractional"),
+        MagicMock(feature_name="name", feature_type="String"),
+        MagicMock(feature_name="event_time", feature_type="String"),
+    ]
+    fg.offline_store_config = MagicMock()
+    fg.offline_store_config.s3_storage_config.s3_uri = "s3://bucket/prefix"
+    fg.offline_store_config.s3_storage_config.resolved_output_s3_uri = "s3://bucket/prefix/resolved"
+    fg.offline_store_config.data_catalog_config.catalog = "AwsDataCatalog"
+    fg.offline_store_config.data_catalog_config.database = "sagemaker_featurestore"
+    fg.offline_store_config.data_catalog_config.table_name = "test_feature_group"
+    fg.offline_store_config.data_catalog_config.disable_glue_table_creation = False
+    fg.online_store_config = MagicMock()
+    fg.online_store_config.enable_online_store = True
+    return fg
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_athena_query.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_athena_query.py
new file mode 100644
index 0000000000..2fed784208
--- /dev/null
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_athena_query.py
@@ -0,0 +1,113 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
+"""Unit tests for athena_query.py"""
+import os
+import pytest
+from unittest.mock import Mock, patch, MagicMock
+import pandas as pd
+
+from sagemaker.mlops.feature_store.athena_query import AthenaQuery
+
+
+class TestAthenaQuery:
+    @pytest.fixture
+    def mock_session(self):
+        session = Mock()
+        session.boto_session.client.return_value = Mock()
+        session.boto_region_name = "us-west-2"
+        return session
+
+    @pytest.fixture
+    def athena_query(self, mock_session):
+        return AthenaQuery(
+            catalog="AwsDataCatalog",
+            database="sagemaker_featurestore",
+            table_name="my_feature_group",
+            sagemaker_session=mock_session,
+        )
+
+    def test_initialization(self, athena_query):
+        assert athena_query.catalog == "AwsDataCatalog"
+        assert athena_query.database == "sagemaker_featurestore"
+        assert athena_query.table_name == "my_feature_group"
+        assert athena_query._current_query_execution_id is None
+
+    @patch("sagemaker.mlops.feature_store.athena_query.start_query_execution")
+    def test_run_starts_query(self, mock_start, athena_query):
+        mock_start.return_value = {"QueryExecutionId": "query-123"}
+
+        result = athena_query.run(
+            query_string="SELECT * FROM table",
+            output_location="s3://bucket/output",
+        )
+
+        assert result == "query-123"
+        assert athena_query._current_query_execution_id == "query-123"
+        assert athena_query._result_bucket == "bucket"
+        assert athena_query._result_file_prefix == "output"
+
+    @patch("sagemaker.mlops.feature_store.athena_query.start_query_execution")
+    def test_run_with_kms_key(self, mock_start, athena_query):
+        mock_start.return_value = {"QueryExecutionId": "query-123"}
+
+        athena_query.run(
+            query_string="SELECT * FROM table",
+            output_location="s3://bucket/output",
+            kms_key="arn:aws:kms:us-west-2:123:key/abc",
+        )
+
+        mock_start.assert_called_once()
+        call_kwargs = mock_start.call_args[1]
+        assert call_kwargs["kms_key"] == "arn:aws:kms:us-west-2:123:key/abc"
+
+    @patch("sagemaker.mlops.feature_store.athena_query.wait_for_athena_query")
+    def test_wait_calls_helper(self, mock_wait, athena_query):
+        athena_query._current_query_execution_id = "query-123"
+
+        athena_query.wait()
+
+        mock_wait.assert_called_once_with(athena_query.sagemaker_session, "query-123")
+
+    @patch("sagemaker.mlops.feature_store.athena_query.get_query_execution")
+    def test_get_query_execution(self, mock_get, athena_query):
+        athena_query._current_query_execution_id = "query-123"
+        mock_get.return_value = {"QueryExecution": {"Status": {"State": "SUCCEEDED"}}}
+
+        result = athena_query.get_query_execution()
+
+        assert result["QueryExecution"]["Status"]["State"] == "SUCCEEDED"
+
+    @patch("sagemaker.mlops.feature_store.athena_query.get_query_execution")
+    @patch("sagemaker.mlops.feature_store.athena_query.download_athena_query_result")
+    @patch("pandas.read_csv")
+    @patch("os.path.join")
+    def test_as_dataframe_success(self, mock_join, mock_read_csv, mock_download, mock_get, athena_query):
+        athena_query._current_query_execution_id = "query-123"
+        athena_query._result_bucket = "bucket"
+        athena_query._result_file_prefix = "prefix"
+
+        mock_get.return_value = {"QueryExecution": {"Status": {"State": "SUCCEEDED"}}}
+        mock_join.return_value = "/tmp/query-123.csv"
+        mock_read_csv.return_value = pd.DataFrame({"col": [1, 2, 3]})
+
+        with patch("tempfile.gettempdir", return_value="/tmp"):
+            with patch("os.remove"):
+                df = athena_query.as_dataframe()
+
+        assert len(df) == 3
+
+    @patch("sagemaker.mlops.feature_store.athena_query.get_query_execution")
+    def test_as_dataframe_raises_when_running(self, mock_get, athena_query):
+        athena_query._current_query_execution_id = "query-123"
+        mock_get.return_value = {"QueryExecution": {"Status": {"State": "RUNNING"}}}
+
+        with pytest.raises(RuntimeError, match="still executing"):
+            athena_query.as_dataframe()
+
+    @patch("sagemaker.mlops.feature_store.athena_query.get_query_execution")
+    def test_as_dataframe_raises_when_failed(self, mock_get, athena_query):
+        athena_query._current_query_execution_id = "query-123"
+        mock_get.return_value = {"QueryExecution": {"Status": {"State": "FAILED"}}}
+
+        with pytest.raises(RuntimeError, match="failed"):
+            athena_query.as_dataframe()
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_dataset_builder.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_dataset_builder.py
new file mode 100644
index 0000000000..254fb0e196
--- /dev/null
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_dataset_builder.py
@@ -0,0 +1,345 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
+"""Unit tests for dataset_builder.py"""
+import datetime
+import pytest
+from unittest.mock import Mock, patch, MagicMock
+import pandas as pd
+
+from sagemaker.mlops.feature_store import FeatureGroup
+from sagemaker.mlops.feature_store.dataset_builder import (
+    DatasetBuilder,
+    FeatureGroupToBeMerged,
+    TableType,
+    JoinTypeEnum,
+    JoinComparatorEnum,
+    construct_feature_group_to_be_merged,
+)
+from sagemaker.mlops.feature_store.feature_definition import (
+    FeatureDefinition,
+    FeatureTypeEnum,
+)
+
+
+class TestTableType:
+    def test_feature_group_value(self):
+        assert TableType.FEATURE_GROUP.value == "FeatureGroup"
+
+    def test_data_frame_value(self):
+        assert TableType.DATA_FRAME.value == "DataFrame"
+
+
+class TestJoinTypeEnum:
+    def test_inner_join(self):
+        assert JoinTypeEnum.INNER_JOIN.value == "JOIN"
+
+    def test_left_join(self):
+        assert JoinTypeEnum.LEFT_JOIN.value == "LEFT JOIN"
+
+    def test_right_join(self):
+        assert JoinTypeEnum.RIGHT_JOIN.value == "RIGHT JOIN"
+
+    def test_full_join(self):
+        assert JoinTypeEnum.FULL_JOIN.value == "FULL JOIN"
+
+    def test_cross_join(self):
+        assert JoinTypeEnum.CROSS_JOIN.value == "CROSS JOIN"
+
+
+class TestJoinComparatorEnum:
+    def test_equals(self):
+        assert JoinComparatorEnum.EQUALS.value == "="
+
+    def test_greater_than(self):
+        assert JoinComparatorEnum.GREATER_THAN.value == ">"
+
+    def test_less_than(self):
+        assert JoinComparatorEnum.LESS_THAN.value == "<"
+
+
+class TestFeatureGroupToBeMerged:
+    def test_initialization(self):
+        fg = FeatureGroupToBeMerged(
+            features=["id", "value"],
+            included_feature_names=["id", "value"],
+            projected_feature_names=["id", "value"],
+            catalog="AwsDataCatalog",
+            database="sagemaker_featurestore",
+            table_name="my_table",
+            record_identifier_feature_name="id",
+            event_time_identifier_feature=FeatureDefinition(
+                feature_name="event_time",
+                feature_type="String",
+            ),
+        )
+
+        assert fg.features == ["id", "value"]
+        assert fg.catalog == "AwsDataCatalog"
+        assert fg.table_name == "my_table"
+        assert fg.join_type == JoinTypeEnum.INNER_JOIN
+        assert fg.join_comparator == JoinComparatorEnum.EQUALS
+
+    def test_custom_join_settings(self):
+        fg = FeatureGroupToBeMerged(
+            features=["id"],
+            included_feature_names=["id"],
+            projected_feature_names=["id"],
+            catalog="AwsDataCatalog",
+            database="db",
+            table_name="table",
+            record_identifier_feature_name="id",
+            event_time_identifier_feature=FeatureDefinition(
+                feature_name="ts",
+                feature_type="String",
+            ),
+            join_type=JoinTypeEnum.LEFT_JOIN,
+            join_comparator=JoinComparatorEnum.GREATER_THAN,
+        )
+
+        assert fg.join_type == JoinTypeEnum.LEFT_JOIN
+        assert fg.join_comparator == JoinComparatorEnum.GREATER_THAN
+
+
+class TestConstructFeatureGroupToBeMerged:
+    @patch("sagemaker.mlops.feature_store.dataset_builder.FeatureGroup")
+    def test_constructs_from_feature_group(self, mock_fg_class):
+        mock_fg = MagicMock()
+        mock_fg.feature_group_name = "test-fg"
+        mock_fg.record_identifier_feature_name = "id"
+        mock_fg.event_time_feature_name = "event_time"
+        mock_fg.feature_definitions = [
+            MagicMock(feature_name="id", feature_type="Integral"),
+            MagicMock(feature_name="value", feature_type="Fractional"),
+            MagicMock(feature_name="event_time", feature_type="String"),
+        ]
+        mock_fg.offline_store_config.data_catalog_config.catalog = "MyCatalog"
+        mock_fg.offline_store_config.data_catalog_config.database = "MyDatabase"
+        mock_fg.offline_store_config.data_catalog_config.table_name = "MyTable"
+        mock_fg.offline_store_config.data_catalog_config.disable_glue_table_creation = False
+        mock_fg_class.get.return_value = mock_fg
+
+        target_fg = MagicMock()
+        target_fg.feature_group_name = "test-fg"
+
+        result = construct_feature_group_to_be_merged(
+            target_feature_group=target_fg,
+            included_feature_names=["id", "value"],
+        )
+
+        assert result.table_name == "MyTable"
+        assert result.database == "MyDatabase"
+        assert result.record_identifier_feature_name == "id"
+        assert result.table_type == TableType.FEATURE_GROUP
+
+    @patch("sagemaker.mlops.feature_store.dataset_builder.FeatureGroup")
+    def test_raises_when_no_metastore(self, mock_fg_class):
+        mock_fg = MagicMock()
+        mock_fg.feature_group_name = "test-fg"
+        mock_fg.offline_store_config = None
+        mock_fg_class.get.return_value = mock_fg
+
+        target_fg = MagicMock()
+        target_fg.feature_group_name = "test-fg"
+
+        with pytest.raises(RuntimeError, match="No metastore"):
+            construct_feature_group_to_be_merged(target_fg, None)
+
+
+class TestDatasetBuilder:
+    @pytest.fixture
+    def mock_session(self):
+        return Mock()
+
+    @pytest.fixture
+    def sample_dataframe(self):
+        return pd.DataFrame({
+            "id": [1, 2, 3],
+            "value": [1.1, 2.2, 3.3],
+            "event_time": ["2024-01-01", "2024-01-02", "2024-01-03"],
+        })
+
+    def test_initialization_with_dataframe(self, mock_session, sample_dataframe):
+        builder = DatasetBuilder(
+            _sagemaker_session=mock_session,
+            _base=sample_dataframe,
+            _output_path="s3://bucket/output",
+            _record_identifier_feature_name="id",
+            _event_time_identifier_feature_name="event_time",
+        )
+
+        assert builder._output_path == "s3://bucket/output"
+        assert builder._record_identifier_feature_name == "id"
+
+    def test_fluent_api_point_in_time(self, mock_session, sample_dataframe):
+        builder = DatasetBuilder(
+            _sagemaker_session=mock_session,
+            _base=sample_dataframe,
+            _output_path="s3://bucket/output",
+            _record_identifier_feature_name="id",
+            _event_time_identifier_feature_name="event_time",
+        )
+
+        result = builder.point_in_time_accurate_join()
+
+        assert result is builder
+        assert builder._point_in_time_accurate_join is True
+
+    def test_fluent_api_include_duplicated(self, mock_session, sample_dataframe):
+        builder = DatasetBuilder(
+            _sagemaker_session=mock_session,
+            _base=sample_dataframe,
+            _output_path="s3://bucket/output",
+            _record_identifier_feature_name="id",
+            _event_time_identifier_feature_name="event_time",
+        )
+
+        result = builder.include_duplicated_records()
+
+        assert result is builder
+        assert builder._include_duplicated_records is True
+
+    def test_fluent_api_include_deleted(self, mock_session, sample_dataframe):
+        builder = DatasetBuilder(
+            _sagemaker_session=mock_session,
+            _base=sample_dataframe,
+            _output_path="s3://bucket/output",
+            _record_identifier_feature_name="id",
+            _event_time_identifier_feature_name="event_time",
+        )
+
+        result = builder.include_deleted_records()
+
+        assert result is builder
+        assert builder._include_deleted_records is True
+
+    def test_fluent_api_number_of_recent_records(self, mock_session, sample_dataframe):
+        builder = DatasetBuilder(
+            _sagemaker_session=mock_session,
+            _base=sample_dataframe,
+            _output_path="s3://bucket/output",
+            _record_identifier_feature_name="id",
+            _event_time_identifier_feature_name="event_time",
+        )
+
+        result = builder.with_number_of_recent_records_by_record_identifier(5)
+
+        assert result is builder
+        assert builder._number_of_recent_records == 5
+
+    def test_fluent_api_number_of_records(self, mock_session, sample_dataframe):
+        builder = DatasetBuilder(
+            _sagemaker_session=mock_session,
+            _base=sample_dataframe,
+            _output_path="s3://bucket/output",
+            _record_identifier_feature_name="id",
+            _event_time_identifier_feature_name="event_time",
+        )
+
+        result = builder.with_number_of_records_from_query_results(100)
+
+        assert result is builder
+        assert builder._number_of_records == 100
+
+    def test_fluent_api_as_of(self, mock_session, sample_dataframe):
+        builder = DatasetBuilder(
+            _sagemaker_session=mock_session,
+            _base=sample_dataframe,
+            _output_path="s3://bucket/output",
+            _record_identifier_feature_name="id",
+            _event_time_identifier_feature_name="event_time",
+        )
+
+        timestamp = datetime.datetime(2024, 1, 15, 12, 0, 0)
+        result = builder.as_of(timestamp)
+
+        assert result is builder
+        assert builder._write_time_ending_timestamp == timestamp
+
+    def test_fluent_api_event_time_range(self, mock_session, sample_dataframe):
+        builder = DatasetBuilder(
+            _sagemaker_session=mock_session,
+            _base=sample_dataframe,
+            _output_path="s3://bucket/output",
+            _record_identifier_feature_name="id",
+            _event_time_identifier_feature_name="event_time",
+        )
+
+        start = datetime.datetime(2024, 1, 1)
+        end = datetime.datetime(2024, 1, 31)
+        result = builder.with_event_time_range(start, end)
+
+        assert result is builder
+        assert builder._event_time_starting_timestamp == start
+        assert builder._event_time_ending_timestamp == end
+
+    @patch.object(DatasetBuilder, "_run_query")
+    @patch("sagemaker.mlops.feature_store.dataset_builder.construct_feature_group_to_be_merged")
+    def test_with_feature_group(self, mock_construct, mock_run, mock_session, sample_dataframe):
+        mock_fg_to_merge = MagicMock()
+        mock_construct.return_value = mock_fg_to_merge
+
+        builder = DatasetBuilder(
+            _sagemaker_session=mock_session,
+            _base=sample_dataframe,
+            _output_path="s3://bucket/output",
+            _record_identifier_feature_name="id",
+            _event_time_identifier_feature_name="event_time",
+        )
+
+        mock_fg = MagicMock()
+        result = builder.with_feature_group(mock_fg, target_feature_name_in_base="id")
+
+        assert result is builder
+        assert len(builder._feature_groups_to_be_merged) == 1
+
+
+class TestDatasetBuilderCreate:
+    @pytest.fixture
+    def mock_session(self):
+        return Mock()
+
+    def test_create_with_feature_group(self, mock_session):
+        mock_fg = MagicMock(spec=FeatureGroup)
+        builder = DatasetBuilder.create(
+            base=mock_fg,
+            output_path="s3://bucket/output",
+            session=mock_session,
+        )
+        assert builder._base == mock_fg
+        assert builder._output_path == "s3://bucket/output"
+
+    def test_create_with_dataframe(self, mock_session):
+        df = pd.DataFrame({"id": [1], "value": [10]})
+        builder = DatasetBuilder.create(
+            base=df,
+            output_path="s3://bucket/output",
+            session=mock_session,
+            record_identifier_feature_name="id",
+            event_time_identifier_feature_name="event_time",
+        )
+        assert builder._record_identifier_feature_name == "id"
+
+    def test_create_with_dataframe_requires_identifiers(self, mock_session):
+        df = pd.DataFrame({"id": [1], "value": [10]})
+        with pytest.raises(ValueError, match="record_identifier_feature_name"):
+            DatasetBuilder.create(
+                base=df,
+                output_path="s3://bucket/output",
+                session=mock_session,
+            )
+
+
+class TestDatasetBuilderValidation:
+    @pytest.fixture
+    def mock_session(self):
+        return Mock()
+
+    def test_to_csv_raises_for_invalid_base(self, mock_session):
+        builder = DatasetBuilder(
+            _sagemaker_session=mock_session,
+            _base="invalid",  # Not DataFrame or FeatureGroup
+            _output_path="s3://bucket/output",
+        )
+
+        with pytest.raises(ValueError, match="must be either"):
+            builder.to_csv_file()
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_feature_definition.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_feature_definition.py
new file mode 100644
index 0000000000..299868b5d2
--- /dev/null
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_feature_definition.py
@@ -0,0 +1,126 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
+"""Unit tests for feature_definition.py"""
+import pytest
+
+from sagemaker.mlops.feature_store.feature_definition import (
+    FeatureDefinition,
+    FeatureTypeEnum,
+    CollectionTypeEnum,
+    IntegralFeatureDefinition,
+    FractionalFeatureDefinition,
+    StringFeatureDefinition,
+    VectorCollectionType,
+    ListCollectionType,
+    SetCollectionType,
+)
+
+
+class TestFeatureTypeEnum:
+    def test_fractional_value(self):
+        assert FeatureTypeEnum.FRACTIONAL.value == "Fractional"
+
+    def test_integral_value(self):
+        assert FeatureTypeEnum.INTEGRAL.value == "Integral"
+
+    def test_string_value(self):
+        assert FeatureTypeEnum.STRING.value == "String"
+
+
+class TestCollectionTypeEnum:
+    def test_list_value(self):
+        assert CollectionTypeEnum.LIST.value == "List"
+
+    def test_set_value(self):
+        assert CollectionTypeEnum.SET.value == "Set"
+
+    def test_vector_value(self):
+        assert CollectionTypeEnum.VECTOR.value == "Vector"
+
+
+class TestCollectionTypes:
+    def test_list_collection_type(self):
+        collection = ListCollectionType()
+        assert collection.collection_type == "List"
+        assert collection.collection_config is None
+
+    def test_set_collection_type(self):
+        collection = SetCollectionType()
+        assert collection.collection_type == "Set"
+        assert collection.collection_config is None
+
+    def test_vector_collection_type(self):
+        collection = VectorCollectionType(dimension=128)
+        assert collection.collection_type == "Vector"
+        assert collection.collection_config is not None
+        assert collection.collection_config.vector_config.dimension == 128
+
+
+class TestFeatureDefinitionFactories:
+    def test_integral_feature_definition(self):
+        definition = IntegralFeatureDefinition(feature_name="my_int_feature")
+        assert definition.feature_name == "my_int_feature"
+        assert definition.feature_type == "Integral"
+        assert definition.collection_type is None
+
+    def test_fractional_feature_definition(self):
+        definition = FractionalFeatureDefinition(feature_name="my_float_feature")
+        assert definition.feature_name == "my_float_feature"
+        assert definition.feature_type == "Fractional"
+        assert definition.collection_type is None
+
+    def test_string_feature_definition(self):
+        definition = StringFeatureDefinition(feature_name="my_string_feature")
+        assert definition.feature_name == "my_string_feature"
+        assert definition.feature_type == "String"
+        assert definition.collection_type is None
+
+    def test_integral_with_list_collection(self):
+        definition = IntegralFeatureDefinition(
+            feature_name="my_int_list",
+            collection_type=ListCollectionType(),
+        )
+        assert definition.feature_name == "my_int_list"
+        assert definition.feature_type == "Integral"
+        assert definition.collection_type == "List"
+
+    def test_string_with_set_collection(self):
+        definition = StringFeatureDefinition(
+            feature_name="my_string_set",
+            collection_type=SetCollectionType(),
+        )
+        assert definition.feature_name == "my_string_set"
+        assert definition.feature_type == "String"
+        assert definition.collection_type == "Set"
+
+    def test_fractional_with_vector_collection(self):
+        definition = FractionalFeatureDefinition(
+            feature_name="my_embedding",
+            collection_type=VectorCollectionType(dimension=256),
+        )
+        assert definition.feature_name == "my_embedding"
+        assert definition.feature_type == "Fractional"
+        assert definition.collection_type == "Vector"
+        assert definition.collection_config.vector_config.dimension == 256
+
+
+class TestFeatureDefinitionSerialization:
+    """Test that FeatureDefinition can be serialized (Pydantic model_dump)."""
+
+    def test_simple_definition_serialization(self):
+        definition = IntegralFeatureDefinition(feature_name="id")
+        # Pydantic model - use model_dump
+        data = definition.model_dump(exclude_none=True)
+        assert data["feature_name"] == "id"
+        assert data["feature_type"] == "Integral"
+
+    def test_collection_definition_serialization(self):
+        definition = FractionalFeatureDefinition(
+            feature_name="vector",
+            collection_type=VectorCollectionType(dimension=10),
+        )
+        data = definition.model_dump(exclude_none=True)
+        assert data["feature_name"] == "vector"
+        assert data["feature_type"] == "Fractional"
+        assert data["collection_type"] == "Vector"
+        assert data["collection_config"]["vector_config"]["dimension"] == 10
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_feature_utils.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_feature_utils.py
new file mode 100644
index 0000000000..a9d5408bf6
--- /dev/null
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_feature_utils.py
@@ -0,0 +1,202 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
+"""Unit tests for feature_utils.py"""
+import pytest
+from unittest.mock import Mock, patch, MagicMock
+import pandas as pd
+import numpy as np
+
+from sagemaker.mlops.feature_store.feature_utils import (
+    load_feature_definitions_from_dataframe,
+    as_hive_ddl,
+    create_athena_query,
+    ingest_dataframe,
+    get_session_from_role,
+    _is_collection_column,
+    _generate_feature_definition,
+)
+from sagemaker.mlops.feature_store.feature_definition import (
+    FeatureDefinition,
+    ListCollectionType,
+)
+
+
+class TestLoadFeatureDefinitionsFromDataframe:
+    @pytest.fixture
+    def sample_dataframe(self):
+        return pd.DataFrame({
+            "id": pd.Series([1, 2, 3], dtype="int64"),
+            "value": pd.Series([1.1, 2.2, 3.3], dtype="float64"),
+            "name": pd.Series(["a", "b", "c"], dtype="string"),
+        })
+
+    def test_infers_integral_type(self, sample_dataframe):
+        defs = load_feature_definitions_from_dataframe(sample_dataframe)
+        id_def = next(d for d in defs if d.feature_name == "id")
+        assert id_def.feature_type == "Integral"
+
+    def test_infers_fractional_type(self, sample_dataframe):
+        defs = load_feature_definitions_from_dataframe(sample_dataframe)
+        value_def = next(d for d in defs if d.feature_name == "value")
+        assert value_def.feature_type == "Fractional"
+
+    def test_infers_string_type(self, sample_dataframe):
+        defs = load_feature_definitions_from_dataframe(sample_dataframe)
+        name_def = next(d for d in defs if d.feature_name == "name")
+        assert name_def.feature_type == "String"
+
+    def test_returns_correct_count(self, sample_dataframe):
+        defs = load_feature_definitions_from_dataframe(sample_dataframe)
+        assert len(defs) == 3
+
+    def test_collection_type_with_in_memory_storage(self):
+        df = pd.DataFrame({
+            "id": pd.Series([1, 2], dtype="int64"),
+            "tags": pd.Series([["a", "b"], ["c"]], dtype="object"),
+        })
+        defs = load_feature_definitions_from_dataframe(df, online_storage_type="InMemory")
+        tags_def = next(d for d in defs if d.feature_name == "tags")
+        assert tags_def.collection_type == "List"
+
+
+class TestIsCollectionColumn:
+    def test_list_column_returns_true(self):
+        series = pd.Series([[1, 2], [3, 4], [5]])
+        assert _is_collection_column(series) == True
+
+    def test_scalar_column_returns_false(self):
+        series = pd.Series([1, 2, 3])
+        assert _is_collection_column(series) == False
+
+    def test_empty_series(self):
+        series = pd.Series([], dtype="object")
+        assert _is_collection_column(series) == False
+
+
+class TestAsHiveDdl:
+    @patch("sagemaker.mlops.feature_store.feature_utils.CoreFeatureGroup")
+    def test_generates_ddl_string(self, mock_fg_class):
+        # Setup mock
+        mock_fg = MagicMock()
+        mock_fg.feature_definitions = [
+            MagicMock(feature_name="id", feature_type="Integral"),
+            MagicMock(feature_name="value", feature_type="Fractional"),
+            MagicMock(feature_name="name", feature_type="String"),
+        ]
+        mock_fg.offline_store_config.s3_storage_config.resolved_output_s3_uri = "s3://bucket/prefix"
+        mock_fg_class.get.return_value = mock_fg
+
+        ddl = as_hive_ddl("my-feature-group")
+
+        assert "CREATE EXTERNAL TABLE" in ddl
+        assert "my-feature-group" in ddl
+        assert "id INT" in ddl
+        assert "value FLOAT" in ddl
+        assert "name STRING" in ddl
+        assert "write_time TIMESTAMP" in ddl
+        assert "event_time TIMESTAMP" in ddl
+        assert "is_deleted BOOLEAN" in ddl
+        assert "s3://bucket/prefix" in ddl
+
+    @patch("sagemaker.mlops.feature_store.feature_utils.CoreFeatureGroup")
+    def test_custom_database_and_table(self, mock_fg_class):
+        mock_fg = MagicMock()
+        mock_fg.feature_definitions = []
+        mock_fg.offline_store_config.s3_storage_config.resolved_output_s3_uri = "s3://bucket/prefix"
+        mock_fg_class.get.return_value = mock_fg
+
+        ddl = as_hive_ddl("my-fg", database="custom_db", table_name="custom_table")
+
+        assert "custom_db.custom_table" in ddl
+
+
+class TestCreateAthenaQuery:
+    @patch("sagemaker.mlops.feature_store.feature_utils.CoreFeatureGroup")
+    def test_creates_athena_query(self, mock_fg_class):
+        mock_fg = MagicMock()
+        mock_fg.offline_store_config.data_catalog_config.catalog = "MyCatalog"
+        mock_fg.offline_store_config.data_catalog_config.database = "MyDatabase"
+        mock_fg.offline_store_config.data_catalog_config.table_name = "MyTable"
+        mock_fg.offline_store_config.data_catalog_config.disable_glue_table_creation = False
+        mock_fg_class.get.return_value = mock_fg
+
+        session = Mock()
+        query = create_athena_query("my-fg", session)
+
+        assert query.catalog == "AwsDataCatalog"  # disable_glue=False uses default
+        assert query.database == "MyDatabase"
+        assert query.table_name == "MyTable"
+
+    @patch("sagemaker.mlops.feature_store.feature_utils.CoreFeatureGroup")
+    def test_raises_when_no_metastore(self, mock_fg_class):
+        mock_fg = MagicMock()
+        mock_fg.offline_store_config = None
+        mock_fg_class.get.return_value = mock_fg
+
+        session = Mock()
+        with pytest.raises(RuntimeError, match="No metastore"):
+            create_athena_query("my-fg", session)
+
+
+class TestIngestDataframe:
+    @patch("sagemaker.mlops.feature_store.feature_utils.IngestionManagerPandas")
+    @patch("sagemaker.mlops.feature_store.feature_utils.CoreFeatureGroup")
+    def test_creates_manager_and_runs(self, mock_fg_class, mock_manager_class):
+        mock_fg = MagicMock()
+        mock_fg.feature_definitions = [
+            MagicMock(feature_name="id", feature_type="Integral"),
+        ]
+        mock_fg_class.get.return_value = mock_fg
+
+        mock_manager = MagicMock()
+        mock_manager_class.return_value = mock_manager
+
+        df = pd.DataFrame({"id": [1, 2, 3]})
+        result = ingest_dataframe("my-fg", df, max_workers=2, max_processes=1)
+
+        mock_manager_class.assert_called_once()
+        mock_manager.run.assert_called_once()
+        assert result == mock_manager
+
+    def test_raises_on_invalid_max_workers(self):
+        df = pd.DataFrame({"id": [1, 2, 3]})
+        with pytest.raises(ValueError, match="max_workers"):
+            ingest_dataframe("my-fg", df, max_workers=0)
+
+    def test_raises_on_invalid_max_processes(self):
+        df = pd.DataFrame({"id": [1, 2, 3]})
+        with pytest.raises(ValueError, match="max_processes"):
+            ingest_dataframe("my-fg", df, max_processes=-1)
+
+
+class TestGetSessionFromRole:
+    @patch("sagemaker.mlops.feature_store.feature_utils.boto3")
+    @patch("sagemaker.mlops.feature_store.feature_utils.Session")
+    def test_creates_session_without_role(self, mock_session_class, mock_boto3):
+        mock_boto_session = MagicMock()
+        mock_boto3.Session.return_value = mock_boto_session
+
+        get_session_from_role(region="us-west-2")
+
+        mock_boto3.Session.assert_called_with(region_name="us-west-2")
+        mock_session_class.assert_called_once()
+
+    @patch("sagemaker.mlops.feature_store.feature_utils.boto3")
+    @patch("sagemaker.mlops.feature_store.feature_utils.Session")
+    def test_assumes_role_when_provided(self, mock_session_class, mock_boto3):
+        mock_boto_session = MagicMock()
+        mock_sts = MagicMock()
+        mock_sts.assume_role.return_value = {
+            "Credentials": {
+                "AccessKeyId": "key",
+                "SecretAccessKey": "secret",
+                "SessionToken": "token",
+            }
+        }
+        mock_boto_session.client.return_value = mock_sts
+        mock_boto3.Session.return_value = mock_boto_session
+
+        get_session_from_role(region="us-west-2", assume_role="arn:aws:iam::123:role/MyRole")
+
+        mock_sts.assume_role.assert_called_once()
+        assert mock_boto3.Session.call_count == 2  # Initial + after assume
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_ingestion_manager_pandas.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_ingestion_manager_pandas.py
new file mode 100644
index 0000000000..2ecf495967
--- /dev/null
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_ingestion_manager_pandas.py
@@ -0,0 +1,256 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
+"""Unit tests for ingestion_manager_pandas.py"""
+import pytest
+from unittest.mock import Mock, patch, MagicMock
+import pandas as pd
+import numpy as np
+
+from sagemaker.mlops.feature_store.ingestion_manager_pandas import (
+    IngestionManagerPandas,
+    IngestionError,
+)
+
+
+class TestIngestionError:
+    def test_stores_failed_rows(self):
+        error = IngestionError([1, 5, 10], "Some rows failed")
+        assert error.failed_rows == [1, 5, 10]
+        assert "Some rows failed" in str(error)
+
+
+class TestIngestionManagerPandas:
+    @pytest.fixture
+    def feature_definitions(self):
+        return {
+            "id": {"FeatureName": "id", "FeatureType": "Integral"},
+            "value": {"FeatureName": "value", "FeatureType": "Fractional"},
+            "name": {"FeatureName": "name", "FeatureType": "String"},
+        }
+
+    @pytest.fixture
+    def sample_dataframe(self):
+        return pd.DataFrame({
+            "id": [1, 2, 3],
+            "value": [1.1, 2.2, 3.3],
+            "name": ["a", "b", "c"],
+        })
+
+    @pytest.fixture
+    def manager(self, feature_definitions):
+        return IngestionManagerPandas(
+            feature_group_name="test-fg",
+            feature_definitions=feature_definitions,
+            max_workers=1,
+            max_processes=1,
+        )
+
+    def test_initialization(self, manager):
+        assert manager.feature_group_name == "test-fg"
+        assert manager.max_workers == 1
+        assert manager.max_processes == 1
+        assert manager.failed_rows == []
+
+    def test_failed_rows_property(self, manager):
+        manager._failed_indices = [1, 2, 3]
+        assert manager.failed_rows == [1, 2, 3]
+
+
+class TestIngestionManagerHelpers:
+    def test_is_feature_collection_type_true(self):
+        feature_defs = {
+            "tags": {"FeatureName": "tags", "FeatureType": "String", "CollectionType": "List"},
+        }
+        assert IngestionManagerPandas._is_feature_collection_type("tags", feature_defs) is True
+
+    def test_is_feature_collection_type_false(self):
+        feature_defs = {
+            "id": {"FeatureName": "id", "FeatureType": "Integral"},
+        }
+        assert IngestionManagerPandas._is_feature_collection_type("id", feature_defs) is False
+
+    def test_is_feature_collection_type_missing(self):
+        feature_defs = {}
+        assert IngestionManagerPandas._is_feature_collection_type("unknown", feature_defs) is False
+
+    def test_feature_value_is_not_none_scalar(self):
+        assert IngestionManagerPandas._feature_value_is_not_none(5) is True
+        assert IngestionManagerPandas._feature_value_is_not_none(None) is False
+        assert IngestionManagerPandas._feature_value_is_not_none(np.nan) is False
+
+    def test_feature_value_is_not_none_list(self):
+        assert IngestionManagerPandas._feature_value_is_not_none([1, 2, 3]) is True
+        assert IngestionManagerPandas._feature_value_is_not_none([]) is True
+        assert IngestionManagerPandas._feature_value_is_not_none(None) is False
+
+    def test_convert_to_string_list(self):
+        result = IngestionManagerPandas._convert_to_string_list([1, 2, 3])
+        assert result == ["1", "2", "3"]
+
+    def test_convert_to_string_list_with_none(self):
+        result = IngestionManagerPandas._convert_to_string_list([1, None, 3])
+        assert result == ["1", None, "3"]
+
+    def test_convert_to_string_list_raises_for_non_list(self):
+        with pytest.raises(ValueError, match="must be an Array"):
+            IngestionManagerPandas._convert_to_string_list("not a list")
+
+
+class TestIngestionManagerRun:
+    @pytest.fixture
+    def feature_definitions(self):
+        return {
+            "id": {"FeatureName": "id", "FeatureType": "Integral"},
+            "value": {"FeatureName": "value", "FeatureType": "Fractional"},
+        }
+
+    @pytest.fixture
+    def sample_dataframe(self):
+        return pd.DataFrame({
+            "id": [1, 2, 3],
+            "value": [1.1, 2.2, 3.3],
+        })
+
+    @patch.object(IngestionManagerPandas, "_run_single_process_single_thread")
+    def test_run_single_thread_mode(self, mock_single, feature_definitions, sample_dataframe):
+        manager = IngestionManagerPandas(
+            feature_group_name="test-fg",
+            feature_definitions=feature_definitions,
+            max_workers=1,
+            max_processes=1,
+        )
+
+        manager.run(sample_dataframe)
+
+        mock_single.assert_called_once()
+
+    @patch.object(IngestionManagerPandas, "_run_multi_process")
+    def test_run_multi_process_mode(self, mock_multi, feature_definitions, sample_dataframe):
+        manager = IngestionManagerPandas(
+            feature_group_name="test-fg",
+            feature_definitions=feature_definitions,
+            max_workers=2,
+            max_processes=2,
+        )
+
+        manager.run(sample_dataframe)
+
+        mock_multi.assert_called_once()
+
+
+class TestIngestionManagerIngestRow:
+    @pytest.fixture
+    def feature_definitions(self):
+        return {
+            "id": {"FeatureName": "id", "FeatureType": "Integral"},
+            "name": {"FeatureName": "name", "FeatureType": "String"},
+        }
+
+    @pytest.fixture
+    def collection_feature_definitions(self):
+        return {
+            "id": {"FeatureName": "id", "FeatureType": "Integral"},
+            "tags": {"FeatureName": "tags", "FeatureType": "String", "CollectionType": "List"},
+        }
+
+    def test_ingest_row_success(self, feature_definitions):
+        df = pd.DataFrame({"id": [1], "name": ["test"]})
+        mock_fg = MagicMock()
+        failed_rows = []
+
+        for row in df.itertuples():
+            IngestionManagerPandas._ingest_row(
+                data_frame=df,
+                row=row,
+                feature_group=mock_fg,
+                feature_definitions=feature_definitions,
+                failed_rows=failed_rows,
+                target_stores=None,
+            )
+
+        mock_fg.put_record.assert_called_once()
+        assert len(failed_rows) == 0
+
+    def test_ingest_row_with_collection_type(self, collection_feature_definitions):
+        df = pd.DataFrame({
+            "id": [1],
+            "tags": [["tag1", "tag2"]],
+        })
+        mock_fg = MagicMock()
+        failed_rows = []
+
+        for row in df.itertuples():
+            IngestionManagerPandas._ingest_row(
+                data_frame=df,
+                row=row,
+                feature_group=mock_fg,
+                feature_definitions=collection_feature_definitions,
+                failed_rows=failed_rows,
+                target_stores=None,
+            )
+
+        mock_fg.put_record.assert_called_once()
+        call_args = mock_fg.put_record.call_args
+        record = call_args[1]["record"]
+        
+        # Find the tags feature value
+        tags_value = next(v for v in record if v.feature_name == "tags")
+        assert tags_value.value_as_string_list == ["tag1", "tag2"]
+
+    def test_ingest_row_failure_appends_to_failed(self, feature_definitions):
+        df = pd.DataFrame({"id": [1], "name": ["test"]})
+        mock_fg = MagicMock()
+        mock_fg.put_record.side_effect = Exception("API Error")
+        failed_rows = []
+
+        for row in df.itertuples():
+            IngestionManagerPandas._ingest_row(
+                data_frame=df,
+                row=row,
+                feature_group=mock_fg,
+                feature_definitions=feature_definitions,
+                failed_rows=failed_rows,
+                target_stores=None,
+            )
+
+        assert len(failed_rows) == 1
+        assert failed_rows[0] == 0  # Index of failed row
+
+    def test_ingest_row_with_target_stores(self, feature_definitions):
+        df = pd.DataFrame({"id": [1], "name": ["test"]})
+        mock_fg = MagicMock()
+        failed_rows = []
+
+        for row in df.itertuples():
+            IngestionManagerPandas._ingest_row(
+                data_frame=df,
+                row=row,
+                feature_group=mock_fg,
+                feature_definitions=feature_definitions,
+                failed_rows=failed_rows,
+                target_stores=["OnlineStore"],
+            )
+
+        call_args = mock_fg.put_record.call_args
+        assert call_args[1]["target_stores"] == ["OnlineStore"]
+
+    def test_ingest_row_skips_none_values(self, feature_definitions):
+        df = pd.DataFrame({"id": [1], "name": [None]})
+        mock_fg = MagicMock()
+        failed_rows = []
+
+        for row in df.itertuples():
+            IngestionManagerPandas._ingest_row(
+                data_frame=df,
+                row=row,
+                feature_group=mock_fg,
+                feature_definitions=feature_definitions,
+                failed_rows=failed_rows,
+                target_stores=None,
+            )
+
+        call_args = mock_fg.put_record.call_args
+        record = call_args[1]["record"]
+        # Only id should be in record, name is None
+        assert len(record) == 1
+        assert record[0].feature_name == "id"
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_inputs.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_inputs.py
new file mode 100644
index 0000000000..44e3ec6085
--- /dev/null
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_inputs.py
@@ -0,0 +1,109 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
+"""Unit tests for inputs.py (enums)."""
+import pytest
+
+from sagemaker.mlops.feature_store.inputs import (
+    TargetStoreEnum,
+    OnlineStoreStorageTypeEnum,
+    TableFormatEnum,
+    ResourceEnum,
+    SearchOperatorEnum,
+    SortOrderEnum,
+    FilterOperatorEnum,
+    DeletionModeEnum,
+    ExpirationTimeResponseEnum,
+    ThroughputModeEnum,
+)
+
+
+class TestTargetStoreEnum:
+    def test_online_store(self):
+        assert TargetStoreEnum.ONLINE_STORE.value == "OnlineStore"
+
+    def test_offline_store(self):
+        assert TargetStoreEnum.OFFLINE_STORE.value == "OfflineStore"
+
+
+class TestOnlineStoreStorageTypeEnum:
+    def test_standard(self):
+        assert OnlineStoreStorageTypeEnum.STANDARD.value == "Standard"
+
+    def test_in_memory(self):
+        assert OnlineStoreStorageTypeEnum.IN_MEMORY.value == "InMemory"
+
+
+class TestTableFormatEnum:
+    def test_glue(self):
+        assert TableFormatEnum.GLUE.value == "Glue"
+
+    def test_iceberg(self):
+        assert TableFormatEnum.ICEBERG.value == "Iceberg"
+
+
+class TestResourceEnum:
+    def test_feature_group(self):
+        assert ResourceEnum.FEATURE_GROUP.value == "FeatureGroup"
+
+    def test_feature_metadata(self):
+        assert ResourceEnum.FEATURE_METADATA.value == "FeatureMetadata"
+
+
+class TestSearchOperatorEnum:
+    def test_and(self):
+        assert SearchOperatorEnum.AND.value == "And"
+
+    def test_or(self):
+        assert SearchOperatorEnum.OR.value == "Or"
+
+
+class TestSortOrderEnum:
+    def test_ascending(self):
+        assert SortOrderEnum.ASCENDING.value == "Ascending"
+
+    def test_descending(self):
+        assert SortOrderEnum.DESCENDING.value == "Descending"
+
+
+class TestFilterOperatorEnum:
+    def test_equals(self):
+        assert FilterOperatorEnum.EQUALS.value == "Equals"
+
+    def test_not_equals(self):
+        assert FilterOperatorEnum.NOT_EQUALS.value == "NotEquals"
+
+    def test_greater_than(self):
+        assert FilterOperatorEnum.GREATER_THAN.value == "GreaterThan"
+
+    def test_contains(self):
+        assert FilterOperatorEnum.CONTAINS.value == "Contains"
+
+    def test_exists(self):
+        assert FilterOperatorEnum.EXISTS.value == "Exists"
+
+    def test_in(self):
+        assert FilterOperatorEnum.IN.value == "In"
+
+
+class TestDeletionModeEnum:
+    def test_soft_delete(self):
+        assert DeletionModeEnum.SOFT_DELETE.value == "SoftDelete"
+
+    def test_hard_delete(self):
+        assert DeletionModeEnum.HARD_DELETE.value == "HardDelete"
+
+
+class TestExpirationTimeResponseEnum:
+    def test_disabled(self):
+        assert ExpirationTimeResponseEnum.DISABLED.value == "Disabled"
+
+    def test_enabled(self):
+        assert ExpirationTimeResponseEnum.ENABLED.value == "Enabled"
+
+
+class TestThroughputModeEnum:
+    def test_on_demand(self):
+        assert ThroughputModeEnum.ON_DEMAND.value == "OnDemand"
+
+    def test_provisioned(self):
+        assert ThroughputModeEnum.PROVISIONED.value == "Provisioned"

From f38579455720e0a70a5b7d4dc215e8e095489b18 Mon Sep 17 00:00:00 2001
From: Basssem Halim <bhhalim@amazon.com>
Date: Mon, 26 Jan 2026 16:32:37 -0800
Subject: [PATCH 03/22] feat(feature_store): Add Lake Formation support to
 Feature Group

- Add LakeFormationConfig class to configure Lake Formation governance on offline stores
- Implement FeatureGroup subclass with Lake Formation integration capabilities
- Add helper methods for S3 URI/ARN conversion and Lake Formation role management
- Add S3 deny policy generation for Lake Formation access control
- Implement Lake Formation resource registration and S3 bucket policy setup
- Add integration tests for Lake Formation feature store workflows
- Add unit tests for Lake Formation configuration and policy generation
- Update feature_store module exports to include FeatureGroup and LakeFormationConfig
- Update API documentation to include Feature Store section in sagemaker_mlops.rst
- Enable fine-grained access control for feature store offline stores using AWS Lake Formation
---
 docs/api/sagemaker_mlops.rst                  |    8 +
 .../sagemaker/mlops/feature_store/__init__.py |    6 +-
 .../mlops/feature_store/feature_group.py      |  711 ++++++
 .../integ/test_featureStore_lakeformation.py  |  660 +++++
 .../mlops/feature_store/test_lakeformation.py | 2141 +++++++++++++++++
 5 files changed, 3525 insertions(+), 1 deletion(-)
 create mode 100644 sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
 create mode 100644 sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py
 create mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py

diff --git a/docs/api/sagemaker_mlops.rst b/docs/api/sagemaker_mlops.rst
index f67879111d..d9f911068e 100644
--- a/docs/api/sagemaker_mlops.rst
+++ b/docs/api/sagemaker_mlops.rst
@@ -21,6 +21,14 @@ Workflow Management
    :undoc-members:
    :show-inheritance:
 
+Feature Store
+-------------
+
+.. automodule:: sagemaker.mlops.feature_store
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
 Local Development
 -----------------
 
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
index f15d6d3845..1b635df2a7 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
@@ -2,8 +2,11 @@
 # Licensed under the Apache License, Version 2.0
 """SageMaker FeatureStore V3 - powered by sagemaker-core."""
 
+# FeatureGroup with Lake Formation support (local subclass)
+from sagemaker.mlops.feature_store.feature_group import FeatureGroup, LakeFormationConfig
+
 # Resources from core
-from sagemaker.core.resources import FeatureGroup, FeatureMetadata
+from sagemaker.core.resources import FeatureMetadata
 
 # Shapes from core (Pydantic - no to_dict() needed)
 from sagemaker.core.shapes import (
@@ -79,6 +82,7 @@
     "FeatureParameter",
     "FeatureValue",
     "Filter",
+    "LakeFormationConfig",
     "OfflineStoreConfig",
     "OnlineStoreConfig",
     "OnlineStoreSecurityConfig",
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
new file mode 100644
index 0000000000..c5fcb9211a
--- /dev/null
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
@@ -0,0 +1,711 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
+"""FeatureGroup with Lake Formation support."""
+
+import logging
+from typing import List, Optional
+
+import botocore.exceptions
+
+from sagemaker.core.resources import FeatureGroup as CoreFeatureGroup
+from sagemaker.core.resources import Base
+from sagemaker.core.shapes import (
+    FeatureDefinition,
+    OfflineStoreConfig,
+    OnlineStoreConfig,
+    Tag,
+    ThroughputConfig,
+)
+from sagemaker.core.shapes import Unassigned
+from sagemaker.core.helper.pipeline_variable import StrPipeVar
+from sagemaker.core.s3.utils import parse_s3_url
+from sagemaker.core.common_utils import aws_partition
+from boto3 import Session
+
+
+logger = logging.getLogger(__name__)
+
+
+class LakeFormationConfig:
+    """Configuration for Lake Formation governance on Feature Group offline stores.
+
+    Attributes:
+        enabled: If True, enables Lake Formation governance for the offline store.
+            Requires offline_store_config and role_arn to be set on the Feature Group.
+        use_service_linked_role: Whether to use the Lake Formation service-linked role
+            for S3 registration. If True, Lake Formation uses its service-linked role.
+            If False, registration_role_arn must be provided. Default is True.
+        registration_role_arn: IAM role ARN to use for S3 registration with Lake Formation.
+            Required when use_service_linked_role is False. This can be different from the
+            Feature Group's execution role.
+        show_s3_policy: If True, prints the S3 deny policy to the console after successful
+            Lake Formation setup. This policy should be added to your S3 bucket to restrict
+            access to only the allowed principals. Default is False.
+    """
+
+    enabled: bool = False
+    use_service_linked_role: bool = True
+    registration_role_arn: Optional[str] = None
+    show_s3_policy: bool = False
+
+
+class FeatureGroup(CoreFeatureGroup):
+
+    # Inherit parent docstring and append our additions
+    if CoreFeatureGroup.__doc__ and __doc__:
+        __doc__ = CoreFeatureGroup.__doc__
+
+    @staticmethod
+    def _s3_uri_to_arn(s3_uri: str, region: Optional[str] = None) -> str:
+        """
+        Convert S3 URI to S3 ARN format for Lake Formation.
+
+        Args:
+            s3_uri: S3 URI in format s3://bucket/path or already an ARN
+            region: AWS region name (e.g., 'us-west-2'). Used to determine the correct
+                partition for the ARN. If not provided, defaults to 'aws' partition.
+
+        Returns:
+            S3 ARN in format arn:{partition}:s3:::bucket/path
+
+        Note:
+            This format is specifically used for Lake Formation resource registration.
+            The triple colon (:::) after 's3' is correct - S3 ARNs don't include
+            region or account ID fields.
+        """
+        if s3_uri.startswith("arn:"):
+            return s3_uri
+        
+        # Determine partition based on region
+        partition = aws_partition(region) if region else "aws"
+        
+        bucket, key = parse_s3_url(s3_uri)
+        # Reconstruct as ARN - key may be empty string
+        s3_path = f"{bucket}/{key}" if key else bucket
+        return f"arn:{partition}:s3:::{s3_path}"
+
+    @staticmethod
+    def _extract_account_id_from_arn(arn: str) -> str:
+        """
+        Extract AWS account ID from an ARN.
+
+        Args:
+            arn: AWS ARN in format arn:aws:service:region:account:resource
+
+        Returns:
+            AWS account ID (the 5th colon-separated field)
+
+        Raises:
+            ValueError: If ARN format is invalid (fewer than 5 colon-separated parts)
+        """
+        parts = arn.split(":")
+        if len(parts) < 5:
+            raise ValueError(f"Invalid ARN format: {arn}")
+        return parts[4]
+
+    @staticmethod
+    def _get_lake_formation_service_linked_role_arn(
+        account_id: str, region: Optional[str] = None
+    ) -> str:
+        """
+        Generate the Lake Formation service-linked role ARN for an account.
+
+        Args:
+            account_id: AWS account ID
+            region: AWS region name (e.g., 'us-west-2'). Used to determine the correct
+                partition for the ARN. If not provided, defaults to 'aws' partition.
+
+        Returns:
+            Lake Formation service-linked role ARN in format:
+            arn:{partition}:iam::{account}:role/aws-service-role/lakeformation.amazonaws.com/
+            AWSServiceRoleForLakeFormationDataAccess
+        """
+        partition = aws_partition(region) if region else "aws"
+        return (
+            f"arn:{partition}:iam::{account_id}:role/aws-service-role/"
+            f"lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess"
+        )
+
+    def _generate_s3_deny_policy(
+        self,
+        bucket_name: str,
+        s3_prefix: str,
+        lake_formation_role_arn: str,
+        feature_store_role_arn: str,
+    ) -> dict:
+        """
+        Generate an S3 deny policy for Lake Formation governance.
+
+        This policy denies S3 access to the offline store data prefix except for
+        the Lake Formation role and Feature Store execution role.
+
+        Args:
+            bucket_name: S3 bucket name.
+            s3_prefix: S3 prefix path (without bucket name).
+            lake_formation_role_arn: Lake Formation registration role ARN.
+            feature_store_role_arn: Feature Store execution role ARN.
+
+        Returns:
+            S3 bucket policy as a dict with valid JSON structure containing:
+            - Version: "2012-10-17"
+            - Statement: List with two deny statements:
+              1. Deny GetObject, PutObject, DeleteObject on data prefix except allowed principals
+              2. Deny ListBucket on bucket with prefix condition except allowed principals
+        """
+        policy = {
+            "Version": "2012-10-17",
+            "Statement": [
+                {
+                    "Sid": "DenyAllAccessToFeatureStorePrefixExceptAllowedPrincipals",
+                    "Effect": "Deny",
+                    "Principal": "*",
+                    "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
+                    "Resource": f"arn:aws:s3:::{bucket_name}/{s3_prefix}/*",
+                    "Condition": {
+                        "StringNotEquals": {
+                            "aws:PrincipalArn": [
+                                lake_formation_role_arn,
+                                feature_store_role_arn,
+                            ]
+                        }
+                    },
+                },
+                {
+                    "Sid": "DenyListOnPrefixExceptAllowedPrincipals",
+                    "Effect": "Deny",
+                    "Principal": "*",
+                    "Action": "s3:ListBucket",
+                    "Resource": f"arn:aws:s3:::{bucket_name}",
+                    "Condition": {
+                        "StringLike": {"s3:prefix": f"{s3_prefix}/*"},
+                        "StringNotEquals": {
+                            "aws:PrincipalArn": [
+                                lake_formation_role_arn,
+                                feature_store_role_arn,
+                            ]
+                        },
+                    },
+                },
+            ],
+        }
+        return policy
+
+    def _get_lake_formation_client(
+        self,
+        session: Optional[Session] = None,
+        region: Optional[str] = None,
+    ):
+        """
+        Get a Lake Formation client.
+
+        Args:
+            session: Boto3 session. If not provided, a new session will be created.
+            region: AWS region name.
+
+        Returns:
+            A boto3 Lake Formation client.
+        """
+        # TODO: don't create w new client for each call
+        boto_session = session or Session()
+        return boto_session.client("lakeformation", region_name=region)
+
+    def _register_s3_with_lake_formation(
+        self,
+        s3_location: str,
+        session: Optional[Session] = None,
+        region: Optional[str] = None,
+        use_service_linked_role: bool = True,
+        role_arn: Optional[str] = None,
+    ) -> bool:
+        """
+        Register an S3 location with Lake Formation.
+
+        Args:
+            s3_location: S3 URI or ARN to register.
+            session: Boto3 session.
+            region: AWS region. If not provided, will be inferred from the session.
+            use_service_linked_role: Whether to use the Lake Formation service-linked role.
+                If True, Lake Formation uses its service-linked role for registration.
+                If False, role_arn must be provided.
+            role_arn: IAM role ARN to use for registration. Required when
+                use_service_linked_role is False.
+
+        Returns:
+            True if registration succeeded or location already registered.
+
+        Raises:
+            ValueError: If use_service_linked_role is False but role_arn is not provided.
+            ClientError: If registration fails for unexpected reasons.
+        """
+        if not use_service_linked_role and not role_arn:
+            raise ValueError("role_arn must be provided when use_service_linked_role is False")
+
+        # Get region from session if not provided
+        if region is None and session is not None:
+            region = session.region_name()
+
+        client = self._get_lake_formation_client(session, region)
+        resource_arn = self._s3_uri_to_arn(s3_location, region)
+
+        try:
+            register_params = {"ResourceArn": resource_arn}
+
+            if use_service_linked_role:
+                register_params["UseServiceLinkedRole"] = True
+            else:
+                register_params["RoleArn"] = role_arn
+
+            client.register_resource(**register_params)
+            logger.info(f"Successfully registered S3 location: {resource_arn}")
+            return True
+        except botocore.exceptions.ClientError as e:
+            if e.response["Error"]["Code"] == "AlreadyExistsException":
+                logger.info(f"S3 location already registered: {resource_arn}")
+                return True
+            raise
+
+    def _revoke_iam_allowed_principal(
+        self,
+        database_name: str,
+        table_name: str,
+        session: Optional[Session] = None,
+        region: Optional[str] = None,
+    ) -> bool:
+        """
+        Revoke IAMAllowedPrincipal permissions from a Glue table.
+
+        Args:
+            database_name: Glue database name.
+            table_name: Glue table name.
+            session: Boto3 session.
+            region: AWS region. If not provided, will be inferred from the session.
+
+        Returns:
+            True if revocation succeeded or permissions didn't exist.
+
+        Raises:
+            ClientError: If revocation fails for unexpected reasons.
+        """
+        # Get region from session if not provided
+        if region is None and session is not None:
+            region = session.region_name()
+
+        client = self._get_lake_formation_client(session, region)
+
+        try:
+            client.revoke_permissions(
+                Principal={"DataLakePrincipalIdentifier": "IAM_ALLOWED_PRINCIPALS"},
+                Resource={
+                    "Table": {
+                        "DatabaseName": database_name,
+                        "Name": table_name,
+                    }
+                },
+                Permissions=["ALL"],
+            )
+            logger.info(f"Revoked IAMAllowedPrincipal from table: {database_name}.{table_name}")
+            return True
+        except botocore.exceptions.ClientError as e:
+            # if the Table doesn't have that permission because the user already revoked it
+            # then just return True
+            if e.response["Error"]["Code"] == "InvalidInputException":
+                logger.info(
+                    f"IAMAllowedPrincipal permissions may not exist on: {database_name}.{table_name}"
+                )
+                return True
+            raise
+
+    def _grant_lake_formation_permissions(
+        self,
+        role_arn: str,
+        database_name: str,
+        table_name: str,
+        session: Optional[Session] = None,
+        region: Optional[str] = None,
+    ) -> bool:
+        """
+        Grant permissions to a role on a Glue table via Lake Formation.
+
+        Args:
+            role_arn: IAM role ARN to grant permissions to.
+            database_name: Glue database name.
+            table_name: Glue table name.
+            session: Boto3 session.
+            region: AWS region. If not provided, will be inferred from the session.
+
+        Returns:
+            True if grant succeeded or permissions already exist.
+
+        Raises:
+            ClientError: If grant fails for unexpected reasons.
+        """
+        # Get region from session if not provided
+        if region is None and session is not None:
+            region = session.region_name()
+
+        client = self._get_lake_formation_client(session, region)
+        permissions = ["SELECT", "INSERT", "DELETE", "DESCRIBE", "ALTER"]
+
+        try:
+            client.grant_permissions(
+                Principal={"DataLakePrincipalIdentifier": role_arn},
+                Resource={
+                    "Table": {
+                        "DatabaseName": database_name,
+                        "Name": table_name,
+                    }
+                },
+                Permissions=permissions,
+                PermissionsWithGrantOption=[],
+            )
+            logger.info(f"Granted permissions to {role_arn} on table: {database_name}.{table_name}")
+            return True
+        except botocore.exceptions.ClientError as e:
+            if e.response["Error"]["Code"] == "InvalidInputException":
+                logger.info(
+                    f"Permissions may already exist for {role_arn} on: {database_name}.{table_name}"
+                )
+                return True
+            raise
+
+    @Base.add_validate_call
+    def enable_lake_formation(
+        self,
+        session: Optional[Session] = None,
+        region: Optional[str] = None,
+        use_service_linked_role: bool = True,
+        registration_role_arn: Optional[str] = None,
+        wait_for_active: bool = False,
+        show_s3_policy: bool = False,
+    ) -> dict:
+        """
+        Enable Lake Formation governance for this Feature Group's offline store.
+
+        This method:
+        1. Optionally waits for Feature Group to reach 'Created' status
+        2. Validates Feature Group status is 'Created'
+        3. Registers the offline store S3 location as data lake location
+        4. Grants the execution role permissions on the Glue table
+        5. Revokes IAMAllowedPrincipal permissions from the Glue table
+
+        The role ARN is automatically extracted from the Feature Group's configuration.
+        Each phase depends on the success of the previous phase - if any phase fails,
+        subsequent phases are not executed.
+
+        Parameters:
+            session: Boto3 session.
+            region: Region name.
+            use_service_linked_role: Whether to use the Lake Formation service-linked role
+                for S3 registration. If True, Lake Formation uses its service-linked role.
+                If False, registration_role_arn must be provided. Default is True.
+            registration_role_arn: IAM role ARN to use for S3 registration with Lake Formation.
+                Required when use_service_linked_role is False. This can be different from the
+                Feature Group's execution role (role_arn)
+            wait_for_active: If True, waits for the Feature Group to reach 'Created' status
+                before enabling Lake Formation. Default is False.
+            show_s3_policy: If True, prints the S3 deny policy to the console after successful
+                Lake Formation setup. This policy should be added to your S3 bucket to restrict
+                access to only the allowed principals. Default is False.
+
+        Returns:
+            Dict with status of each Lake Formation operation:
+            - s3_registration: bool
+            - iam_principal_revoked: bool
+            - permissions_granted: bool
+
+        Raises:
+            ValueError: If the Feature Group has no offline store configured,
+                if role_arn is not set on the Feature Group, if use_service_linked_role
+                is False but registration_role_arn is not provided, or if the Feature Group
+                is not in 'Created' status.
+            ClientError: If Lake Formation operations fail.
+            RuntimeError: If a phase fails and subsequent phases cannot proceed.
+        """
+        # Get region from session if not provided
+        if region is None and session is not None:
+            region = session.region_name()
+
+        # Wait for Created status if requested
+        if wait_for_active:
+            self.wait_for_status(target_status="Created")
+
+        # Refresh to get latest state
+        self.refresh()
+
+        # Validate Feature Group status
+        if self.feature_group_status not in ["Created"]:
+            raise ValueError(
+                f"Feature Group '{self.feature_group_name}' must be in 'Created' status "
+                f"to enable Lake Formation. Current status: '{self.feature_group_status}'. "
+                f"Use wait_for_active=True to automatically wait for the Feature Group to be ready."
+            )
+
+        # Validate offline store exists
+        if self.offline_store_config is None or self.offline_store_config == Unassigned():
+            raise ValueError(
+                f"Feature Group '{self.feature_group_name}' does not have an offline store configured. "
+                "Lake Formation can only be enabled for Feature Groups with offline stores."
+            )
+
+        # Get role ARN from Feature Group config
+        if self.role_arn is None or self.role_arn == Unassigned():
+            raise ValueError(
+                f"Feature Group '{self.feature_group_name}' does not have a role_arn configured. "
+                "Lake Formation requires a role ARN to grant permissions."
+            )
+        if not use_service_linked_role and registration_role_arn is None:
+            raise ValueError(
+                "Either 'use_service_linked_role' must be True or 'registration_role_arn' must be provided."
+            )
+
+        # Extract required configuration
+        s3_config = self.offline_store_config.s3_storage_config
+        if s3_config is None:
+            raise ValueError("Offline store S3 configuration is missing")
+
+        resolved_s3_uri = s3_config.resolved_output_s3_uri
+        if resolved_s3_uri is None or resolved_s3_uri == Unassigned():
+            raise ValueError(
+                "Resolved S3 URI not available. Ensure the Feature Group is in 'Created' status."
+            )
+
+        data_catalog_config = self.offline_store_config.data_catalog_config
+        if data_catalog_config is None:
+            raise ValueError("Data catalog configuration is missing from offline store config")
+
+        database_name = data_catalog_config.database
+        table_name = data_catalog_config.table_name
+
+        if not database_name or not table_name:
+            raise ValueError("Database name and table name are required from data catalog config")
+
+        # Convert to str to handle PipelineVariable types
+        resolved_s3_uri_str = str(resolved_s3_uri)
+        database_name_str = str(database_name)
+        table_name_str = str(table_name)
+        role_arn_str = str(self.role_arn)
+
+        # Execute Lake Formation setup with fail-fast behavior
+        results = {
+            "s3_registration": False,
+            "iam_principal_revoked": False,
+            "permissions_granted": False,
+        }
+
+        # Phase 1: Register S3 with Lake Formation
+        try:
+            results["s3_registration"] = self._register_s3_with_lake_formation(
+                resolved_s3_uri_str,
+                session,
+                region,
+                use_service_linked_role=use_service_linked_role,
+                role_arn=registration_role_arn,
+            )
+        except Exception as e:
+            raise RuntimeError(
+                f"Failed to register S3 location with Lake Formation. "
+                f"Subsequent phases skipped. Results: {results}. Error: {e}"
+            ) from e
+
+        if not results["s3_registration"]:
+            raise RuntimeError(
+                f"Failed to register S3 location with Lake Formation. "
+                f"Subsequent phases skipped. Results: {results}"
+            )
+
+        # Phase 2: Grant Lake Formation permissions to the role
+        try:
+            results["permissions_granted"] = self._grant_lake_formation_permissions(
+                role_arn_str, database_name_str, table_name_str, session, region
+            )
+        except Exception as e:
+            raise RuntimeError(
+                f"Failed to grant Lake Formation permissions. "
+                f"Subsequent phases skipped. Results: {results}. Error: {e}"
+            ) from e
+
+        if not results["permissions_granted"]:
+            raise RuntimeError(
+                f"Failed to grant Lake Formation permissions. "
+                f"Subsequent phases skipped. Results: {results}"
+            )
+
+        # Phase 3: Revoke IAMAllowedPrincipal permissions
+        try:
+            results["iam_principal_revoked"] = self._revoke_iam_allowed_principal(
+                database_name_str, table_name_str, session, region
+            )
+        except Exception as e:
+            raise RuntimeError(
+                f"Failed to revoke IAMAllowedPrincipal permissions. Results: {results}. Error: {e}"
+            ) from e
+
+        if not results["iam_principal_revoked"]:
+            raise RuntimeError(
+                f"Failed to revoke IAMAllowedPrincipal permissions. Results: {results}"
+            )
+
+        logger.info(f"Lake Formation setup complete for {self.feature_group_name}: {results}")
+
+        # Generate and optionally print S3 deny policy
+        if show_s3_policy:
+            # Extract bucket name and prefix from resolved S3 URI using core utility
+            bucket_name, s3_prefix = parse_s3_url(resolved_s3_uri_str)
+
+            # Extract account ID from Feature Group ARN
+            feature_group_arn_str = str(self.feature_group_arn) if self.feature_group_arn else ""
+            account_id = self._extract_account_id_from_arn(feature_group_arn_str)
+
+            # Determine Lake Formation role ARN based on use_service_linked_role flag
+            if use_service_linked_role:
+                lf_role_arn = self._get_lake_formation_service_linked_role_arn(account_id, region)
+            else:
+                # registration_role_arn is validated earlier when use_service_linked_role is False
+                lf_role_arn = str(registration_role_arn)
+
+            # Generate the S3 deny policy
+            policy = self._generate_s3_deny_policy(
+                bucket_name=bucket_name,
+                s3_prefix=s3_prefix,
+                lake_formation_role_arn=lf_role_arn,
+                feature_store_role_arn=role_arn_str,
+            )
+
+            # Print policy with clear instructions
+            import json
+
+            print("\n" + "=" * 80)
+            print("S3 Bucket Policy Update recommended")
+            print("=" * 80)
+            print(
+                "\nTo complete Lake Formation setup, add the following deny policy to your S3 bucket."
+            )
+            print(
+                "This policy restricts access to the offline store data to only the allowed principals."
+            )
+            print("\nBucket:", bucket_name)
+            print("\nPolicy to add:")
+            print("-" * 40)
+            print(json.dumps(policy, indent=2))
+            print("-" * 40)
+            print("\nNote: Merge this with your existing bucket policy if one exists.")
+            print("=" * 80 + "\n")
+
+        return results
+
+    @classmethod
+    @Base.add_validate_call
+    def create(
+        cls,
+        feature_group_name: StrPipeVar,
+        record_identifier_feature_name: StrPipeVar,
+        event_time_feature_name: StrPipeVar,
+        feature_definitions: List[FeatureDefinition],
+        online_store_config: Optional[OnlineStoreConfig] = None,
+        offline_store_config: Optional[OfflineStoreConfig] = None,
+        throughput_config: Optional[ThroughputConfig] = None,
+        role_arn: Optional[StrPipeVar] = None,
+        description: Optional[StrPipeVar] = None,
+        tags: Optional[List[Tag]] = None,
+        use_pre_prod_offline_store_replicator_lambda: Optional[bool] = None,
+        lake_formation_config: Optional[LakeFormationConfig] = None,
+        session: Optional[Session] = None,
+        region: Optional[StrPipeVar] = None,
+    ) -> Optional["FeatureGroup"]:
+        """
+        Create a FeatureGroup resource with optional Lake Formation governance.
+
+        Parameters:
+            feature_group_name: The name of the FeatureGroup.
+            record_identifier_feature_name: The name of the Feature whose value uniquely
+                identifies a Record.
+            event_time_feature_name: The name of the feature that stores the EventTime.
+            feature_definitions: A list of Feature names and types.
+            online_store_config: Configuration for the OnlineStore.
+            offline_store_config: Configuration for the OfflineStore.
+            throughput_config: Throughput configuration.
+            role_arn: IAM execution role ARN for the OfflineStore.
+            description: A free-form description of the FeatureGroup.
+            tags: Tags used to identify Features in each FeatureGroup.
+            use_pre_prod_offline_store_replicator_lambda: Pre-prod replicator flag.
+            lake_formation_config: Optional LakeFormationConfig to configure Lake Formation
+                governance. When enabled=True, requires offline_store_config and role_arn.
+            session: Boto3 session.
+            region: Region name.
+
+        Returns:
+            The FeatureGroup resource.
+
+        Raises:
+            botocore.exceptions.ClientError: This exception is raised for AWS service related errors.
+                The error message and error code can be parsed from the exception as follows:
+                ```
+                try:
+                    # AWS service call here
+                except botocore.exceptions.ClientError as e:
+                    error_message = e.response['Error']['Message']
+                    error_code = e.response['Error']['Code']
+                ```
+            ResourceInUse: Resource being accessed is in use.
+            ResourceLimitExceeded: You have exceeded an SageMaker resource limit.
+                For example, you might have too many training jobs created.
+            ConfigSchemaValidationError: Raised when a configuration file does not adhere to the schema
+            LocalConfigNotFoundError: Raised when a configuration file is not found in local file system
+            S3ConfigNotFoundError: Raised when a configuration file is not found in S3
+        """
+        # Validation for Lake Formation
+        if lake_formation_config is not None and lake_formation_config.enabled:
+            if offline_store_config is None:
+                raise ValueError(
+                    "lake_formation_config with enabled=True requires offline_store_config to be configured"
+                )
+            if role_arn is None:
+                raise ValueError(
+                    "lake_formation_config with enabled=True requires role_arn to be specified"
+                )
+            if (
+                not lake_formation_config.use_service_linked_role
+                and not lake_formation_config.registration_role_arn
+            ):
+                raise ValueError(
+                    "registration_role_arn must be provided in lake_formation_config "
+                    "when use_service_linked_role is False"
+                )
+
+        # Build kwargs, only including non-None values so parent uses its defaults
+        create_kwargs = {
+            "feature_group_name": feature_group_name,
+            "record_identifier_feature_name": record_identifier_feature_name,
+            "event_time_feature_name": event_time_feature_name,
+            "feature_definitions": feature_definitions,
+            "session": session,
+            "region": region,
+        }
+        if online_store_config is not None:
+            create_kwargs["online_store_config"] = online_store_config
+        if offline_store_config is not None:
+            create_kwargs["offline_store_config"] = offline_store_config
+        if throughput_config is not None:
+            create_kwargs["throughput_config"] = throughput_config
+        if role_arn is not None:
+            create_kwargs["role_arn"] = role_arn
+        if description is not None:
+            create_kwargs["description"] = description
+        if tags is not None:
+            create_kwargs["tags"] = tags
+        if use_pre_prod_offline_store_replicator_lambda is not None:
+            create_kwargs["use_pre_prod_offline_store_replicator_lambda"] = use_pre_prod_offline_store_replicator_lambda
+
+        feature_group = super().create(**create_kwargs)
+
+        # Enable Lake Formation if requested
+        if lake_formation_config is not None and lake_formation_config.enabled:
+            feature_group.wait_for_status(target_status="Created")
+            feature_group.enable_lake_formation(
+                session=session,
+                region=region,
+                use_service_linked_role=lake_formation_config.use_service_linked_role,
+                registration_role_arn=lake_formation_config.registration_role_arn,
+                show_s3_policy=lake_formation_config.show_s3_policy,
+            )
+        return feature_group
diff --git a/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py b/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py
new file mode 100644
index 0000000000..dc6f12181a
--- /dev/null
+++ b/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py
@@ -0,0 +1,660 @@
+"""
+Integration tests for Lake Formation with FeatureGroup.
+
+These tests require:
+- AWS credentials with Lake Formation and SageMaker permissions
+- An S3 bucket for offline store (uses default SageMaker bucket)
+- An IAM role for Feature Store (uses execution role)
+
+Run with: pytest tests/integ/test_featureStore_lakeformation.py -v -m integ
+"""
+
+import uuid
+
+import boto3
+import pytest
+from botocore.exceptions import ClientError
+
+from sagemaker.core.helper.session_helper import Session, get_execution_role
+from sagemaker.mlops.feature_store import (
+    FeatureGroup,
+    LakeFormationConfig,
+    OfflineStoreConfig,
+    OnlineStoreConfig,
+    S3StorageConfig,
+    StringFeatureDefinition,
+    FractionalFeatureDefinition,
+)
+
+feature_definitions = [
+    StringFeatureDefinition(feature_name="record_id"),
+    StringFeatureDefinition(feature_name="event_time"),
+    FractionalFeatureDefinition(feature_name="feature_value"),
+]
+
+
+@pytest.fixture(scope="module")
+def sagemaker_session():
+    return Session()
+
+
+@pytest.fixture(scope="module")
+def role(sagemaker_session):
+    return get_execution_role(sagemaker_session)
+
+
+@pytest.fixture(scope="module")
+def s3_uri(sagemaker_session):
+    bucket = sagemaker_session.default_bucket()
+    return f"s3://{bucket}/feature-store-test"
+
+
+@pytest.fixture(scope="module")
+def region():
+    return "us-west-2"
+
+
+@pytest.fixture(scope="module")
+def shared_feature_group_for_negative_tests(s3_uri, role, region):
+    """
+    Create a single FeatureGroup for negative tests that only need to verify
+    error conditions without modifying the resource.
+
+    This fixture is module-scoped to be created once and shared across tests,
+    reducing test execution time.
+    """
+    fg_name = f"test-lf-negative-{uuid.uuid4().hex[:8]}"
+    fg = None
+
+    try:
+        fg = create_test_feature_group(fg_name, s3_uri, role, region)
+        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
+        yield fg
+    finally:
+        if fg:
+            cleanup_feature_group(fg)
+
+
+def generate_feature_group_name():
+    """Generate a unique feature group name for testing."""
+    return f"test-lf-fg-{uuid.uuid4().hex[:8]}"
+
+
+def create_test_feature_group(name: str, s3_uri: str, role_arn: str, region: str) -> FeatureGroup:
+    """Create a FeatureGroup with offline store for testing."""
+
+    offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri))
+
+    fg = FeatureGroup.create(
+        feature_group_name=name,
+        record_identifier_feature_name="record_id",
+        event_time_feature_name="event_time",
+        feature_definitions=feature_definitions,
+        offline_store_config=offline_store_config,
+        role_arn=role_arn,
+        region=region,
+    )
+
+    return fg
+
+
+def cleanup_feature_group(fg: FeatureGroup):
+    """
+    Delete a FeatureGroup and its associated Glue table.
+
+    Args:
+        fg: The FeatureGroup to delete.
+    """
+    try:
+        # Delete the Glue table if it exists
+        if fg.offline_store_config is not None:
+            try:
+                fg.refresh()  # Ensure we have latest config
+                data_catalog_config = fg.offline_store_config.data_catalog_config
+                if data_catalog_config is not None:
+                    database_name = data_catalog_config.database
+                    table_name = data_catalog_config.table_name
+
+                    if database_name and table_name:
+                        glue_client = boto3.client("glue")
+                        try:
+                            glue_client.delete_table(DatabaseName=database_name, Name=table_name)
+                        except ClientError as e:
+                            # Ignore if table doesn't exist
+                            if e.response["Error"]["Code"] != "EntityNotFoundException":
+                                raise
+            except Exception:
+                # Don't fail cleanup if Glue table deletion fails
+                pass
+
+        # Delete the FeatureGroup
+        fg.delete()
+    except ClientError:
+        # Don't fail cleanup if Glue table deletion fails
+        pass
+
+
+@pytest.mark.serial
+@pytest.mark.slow_test
+def test_create_feature_group_and_enable_lake_formation(s3_uri, role, region):
+    """
+    Test creating a FeatureGroup and enabling Lake Formation governance.
+
+    This test:
+    1. Creates a new FeatureGroup with offline store
+    2. Waits for it to reach Created status
+    3. Enables Lake Formation governance (registers S3, grants permissions, revokes IAM principals)
+    4. Cleans up the FeatureGroup
+    """
+
+    fg_name = generate_feature_group_name()
+    fg = None
+
+    try:
+        # Create the FeatureGroup
+        fg = create_test_feature_group(fg_name, s3_uri, role, region)
+        assert fg is not None
+
+        # Wait for Created status
+        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
+        assert fg.feature_group_status == "Created"
+
+        # Enable Lake Formation governance
+        result = fg.enable_lake_formation()
+
+        # Verify all phases completed successfully
+        assert result["s3_registration"] is True
+        assert result["permissions_granted"] is True
+        assert result["iam_principal_revoked"] is True
+
+    finally:
+        print('done')
+        # Cleanup
+        if fg:
+            cleanup_feature_group(fg)
+
+
+@pytest.mark.serial
+@pytest.mark.slow_test
+def test_create_feature_group_with_lake_formation_enabled(s3_uri, role, region):
+    """
+    Test creating a FeatureGroup with lake_formation_config.enabled=True.
+
+    This test verifies the integrated workflow where Lake Formation is enabled
+    automatically during FeatureGroup creation:
+    1. Creates a new FeatureGroup with lake_formation_config.enabled=True
+    2. Verifies the FeatureGroup is created and Lake Formation is configured
+    3. Cleans up the FeatureGroup
+    """
+
+    fg_name = generate_feature_group_name()
+    fg = None
+
+    try:
+        # Create the FeatureGroup with Lake Formation enabled
+
+        offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri))
+        lake_formation_config = LakeFormationConfig()
+        lake_formation_config.enabled = True
+
+        fg = FeatureGroup.create(
+            feature_group_name=fg_name,
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=feature_definitions,
+            offline_store_config=offline_store_config,
+            role_arn=role,
+            lake_formation_config=lake_formation_config,
+        )
+
+        # Verify the FeatureGroup was created
+        assert fg is not None
+        assert fg.feature_group_name == fg_name
+        assert fg.feature_group_status == "Created"
+
+        # Verify Lake Formation is configured by checking we can refresh without errors
+        fg.refresh()
+        assert fg.offline_store_config is not None
+
+    finally:
+        # Cleanup
+        if fg:
+            cleanup_feature_group(fg)
+
+
+@pytest.mark.serial
+def test_create_feature_group_without_lake_formation(s3_uri, role, region):
+    """
+    Test creating a FeatureGroup without Lake Formation enabled.
+
+    This test verifies that when lake_formation_config is not provided or enabled=False,
+    the FeatureGroup is created successfully without any Lake Formation operations:
+    1. Creates a new FeatureGroup without lake_formation_config
+    2. Verifies the FeatureGroup is created successfully
+    3. Verifies no Lake Formation operations were performed
+    4. Cleans up the FeatureGroup
+    """
+    fg_name = generate_feature_group_name()
+    fg = None
+
+    try:
+        # Create the FeatureGroup without Lake Formation
+        offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri))
+
+        # Create without lake_formation_config (default behavior)
+        fg = FeatureGroup.create(
+            feature_group_name=fg_name,
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=feature_definitions,
+            offline_store_config=offline_store_config,
+            role_arn=role,
+        )
+
+        # Verify the FeatureGroup was created
+        assert fg is not None
+        assert fg.feature_group_name == fg_name
+
+        # Wait for Created status to ensure it's fully provisioned
+        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
+        assert fg.feature_group_status == "Created"
+
+        # Verify offline store is configured
+        fg.refresh()
+        assert fg.offline_store_config is not None
+        assert fg.offline_store_config.s3_storage_config is not None
+
+    finally:
+        # Cleanup
+        if fg:
+            cleanup_feature_group(fg)
+
+
+# ============================================================================
+# Negative Integration Tests
+# ============================================================================
+
+
+def test_create_feature_group_with_lake_formation_fails_without_offline_store(role, region):
+    """
+    Test that creating a FeatureGroup with enable_lake_formation=True fails
+    when no offline store is configured.
+
+    Expected behavior: ValueError should be raised indicating offline store is required.
+    """
+    fg_name = generate_feature_group_name()
+
+    lake_formation_config = LakeFormationConfig()
+    lake_formation_config.enabled = True
+
+    # Attempt to create without offline store but with Lake Formation enabled
+    with pytest.raises(ValueError) as exc_info:
+        FeatureGroup.create(
+            feature_group_name=fg_name,
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=feature_definitions,
+            role_arn=role,
+            lake_formation_config=lake_formation_config,
+        )
+
+    # Verify error message mentions offline_store_config requirement
+    assert "lake_formation_config with enabled=True requires offline_store_config to be configured" in str(
+        exc_info.value
+    )
+
+
+def test_create_feature_group_with_lake_formation_fails_without_role(s3_uri, region):
+    """
+    Test that creating a FeatureGroup with lake_formation_config.enabled=True fails
+    when no role_arn is provided.
+
+    Expected behavior: ValueError should be raised indicating role_arn is required.
+    """
+    fg_name = generate_feature_group_name()
+
+    offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri))
+    lake_formation_config = LakeFormationConfig()
+    lake_formation_config.enabled = True
+
+    # Attempt to create without role_arn but with Lake Formation enabled
+    with pytest.raises(ValueError) as exc_info:
+        FeatureGroup.create(
+            feature_group_name=fg_name,
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=feature_definitions,
+            offline_store_config=offline_store_config,
+            lake_formation_config=lake_formation_config,
+        )
+
+    # Verify error message mentions role_arn requirement
+    assert "lake_formation_config with enabled=True requires role_arn to be specified" in str(exc_info.value)
+
+
+def test_enable_lake_formation_fails_for_non_created_status(s3_uri, role, region):
+    """
+    Test that enable_lake_formation() fails when called on a FeatureGroup
+    that is not in 'Created' status.
+
+    Expected behavior: ValueError should be raised indicating the Feature Group
+    must be in 'Created' status.
+
+    Note: This test creates its own FeatureGroup because it needs to test
+    behavior during the 'Creating' status, which requires a fresh resource.
+    """
+    fg_name = generate_feature_group_name()
+    fg = None
+
+    try:
+        # Create the FeatureGroup
+        fg = create_test_feature_group(fg_name, s3_uri, role, region)
+        assert fg is not None
+
+        # Immediately try to enable Lake Formation without waiting for Created status
+        # The Feature Group will be in 'Creating' status
+        with pytest.raises(ValueError) as exc_info:
+            fg.enable_lake_formation(wait_for_active=False)
+
+        # Verify error message mentions status requirement
+        error_msg = str(exc_info.value)
+        assert "must be in 'Created' status to enable Lake Formation" in error_msg
+
+    finally:
+        # Cleanup
+        if fg:
+            fg.wait_for_status(target_status="Created", poll=30, timeout=300)
+            cleanup_feature_group(fg)
+
+
+def test_enable_lake_formation_without_offline_store(role, region):
+    """
+    Test that enable_lake_formation() fails when called on a FeatureGroup
+    without an offline store configured.
+
+    Expected behavior: ValueError should be raised indicating offline store is required.
+
+    Note: This test creates a FeatureGroup with only online store, which is a valid
+    configuration, but Lake Formation cannot be enabled for it.
+    """
+    fg_name = generate_feature_group_name()
+    fg = None
+
+    try:
+        # Create a FeatureGroup with only online store (no offline store)
+        online_store_config = OnlineStoreConfig(enable_online_store=True)
+
+        fg = FeatureGroup.create(
+            feature_group_name=fg_name,
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=feature_definitions,
+            online_store_config=online_store_config,
+            role_arn=role,
+        )
+
+        # Wait for Created status
+        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
+
+        # Attempt to enable Lake Formation
+        with pytest.raises(ValueError) as exc_info:
+            fg.enable_lake_formation()
+        # Verify error message mentions offline store requirement
+        assert "does not have an offline store configured" in str(exc_info.value)
+
+    finally:
+        # Cleanup
+        if fg:
+            cleanup_feature_group(fg)
+
+
+def test_enable_lake_formation_fails_with_invalid_registration_role(
+    shared_feature_group_for_negative_tests,
+):
+    """
+    Test that enable_lake_formation() fails when use_service_linked_role=False
+    but no registration_role_arn is provided.
+
+    Expected behavior: ValueError should be raised indicating registration_role_arn
+    is required when not using service-linked role.
+    """
+    fg = shared_feature_group_for_negative_tests
+
+    # Attempt to enable Lake Formation without service-linked role and without registration_role_arn
+    with pytest.raises(ValueError) as exc_info:
+        fg.enable_lake_formation(
+            use_service_linked_role=False,
+            registration_role_arn=None,
+        )
+
+    # Verify error message mentions role requirement
+    error_msg = str(exc_info.value)
+    assert "registration_role_arn" in error_msg
+
+
+def test_enable_lake_formation_fails_with_nonexistent_role(
+    shared_feature_group_for_negative_tests, role
+):
+    """
+    Test that enable_lake_formation() properly bubbles errors when using
+    a nonexistent role ARN for Lake Formation registration.
+
+    Expected behavior: RuntimeError or ClientError should be raised with details
+    about the registration failure.
+
+    Note: This test uses a nonexistent role ARN (current role with random suffix)
+    to trigger an error during S3 registration with Lake Formation.
+    """
+    fg = shared_feature_group_for_negative_tests
+
+    # Generate a nonexistent role ARN by appending a random string to the current role
+    nonexistent_role = f"{role}-nonexistent-{uuid.uuid4().hex[:8]}"
+
+    with pytest.raises(RuntimeError) as exc_info:
+        fg.enable_lake_formation(
+            use_service_linked_role=False,
+            registration_role_arn=nonexistent_role,
+        )
+
+    # Verify we got an appropriate error
+    error_msg = str(exc_info.value)
+    print(exc_info)
+    # Should mention role-related issues (not found, invalid, access denied, etc.)
+    assert "EntityNotFoundException" in error_msg
+
+
+# ============================================================================
+# Full Flow Integration Tests with Policy Output
+# ============================================================================
+
+
+@pytest.mark.serial
+@pytest.mark.slow_test
+def test_enable_lake_formation_full_flow_with_policy_output(s3_uri, role, region, capsys):
+    """
+    Test the full Lake Formation flow with S3 deny policy output.
+
+    This test verifies:
+    1. Creates a FeatureGroup with offline store
+    2. Enables Lake Formation with show_s3_policy=True
+    3. Verifies all Lake Formation phases complete successfully
+    4. Verifies the S3 deny policy is printed to the console
+    5. Verifies the policy structure contains expected elements
+
+    This validates Requirements 6.1-6.9 from the design document.
+    """
+    fg_name = generate_feature_group_name()
+    fg = None
+
+    try:
+        # Create the FeatureGroup
+        fg = create_test_feature_group(fg_name, s3_uri, role, region)
+        assert fg is not None
+
+        # Wait for Created status
+        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
+        assert fg.feature_group_status == "Created"
+
+        # Enable Lake Formation governance with policy output
+        result = fg.enable_lake_formation(show_s3_policy=True)
+
+        # Verify all phases completed successfully
+        assert result["s3_registration"] is True
+        assert result["permissions_granted"] is True
+        assert result["iam_principal_revoked"] is True
+
+        # Capture the printed output
+        captured = capsys.readouterr()
+        output = captured.out
+
+        # Re-print the output so it's visible in terminal with -s flag
+        print(output)
+
+        # Verify the policy header is printed
+        assert "S3 Bucket Policy Update recommended" in output
+        assert "=" * 80 in output
+
+        # Verify bucket information is printed
+        # Extract bucket name from s3_uri (s3://bucket/path -> bucket)
+        expected_bucket = s3_uri.replace("s3://", "").split("/")[0]
+        assert f"Bucket: {expected_bucket}" in output
+
+        # Verify policy structure elements are present
+        assert '"Version": "2012-10-17"' in output
+        assert '"Statement"' in output
+        assert '"Effect": "Deny"' in output
+        assert '"Principal": "*"' in output
+
+        # Verify the deny actions are present
+        assert "s3:GetObject" in output
+        assert "s3:PutObject" in output
+        assert "s3:DeleteObject" in output
+        assert "s3:ListBucket" in output
+
+        # Verify the condition structure is present
+        assert "StringNotEquals" in output
+        assert "aws:PrincipalArn" in output
+
+        # Verify the role ARN is in the allowed principals
+        assert role in output
+
+        # Verify the service-linked role pattern is present (default use_service_linked_role=True)
+        assert "aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess" in output
+
+        # Verify instructions are printed
+        assert "Merge this with your existing bucket policy" in output
+
+    finally:
+        # Cleanup
+        if fg:
+            cleanup_feature_group(fg)
+
+
+@pytest.mark.serial
+@pytest.mark.slow_test
+def test_enable_lake_formation_no_policy_output_by_default(s3_uri, role, region, capsys):
+    """
+    Test that S3 deny policy is NOT printed when show_s3_policy=False (default).
+
+    This test verifies:
+    1. Creates a FeatureGroup with offline store
+    2. Enables Lake Formation without show_s3_policy (defaults to False)
+    3. Verifies all Lake Formation phases complete successfully
+    4. Verifies the S3 deny policy is NOT printed to the console
+
+    This validates Requirement 6.2 from the design document.
+    """
+    fg_name = generate_feature_group_name()
+    fg = None
+
+    try:
+        # Create the FeatureGroup
+        fg = create_test_feature_group(fg_name, s3_uri, role, region)
+        assert fg is not None
+
+        # Wait for Created status
+        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
+        assert fg.feature_group_status == "Created"
+
+        # Enable Lake Formation governance WITHOUT policy output (default)
+        result = fg.enable_lake_formation()
+
+        # Verify all phases completed successfully
+        assert result["s3_registration"] is True
+        assert result["permissions_granted"] is True
+        assert result["iam_principal_revoked"] is True
+
+        # Capture the printed output
+        captured = capsys.readouterr()
+        output = captured.out
+
+        # Verify the policy is NOT printed
+        assert "S3 Bucket Policy Update recommended" not in output
+        assert '"Version": "2012-10-17"' not in output
+        assert "s3:GetObject" not in output
+
+    finally:
+        # Cleanup
+        if fg:
+            cleanup_feature_group(fg)
+
+
+@pytest.mark.serial
+@pytest.mark.slow_test
+def test_enable_lake_formation_with_custom_role_policy_output(s3_uri, role, region, capsys):
+    """
+    Test the full Lake Formation flow with custom registration role and policy output.
+
+    This test verifies:
+    1. Creates a FeatureGroup with offline store
+    2. Enables Lake Formation with use_service_linked_role=False and a custom registration_role_arn
+    3. Verifies the S3 deny policy uses the custom role ARN instead of service-linked role
+
+    This validates Requirements 6.4, 6.5 from the design document.
+
+    Note: This test uses the same execution role as the registration role for simplicity.
+    In production, these would typically be different roles.
+    """
+    fg_name = generate_feature_group_name()
+    fg = None
+
+    try:
+        # Create the FeatureGroup
+        fg = create_test_feature_group(fg_name, s3_uri, role, region)
+        assert fg is not None
+
+        # Wait for Created status
+        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
+        assert fg.feature_group_status == "Created"
+
+        # Enable Lake Formation with custom registration role and policy output
+        # Using the same role for both execution and registration for test simplicity
+        result = fg.enable_lake_formation(
+            use_service_linked_role=False,
+            registration_role_arn=role,
+            show_s3_policy=True,
+        )
+
+        # Verify all phases completed successfully
+        assert result["s3_registration"] is True
+        assert result["permissions_granted"] is True
+        assert result["iam_principal_revoked"] is True
+
+        # Capture the printed output
+        captured = capsys.readouterr()
+        output = captured.out
+
+        # Verify the policy header is printed
+        assert "S3 Bucket Policy Update recommended" in output
+
+        # Verify the custom role ARN is used in the policy (appears twice - once for each principal)
+        # The role should appear as both the Lake Formation role and the Feature Store role
+        assert output.count(role) >= 2
+
+        # Verify the service-linked role is NOT used
+        assert "aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess" not in output
+
+    finally:
+        # Cleanup
+        if fg:
+            cleanup_feature_group(fg)
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py
new file mode 100644
index 0000000000..e4d44df37a
--- /dev/null
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py
@@ -0,0 +1,2141 @@
+"""Unit tests for Lake Formation integration with FeatureGroup."""
+from unittest.mock import MagicMock, patch
+
+import botocore.exceptions
+import pytest
+
+from sagemaker.mlops.feature_store import FeatureGroup, LakeFormationConfig
+
+
+class TestS3UriToArn:
+    """Tests for _s3_uri_to_arn static method."""
+
+    def test_converts_s3_uri_to_arn(self):
+        """Test S3 URI is converted to ARN format."""
+        uri = "s3://my-bucket/my-prefix/data"
+        result = FeatureGroup._s3_uri_to_arn(uri)
+        assert result == "arn:aws:s3:::my-bucket/my-prefix/data"
+
+    def test_handles_bucket_only_uri(self):
+        """Test S3 URI with bucket only."""
+        uri = "s3://my-bucket"
+        result = FeatureGroup._s3_uri_to_arn(uri)
+        assert result == "arn:aws:s3:::my-bucket"
+
+    def test_returns_arn_unchanged(self):
+        """Test ARN input is returned unchanged (idempotent)."""
+        arn = "arn:aws:s3:::my-bucket/path"
+        result = FeatureGroup._s3_uri_to_arn(arn)
+        assert result == arn
+
+    def test_uses_region_for_partition(self):
+        """Test that region is used to determine partition."""
+        uri = "s3://my-bucket/path"
+        result = FeatureGroup._s3_uri_to_arn(uri, region="cn-north-1")
+        assert result.startswith("arn:aws-cn:s3:::")
+
+
+
+class TestGetLakeFormationClient:
+    """Tests for _get_lake_formation_client method."""
+
+    @patch("sagemaker.mlops.feature_store.feature_group.Session")
+    def test_creates_client_with_default_session(self, mock_session_class):
+        """Test client creation with default session."""
+        mock_session = MagicMock()
+        mock_client = MagicMock()
+        mock_session.client.return_value = mock_client
+        mock_session_class.return_value = mock_session
+
+        fg = MagicMock(spec=FeatureGroup)
+        fg._get_lake_formation_client = FeatureGroup._get_lake_formation_client.__get__(fg)
+
+        client = fg._get_lake_formation_client(region="us-west-2")
+
+        mock_session.client.assert_called_with("lakeformation", region_name="us-west-2")
+        assert client == mock_client
+
+    def test_creates_client_with_provided_session(self):
+        """Test client creation with provided session."""
+        mock_session = MagicMock()
+        mock_client = MagicMock()
+        mock_session.client.return_value = mock_client
+
+        fg = MagicMock(spec=FeatureGroup)
+        fg._get_lake_formation_client = FeatureGroup._get_lake_formation_client.__get__(fg)
+
+        client = fg._get_lake_formation_client(session=mock_session, region="us-west-2")
+
+        mock_session.client.assert_called_with("lakeformation", region_name="us-west-2")
+        assert client == mock_client
+
+
+class TestRegisterS3WithLakeFormation:
+    """Tests for _register_s3_with_lake_formation method."""
+
+    def setup_method(self):
+        """Set up test fixtures."""
+        self.fg = MagicMock(spec=FeatureGroup)
+        self.fg._s3_uri_to_arn = FeatureGroup._s3_uri_to_arn
+        self.fg._register_s3_with_lake_formation = (
+            FeatureGroup._register_s3_with_lake_formation.__get__(self.fg)
+        )
+        self.mock_client = MagicMock()
+        self.fg._get_lake_formation_client = MagicMock(return_value=self.mock_client)
+
+    def test_successful_registration_returns_true(self):
+        """Test successful S3 registration returns True."""
+        self.mock_client.register_resource.return_value = {}
+
+        result = self.fg._register_s3_with_lake_formation("s3://test-bucket/prefix")
+
+        assert result is True
+        self.mock_client.register_resource.assert_called_with(
+            ResourceArn="arn:aws:s3:::test-bucket/prefix",
+            UseServiceLinkedRole=True,
+        )
+
+    def test_already_exists_exception_returns_true(self):
+        """Test AlreadyExistsException is handled gracefully."""
+        self.mock_client.register_resource.side_effect = botocore.exceptions.ClientError(
+            {"Error": {"Code": "AlreadyExistsException", "Message": "Already exists"}},
+            "RegisterResource",
+        )
+
+        result = self.fg._register_s3_with_lake_formation("s3://test-bucket/prefix")
+
+        assert result is True
+
+    def test_other_exceptions_are_propagated(self):
+        """Test non-AlreadyExistsException errors are propagated."""
+        self.mock_client.register_resource.side_effect = botocore.exceptions.ClientError(
+            {"Error": {"Code": "AccessDeniedException", "Message": "Access denied"}},
+            "RegisterResource",
+        )
+
+        with pytest.raises(botocore.exceptions.ClientError) as exc_info:
+            self.fg._register_s3_with_lake_formation("s3://test-bucket/prefix")
+
+        assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException"
+
+    def test_uses_service_linked_role(self):
+        """Test UseServiceLinkedRole is set to True."""
+        self.mock_client.register_resource.return_value = {}
+
+        self.fg._register_s3_with_lake_formation("s3://bucket/path")
+
+        call_args = self.mock_client.register_resource.call_args
+        assert call_args[1]["UseServiceLinkedRole"] is True
+
+    def test_uses_custom_role_arn_when_service_linked_role_disabled(self):
+        """Test custom role ARN is used when use_service_linked_role is False."""
+        self.mock_client.register_resource.return_value = {}
+        custom_role = "arn:aws:iam::123456789012:role/CustomLakeFormationRole"
+
+        self.fg._register_s3_with_lake_formation(
+            "s3://bucket/path",
+            use_service_linked_role=False,
+            role_arn=custom_role,
+        )
+
+        call_args = self.mock_client.register_resource.call_args
+        assert call_args[1]["RoleArn"] == custom_role
+        assert "UseServiceLinkedRole" not in call_args[1]
+
+    def test_raises_error_when_role_arn_missing_and_service_linked_role_disabled(self):
+        """Test ValueError when use_service_linked_role is False but role_arn not provided."""
+        with pytest.raises(ValueError) as exc_info:
+            self.fg._register_s3_with_lake_formation(
+                "s3://bucket/path", use_service_linked_role=False
+            )
+
+        assert "role_arn must be provided when use_service_linked_role is False" in str(
+            exc_info.value
+        )
+
+
+
+class TestRevokeIamAllowedPrincipal:
+    """Tests for _revoke_iam_allowed_principal method."""
+
+    def setup_method(self):
+        """Set up test fixtures."""
+        self.fg = MagicMock(spec=FeatureGroup)
+        self.fg._revoke_iam_allowed_principal = FeatureGroup._revoke_iam_allowed_principal.__get__(
+            self.fg
+        )
+        self.mock_client = MagicMock()
+        self.fg._get_lake_formation_client = MagicMock(return_value=self.mock_client)
+
+    def test_successful_revocation_returns_true(self):
+        """Test successful revocation returns True."""
+        self.mock_client.revoke_permissions.return_value = {}
+
+        result = self.fg._revoke_iam_allowed_principal("test_database", "test_table")
+
+        assert result is True
+        self.mock_client.revoke_permissions.assert_called_once()
+
+    def test_revoke_permissions_call_structure(self):
+        """Test that revoke_permissions is called with correct parameters."""
+        self.mock_client.revoke_permissions.return_value = {}
+        database_name = "my_database"
+        table_name = "my_table"
+
+        self.fg._revoke_iam_allowed_principal(database_name, table_name)
+
+        call_args = self.mock_client.revoke_permissions.call_args
+        assert call_args[1]["Principal"] == {
+            "DataLakePrincipalIdentifier": "IAM_ALLOWED_PRINCIPALS"
+        }
+        assert call_args[1]["Permissions"] == ["ALL"]
+        assert call_args[1]["Resource"] == {
+            "Table": {
+                "DatabaseName": database_name,
+                "Name": table_name,
+            }
+        }
+
+    def test_invalid_input_exception_returns_true(self):
+        """Test InvalidInputException is handled gracefully (permissions may not exist)."""
+        self.mock_client.revoke_permissions.side_effect = botocore.exceptions.ClientError(
+            {"Error": {"Code": "InvalidInputException", "Message": "Permissions not found"}},
+            "RevokePermissions",
+        )
+
+        result = self.fg._revoke_iam_allowed_principal("test_database", "test_table")
+
+        assert result is True
+
+    def test_other_exceptions_are_propagated(self):
+        """Test non-InvalidInputException errors are propagated."""
+        self.mock_client.revoke_permissions.side_effect = botocore.exceptions.ClientError(
+            {"Error": {"Code": "AccessDeniedException", "Message": "Access denied"}},
+            "RevokePermissions",
+        )
+
+        with pytest.raises(botocore.exceptions.ClientError) as exc_info:
+            self.fg._revoke_iam_allowed_principal("test_database", "test_table")
+
+        assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException"
+
+    def test_passes_session_and_region_to_client(self):
+        """Test session and region are passed to get_lake_formation_client."""
+        self.mock_client.revoke_permissions.return_value = {}
+        mock_session = MagicMock()
+
+        self.fg._revoke_iam_allowed_principal(
+            "test_database", "test_table", session=mock_session, region="us-west-2"
+        )
+
+        self.fg._get_lake_formation_client.assert_called_with(mock_session, "us-west-2")
+
+
+
+class TestGrantLakeFormationPermissions:
+    """Tests for _grant_lake_formation_permissions method."""
+
+    def setup_method(self):
+        """Set up test fixtures."""
+        self.fg = MagicMock(spec=FeatureGroup)
+        self.fg._grant_lake_formation_permissions = (
+            FeatureGroup._grant_lake_formation_permissions.__get__(self.fg)
+        )
+        self.mock_client = MagicMock()
+        self.fg._get_lake_formation_client = MagicMock(return_value=self.mock_client)
+
+    def test_successful_grant_returns_true(self):
+        """Test successful permission grant returns True."""
+        self.mock_client.grant_permissions.return_value = {}
+
+        result = self.fg._grant_lake_formation_permissions(
+            "arn:aws:iam::123456789012:role/TestRole", "test_database", "test_table"
+        )
+
+        assert result is True
+        self.mock_client.grant_permissions.assert_called_once()
+
+    def test_grant_permissions_call_structure(self):
+        """Test that grant_permissions is called with correct parameters."""
+        self.mock_client.grant_permissions.return_value = {}
+        role_arn = "arn:aws:iam::123456789012:role/MyExecutionRole"
+
+        self.fg._grant_lake_formation_permissions(role_arn, "my_database", "my_table")
+
+        call_args = self.mock_client.grant_permissions.call_args
+        assert call_args[1]["Principal"] == {"DataLakePrincipalIdentifier": role_arn}
+        assert call_args[1]["Resource"] == {
+            "Table": {
+                "DatabaseName": "my_database",
+                "Name": "my_table",
+            }
+        }
+        assert call_args[1]["Permissions"] == ["SELECT", "INSERT", "DELETE", "DESCRIBE", "ALTER"]
+        assert call_args[1]["PermissionsWithGrantOption"] == []
+
+    def test_invalid_input_exception_returns_true(self):
+        """Test InvalidInputException is handled gracefully (permissions may exist)."""
+        self.mock_client.grant_permissions.side_effect = botocore.exceptions.ClientError(
+            {"Error": {"Code": "InvalidInputException", "Message": "Permissions already exist"}},
+            "GrantPermissions",
+        )
+
+        result = self.fg._grant_lake_formation_permissions(
+            "arn:aws:iam::123456789012:role/TestRole", "test_database", "test_table"
+        )
+
+        assert result is True
+
+    def test_other_exceptions_are_propagated(self):
+        """Test non-InvalidInputException errors are propagated."""
+        self.mock_client.grant_permissions.side_effect = botocore.exceptions.ClientError(
+            {"Error": {"Code": "AccessDeniedException", "Message": "Access denied"}},
+            "GrantPermissions",
+        )
+
+        with pytest.raises(botocore.exceptions.ClientError) as exc_info:
+            self.fg._grant_lake_formation_permissions(
+                "arn:aws:iam::123456789012:role/TestRole", "test_database", "test_table"
+            )
+
+        assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException"
+
+    def test_passes_session_and_region_to_client(self):
+        """Test session and region are passed to get_lake_formation_client."""
+        self.mock_client.grant_permissions.return_value = {}
+        mock_session = MagicMock()
+
+        self.fg._grant_lake_formation_permissions(
+            "arn:aws:iam::123456789012:role/TestRole",
+            "test_database",
+            "test_table",
+            session=mock_session,
+            region="us-west-2",
+        )
+
+        self.fg._get_lake_formation_client.assert_called_with(mock_session, "us-west-2")
+
+
+
+class TestEnableLakeFormationValidation:
+    """Tests for enable_lake_formation validation logic."""
+
+    @patch.object(FeatureGroup, "refresh")
+    def test_raises_error_when_no_offline_store(self, mock_refresh):
+        """Test that enable_lake_formation raises ValueError when no offline store is configured."""
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = None
+        fg.feature_group_status = "Created"
+
+        with pytest.raises(ValueError, match="does not have an offline store configured"):
+            fg.enable_lake_formation()
+
+        # Verify refresh was called
+        mock_refresh.assert_called_once()
+
+    @patch.object(FeatureGroup, "refresh")
+    def test_raises_error_when_no_role_arn(self, mock_refresh):
+        """Test that enable_lake_formation raises ValueError when no role_arn is configured."""
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = None
+        fg.feature_group_status = "Created"
+
+        with pytest.raises(ValueError, match="does not have a role_arn configured"):
+            fg.enable_lake_formation()
+
+        # Verify refresh was called
+        mock_refresh.assert_called_once()
+
+    @patch.object(FeatureGroup, "refresh")
+    def test_raises_error_when_invalid_status(self, mock_refresh):
+        """Test enable_lake_formation raises ValueError when Feature Group not in Created status."""
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = "arn:aws:iam::123456789012:role/TestRole"
+        fg.feature_group_status = "Creating"
+
+        with pytest.raises(ValueError, match="must be in 'Created' status"):
+            fg.enable_lake_formation()
+
+        # Verify refresh was called
+        mock_refresh.assert_called_once()
+
+    @patch.object(FeatureGroup, "wait_for_status")
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    def test_wait_for_active_calls_wait_for_status(
+        self, mock_revoke, mock_grant, mock_register, mock_refresh, mock_wait
+    ):
+        """Test that wait_for_active=True calls wait_for_status with 'Created' target."""
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = "arn:aws:iam::123456789012:role/TestRole"
+        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock successful Lake Formation operations
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+
+        # Call with wait_for_active=True
+        fg.enable_lake_formation(wait_for_active=True)
+
+        # Verify wait_for_status was called with "Created"
+        mock_wait.assert_called_once_with(target_status="Created")
+        # Verify refresh was called after wait
+        mock_refresh.assert_called_once()
+
+    @patch.object(FeatureGroup, "wait_for_status")
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    def test_wait_for_active_false_does_not_call_wait(
+        self, mock_revoke, mock_grant, mock_register, mock_refresh, mock_wait
+    ):
+        """Test that wait_for_active=False does not call wait_for_status."""
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = "arn:aws:iam::123456789012:role/TestRole"
+        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock successful Lake Formation operations
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+
+        # Call with wait_for_active=False (default)
+        fg.enable_lake_formation(wait_for_active=False)
+
+        # Verify wait_for_status was NOT called
+        mock_wait.assert_not_called()
+        # Verify refresh was still called
+        mock_refresh.assert_called_once()
+
+
+    @pytest.mark.parametrize(
+        "feature_group_name,role_arn,s3_uri,database_name,table_name",
+        [
+            ("test-fg", "TestRole", "path1", "db1", "table1"),
+            ("my_feature_group", "ExecutionRole", "data/features", "feature_db", "feature_table"),
+            ("fg123", "MyRole123", "ml/features/v1", "analytics", "features_v1"),
+            ("simple", "SimpleRole", "simple-path", "simple_db", "simple_table"),
+            (
+                "complex-name",
+                "ComplexExecutionRole",
+                "complex/path/structure",
+                "complex_database",
+                "complex_table_name",
+            ),
+            (
+                "underscore_name",
+                "Underscore_Role",
+                "underscore_path",
+                "underscore_db",
+                "underscore_table",
+            ),
+            ("mixed-123", "Mixed123Role", "mixed/path/123", "mixed_db_123", "mixed_table_123"),
+            ("x", "XRole", "x", "x", "x"),
+            (
+                "very-long-name",
+                "VeryLongRoleName",
+                "very/long/path/structure",
+                "very_long_database_name",
+                "very_long_table_name",
+            ),
+        ],
+    )
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    def test_fail_fast_phase_execution(
+        self,
+        mock_revoke,
+        mock_grant,
+        mock_register,
+        mock_refresh,
+        feature_group_name,
+        role_arn,
+        s3_uri,
+        database_name,
+        table_name,
+    ):
+        """
+        Test fail-fast behavior for Lake Formation phases.
+
+        If Phase 1 (S3 registration) fails, Phase 2 and 3 should not execute.
+        If Phase 2 fails, Phase 3 should not execute.
+        RuntimeError should indicate which phase failed.
+        """
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        fg = FeatureGroup(feature_group_name=feature_group_name)
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri=f"s3://test-bucket/{s3_uri}",
+                resolved_output_s3_uri=f"s3://test-bucket/resolved-{s3_uri}",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database=database_name, table_name=table_name
+            ),
+        )
+        fg.role_arn = f"arn:aws:iam::123456789012:role/{role_arn}"
+        fg.feature_group_status = "Created"
+
+        # Test Phase 1 failure - subsequent phases should not be called
+        mock_register.side_effect = Exception("Phase 1 failed")
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+
+        with pytest.raises(
+            RuntimeError, match="Failed to register S3 location with Lake Formation"
+        ):
+            fg.enable_lake_formation()
+
+        # Verify Phase 1 was called but Phase 2 and 3 were not
+        mock_register.assert_called_once()
+        mock_grant.assert_not_called()
+        mock_revoke.assert_not_called()
+
+        # Reset mocks for Phase 2 failure test
+        mock_register.reset_mock()
+        mock_grant.reset_mock()
+        mock_revoke.reset_mock()
+
+        # Test Phase 2 failure - Phase 3 should not be called
+        mock_register.side_effect = None
+        mock_register.return_value = True
+        mock_grant.side_effect = Exception("Phase 2 failed")
+        mock_revoke.return_value = True
+
+        with pytest.raises(RuntimeError, match="Failed to grant Lake Formation permissions"):
+            fg.enable_lake_formation()
+
+        # Verify Phase 1 and 2 were called but Phase 3 was not
+        mock_register.assert_called_once()
+        mock_grant.assert_called_once()
+        mock_revoke.assert_not_called()
+
+        # Reset mocks for Phase 3 failure test
+        mock_register.reset_mock()
+        mock_grant.reset_mock()
+        mock_revoke.reset_mock()
+
+        # Test Phase 3 failure - all phases should be called
+        mock_register.side_effect = None
+        mock_register.return_value = True
+        mock_grant.side_effect = None
+        mock_grant.return_value = True
+        mock_revoke.side_effect = Exception("Phase 3 failed")
+
+        with pytest.raises(RuntimeError, match="Failed to revoke IAMAllowedPrincipal permissions"):
+            fg.enable_lake_formation()
+
+        # Verify all phases were called
+        mock_register.assert_called_once()
+        mock_grant.assert_called_once()
+        mock_revoke.assert_called_once()
+
+
+
+class TestUnhandledExceptionPropagation:
+    """Tests for proper propagation of unhandled boto3 exceptions."""
+
+    def test_register_s3_propagates_unhandled_exceptions(self):
+        """
+        Non-AlreadyExists Errors Propagate from S3 Registration
+
+        For any error from Lake Formation's register_resource API that is not
+        AlreadyExistsException, the error should be propagated to the caller unchanged.
+
+        """
+        fg = MagicMock(spec=FeatureGroup)
+        fg._s3_uri_to_arn = FeatureGroup._s3_uri_to_arn
+        fg._register_s3_with_lake_formation = FeatureGroup._register_s3_with_lake_formation.__get__(
+            fg
+        )
+        mock_client = MagicMock()
+        fg._get_lake_formation_client = MagicMock(return_value=mock_client)
+
+        # Configure mock to raise an unhandled error
+        mock_client.register_resource.side_effect = botocore.exceptions.ClientError(
+            {
+                "Error": {
+                    "Code": "AccessDeniedException",
+                    "Message": "User does not have permission",
+                }
+            },
+            "RegisterResource",
+        )
+
+        # Verify the exception is propagated unchanged
+        with pytest.raises(botocore.exceptions.ClientError) as exc_info:
+            fg._register_s3_with_lake_formation("s3://test-bucket/path")
+
+        # Verify error details are preserved
+        assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException"
+        assert exc_info.value.response["Error"]["Message"] == "User does not have permission"
+        assert exc_info.value.operation_name == "RegisterResource"
+
+    def test_revoke_iam_principal_propagates_unhandled_exceptions(self):
+        """
+        Non-InvalidInput Errors Propagate from IAM Principal Revocation
+
+        For any error from Lake Formation's revoke_permissions API that is not
+        InvalidInputException, the error should be propagated to the caller unchanged.
+
+        """
+        fg = MagicMock(spec=FeatureGroup)
+        fg._revoke_iam_allowed_principal = FeatureGroup._revoke_iam_allowed_principal.__get__(fg)
+        mock_client = MagicMock()
+        fg._get_lake_formation_client = MagicMock(return_value=mock_client)
+
+        # Configure mock to raise an unhandled error
+        mock_client.revoke_permissions.side_effect = botocore.exceptions.ClientError(
+            {
+                "Error": {
+                    "Code": "AccessDeniedException",
+                    "Message": "User does not have permission",
+                }
+            },
+            "RevokePermissions",
+        )
+
+        # Verify the exception is propagated unchanged
+        with pytest.raises(botocore.exceptions.ClientError) as exc_info:
+            fg._revoke_iam_allowed_principal("test_database", "test_table")
+
+        # Verify error details are preserved
+        assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException"
+        assert exc_info.value.response["Error"]["Message"] == "User does not have permission"
+        assert exc_info.value.operation_name == "RevokePermissions"
+
+    def test_grant_permissions_propagates_unhandled_exceptions(self):
+        """
+        Non-InvalidInput Errors Propagate from Permission Grant
+
+        For any error from Lake Formation's grant_permissions API that is not
+        InvalidInputException, the error should be propagated to the caller unchanged.
+
+        """
+        fg = MagicMock(spec=FeatureGroup)
+        fg._grant_lake_formation_permissions = (
+            FeatureGroup._grant_lake_formation_permissions.__get__(fg)
+        )
+        mock_client = MagicMock()
+        fg._get_lake_formation_client = MagicMock(return_value=mock_client)
+
+        # Configure mock to raise an unhandled error
+        mock_client.grant_permissions.side_effect = botocore.exceptions.ClientError(
+            {
+                "Error": {
+                    "Code": "AccessDeniedException",
+                    "Message": "User does not have permission",
+                }
+            },
+            "GrantPermissions",
+        )
+
+        # Verify the exception is propagated unchanged
+        with pytest.raises(botocore.exceptions.ClientError) as exc_info:
+            fg._grant_lake_formation_permissions(
+                "arn:aws:iam::123456789012:role/TestRole", "test_database", "test_table"
+            )
+
+        # Verify error details are preserved
+        assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException"
+        assert exc_info.value.response["Error"]["Message"] == "User does not have permission"
+        assert exc_info.value.operation_name == "GrantPermissions"
+
+    def test_handled_exceptions_do_not_propagate(self):
+        """
+        Verify that specifically handled exceptions (AlreadyExistsException, InvalidInputException)
+        do NOT propagate but return True instead, while all other exceptions are propagated.
+        """
+        fg = MagicMock(spec=FeatureGroup)
+        fg._s3_uri_to_arn = FeatureGroup._s3_uri_to_arn
+        fg._register_s3_with_lake_formation = FeatureGroup._register_s3_with_lake_formation.__get__(
+            fg
+        )
+        fg._revoke_iam_allowed_principal = FeatureGroup._revoke_iam_allowed_principal.__get__(fg)
+        fg._grant_lake_formation_permissions = (
+            FeatureGroup._grant_lake_formation_permissions.__get__(fg)
+        )
+        mock_client = MagicMock()
+        fg._get_lake_formation_client = MagicMock(return_value=mock_client)
+
+        # Test AlreadyExistsException is handled (not propagated)
+        mock_client.register_resource.side_effect = botocore.exceptions.ClientError(
+            {"Error": {"Code": "AlreadyExistsException", "Message": "Already exists"}},
+            "RegisterResource",
+        )
+        result = fg._register_s3_with_lake_formation("s3://test-bucket/path")
+        assert result is True  # Should return True, not raise
+
+        # Test InvalidInputException is handled for revoke (not propagated)
+        mock_client.revoke_permissions.side_effect = botocore.exceptions.ClientError(
+            {"Error": {"Code": "InvalidInputException", "Message": "Invalid input"}},
+            "RevokePermissions",
+        )
+        result = fg._revoke_iam_allowed_principal("db", "table")
+        assert result is True  # Should return True, not raise
+
+        # Test InvalidInputException is handled for grant (not propagated)
+        mock_client.grant_permissions.side_effect = botocore.exceptions.ClientError(
+            {"Error": {"Code": "InvalidInputException", "Message": "Invalid input"}},
+            "GrantPermissions",
+        )
+        result = fg._grant_lake_formation_permissions(
+            "arn:aws:iam::123456789012:role/TestRole", "db", "table"
+        )
+        assert result is True  # Should return True, not raise
+
+
+
+class TestCreateWithLakeFormation:
+    """Tests for create() method with Lake Formation integration."""
+
+    @pytest.mark.parametrize(
+        "feature_group_name,record_id_feature,event_time_feature",
+        [
+            ("test-fg", "record_id", "event_time"),
+            ("my_feature_group", "id", "timestamp"),
+            ("fg123", "identifier", "time"),
+            ("simple", "rec_id", "evt_time"),
+            ("complex-name", "record_identifier", "event_timestamp"),
+            ("underscore_name", "record_id_field", "event_time_field"),
+            ("mixed-123", "id_123", "time_123"),
+            ("x", "x_id", "x_time"),
+            ("very-long-name", "very_long_record_id", "very_long_event_time"),
+        ],
+    )
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    @patch.object(FeatureGroup, "get")
+    @patch.object(FeatureGroup, "wait_for_status")
+    @patch.object(FeatureGroup, "enable_lake_formation")
+    def test_no_lake_formation_operations_when_disabled(
+        self,
+        mock_enable_lf,
+        mock_wait,
+        mock_get,
+        mock_get_client,
+        feature_group_name,
+        record_id_feature,
+        event_time_feature,
+    ):
+        """
+        No Lake Formation Operations When Disabled
+
+        For any call to FeatureGroup.create() where lake_formation_config is None or has enabled=False,
+        no Lake Formation client methods should be invoked.
+
+        """
+        from sagemaker.core.shapes import FeatureDefinition
+
+        # Mock the SageMaker client
+        mock_client = MagicMock()
+        mock_client.create_feature_group.return_value = {
+            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test"
+        }
+        mock_get_client.return_value = mock_client
+
+        # Mock the get method to return a feature group
+        mock_fg = MagicMock(spec=FeatureGroup)
+        mock_fg.feature_group_name = feature_group_name
+        mock_get.return_value = mock_fg
+
+        # Create feature definitions
+        feature_definitions = [
+            FeatureDefinition(feature_name=record_id_feature, feature_type="String"),
+            FeatureDefinition(feature_name=event_time_feature, feature_type="String"),
+        ]
+
+        # Test 1: lake_formation_config with enabled=False (explicit)
+        lf_config = LakeFormationConfig()
+        lf_config.enabled = False
+        result = FeatureGroup.create(
+            feature_group_name=feature_group_name,
+            record_identifier_feature_name=record_id_feature,
+            event_time_feature_name=event_time_feature,
+            feature_definitions=feature_definitions,
+            lake_formation_config=lf_config,
+        )
+
+        # Verify enable_lake_formation was NOT called
+        mock_enable_lf.assert_not_called()
+        # Verify wait_for_status was NOT called
+        mock_wait.assert_not_called()
+        # Verify the feature group was returned
+        assert result == mock_fg
+
+        # Reset mocks for next test
+        mock_enable_lf.reset_mock()
+        mock_wait.reset_mock()
+        mock_get.reset_mock()
+        mock_get.return_value = mock_fg
+
+        # Test 2: lake_formation_config not specified (defaults to None)
+        result = FeatureGroup.create(
+            feature_group_name=feature_group_name,
+            record_identifier_feature_name=record_id_feature,
+            event_time_feature_name=event_time_feature,
+            feature_definitions=feature_definitions,
+            # lake_formation_config not specified, should default to None
+        )
+
+        # Verify enable_lake_formation was NOT called
+        mock_enable_lf.assert_not_called()
+        # Verify wait_for_status was NOT called
+        mock_wait.assert_not_called()
+        # Verify the feature group was returned
+        assert result == mock_fg
+
+    @pytest.mark.parametrize(
+        "feature_group_name,record_id_feature,event_time_feature,role_arn,s3_uri,database,table",
+        [
+            ("test-fg", "record_id", "event_time", "TestRole", "path1", "db1", "table1"),
+            (
+                "my_feature_group",
+                "id",
+                "timestamp",
+                "ExecutionRole",
+                "data/features",
+                "feature_db",
+                "feature_table",
+            ),
+            (
+                "fg123",
+                "identifier",
+                "time",
+                "MyRole123",
+                "ml/features/v1",
+                "analytics",
+                "features_v1",
+            ),
+        ],
+    )
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    @patch.object(FeatureGroup, "get")
+    @patch.object(FeatureGroup, "wait_for_status")
+    @patch.object(FeatureGroup, "enable_lake_formation")
+    def test_enable_lake_formation_called_when_enabled(
+        self,
+        mock_enable_lf,
+        mock_wait,
+        mock_get,
+        mock_get_client,
+        feature_group_name,
+        record_id_feature,
+        event_time_feature,
+        role_arn,
+        s3_uri,
+        database,
+        table,
+    ):
+        """
+        Test that enable_lake_formation is called when lake_formation_config has enabled=True.
+
+        This verifies the integration between create() and enable_lake_formation().
+        """
+        from sagemaker.core.shapes import (
+            FeatureDefinition,
+            OfflineStoreConfig,
+            S3StorageConfig,
+            DataCatalogConfig,
+        )
+
+        # Mock the SageMaker client
+        mock_client = MagicMock()
+        mock_client.create_feature_group.return_value = {
+            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test"
+        }
+        mock_get_client.return_value = mock_client
+
+        # Mock the get method to return a feature group
+        mock_fg = MagicMock(spec=FeatureGroup)
+        mock_fg.feature_group_name = feature_group_name
+        mock_fg.wait_for_status = mock_wait
+        mock_fg.enable_lake_formation = mock_enable_lf
+        mock_get.return_value = mock_fg
+
+        # Create feature definitions
+        feature_definitions = [
+            FeatureDefinition(feature_name=record_id_feature, feature_type="String"),
+            FeatureDefinition(feature_name=event_time_feature, feature_type="String"),
+        ]
+
+        # Create offline store config
+        offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(s3_uri=f"s3://test-bucket/{s3_uri}"),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database=database, table_name=table
+            ),
+        )
+
+        # Create LakeFormationConfig with enabled=True
+        lf_config = LakeFormationConfig()
+        lf_config.enabled = True
+
+        # Create with lake_formation_config enabled=True
+        result = FeatureGroup.create(
+            feature_group_name=feature_group_name,
+            record_identifier_feature_name=record_id_feature,
+            event_time_feature_name=event_time_feature,
+            feature_definitions=feature_definitions,
+            offline_store_config=offline_store_config,
+            role_arn=f"arn:aws:iam::123456789012:role/{role_arn}",
+            lake_formation_config=lf_config,
+        )
+
+        # Verify wait_for_status was called with "Created"
+        mock_wait.assert_called_once_with(target_status="Created")
+        # Verify enable_lake_formation was called with default use_service_linked_role=True
+        mock_enable_lf.assert_called_once_with(
+            session=None,
+            region=None,
+            use_service_linked_role=True,
+            registration_role_arn=None,
+            show_s3_policy=False,
+        )
+        # Verify the feature group was returned
+        assert result == mock_fg
+
+    @pytest.mark.parametrize(
+        "feature_group_name,record_id_feature,event_time_feature",
+        [
+            ("test-fg", "record_id", "event_time"),
+            ("my_feature_group", "id", "timestamp"),
+            ("fg123", "identifier", "time"),
+        ],
+    )
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_validation_error_when_lake_formation_enabled_without_offline_store(
+        self, mock_get_client, feature_group_name, record_id_feature, event_time_feature
+    ):
+        """Test create() raises ValueError when lake_formation_config enabled=True without offline_store."""
+        from sagemaker.core.shapes import FeatureDefinition
+
+        # Mock the SageMaker client
+        mock_client = MagicMock()
+        mock_get_client.return_value = mock_client
+
+        # Create feature definitions
+        feature_definitions = [
+            FeatureDefinition(feature_name=record_id_feature, feature_type="String"),
+            FeatureDefinition(feature_name=event_time_feature, feature_type="String"),
+        ]
+
+        # Create LakeFormationConfig with enabled=True
+        lf_config = LakeFormationConfig()
+        lf_config.enabled = True
+
+        # Test with lake_formation_config enabled=True but no offline_store_config
+        with pytest.raises(
+            ValueError,
+            match="lake_formation_config with enabled=True requires offline_store_config to be configured",
+        ):
+            FeatureGroup.create(
+                feature_group_name=feature_group_name,
+                record_identifier_feature_name=record_id_feature,
+                event_time_feature_name=event_time_feature,
+                feature_definitions=feature_definitions,
+                lake_formation_config=lf_config,
+                # offline_store_config not provided
+            )
+
+    @pytest.mark.parametrize(
+        "feature_group_name,record_id_feature,event_time_feature,s3_uri,database,table",
+        [
+            ("test-fg", "record_id", "event_time", "path1", "db1", "table1"),
+            ("my_feature_group", "id", "timestamp", "data/features", "feature_db", "feature_table"),
+            ("fg123", "identifier", "time", "ml/features/v1", "analytics", "features_v1"),
+        ],
+    )
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_validation_error_when_lake_formation_enabled_without_role_arn(
+        self,
+        mock_get_client,
+        feature_group_name,
+        record_id_feature,
+        event_time_feature,
+        s3_uri,
+        database,
+        table,
+    ):
+        """Test create() raises ValueError when lake_formation_config enabled=True without role_arn."""
+        from sagemaker.core.shapes import (
+            FeatureDefinition,
+            OfflineStoreConfig,
+            S3StorageConfig,
+            DataCatalogConfig,
+        )
+
+        # Mock the SageMaker client
+        mock_client = MagicMock()
+        mock_get_client.return_value = mock_client
+
+        # Create feature definitions
+        feature_definitions = [
+            FeatureDefinition(feature_name=record_id_feature, feature_type="String"),
+            FeatureDefinition(feature_name=event_time_feature, feature_type="String"),
+        ]
+
+        # Create offline store config
+        offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(s3_uri=f"s3://test-bucket/{s3_uri}"),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database=database, table_name=table
+            ),
+        )
+
+        # Create LakeFormationConfig with enabled=True
+        lf_config = LakeFormationConfig()
+        lf_config.enabled = True
+
+        # Test with lake_formation_config enabled=True but no role_arn
+        with pytest.raises(
+            ValueError, match="lake_formation_config with enabled=True requires role_arn to be specified"
+        ):
+            FeatureGroup.create(
+                feature_group_name=feature_group_name,
+                record_identifier_feature_name=record_id_feature,
+                event_time_feature_name=event_time_feature,
+                feature_definitions=feature_definitions,
+                offline_store_config=offline_store_config,
+                lake_formation_config=lf_config,
+                # role_arn not provided
+            )
+
+
+    @pytest.mark.parametrize(
+        "feature_group_name,record_id_feature,event_time_feature,role_arn,s3_uri,database,table,use_slr",
+        [
+            ("test-fg", "record_id", "event_time", "TestRole", "path1", "db1", "table1", True),
+            ("my_feature_group", "id", "timestamp", "ExecutionRole", "data/features", "feature_db", "feature_table", False),
+            ("fg123", "identifier", "time", "MyRole123", "ml/features/v1", "analytics", "features_v1", True),
+        ],
+    )
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    @patch.object(FeatureGroup, "get")
+    @patch.object(FeatureGroup, "wait_for_status")
+    @patch.object(FeatureGroup, "enable_lake_formation")
+    def test_use_service_linked_role_extraction_from_config(
+        self,
+        mock_enable_lf,
+        mock_wait,
+        mock_get,
+        mock_get_client,
+        feature_group_name,
+        record_id_feature,
+        event_time_feature,
+        role_arn,
+        s3_uri,
+        database,
+        table,
+        use_slr,
+    ):
+        """
+        Test that use_service_linked_role is correctly extracted from lake_formation_config.
+
+        Verifies:
+        - use_service_linked_role defaults to True when not specified
+        - use_service_linked_role is passed correctly to enable_lake_formation()
+        """
+        from sagemaker.core.shapes import (
+            FeatureDefinition,
+            OfflineStoreConfig,
+            S3StorageConfig,
+            DataCatalogConfig,
+        )
+
+        # Mock the SageMaker client
+        mock_client = MagicMock()
+        mock_client.create_feature_group.return_value = {
+            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test"
+        }
+        mock_get_client.return_value = mock_client
+
+        # Mock the get method to return a feature group
+        mock_fg = MagicMock(spec=FeatureGroup)
+        mock_fg.feature_group_name = feature_group_name
+        mock_fg.wait_for_status = mock_wait
+        mock_fg.enable_lake_formation = mock_enable_lf
+        mock_get.return_value = mock_fg
+
+        # Create feature definitions
+        feature_definitions = [
+            FeatureDefinition(feature_name=record_id_feature, feature_type="String"),
+            FeatureDefinition(feature_name=event_time_feature, feature_type="String"),
+        ]
+
+        # Create offline store config
+        offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(s3_uri=f"s3://test-bucket/{s3_uri}"),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database=database, table_name=table
+            ),
+        )
+
+        # Build LakeFormationConfig with use_service_linked_role
+        lf_config = LakeFormationConfig()
+        lf_config.enabled = True
+        lf_config.use_service_linked_role = use_slr
+        # When use_service_linked_role is False, registration_role_arn is required
+        expected_registration_role = None
+        if not use_slr:
+            lf_config.registration_role_arn = "arn:aws:iam::123456789012:role/LFRegistrationRole"
+            expected_registration_role = "arn:aws:iam::123456789012:role/LFRegistrationRole"
+
+        # Create with lake_formation_config
+        result = FeatureGroup.create(
+            feature_group_name=feature_group_name,
+            record_identifier_feature_name=record_id_feature,
+            event_time_feature_name=event_time_feature,
+            feature_definitions=feature_definitions,
+            offline_store_config=offline_store_config,
+            role_arn=f"arn:aws:iam::123456789012:role/{role_arn}",
+            lake_formation_config=lf_config,
+        )
+
+        # Verify enable_lake_formation was called with correct use_service_linked_role value
+        mock_enable_lf.assert_called_once_with(
+            session=None,
+            region=None,
+            use_service_linked_role=use_slr,
+            registration_role_arn=expected_registration_role,
+            show_s3_policy=False,
+        )
+        # Verify the feature group was returned
+        assert result == mock_fg
+
+
+class TestExtractAccountIdFromArn:
+    """Tests for _extract_account_id_from_arn static method."""
+
+    def test_extracts_account_id_from_sagemaker_arn(self):
+        """Test extracting account ID from a SageMaker Feature Group ARN."""
+        arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/my-feature-group"
+        result = FeatureGroup._extract_account_id_from_arn(arn)
+        assert result == "123456789012"
+
+    def test_raises_value_error_for_invalid_arn_too_few_parts(self):
+        """Test that ValueError is raised for ARN with fewer than 5 colon-separated parts."""
+        invalid_arn = "arn:aws:sagemaker:us-west-2"  # Only 4 parts
+        with pytest.raises(ValueError, match="Invalid ARN format"):
+            FeatureGroup._extract_account_id_from_arn(invalid_arn)
+
+    def test_raises_value_error_for_empty_string(self):
+        """Test that ValueError is raised for empty string."""
+        with pytest.raises(ValueError, match="Invalid ARN format"):
+            FeatureGroup._extract_account_id_from_arn("")
+
+    def test_raises_value_error_for_non_arn_string(self):
+        """Test that ValueError is raised for non-ARN string."""
+        with pytest.raises(ValueError, match="Invalid ARN format"):
+            FeatureGroup._extract_account_id_from_arn("not-an-arn")
+
+    def test_raises_value_error_for_s3_uri(self):
+        """Test that ValueError is raised for S3 URI (not ARN)."""
+        with pytest.raises(ValueError, match="Invalid ARN format"):
+            FeatureGroup._extract_account_id_from_arn("s3://my-bucket/my-prefix")
+
+    def test_handles_arn_with_resource_path(self):
+        """Test extracting account ID from ARN with complex resource path."""
+        arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/my-fg/version/1"
+        result = FeatureGroup._extract_account_id_from_arn(arn)
+        assert result == "123456789012"
+
+
+class TestGetLakeFormationServiceLinkedRoleArn:
+    """Tests for _get_lake_formation_service_linked_role_arn static method."""
+
+    def test_generates_correct_service_linked_role_arn(self):
+        """Test that the method generates the correct service-linked role ARN format."""
+        account_id = "123456789012"
+        result = FeatureGroup._get_lake_formation_service_linked_role_arn(account_id)
+        expected = "arn:aws:iam::123456789012:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess"
+        assert result == expected
+
+    def test_uses_region_for_partition(self):
+        """Test that region is used to determine partition."""
+        account_id = "123456789012"
+        result = FeatureGroup._get_lake_formation_service_linked_role_arn(account_id, region="cn-north-1")
+        assert result.startswith("arn:aws-cn:iam::")
+
+
+
+class TestGenerateS3DenyPolicy:
+    """Tests for _generate_s3_deny_policy method."""
+
+    def setup_method(self):
+        """Set up test fixtures."""
+        self.fg = MagicMock(spec=FeatureGroup)
+        self.fg._generate_s3_deny_policy = FeatureGroup._generate_s3_deny_policy.__get__(self.fg)
+
+    def test_policy_includes_correct_bucket_arn_in_object_statement(self):
+        """Test that the policy includes correct bucket ARN and prefix in object actions statement."""
+        bucket_name = "my-feature-store-bucket"
+        s3_prefix = "feature-store/data/my-feature-group"
+        lf_role_arn = "arn:aws:iam::123456789012:role/LakeFormationRole"
+        fs_role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+
+        policy = self.fg._generate_s3_deny_policy(
+            bucket_name=bucket_name,
+            s3_prefix=s3_prefix,
+            lake_formation_role_arn=lf_role_arn,
+            feature_store_role_arn=fs_role_arn,
+        )
+
+        # Verify the object actions statement has correct Resource ARN
+        object_statement = policy["Statement"][0]
+        expected_resource = f"arn:aws:s3:::{bucket_name}/{s3_prefix}/*"
+        assert object_statement["Resource"] == expected_resource
+
+    def test_policy_includes_correct_bucket_arn_in_list_statement(self):
+        """Test that the policy includes correct bucket ARN in ListBucket statement."""
+        bucket_name = "my-feature-store-bucket"
+        s3_prefix = "feature-store/data/my-feature-group"
+        lf_role_arn = "arn:aws:iam::123456789012:role/LakeFormationRole"
+        fs_role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+
+        policy = self.fg._generate_s3_deny_policy(
+            bucket_name=bucket_name,
+            s3_prefix=s3_prefix,
+            lake_formation_role_arn=lf_role_arn,
+            feature_store_role_arn=fs_role_arn,
+        )
+
+        # Verify the ListBucket statement has correct Resource ARN (bucket only)
+        list_statement = policy["Statement"][1]
+        expected_resource = f"arn:aws:s3:::{bucket_name}"
+        assert list_statement["Resource"] == expected_resource
+
+    def test_policy_includes_correct_prefix_condition_in_list_statement(self):
+        """Test that the policy includes correct prefix condition in ListBucket statement."""
+        bucket_name = "my-feature-store-bucket"
+        s3_prefix = "feature-store/data/my-feature-group"
+        lf_role_arn = "arn:aws:iam::123456789012:role/LakeFormationRole"
+        fs_role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+
+        policy = self.fg._generate_s3_deny_policy(
+            bucket_name=bucket_name,
+            s3_prefix=s3_prefix,
+            lake_formation_role_arn=lf_role_arn,
+            feature_store_role_arn=fs_role_arn,
+        )
+
+        # Verify the ListBucket statement has correct prefix condition
+        list_statement = policy["Statement"][1]
+        expected_prefix = f"{s3_prefix}/*"
+        assert list_statement["Condition"]["StringLike"]["s3:prefix"] == expected_prefix
+
+    def test_policy_preserves_bucket_name_exactly(self):
+        """Test that bucket name is preserved exactly without modification."""
+        # Test with various bucket name formats
+        test_cases = [
+            "simple-bucket",
+            "bucket.with.dots",
+            "bucket-with-dashes-123",
+            "mybucket",
+            "a" * 63,  # Max bucket name length
+        ]
+
+        for bucket_name in test_cases:
+            policy = self.fg._generate_s3_deny_policy(
+                bucket_name=bucket_name,
+                s3_prefix="prefix",
+                lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole",
+                feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole",
+            )
+
+            # Verify bucket name is preserved in both statements
+            assert bucket_name in policy["Statement"][0]["Resource"]
+            assert bucket_name in policy["Statement"][1]["Resource"]
+
+    def test_policy_preserves_prefix_exactly(self):
+        """Test that S3 prefix is preserved exactly without modification."""
+        # Test with various prefix formats
+        test_cases = [
+            "simple-prefix",
+            "path/to/data",
+            "feature-store/account-id/region/feature-group-name",
+            "deep/nested/path/structure/data",
+            "prefix_with_underscores",
+            "prefix-with-dashes",
+        ]
+
+        for s3_prefix in test_cases:
+            policy = self.fg._generate_s3_deny_policy(
+                bucket_name="test-bucket",
+                s3_prefix=s3_prefix,
+                lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole",
+                feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole",
+            )
+
+            # Verify prefix is preserved in object statement Resource
+            assert f"{s3_prefix}/*" in policy["Statement"][0]["Resource"]
+            # Verify prefix is preserved in list statement Condition
+            assert policy["Statement"][1]["Condition"]["StringLike"]["s3:prefix"] == f"{s3_prefix}/*"
+
+    def test_policy_has_correct_s3_arn_format(self):
+        """Test that the policy uses correct S3 ARN format (arn:aws:s3:::bucket/path)."""
+        bucket_name = "test-bucket"
+        s3_prefix = "test/prefix"
+
+        policy = self.fg._generate_s3_deny_policy(
+            bucket_name=bucket_name,
+            s3_prefix=s3_prefix,
+            lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole",
+            feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole",
+        )
+
+        # Verify object statement Resource starts with correct ARN prefix
+        object_resource = policy["Statement"][0]["Resource"]
+        assert object_resource.startswith("arn:aws:s3:::")
+        assert object_resource == f"arn:aws:s3:::{bucket_name}/{s3_prefix}/*"
+
+        # Verify list statement Resource is bucket-only ARN
+        list_resource = policy["Statement"][1]["Resource"]
+        assert list_resource.startswith("arn:aws:s3:::")
+        assert list_resource == f"arn:aws:s3:::{bucket_name}"
+
+    def test_policy_structure_validation(self):
+        """Test that the policy has correct overall structure."""
+        policy = self.fg._generate_s3_deny_policy(
+            bucket_name="test-bucket",
+            s3_prefix="test/prefix",
+            lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole",
+            feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole",
+        )
+
+        # Verify policy version
+        assert policy["Version"] == "2012-10-17"
+
+        # Verify exactly two statements
+        assert len(policy["Statement"]) == 2
+
+        # Verify first statement structure (object actions)
+        object_statement = policy["Statement"][0]
+        assert object_statement["Sid"] == "DenyAllAccessToFeatureStorePrefixExceptAllowedPrincipals"
+        assert object_statement["Effect"] == "Deny"
+        assert object_statement["Principal"] == "*"
+        assert "Condition" in object_statement
+        assert "StringNotEquals" in object_statement["Condition"]
+
+        # Verify second statement structure (list bucket)
+        list_statement = policy["Statement"][1]
+        assert list_statement["Sid"] == "DenyListOnPrefixExceptAllowedPrincipals"
+        assert list_statement["Effect"] == "Deny"
+        assert list_statement["Principal"] == "*"
+        assert "Condition" in list_statement
+        assert "StringLike" in list_statement["Condition"]
+        assert "StringNotEquals" in list_statement["Condition"]
+
+    def test_policy_includes_both_principals_in_allowed_list(self):
+        """Test that both Lake Formation role and Feature Store role are in allowed principals."""
+        lf_role_arn = "arn:aws:iam::123456789012:role/LakeFormationRole"
+        fs_role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+
+        policy = self.fg._generate_s3_deny_policy(
+            bucket_name="test-bucket",
+            s3_prefix="test/prefix",
+            lake_formation_role_arn=lf_role_arn,
+            feature_store_role_arn=fs_role_arn,
+        )
+
+        # Verify both principals in object statement
+        object_principals = policy["Statement"][0]["Condition"]["StringNotEquals"]["aws:PrincipalArn"]
+        assert lf_role_arn in object_principals
+        assert fs_role_arn in object_principals
+        assert len(object_principals) == 2
+
+        # Verify both principals in list statement
+        list_principals = policy["Statement"][1]["Condition"]["StringNotEquals"]["aws:PrincipalArn"]
+        assert lf_role_arn in list_principals
+        assert fs_role_arn in list_principals
+        assert len(list_principals) == 2
+
+    def test_policy_has_correct_actions_in_each_statement(self):
+        """Test that each statement has the correct S3 actions."""
+        policy = self.fg._generate_s3_deny_policy(
+            bucket_name="test-bucket",
+            s3_prefix="test/prefix",
+            lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole",
+            feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole",
+        )
+
+        # Verify object statement has correct actions
+        object_actions = policy["Statement"][0]["Action"]
+        assert "s3:GetObject" in object_actions
+        assert "s3:PutObject" in object_actions
+        assert "s3:DeleteObject" in object_actions
+        assert len(object_actions) == 3
+
+        # Verify list statement has correct action
+        list_action = policy["Statement"][1]["Action"]
+        assert list_action == "s3:ListBucket"
+
+
+
+class TestEnableLakeFormationServiceLinkedRoleInPolicy:
+    """Tests for service-linked role ARN usage in S3 deny policy generation."""
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroup, "_generate_s3_deny_policy")
+    @patch("builtins.print")
+    def test_uses_service_linked_role_arn_when_use_service_linked_role_true(
+        self,
+        mock_print,
+        mock_generate_policy,
+        mock_revoke,
+        mock_grant,
+        mock_register,
+        mock_refresh,
+    ):
+        """
+        Test that enable_lake_formation uses the auto-generated service-linked role ARN
+        when use_service_linked_role=True.
+        """
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock successful Lake Formation operations
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+        mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []}
+
+        # Call with use_service_linked_role=True (default)
+        fg.enable_lake_formation(use_service_linked_role=True, show_s3_policy=True)
+
+        # Verify _generate_s3_deny_policy was called with the service-linked role ARN
+        expected_slr_arn = "arn:aws:iam::123456789012:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess"
+        mock_generate_policy.assert_called_once()
+        call_kwargs = mock_generate_policy.call_args[1]
+        assert call_kwargs["lake_formation_role_arn"] == expected_slr_arn
+        assert call_kwargs["feature_store_role_arn"] == fg.role_arn
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroup, "_generate_s3_deny_policy")
+    @patch("builtins.print")
+    def test_uses_service_linked_role_arn_by_default(
+        self,
+        mock_print,
+        mock_generate_policy,
+        mock_revoke,
+        mock_grant,
+        mock_register,
+        mock_refresh,
+    ):
+        """
+        Test that enable_lake_formation uses the service-linked role ARN by default
+        (when use_service_linked_role is not explicitly specified).
+        """
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = "arn:aws:iam::987654321098:role/MyFeatureStoreRole"
+        fg.feature_group_arn = "arn:aws:sagemaker:us-east-1:987654321098:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock successful Lake Formation operations
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+        mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []}
+
+        # Call without specifying use_service_linked_role (should default to True)
+        fg.enable_lake_formation(show_s3_policy=True)
+
+        # Verify _generate_s3_deny_policy was called with the service-linked role ARN
+        expected_slr_arn = "arn:aws:iam::987654321098:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess"
+        mock_generate_policy.assert_called_once()
+        call_kwargs = mock_generate_policy.call_args[1]
+        assert call_kwargs["lake_formation_role_arn"] == expected_slr_arn
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroup, "_generate_s3_deny_policy")
+    @patch("builtins.print")
+    def test_service_linked_role_arn_uses_correct_account_id(
+        self,
+        mock_print,
+        mock_generate_policy,
+        mock_revoke,
+        mock_grant,
+        mock_register,
+        mock_refresh,
+    ):
+        """
+        Test that the service-linked role ARN is generated with the correct account ID
+        extracted from the Feature Group ARN.
+        """
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        # Use a specific account ID to verify it's extracted correctly
+        account_id = "111222333444"
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = f"arn:aws:iam::{account_id}:role/FeatureStoreRole"
+        fg.feature_group_arn = f"arn:aws:sagemaker:us-west-2:{account_id}:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock successful Lake Formation operations
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+        mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []}
+
+        # Call with use_service_linked_role=True
+        fg.enable_lake_formation(use_service_linked_role=True, show_s3_policy=True)
+
+        # Verify the service-linked role ARN contains the correct account ID
+        expected_slr_arn = f"arn:aws:iam::{account_id}:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess"
+        mock_generate_policy.assert_called_once()
+        call_kwargs = mock_generate_policy.call_args[1]
+        assert call_kwargs["lake_formation_role_arn"] == expected_slr_arn
+        assert account_id in call_kwargs["lake_formation_role_arn"]
+
+
+
+class TestRegistrationRoleArnUsedWhenServiceLinkedRoleFalse:
+    """Tests for verifying registration_role_arn is used when use_service_linked_role=False."""
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroup, "_generate_s3_deny_policy")
+    @patch("builtins.print")
+    def test_uses_registration_role_arn_when_use_service_linked_role_false(
+        self,
+        mock_print,
+        mock_generate_policy,
+        mock_revoke,
+        mock_grant,
+        mock_register,
+        mock_refresh,
+    ):
+        """
+        Test that when use_service_linked_role=False, the registration_role_arn is used
+        in the S3 deny policy instead of the auto-generated service-linked role ARN.
+        """
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        # Set up Feature Group with required configuration
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock successful Lake Formation operations
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+        mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []}
+
+        # Custom registration role ARN
+        custom_registration_role = "arn:aws:iam::123456789012:role/CustomLakeFormationRole"
+
+        # Call with use_service_linked_role=False and registration_role_arn
+        fg.enable_lake_formation(
+            use_service_linked_role=False,
+            registration_role_arn=custom_registration_role,
+            show_s3_policy=True,
+        )
+
+        # Verify _generate_s3_deny_policy was called with the custom registration role ARN
+        mock_generate_policy.assert_called_once()
+        call_kwargs = mock_generate_policy.call_args[1]
+        assert call_kwargs["lake_formation_role_arn"] == custom_registration_role
+
+        # Verify it's NOT the service-linked role ARN
+        service_linked_role_pattern = "aws-service-role/lakeformation.amazonaws.com"
+        assert service_linked_role_pattern not in call_kwargs["lake_formation_role_arn"]
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroup, "_generate_s3_deny_policy")
+    @patch("builtins.print")
+    def test_registration_role_arn_passed_to_s3_registration(
+        self,
+        mock_print,
+        mock_generate_policy,
+        mock_revoke,
+        mock_grant,
+        mock_register,
+        mock_refresh,
+    ):
+        """
+        Test that when use_service_linked_role=False, the registration_role_arn is also
+        passed to _register_s3_with_lake_formation.
+        """
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        # Set up Feature Group with required configuration
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock successful Lake Formation operations
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+        mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []}
+
+        # Custom registration role ARN
+        custom_registration_role = "arn:aws:iam::123456789012:role/CustomLakeFormationRole"
+
+        # Call with use_service_linked_role=False and registration_role_arn
+        fg.enable_lake_formation(
+            use_service_linked_role=False,
+            registration_role_arn=custom_registration_role,
+            show_s3_policy=True,
+        )
+
+        # Verify _register_s3_with_lake_formation was called with the correct parameters
+        mock_register.assert_called_once()
+        call_args = mock_register.call_args
+        assert call_args[1]["use_service_linked_role"] == False
+        assert call_args[1]["role_arn"] == custom_registration_role
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroup, "_generate_s3_deny_policy")
+    @patch("builtins.print")
+    def test_different_registration_role_arns_produce_different_policies(
+        self,
+        mock_print,
+        mock_generate_policy,
+        mock_revoke,
+        mock_grant,
+        mock_register,
+        mock_refresh,
+    ):
+        """
+        Test that different registration_role_arn values result in different
+        lake_formation_role_arn values in the generated policy.
+        """
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        # Set up Feature Group with required configuration
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock successful Lake Formation operations
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+        mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []}
+
+        # First call with one registration role
+        first_role = "arn:aws:iam::123456789012:role/FirstLakeFormationRole"
+        fg.enable_lake_formation(
+            use_service_linked_role=False,
+            registration_role_arn=first_role,
+            show_s3_policy=True,
+        )
+
+        first_call_kwargs = mock_generate_policy.call_args[1]
+        first_lf_role = first_call_kwargs["lake_formation_role_arn"]
+
+        # Reset mocks
+        mock_generate_policy.reset_mock()
+        mock_register.reset_mock()
+        mock_grant.reset_mock()
+        mock_revoke.reset_mock()
+
+        # Second call with different registration role
+        second_role = "arn:aws:iam::123456789012:role/SecondLakeFormationRole"
+        fg.enable_lake_formation(
+            use_service_linked_role=False,
+            registration_role_arn=second_role,
+            show_s3_policy=True,
+        )
+
+        second_call_kwargs = mock_generate_policy.call_args[1]
+        second_lf_role = second_call_kwargs["lake_formation_role_arn"]
+
+        # Verify different roles were used
+        assert first_lf_role == first_role
+        assert second_lf_role == second_role
+        assert first_lf_role != second_lf_role
+
+
+
+class TestPolicyPrintedWithClearInstructions:
+    """Tests for verifying the S3 deny policy is printed with clear instructions."""
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch("builtins.print")
+    def test_policy_printed_with_header_and_instructions(
+        self,
+        mock_print,
+        mock_revoke,
+        mock_grant,
+        mock_register,
+        mock_refresh,
+    ):
+        """
+        Test that enable_lake_formation prints the S3 deny policy with clear
+        header and instructions for the user.
+        """
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        # Set up Feature Group with required configuration
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock successful Lake Formation operations
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+
+        # Call enable_lake_formation with show_s3_policy=True
+        fg.enable_lake_formation(show_s3_policy=True)
+
+        # Collect all print calls
+        print_calls = [str(call) for call in mock_print.call_args_list]
+        all_printed_text = " ".join(print_calls)
+
+        # Verify header is printed
+        assert "S3 Bucket Policy" in all_printed_text, "Header should mention 'S3 Bucket Policy'"
+
+        # Verify instructions are printed
+        assert (
+            "Lake Formation" in all_printed_text
+            or "deny policy" in all_printed_text
+        ), "Instructions should mention Lake Formation or deny policy"
+
+        # Verify bucket name is printed
+        assert "test-bucket" in all_printed_text, "Bucket name should be printed"
+
+        # Verify note about merging with existing policy is printed
+        assert (
+            "Merge" in all_printed_text or "existing" in all_printed_text
+        ), "Note about merging with existing policy should be printed"
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch("builtins.print")
+    def test_policy_json_is_printed(
+        self,
+        mock_print,
+        mock_revoke,
+        mock_grant,
+        mock_register,
+        mock_refresh,
+    ):
+        """
+        Test that the S3 deny policy JSON is printed to the console when show_s3_policy=True.
+        """
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        # Set up Feature Group with required configuration
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock successful Lake Formation operations
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+
+        # Call enable_lake_formation with show_s3_policy=True
+        fg.enable_lake_formation(show_s3_policy=True)
+
+        # Collect all print calls
+        print_calls = [str(call) for call in mock_print.call_args_list]
+        all_printed_text = " ".join(print_calls)
+
+        # Verify policy JSON structure elements are printed
+        assert "Version" in all_printed_text, "Policy JSON should contain 'Version'"
+        assert "Statement" in all_printed_text, "Policy JSON should contain 'Statement'"
+        assert "Effect" in all_printed_text, "Policy JSON should contain 'Effect'"
+        assert "Deny" in all_printed_text, "Policy JSON should contain 'Deny' effect"
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch("builtins.print")
+    def test_policy_printed_only_after_successful_setup(
+        self,
+        mock_print,
+        mock_revoke,
+        mock_grant,
+        mock_register,
+        mock_refresh,
+    ):
+        """
+        Test that the S3 deny policy is only printed after all Lake Formation
+        phases complete successfully.
+        """
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        # Set up Feature Group with required configuration
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock Phase 1 failure
+        mock_register.side_effect = Exception("Phase 1 failed")
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+
+        # Call enable_lake_formation with show_s3_policy=True - should fail
+        with pytest.raises(RuntimeError):
+            fg.enable_lake_formation(show_s3_policy=True)
+
+        # Collect all print calls
+        print_calls = [str(call) for call in mock_print.call_args_list]
+        all_printed_text = " ".join(print_calls)
+
+        # Verify policy was NOT printed when setup failed
+        assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed when setup fails"
+
+        # Reset mocks
+        mock_print.reset_mock()
+        mock_register.reset_mock()
+        mock_register.side_effect = None
+        mock_register.return_value = True
+
+        # Mock Phase 2 failure
+        mock_grant.side_effect = Exception("Phase 2 failed")
+
+        # Call enable_lake_formation with show_s3_policy=True - should fail
+        with pytest.raises(RuntimeError):
+            fg.enable_lake_formation(show_s3_policy=True)
+
+        # Collect all print calls
+        print_calls = [str(call) for call in mock_print.call_args_list]
+        all_printed_text = " ".join(print_calls)
+
+        # Verify policy was NOT printed when setup fails at Phase 2
+        assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed when Phase 2 fails"
+
+        # Reset mocks
+        mock_print.reset_mock()
+        mock_grant.reset_mock()
+        mock_grant.side_effect = None
+        mock_grant.return_value = True
+
+        # Mock Phase 3 failure
+        mock_revoke.side_effect = Exception("Phase 3 failed")
+
+        # Call enable_lake_formation with show_s3_policy=True - should fail
+        with pytest.raises(RuntimeError):
+            fg.enable_lake_formation(show_s3_policy=True)
+
+        # Collect all print calls
+        print_calls = [str(call) for call in mock_print.call_args_list]
+        all_printed_text = " ".join(print_calls)
+
+        # Verify policy was NOT printed when setup fails at Phase 3
+        assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed when Phase 3 fails"
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch("builtins.print")
+    def test_policy_includes_both_allowed_principals(
+        self,
+        mock_print,
+        mock_revoke,
+        mock_grant,
+        mock_register,
+        mock_refresh,
+    ):
+        """
+        Test that the printed policy includes both the Lake Formation role
+        and the Feature Store execution role as allowed principals.
+        """
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        # Set up Feature Group with required configuration
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        feature_store_role = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+        fg.role_arn = feature_store_role
+        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock successful Lake Formation operations
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+
+        # Call enable_lake_formation with service-linked role and show_s3_policy=True
+        fg.enable_lake_formation(use_service_linked_role=True, show_s3_policy=True)
+
+        # Collect all print calls
+        print_calls = [str(call) for call in mock_print.call_args_list]
+        all_printed_text = " ".join(print_calls)
+
+        # Verify Feature Store role is in the printed output
+        assert feature_store_role in all_printed_text, "Feature Store role should be in printed policy"
+
+        # Verify Lake Formation service-linked role pattern is in the printed output
+        assert "AWSServiceRoleForLakeFormationDataAccess" in all_printed_text, \
+            "Lake Formation service-linked role should be in printed policy"
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch("builtins.print")
+    def test_policy_not_printed_when_show_s3_policy_false(
+        self,
+        mock_print,
+        mock_revoke,
+        mock_grant,
+        mock_register,
+        mock_refresh,
+    ):
+        """
+        Test that the S3 deny policy is NOT printed when show_s3_policy=False (default).
+        """
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        # Set up Feature Group with required configuration
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock successful Lake Formation operations
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+
+        # Call enable_lake_formation with show_s3_policy=False (default)
+        fg.enable_lake_formation(show_s3_policy=False)
+
+        # Collect all print calls
+        print_calls = [str(call) for call in mock_print.call_args_list]
+        all_printed_text = " ".join(print_calls)
+
+        # Verify policy was NOT printed
+        assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed when show_s3_policy=False"
+        assert "Version" not in all_printed_text, "Policy JSON should not be printed when show_s3_policy=False"
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch("builtins.print")
+    def test_policy_not_printed_by_default(
+        self,
+        mock_print,
+        mock_revoke,
+        mock_grant,
+        mock_register,
+        mock_refresh,
+    ):
+        """
+        Test that the S3 deny policy is NOT printed by default (when show_s3_policy is not specified).
+        """
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        # Set up Feature Group with required configuration
+        fg = FeatureGroup(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
+        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
+        fg.feature_group_status = "Created"
+
+        # Mock successful Lake Formation operations
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+
+        # Call enable_lake_formation without specifying show_s3_policy (should default to False)
+        fg.enable_lake_formation()
+
+        # Collect all print calls
+        print_calls = [str(call) for call in mock_print.call_args_list]
+        all_printed_text = " ".join(print_calls)
+
+        # Verify policy was NOT printed
+        assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed by default"
+        assert "Version" not in all_printed_text, "Policy JSON should not be printed by default"

From a984e4704520df3416b5028a4674d385e8f97f84 Mon Sep 17 00:00:00 2001
From: Basssem Halim <bhhalim@amazon.com>
Date: Wed, 28 Jan 2026 17:06:06 -0800
Subject: [PATCH 04/22] docs(feature_store): Add Lake Formation governance
 example notebook

---
 .../v3-feature-store-lake-formation.ipynb     | 594 ++++++++++++++++++
 1 file changed, 594 insertions(+)
 create mode 100644 v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb

diff --git a/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb b/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb
new file mode 100644
index 0000000000..4f6efa03c4
--- /dev/null
+++ b/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb
@@ -0,0 +1,594 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Feature Store with Lake Formation Governance\n",
+    "\n",
+    "This notebook demonstrates two workflows for using SageMaker Feature Store with Lake Formation governance:\n",
+    "\n",
+    "1. **Example 1**: Create Feature Group with Lake Formation enabled at creation time\n",
+    "2. **Example 2**: Create Feature Group first, then enable Lake Formation separately\n",
+    "\n",
+    "Both workflows include record ingestion to verify everything works end-to-end.\n",
+    "\n",
+    "## Prerequisites\n",
+    "\n",
+    "- AWS credentials configured with permissions for SageMaker, S3, Glue, and Lake Formation\n",
+    "- An S3 bucket for the offline store\n",
+    "- An IAM role with Feature Store permissions\n",
+    "\n",
+    "## Required IAM Permissions\n",
+    "\n",
+    "TODO: Add the required IAM policy document here\n",
+    "\n",
+    "```json\n",
+    "{\n",
+    "    \"Version\": \"2012-10-17\",\n",
+    "    \"Statement\": [\n",
+    "        // TODO: Add required permissions\n",
+    "        1. FS permissions to create FG\n",
+    "        2. LF permissons\n",
+    "    ]\n",
+    "}\n",
+    "```\n",
+    "\n",
+    "## Lake Formation Admin Requirements\n",
+    "\n",
+    "The person enabling Lake Formation governance must be a **Data Lake Administrator** in Lake Formation. There are two options depending on your organization's setup:\n",
+    "\n",
+    "### Option 1: Single User (Data Lake Admin + Feature Store Admin)\n",
+    "\n",
+    "If the caller has both:\n",
+    "- Data Lake Administrator privileges in Lake Formation\n",
+    "- Permissions to create Feature Groups in SageMaker\n",
+    "\n",
+    "Then they can use `FeatureGroup.create()` with `lake_formation_config` to enable governance at creation time (Example 1).\n",
+    "\n",
+    "### Option 2: Separate Roles (ML Engineer + Data Lake Admin)\n",
+    "\n",
+    "If the person creating the Feature Group is different from the Data Lake Administrator:\n",
+    "\n",
+    "1. **ML Engineer** creates the Feature Group without Lake Formation using `FeatureGroup.create()`\n",
+    "2. **Data Lake Admin** later enables governance by calling `enable_lake_formation()` on the existing Feature Group (Example 2)\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Setup"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import time\n",
+    "from datetime import datetime\n",
+    "from datetime import timezone\n",
+    "\n",
+    "import boto3\n",
+    "from botocore.exceptions import ClientError\n",
+    "\n",
+    "# Import the FeatureGroup with Lake Formation support\n",
+    "from sagemaker.mlops.feature_store.feature_group import FeatureGroup, LakeFormationConfig\n",
+    "from sagemaker.core.shapes import (\n",
+    "    FeatureDefinition,\n",
+    "    FeatureValue,\n",
+    "    OfflineStoreConfig,\n",
+    "    OnlineStoreConfig,\n",
+    "    S3StorageConfig,\n",
+    ")\n",
+    "from sagemaker.core.helper.session_helper import Session as SageMakerSession, get_execution_role"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Configuration"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Use SageMaker session to get default bucket and execution role\n",
+    "sagemaker_session = SageMakerSession()\n",
+    "S3_BUCKET = sagemaker_session.default_bucket()\n",
+    "ROLE_ARN = get_execution_role(sagemaker_session)\n",
+    "REGION = sagemaker_session.boto_session.region_name\n",
+    "\n",
+    "print(f\"S3 Bucket: {S3_BUCKET}\")\n",
+    "print(f\"Role ARN: {ROLE_ARN}\")\n",
+    "print(f\"Region: {REGION}\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Common Feature Definitions"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "feature_definitions = [\n",
+    "    FeatureDefinition(feature_name=\"customer_id\", feature_type=\"String\"),\n",
+    "    FeatureDefinition(feature_name=\"event_time\", feature_type=\"String\"),\n",
+    "    FeatureDefinition(feature_name=\"age\", feature_type=\"Integral\"),\n",
+    "    FeatureDefinition(feature_name=\"total_purchases\", feature_type=\"Integral\"),\n",
+    "    FeatureDefinition(feature_name=\"avg_order_value\", feature_type=\"Fractional\"),\n",
+    "]\n",
+    "\n",
+    "print(\"Feature Definitions:\")\n",
+    "for fd in feature_definitions:\n",
+    "    print(f\"  - {fd.feature_name}: {fd.feature_type}\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Helper Function: Ingest Records"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def ingest_sample_records(feature_group, num_records=3):\n",
+    "    \"\"\"\n",
+    "    Ingest sample records into the Feature Group.\n",
+    "    \n",
+    "    Args:\n",
+    "        feature_group: The FeatureGroup to ingest records into\n",
+    "        num_records: Number of sample records to ingest\n",
+    "    \"\"\"\n",
+    "    print(f\"\\nIngesting {num_records} sample records...\")\n",
+    "    \n",
+    "    for i in range(num_records):\n",
+    "        event_time = datetime.now(timezone.utc).isoformat()\n",
+    "        record = [\n",
+    "            FeatureValue(feature_name=\"customer_id\", value_as_string=f\"cust_{i+1}\"),\n",
+    "            FeatureValue(feature_name=\"event_time\", value_as_string=event_time),\n",
+    "            FeatureValue(feature_name=\"age\", value_as_string=str(25 + i * 5)),\n",
+    "            FeatureValue(feature_name=\"total_purchases\", value_as_string=str(10 + i * 3)),\n",
+    "            FeatureValue(feature_name=\"avg_order_value\", value_as_string=str(50.0 + i * 10.5)),\n",
+    "        ]\n",
+    "        \n",
+    "        feature_group.put_record(record=record)\n",
+    "        print(f\"  Ingested record for customer: cust_{i+1}\")\n",
+    "    \n",
+    "    print(f\"Successfully ingested {num_records} records!\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Helper Function: Cleanup"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def cleanup_feature_group(fg):\n",
+    "    \"\"\"\n",
+    "    Delete a FeatureGroup and its associated Glue table.\n",
+    "    \n",
+    "    Args:\n",
+    "        fg: The FeatureGroup to delete.\n",
+    "    \"\"\"\n",
+    "    try:\n",
+    "        # Delete the Glue table if it exists\n",
+    "        if fg.offline_store_config is not None:\n",
+    "            try:\n",
+    "                fg.refresh()  # Ensure we have latest config\n",
+    "                data_catalog_config = fg.offline_store_config.data_catalog_config\n",
+    "                if data_catalog_config is not None:\n",
+    "                    database_name = data_catalog_config.database\n",
+    "                    table_name = data_catalog_config.table_name\n",
+    "\n",
+    "                    if database_name and table_name:\n",
+    "                        glue_client = boto3.client(\"glue\")\n",
+    "                        try:\n",
+    "                            glue_client.delete_table(DatabaseName=database_name, Name=table_name)\n",
+    "                            print(f\"Deleted Glue table: {database_name}.{table_name}\")\n",
+    "                        except ClientError as e:\n",
+    "                            # Ignore if table doesn't exist\n",
+    "                            if e.response[\"Error\"][\"Code\"] != \"EntityNotFoundException\":\n",
+    "                                raise\n",
+    "            except Exception as e:\n",
+    "                # Don't fail cleanup if Glue table deletion fails\n",
+    "                print(f\"Warning: Could not delete Glue table: {e}\")\n",
+    "\n",
+    "        # Delete the FeatureGroup\n",
+    "        fg.delete()\n",
+    "        print(f\"Deleted Feature Group: {fg.feature_group_name}\")\n",
+    "    except ClientError as e:\n",
+    "        print(f\"Error during cleanup: {e}\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "---\n",
+    "# Example 1: Create Feature Group with Lake Formation Enabled\n",
+    "\n",
+    "This example creates a Feature Group with Lake Formation governance enabled at creation time using `LakeFormationConfig`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Generate unique name for example 1\n",
+    "timestamp = datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
+    "FG_NAME_WORKFLOW1 = f\"lf-demo-workflow1-{timestamp}\"\n",
+    "\n",
+    "print(f\"Example 1 Feature Group: {FG_NAME_WORKFLOW1}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Configure online and offline stores\n",
+    "online_store_config = OnlineStoreConfig(enable_online_store=True)\n",
+    "\n",
+    "offline_store_config_1 = OfflineStoreConfig(\n",
+    "    s3_storage_config=S3StorageConfig(\n",
+    "        s3_uri=f\"s3://{S3_BUCKET}/feature-store-demo/\"\n",
+    "    )\n",
+    ")\n",
+    "\n",
+    "# Configure Lake Formation - enabled at creation\n",
+    "lake_formation_config = LakeFormationConfig()\n",
+    "lake_formation_config.enabled = True\n",
+    "lake_formation_config.use_service_linked_role = True\n",
+    "lake_formation_config.show_s3_policy = True\n",
+    "\n",
+    "print(\"Store Config:\")\n",
+    "print(f\"  Online Store: enabled\")\n",
+    "print(f\"  Offline Store S3: s3://{S3_BUCKET}/feature-store-demo/\")\n",
+    "print(\"\\nLake Formation Config:\")\n",
+    "print(f\"  enabled: {lake_formation_config.enabled}\")\n",
+    "print(f\"  use_service_linked_role: {lake_formation_config.use_service_linked_role}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Create Feature Group with Lake Formation enabled\n",
+    "print(\"Creating Feature Group with Lake Formation enabled...\")\n",
+    "print(\"This will:\")\n",
+    "print(\"  1. Create the Feature Group with online + offline stores\")\n",
+    "print(\"  2. Wait for 'Created' status\")\n",
+    "print(\"  3. Register S3 with Lake Formation\")\n",
+    "print(\"  4. Grant permissions to execution role\")\n",
+    "print(\"  5. Revoke IAMAllowedPrincipal permissions\")\n",
+    "print()\n",
+    "\n",
+    "fg_workflow1 = FeatureGroup.create(\n",
+    "    feature_group_name=FG_NAME_WORKFLOW1,\n",
+    "    record_identifier_feature_name=\"customer_id\",\n",
+    "    event_time_feature_name=\"event_time\",\n",
+    "    feature_definitions=feature_definitions,\n",
+    "    online_store_config=online_store_config,\n",
+    "    offline_store_config=offline_store_config_1,\n",
+    "    role_arn=ROLE_ARN,\n",
+    "    description=\"Workflow 1: Lake Formation enabled at creation\",\n",
+    "    lake_formation_config=lake_formation_config, # new field\n",
+    "    region=REGION,\n",
+    ")\n",
+    "\n",
+    "print(f\"\\nFeature Group created: {fg_workflow1.feature_group_name}\")\n",
+    "print(f\"Status: {fg_workflow1.feature_group_status}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Verify Feature Group status\n",
+    "fg_workflow1.refresh()\n",
+    "print(f\"Feature Group: {fg_workflow1.feature_group_name}\")\n",
+    "print(f\"Status: {fg_workflow1.feature_group_status}\")\n",
+    "print(f\"ARN: {fg_workflow1.feature_group_arn}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Ingest sample records to verify everything works\n",
+    "ingest_sample_records(fg_workflow1, num_records=3)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Retrieve a sample record from the online store\n",
+    "print(\"Retrieving record for customer 'cust_1' from online store...\")\n",
+    "response = fg_workflow1.get_record(record_identifier_value_as_string=\"cust_1\")\n",
+    "\n",
+    "print(f\"\\nRecord retrieved successfully!\")\n",
+    "print(f\"Features:\")\n",
+    "for feature in response.record:\n",
+    "    print(f\"  {feature.feature_name}: {feature.value_as_string}\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "---\n",
+    "# Example 2: Create Feature Group, Then Enable Lake Formation\n",
+    "\n",
+    "This example creates a Feature Group first without Lake Formation, then enables it separately using `enable_lake_formation()`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Generate unique name for example 2\n",
+    "timestamp = datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
+    "FG_NAME_WORKFLOW2 = f\"lf-demo-workflow2-{timestamp}\"\n",
+    "\n",
+    "print(f\"Example 2 Feature Group: {FG_NAME_WORKFLOW2}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Configure online and offline stores\n",
+    "online_store_config_2 = OnlineStoreConfig(enable_online_store=True)\n",
+    "\n",
+    "offline_store_config_2 = OfflineStoreConfig(\n",
+    "    s3_storage_config=S3StorageConfig(\n",
+    "        s3_uri=f\"s3://{S3_BUCKET}/feature-store-demo/\"\n",
+    "    ),\n",
+    "    table_format=\"Iceberg\"\n",
+    ")\n",
+    "\n",
+    "# Step 1: Create Feature Group WITHOUT Lake Formation\n",
+    "print(\"Step 1: Creating Feature Group without Lake Formation...\")\n",
+    "\n",
+    "fg_workflow2 = FeatureGroup.create(\n",
+    "    feature_group_name=FG_NAME_WORKFLOW2,\n",
+    "    record_identifier_feature_name=\"customer_id\",\n",
+    "    event_time_feature_name=\"event_time\",\n",
+    "    feature_definitions=feature_definitions,\n",
+    "    online_store_config=online_store_config_2,\n",
+    "    offline_store_config=offline_store_config_2,\n",
+    "    role_arn=ROLE_ARN,\n",
+    "    description=\"Workflow 2: Lake Formation enabled after creation\",\n",
+    "    region=REGION,\n",
+    ")\n",
+    "\n",
+    "print(f\"Feature Group created: {fg_workflow2.feature_group_name}\")\n",
+    "print(f\"Status: {fg_workflow2.feature_group_status}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Step 2: Wait for Feature Group to be ready\n",
+    "print(\"Step 2: Waiting for Feature Group to reach 'Created' status...\")\n",
+    "fg_workflow2.wait_for_status(target_status=\"Created\", poll=10, timeout=300)\n",
+    "print(f\"Status: {fg_workflow2.feature_group_status}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Step 3: Enable Lake Formation governance\n",
+    "print(\"Step 3: Enabling Lake Formation governance...\")\n",
+    "print(\"This will:\")\n",
+    "print(\"  1. Register S3 with Lake Formation\")\n",
+    "print(\"  2. Grant permissions to execution role\")\n",
+    "print(\"  3. Revoke IAMAllowedPrincipal permissions\")\n",
+    "print()\n",
+    "\n",
+    "result = fg_workflow2.enable_lake_formation( # new method\n",
+    "    use_service_linked_role=True\n",
+    ")\n",
+    "\n",
+    "print(f\"\\nLake Formation setup results:\")\n",
+    "print(f\"  s3_registration: {result['s3_registration']}\")\n",
+    "print(f\"  permissions_granted: {result['permissions_granted']}\")\n",
+    "print(f\"  iam_principal_revoked: {result['iam_principal_revoked']}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Step 4: Ingest sample records to verify everything works\n",
+    "print(\"Step 4: Ingesting records to verify Lake Formation setup...\")\n",
+    "ingest_sample_records(fg_workflow2, num_records=3)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Step 5: Retrieve a sample record from the online store\n",
+    "print(\"Step 5: Retrieving record for customer 'cust_1' from online store...\")\n",
+    "response = fg_workflow2.get_record(record_identifier_value_as_string=\"cust_1\")\n",
+    "\n",
+    "print(f\"\\nRecord retrieved successfully!\")\n",
+    "print(f\"Features:\")\n",
+    "for feature in response.record:\n",
+    "    print(f\"  {feature.feature_name}: {feature.value_as_string}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Verify Feature Group status\n",
+    "fg_workflow2.refresh()\n",
+    "print(f\"Feature Group: {fg_workflow2.feature_group_name}\")\n",
+    "print(f\"Status: {fg_workflow2.feature_group_status}\")\n",
+    "print(f\"ARN: {fg_workflow2.feature_group_arn}\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "---\n",
+    "# Cleanup\n",
+    "\n",
+    "Delete the Feature Groups and associated Glue tables created in this demo."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Uncomment to delete the Feature Groups\n",
+    "cleanup_feature_group(fg_workflow1)\n",
+    "# cleanup_feature_group(fg_workflow2)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "---\n",
+    "# Summary\n",
+    "\n",
+    "This notebook demonstrated two workflows:\n",
+    "\n",
+    "**Example 1: Lake Formation at Creation**\n",
+    "- Use `LakeFormationConfig` with `enabled=True` in `FeatureGroup.create()`\n",
+    "- Lake Formation is automatically configured after Feature Group creation\n",
+    "- Both online and offline stores enabled\n",
+    "\n",
+    "**Example 2: Enable Lake Formation Later**\n",
+    "- Create Feature Group normally without Lake Formation\n",
+    "- Call `enable_lake_formation()` method after creation\n",
+    "- More control over when Lake Formation is enabled\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "---\n",
+    "# FAQ:\n",
+    "\n",
+    "## What is the S3 deny policy for?\n",
+    "\n",
+    "When you enable Lake Formation governance, you control access to data through Lake Formation permissions. However, **IAM roles that already have direct S3 access will continue to have access** to the underlying data files, bypassing Lake Formation entirely.\n",
+    "\n",
+    "The S3 deny policy closes this access path by explicitly denying S3 access to all principals except:\n",
+    "- The Lake Formation service-linked role (for data access)\n",
+    "- The Feature Store offline store role provided during Feature Group creation\n",
+    "\n",
+    "## Why don't we apply the S3 deny policy automatically?\n",
+    "\n",
+    "We provide the policy as a **recommendation** rather than applying it automatically for several important reasons:\n",
+    "\n",
+    "### 1. Protect existing SageMaker workflows from breaking\n",
+    "\n",
+    "Many customers already have SageMaker training and processing jobs wired directly to S3 URIs. An automatic S3 deny could cause those jobs to fail the moment governance is enabled on a table.\n",
+    "\n",
+    "### 2. Support different personas and trust levels\n",
+    "\n",
+    "Different users have different access needs:\n",
+    "- **Analysts / BI users** - should only see data through governed surfaces (Lake Formation tables, Athena, Redshift, etc.)\n",
+    "- **ML / Data engineers** - often need raw S3 access for training, feature engineering, and debugging\n",
+    "\n",
+    "### 3. Enable gradual migration to stronger governance\n",
+    "\n",
+    "Many customers want to phase in Lake Formation governance:\n",
+    "1. Start by governing table access only\n",
+    "2. Later tighten S3 access once they've refactored jobs and validated behavior\n",
+    "\n",
+    "### 4. Avoid breaking existing bucket policies\n",
+    "\n",
+    "Automatically modifying bucket policies could:\n",
+    "- Conflict with existing policy statements\n",
+    "- Lock out users or services unexpectedly\n",
+    "- Cause cascading failures across multiple applications sharing the bucket\n",
+    "\n",
+    "Therefore, the S3 policy is provided as a starting point that should be validated by the user. \n"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.10.14"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}

From 6af324019b376d456b15de8a85ca91c67d2d6248 Mon Sep 17 00:00:00 2001
From: BassemHalim <bassemamir459@gmail.com>
Date: Thu, 29 Jan 2026 14:45:37 -0800
Subject: [PATCH 05/22] add role policy to notebook

---
 .../v3-feature-store-lake-formation.ipynb     | 97 +++++++++++++++++--
 1 file changed, 89 insertions(+), 8 deletions(-)

diff --git a/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb b/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb
index 4f6efa03c4..f8c5a8ced0 100644
--- a/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb
+++ b/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb
@@ -21,15 +21,89 @@
     "\n",
     "## Required IAM Permissions\n",
     "\n",
-    "TODO: Add the required IAM policy document here\n",
+    "This notebook uses two separate IAM roles:\n",
+    "1. **Execution Role**: The SageMaker execution role running this notebook\n",
+    "2. **Offline Store Role**: A dedicated role for Feature Store S3 access\n",
+    "\n",
+    "### Execution Role Policy\n",
+    "\n",
+    "The execution role needs permissions to manage Feature Groups and configure Lake Formation:\n",
     "\n",
     "```json\n",
     "{\n",
     "    \"Version\": \"2012-10-17\",\n",
     "    \"Statement\": [\n",
-    "        // TODO: Add required permissions\n",
-    "        1. FS permissions to create FG\n",
-    "        2. LF permissons\n",
+    "        {\n",
+    "            \"Sid\": \"FeatureGroupManagement\",\n",
+    "            \"Effect\": \"Allow\",\n",
+    "            \"Action\": [\n",
+    "                \"sagemaker:*\"\n",
+    "            ],\n",
+    "            \"Resource\": \"arn:aws:sagemaker:*:*:feature-group/*\"\n",
+    "        },\n",
+    "        {\n",
+    "            \"Sid\": \"LakeFormation\",\n",
+    "            \"Effect\": \"Allow\",\n",
+    "            \"Action\": [\n",
+    "                \"lakeformation:RegisterResource\",\n",
+    "                \"lakeformation:DeregisterResource\",\n",
+    "                \"lakeformation:GrantPermissions\",\n",
+    "                \"lakeformation:RevokePermissions\"\n",
+    "            ],\n",
+    "            \"Resource\": \"*\"\n",
+    "        },\n",
+    "        {\n",
+    "            \"Sid\": \"GlueCatalogRead\",\n",
+    "            \"Effect\": \"Allow\",\n",
+    "            \"Action\": [\n",
+    "                \"glue:GetTable\",\n",
+    "                \"glue:GetDatabase\",\n",
+    "                \"glue:DeleteTable\"\n",
+    "            ],\n",
+    "            \"Resource\": [\n",
+    "                \"arn:aws:glue:*:*:catalog\",\n",
+    "                \"arn:aws:glue:*:*:database/sagemaker_featurestore\",\n",
+    "                \"arn:aws:glue:*:*:table/sagemaker_featurestore/*\"\n",
+    "            ]\n",
+    "        },\n",
+    "        {\n",
+    "            \"Sid\": \"PassOfflineStoreRole\",\n",
+    "            \"Effect\": \"Allow\",\n",
+    "            \"Action\": \"iam:PassRole\",\n",
+    "            \"Resource\": \"arn:aws:iam::*:role/SagemakerFeatureStoreOfflineRole\"\n",
+    "        },\n",
+    "        {\n",
+    "            \"Sid\": \"LakeFormationServiceLinkedRole\",\n",
+    "            \"Effect\": \"Allow\",\n",
+    "            \"Action\": [\n",
+    "                \"iam:GetRole\",\n",
+    "                \"iam:PutRolePolicy\",\n",
+    "                \"iam:GetRolePolicy\"\n",
+    "            ],\n",
+    "            \"Resource\": \"arn:aws:iam::*:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess\"\n",
+    "        },\n",
+    "        {\n",
+    "            \"Sid\": \"S3SagemakerDefaultBucket\",\n",
+    "            \"Effect\": \"Allow\",\n",
+    "            \"Action\": [\n",
+    "                \"s3:CreateBucket\",\n",
+    "                \"s3:GetBucketAcl\",\n",
+    "                \"s3:ListBucket\"\n",
+    "            ],\n",
+    "            \"Resource\": [\n",
+    "                \"arn:aws:s3:::sagemaker-*\"\n",
+    "            ]\n",
+    "        },\n",
+    "        {\n",
+    "            \"Sid\": \"CreateGlueTable\",\n",
+    "            \"Effect\": \"Allow\",\n",
+    "            \"Action\": [\n",
+    "                \"glue:CreateTable\"\n",
+    "            ],\n",
+    "            \"Resource\": [\n",
+    "                \"*\"\n",
+    "            ]\n",
+    "        }\n",
     "    ]\n",
     "}\n",
     "```\n",
@@ -102,11 +176,18 @@
     "# Use SageMaker session to get default bucket and execution role\n",
     "sagemaker_session = SageMakerSession()\n",
     "S3_BUCKET = sagemaker_session.default_bucket()\n",
-    "ROLE_ARN = get_execution_role(sagemaker_session)\n",
     "REGION = sagemaker_session.boto_session.region_name\n",
     "\n",
+    "# Execution role (for running this notebook)\n",
+    "EXECUTION_ROLE_ARN = get_execution_role(sagemaker_session)\n",
+    "\n",
+    "# Offline store role (dedicated role for Feature Store S3 access)\n",
+    "# Replace with your dedicated offline store role ARN\n",
+    "OFFLINE_STORE_ROLE_ARN = \"arn:aws:iam::<account-id>:role/<feature-store-role>\"\n",
+    "\n",
     "print(f\"S3 Bucket: {S3_BUCKET}\")\n",
-    "print(f\"Role ARN: {ROLE_ARN}\")\n",
+    "print(f\"Execution Role ARN: {EXECUTION_ROLE_ARN}\")\n",
+    "print(f\"Offline Store Role ARN: {OFFLINE_STORE_ROLE_ARN}\")\n",
     "print(f\"Region: {REGION}\")"
    ]
   },
@@ -300,7 +381,7 @@
     "    feature_definitions=feature_definitions,\n",
     "    online_store_config=online_store_config,\n",
     "    offline_store_config=offline_store_config_1,\n",
-    "    role_arn=ROLE_ARN,\n",
+    "    role_arn=OFFLINE_STORE_ROLE_ARN,\n",
     "    description=\"Workflow 1: Lake Formation enabled at creation\",\n",
     "    lake_formation_config=lake_formation_config, # new field\n",
     "    region=REGION,\n",
@@ -398,7 +479,7 @@
     "    feature_definitions=feature_definitions,\n",
     "    online_store_config=online_store_config_2,\n",
     "    offline_store_config=offline_store_config_2,\n",
-    "    role_arn=ROLE_ARN,\n",
+    "    role_arn=OFFLINE_STORE_ROLE_ARN,\n",
     "    description=\"Workflow 2: Lake Formation enabled after creation\",\n",
     "    region=REGION,\n",
     ")\n",

From 34b90a7682991b8b0401f05790d4579f1290afe2 Mon Sep 17 00:00:00 2001
From: Basssem Halim <bhhalim@amazon.com>
Date: Wed, 4 Feb 2026 15:54:33 -0800
Subject: [PATCH 06/22] chore(docs): update example notebook

---
 .../mlops/feature_store/feature_group.py      |   2 +-
 .../v3-feature-store-lake-formation.ipynb     | 308 +++++++++++++-----
 2 files changed, 222 insertions(+), 88 deletions(-)

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
index c5fcb9211a..dd193471eb 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
@@ -423,7 +423,7 @@ def enable_lake_formation(
         """
         # Get region from session if not provided
         if region is None and session is not None:
-            region = session.region_name()
+            region = session.region_name
 
         # Wait for Created status if requested
         if wait_for_active:
diff --git a/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb b/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb
index f8c5a8ced0..7cde7ca566 100644
--- a/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb
+++ b/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb
@@ -4,8 +4,100 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "# Feature Store with Lake Formation Governance\n",
+    "# Feature Group Lake Formation Governance "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## New SDK API Changes\n",
+    "\n",
+    "This release introduces Lake Formation integration through the following additions:\n",
+    "\n",
+    "### New Class: `LakeFormationConfig`\n",
+    "\n",
+    "A configuration class for Lake Formation governance settings:\n",
+    "\n",
+    "```python\n",
+    "from sagemaker.mlops.feature_store.feature_group import LakeFormationConfig\n",
+    "\n",
+    "lake_formation_config = LakeFormationConfig()\n",
+    "lake_formation_config.enabled = True                    # Enable Lake Formation governance\n",
+    "lake_formation_config.use_service_linked_role = True    # Use LF service-linked role (default)\n",
+    "lake_formation_config.registration_role_arn = None      # This is the role used by LF to access your Resources\n",
+    "lake_formation_config.show_s3_policy = True             # Print recommended S3 deny policy\n",
+    "```\n",
+    "\n",
+    "### New Parameter in FeatureGroup.create(): lake_formation_config\n",
+    "Pass a LakeFormationConfig object to enable Lake Formation at creation time:\n",
+    "```python\n",
+    "fg = FeatureGroup.create(\n",
+    "    feature_group_name=\"my-feature-group\",\n",
+    "    # ... other parameters ...\n",
+    "    lake_formation_config=lake_formation_config,  # OPTIONAL NEW PARAMETER\n",
+    ")\n",
+    "```\n",
+    "\n",
+    "### New Method: FeatureGroup.enable_lake_formation()\n",
+    "Enable Lake Formation on an existing Feature Group:\n",
+    "```python\n",
+    "fg.enable_lake_formation(\n",
+    "    use_service_linked_role=True,      # Use LF service-linked role (default)\n",
+    "    registration_role_arn=None,        # Custom role ARN (if not using SLR)\n",
+    "    wait_for_active=False,             # Wait for Feature Group to be Created\n",
+    "    show_s3_policy=False,              # Print recommended S3 deny policy\n",
+    ")\n",
+    "```\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Lake Formation Setup Process\n",
+    "\n",
+    "When you enable Lake Formation governance (either at creation time or via `enable_lake_formation()`), the SDK performs the following steps automatically:\n",
     "\n",
+    "### Step 1: Register S3 Location with Lake Formation\n",
+    "\n",
+    "The offline store's S3 location is registered as a Lake Formation data lake location. This allows Lake Formation to manage access to the underlying data files.\n",
+    "\n",
+    "- Uses either the Lake Formation service-linked role (default) or a custom registration role\n",
+    "- If the location is already registered, this step is skipped\n",
+    "\n",
+    "### Step 2: Grant Lake Formation Permissions\n",
+    "\n",
+    "The Feature Group's `role_arn` (offline store role) is granted the following permissions on the Glue table via Lake Formation:\n",
+    "\n",
+    "- `SELECT` - Read data from the table\n",
+    "- `INSERT` - Write new records\n",
+    "- `DELETE` - Remove records\n",
+    "- `DESCRIBE` - View table metadata\n",
+    "- `ALTER` - Modify table schema\n",
+    "\n",
+    "### Step 3: Revoke IAMAllowedPrincipal Permissions\n",
+    "\n",
+    "By default, Glue tables allow access to any IAM principal with appropriate IAM permissions (`IAMAllowedPrincipal`). This step revokes that default permission, ensuring that:\n",
+    "\n",
+    "- Access is now controlled exclusively through Lake Formation\n",
+    "- Only principals explicitly granted permissions via Lake Formation can access the data\n",
+    "\n",
+    "### Optional: S3 Deny Policy\n",
+    "\n",
+    "When `show_s3_policy=True`, the SDK prints a recommended S3 bucket policy. This policy adds an additional layer of protection by denying direct S3 access to all principals except:\n",
+    "\n",
+    "- The Lake Formation service-linked role\n",
+    "- The Feature Store offline store role\n",
+    "\n",
+    "**Note:** The S3 policy is not applied automatically—you must manually add it to your bucket policy if desired.\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    " \n",
     "This notebook demonstrates two workflows for using SageMaker Feature Store with Lake Formation governance:\n",
     "\n",
     "1. **Example 1**: Create Feature Group with Lake Formation enabled at creation time\n",
@@ -22,12 +114,33 @@
     "## Required IAM Permissions\n",
     "\n",
     "This notebook uses two separate IAM roles:\n",
-    "1. **Execution Role**: The SageMaker execution role running this notebook\n",
+    "1. **Execution Role**: The SageMaker execution role running this notebook. It requires having Lakeformation Data lake admin permissions and Feature store permissions\n",
     "2. **Offline Store Role**: A dedicated role for Feature Store S3 access\n",
     "\n",
+    "## Lake Formation Admin Requirements\n",
+    "\n",
+    "The person enabling Lake Formation governance must be a **Data Lake Administrator** in Lake Formation. There are two options for enabling lakeformation governance depending on your organization's setup:\n",
+    "\n",
+    "### Option 1: Single Role (Data Lake Admin + Feature Store Admin)\n",
+    "\n",
+    "If the caller has both:\n",
+    "- Data Lake Administrator privileges in Lake Formation\n",
+    "- Permissions to create Feature Groups in SageMaker\n",
+    "\n",
+    "Then they can use `FeatureGroup.create()` with `lake_formation_config` to enable governance at creation time (Example 1).\n",
+    "\n",
+    "### Option 2: Separate Roles (ML Engineer + Data Lake Admin)\n",
+    "\n",
+    "If the person creating the Feature Group is different from the Data Lake Administrator:\n",
+    "\n",
+    "1. **ML Engineer** creates the Feature Group without Lake Formation using `FeatureGroup.create()`\n",
+    "2. **Data Lake Admin** later enables governance by calling `enable_lake_formation()` on the existing Feature Group (Example 2)\n",
+    "\n",
+    "\n",
     "### Execution Role Policy\n",
     "\n",
-    "The execution role needs permissions to manage Feature Groups and configure Lake Formation:\n",
+    "You can assume a role with the following policy to run this notebook\n",
+    "Make sure to update the policy to use the offline store role\n",
     "\n",
     "```json\n",
     "{\n",
@@ -70,7 +183,7 @@
     "            \"Sid\": \"PassOfflineStoreRole\",\n",
     "            \"Effect\": \"Allow\",\n",
     "            \"Action\": \"iam:PassRole\",\n",
-    "            \"Resource\": \"arn:aws:iam::*:role/SagemakerFeatureStoreOfflineRole\"\n",
+    "            \"Resource\": \"arn:aws:iam::*:role/<your offline store role>\"\n",
     "        },\n",
     "        {\n",
     "            \"Sid\": \"LakeFormationServiceLinkedRole\",\n",
@@ -106,26 +219,7 @@
     "        }\n",
     "    ]\n",
     "}\n",
-    "```\n",
-    "\n",
-    "## Lake Formation Admin Requirements\n",
-    "\n",
-    "The person enabling Lake Formation governance must be a **Data Lake Administrator** in Lake Formation. There are two options depending on your organization's setup:\n",
-    "\n",
-    "### Option 1: Single User (Data Lake Admin + Feature Store Admin)\n",
-    "\n",
-    "If the caller has both:\n",
-    "- Data Lake Administrator privileges in Lake Formation\n",
-    "- Permissions to create Feature Groups in SageMaker\n",
-    "\n",
-    "Then they can use `FeatureGroup.create()` with `lake_formation_config` to enable governance at creation time (Example 1).\n",
-    "\n",
-    "### Option 2: Separate Roles (ML Engineer + Data Lake Admin)\n",
-    "\n",
-    "If the person creating the Feature Group is different from the Data Lake Administrator:\n",
-    "\n",
-    "1. **ML Engineer** creates the Feature Group without Lake Formation using `FeatureGroup.create()`\n",
-    "2. **Data Lake Admin** later enables governance by calling `enable_lake_formation()` on the existing Feature Group (Example 2)\n"
+    "```"
    ]
   },
   {
@@ -135,6 +229,24 @@
     "## Setup"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This Demo builds on sagemaker v3 features which is not out yet so we need to tell pip to use local version \n",
+    "\n",
+    "1. install `pyenv` https://github.com/pyenv/pyenv?tab=readme-ov-file#a-getting-pyenv\n",
+    "2. install and activate python for example (this code was tested on python 3.10.14)\n",
+    "```\n",
+    "pyenv install 3.10.14\n",
+    "pyenv virtualenv 3.10.14 py3.10.14\n",
+    "pyenv activate py3.10.14\n",
+    "```\n",
+    "3. You will then need to run `pip install -e .` before starting the jupyter notebook to use the local packages\n",
+    "4. `pip install jupyter notebook`\n",
+    "5. `jupyter notebook`"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -174,6 +286,9 @@
    "outputs": [],
    "source": [
     "# Use SageMaker session to get default bucket and execution role\n",
+    "\n",
+    "boto_session = boto3.Session()\n",
+    "new_sagemaker_session = SageMakerSession(boto_session=boto_session)\n",
     "sagemaker_session = SageMakerSession()\n",
     "S3_BUCKET = sagemaker_session.default_bucket()\n",
     "REGION = sagemaker_session.boto_session.region_name\n",
@@ -183,7 +298,8 @@
     "\n",
     "# Offline store role (dedicated role for Feature Store S3 access)\n",
     "# Replace with your dedicated offline store role ARN\n",
-    "OFFLINE_STORE_ROLE_ARN = \"arn:aws:iam::<account-id>:role/<feature-store-role>\"\n",
+    "# https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store-adding-policies.html\n",
+    "OFFLINE_STORE_ROLE_ARN = \"arn:aws:iam::<aws account id>:role/<role name>\"\n",
     "\n",
     "print(f\"S3 Bucket: {S3_BUCKET}\")\n",
     "print(f\"Execution Role ARN: {EXECUTION_ROLE_ARN}\")\n",
@@ -256,56 +372,6 @@
     "    print(f\"Successfully ingested {num_records} records!\")"
    ]
   },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Helper Function: Cleanup"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "def cleanup_feature_group(fg):\n",
-    "    \"\"\"\n",
-    "    Delete a FeatureGroup and its associated Glue table.\n",
-    "    \n",
-    "    Args:\n",
-    "        fg: The FeatureGroup to delete.\n",
-    "    \"\"\"\n",
-    "    try:\n",
-    "        # Delete the Glue table if it exists\n",
-    "        if fg.offline_store_config is not None:\n",
-    "            try:\n",
-    "                fg.refresh()  # Ensure we have latest config\n",
-    "                data_catalog_config = fg.offline_store_config.data_catalog_config\n",
-    "                if data_catalog_config is not None:\n",
-    "                    database_name = data_catalog_config.database\n",
-    "                    table_name = data_catalog_config.table_name\n",
-    "\n",
-    "                    if database_name and table_name:\n",
-    "                        glue_client = boto3.client(\"glue\")\n",
-    "                        try:\n",
-    "                            glue_client.delete_table(DatabaseName=database_name, Name=table_name)\n",
-    "                            print(f\"Deleted Glue table: {database_name}.{table_name}\")\n",
-    "                        except ClientError as e:\n",
-    "                            # Ignore if table doesn't exist\n",
-    "                            if e.response[\"Error\"][\"Code\"] != \"EntityNotFoundException\":\n",
-    "                                raise\n",
-    "            except Exception as e:\n",
-    "                # Don't fail cleanup if Glue table deletion fails\n",
-    "                print(f\"Warning: Could not delete Glue table: {e}\")\n",
-    "\n",
-    "        # Delete the FeatureGroup\n",
-    "        fg.delete()\n",
-    "        print(f\"Deleted Feature Group: {fg.feature_group_name}\")\n",
-    "    except ClientError as e:\n",
-    "        print(f\"Error during cleanup: {e}\")"
-   ]
-  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -383,8 +449,9 @@
     "    offline_store_config=offline_store_config_1,\n",
     "    role_arn=OFFLINE_STORE_ROLE_ARN,\n",
     "    description=\"Workflow 1: Lake Formation enabled at creation\",\n",
-    "    lake_formation_config=lake_formation_config, # new field\n",
+    "    lake_formation_config=lake_formation_config, # new parameter\n",
     "    region=REGION,\n",
+    "    session=boto_session\n",
     ")\n",
     "\n",
     "print(f\"\\nFeature Group created: {fg_workflow1.feature_group_name}\")\n",
@@ -401,7 +468,10 @@
     "fg_workflow1.refresh()\n",
     "print(f\"Feature Group: {fg_workflow1.feature_group_name}\")\n",
     "print(f\"Status: {fg_workflow1.feature_group_status}\")\n",
-    "print(f\"ARN: {fg_workflow1.feature_group_arn}\")"
+    "print(f\"ARN: {fg_workflow1.feature_group_arn}\")\n",
+    "\n",
+    "DataCatalogConfig = fg_workflow1.offline_store_config.data_catalog_config\n",
+    "print(f'Table Name: {DataCatalogConfig.table_name}')"
    ]
   },
   {
@@ -411,7 +481,7 @@
    "outputs": [],
    "source": [
     "# Ingest sample records to verify everything works\n",
-    "ingest_sample_records(fg_workflow1, num_records=3)"
+    "ingest_sample_records(fg_workflow1, num_records=10)"
    ]
   },
   {
@@ -422,7 +492,7 @@
    "source": [
     "# Retrieve a sample record from the online store\n",
     "print(\"Retrieving record for customer 'cust_1' from online store...\")\n",
-    "response = fg_workflow1.get_record(record_identifier_value_as_string=\"cust_1\")\n",
+    "response = fg_workflow1.get_record(record_identifier_value_as_string=\"cust_3\")\n",
     "\n",
     "print(f\"\\nRecord retrieved successfully!\")\n",
     "print(f\"Features:\")\n",
@@ -482,10 +552,11 @@
     "    role_arn=OFFLINE_STORE_ROLE_ARN,\n",
     "    description=\"Workflow 2: Lake Formation enabled after creation\",\n",
     "    region=REGION,\n",
+    "    session=boto_session\n",
     ")\n",
     "\n",
     "print(f\"Feature Group created: {fg_workflow2.feature_group_name}\")\n",
-    "print(f\"Status: {fg_workflow2.feature_group_status}\")"
+    "print(f\"Status: {fg_workflow2.feature_group_status}\")\n"
    ]
   },
   {
@@ -500,6 +571,15 @@
     "print(f\"Status: {fg_workflow2.feature_group_status}\")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "fg_workflow2 = FeatureGroup.refresh()"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -515,7 +595,8 @@
     "print()\n",
     "\n",
     "result = fg_workflow2.enable_lake_formation( # new method\n",
-    "    use_service_linked_role=True\n",
+    "    use_service_linked_role=True,\n",
+    "    session=boto_session\n",
     ")\n",
     "\n",
     "print(f\"\\nLake Formation setup results:\")\n",
@@ -531,8 +612,9 @@
    "outputs": [],
    "source": [
     "# Step 4: Ingest sample records to verify everything works\n",
+    "# This is still using the first role\n",
     "print(\"Step 4: Ingesting records to verify Lake Formation setup...\")\n",
-    "ingest_sample_records(fg_workflow2, num_records=3)"
+    "ingest_sample_records(fg_workflow2, num_records=4)"
    ]
   },
   {
@@ -561,7 +643,9 @@
     "fg_workflow2.refresh()\n",
     "print(f\"Feature Group: {fg_workflow2.feature_group_name}\")\n",
     "print(f\"Status: {fg_workflow2.feature_group_status}\")\n",
-    "print(f\"ARN: {fg_workflow2.feature_group_arn}\")"
+    "print(f\"ARN: {fg_workflow2.feature_group_arn}\")\n",
+    "DataCatalogTable = fg_workflow2.offline_store_config.data_catalog_config.table_name\n",
+    "print(f\"{DataCatalogTable}\")"
    ]
   },
   {
@@ -571,7 +655,57 @@
     "---\n",
     "# Cleanup\n",
     "\n",
-    "Delete the Feature Groups and associated Glue tables created in this demo."
+    "Delete the Feature Groups and **associated Glue tables** created in this demo."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Helper Function: Cleanup"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def cleanup_feature_group(fg):\n",
+    "    \"\"\"\n",
+    "    Delete a FeatureGroup and its associated Glue table.\n",
+    "    \n",
+    "    Args:\n",
+    "        fg: The FeatureGroup to delete.\n",
+    "    \"\"\"\n",
+    "    try:\n",
+    "        # Delete the Glue table if it exists\n",
+    "        if fg.offline_store_config is not None:\n",
+    "            try:\n",
+    "                fg.refresh()  # Ensure we have latest config\n",
+    "                data_catalog_config = fg.offline_store_config.data_catalog_config\n",
+    "                if data_catalog_config is not None:\n",
+    "                    database_name = data_catalog_config.database\n",
+    "                    table_name = data_catalog_config.table_name\n",
+    "\n",
+    "                    if database_name and table_name:\n",
+    "                        glue_client = boto3.client(\"glue\")\n",
+    "                        try:\n",
+    "                            glue_client.delete_table(DatabaseName=database_name, Name=table_name)\n",
+    "                            print(f\"Deleted Glue table: {database_name}.{table_name}\")\n",
+    "                        except ClientError as e:\n",
+    "                            # Ignore if table doesn't exist\n",
+    "                            if e.response[\"Error\"][\"Code\"] != \"EntityNotFoundException\":\n",
+    "                                raise\n",
+    "            except Exception as e:\n",
+    "                # Don't fail cleanup if Glue table deletion fails\n",
+    "                print(f\"Warning: Could not delete Glue table: {e}\")\n",
+    "\n",
+    "        # Delete the FeatureGroup\n",
+    "        fg.delete()\n",
+    "        print(f\"Deleted Feature Group: {fg.feature_group_name}\")\n",
+    "    except ClientError as e:\n",
+    "        print(f\"Error during cleanup: {e}\")"
    ]
   },
   {
@@ -581,8 +715,8 @@
    "outputs": [],
    "source": [
     "# Uncomment to delete the Feature Groups\n",
-    "cleanup_feature_group(fg_workflow1)\n",
-    "# cleanup_feature_group(fg_workflow2)"
+    "# cleanup_feature_group(fg_workflow1)\n",
+    "cleanup_feature_group(fg_workflow2)"
    ]
   },
   {
@@ -594,7 +728,7 @@
     "\n",
     "This notebook demonstrated two workflows:\n",
     "\n",
-    "**Example 1: Lake Formation at Creation**\n",
+    "**Example 1: Enable Lake Formation Governance at Creation**\n",
     "- Use `LakeFormationConfig` with `enabled=True` in `FeatureGroup.create()`\n",
     "- Lake Formation is automatically configured after Feature Group creation\n",
     "- Both online and offline stores enabled\n",

From 164c3134d5185e9efaf06f44f955f2e283ee8d43 Mon Sep 17 00:00:00 2001
From: BassemHalim <bassemamir459@gmail.com>
Date: Fri, 6 Feb 2026 13:24:36 -0800
Subject: [PATCH 07/22] update setup instructions

---
 .../v3-feature-store-lake-formation.ipynb     | 100 +++++++++++++-----
 1 file changed, 71 insertions(+), 29 deletions(-)

diff --git a/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb b/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb
index 7cde7ca566..5f689a3c0d 100644
--- a/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb
+++ b/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb
@@ -7,6 +7,25 @@
     "# Feature Group Lake Formation Governance "
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This Demo builds on sagemaker v3 features which is not out yet so we need to tell pip to use local version \n",
+    "\n",
+    "1. install `pyenv` following the instructions here https://github.com/pyenv/pyenv?tab=readme-ov-file#a-getting-pyenv\n",
+    "2. setup your shell env for pyenv https://github.com/pyenv/pyenv?tab=readme-ov-file#b-set-up-your-shell-environment-for-pyenv\n",
+    "3. install and activate python for example (this code was tested on python 3.10.14)\n",
+    "```\n",
+    "pyenv install 3.10.14\n",
+    "pyenv virtualenv 3.10.14 py3.10.14\n",
+    "pyenv activate py3.10.14\n",
+    "```\n",
+    "3. You will then need to run `pip install -e ./sagemaker-mlops` before starting the jupyter notebook to use the local packages\n",
+    "4. `pip install jupyter notebook`\n",
+    "5. `jupyter notebook`"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -230,21 +249,43 @@
    ]
   },
   {
-   "cell_type": "markdown",
+   "cell_type": "code",
+   "execution_count": null,
    "metadata": {},
+   "outputs": [],
    "source": [
-    "This Demo builds on sagemaker v3 features which is not out yet so we need to tell pip to use local version \n",
+    "import boto3\n",
+    "import os\n",
     "\n",
-    "1. install `pyenv` https://github.com/pyenv/pyenv?tab=readme-ov-file#a-getting-pyenv\n",
-    "2. install and activate python for example (this code was tested on python 3.10.14)\n",
-    "```\n",
-    "pyenv install 3.10.14\n",
-    "pyenv virtualenv 3.10.14 py3.10.14\n",
-    "pyenv activate py3.10.14\n",
-    "```\n",
-    "3. You will then need to run `pip install -e .` before starting the jupyter notebook to use the local packages\n",
-    "4. `pip install jupyter notebook`\n",
-    "5. `jupyter notebook`"
+    "boto3.DEFAULT_SESSION = None\n",
+    "def assume_role(role_arn, session_name=\"AssumedRoleSession\"):\n",
+    "    \"\"\"\n",
+    "    Assume an AWS IAM role and return temporary credentials.\n",
+    "    \n",
+    "    Args:\n",
+    "        role_arn: The ARN of the role to assume\n",
+    "        session_name: A name for the assumed role session\n",
+    "    \n",
+    "    Returns:\n",
+    "        A boto3 session with the assumed role credentials\n",
+    "    \"\"\"\n",
+    "    sts_client = boto3.client('sts')\n",
+    "    \n",
+    "    response = sts_client.assume_role(\n",
+    "        RoleArn=role_arn,\n",
+    "        RoleSessionName=session_name\n",
+    "    )\n",
+    "    \n",
+    "    credentials = response['Credentials']\n",
+    "    \n",
+    "    # Create a new session with the temporary credentials\n",
+    "    session = boto3.Session(\n",
+    "        aws_access_key_id=credentials['AccessKeyId'],\n",
+    "        aws_secret_access_key=credentials['SecretAccessKey'],\n",
+    "        aws_session_token=credentials['SessionToken']\n",
+    "    )\n",
+    "    \n",
+    "    return session"
    ]
   },
   {
@@ -287,22 +328,26 @@
    "source": [
     "# Use SageMaker session to get default bucket and execution role\n",
     "\n",
-    "boto_session = boto3.Session()\n",
-    "new_sagemaker_session = SageMakerSession(boto_session=boto_session)\n",
-    "sagemaker_session = SageMakerSession()\n",
-    "S3_BUCKET = sagemaker_session.default_bucket()\n",
-    "REGION = sagemaker_session.boto_session.region_name\n",
-    "\n",
     "# Execution role (for running this notebook)\n",
-    "EXECUTION_ROLE_ARN = get_execution_role(sagemaker_session)\n",
+    "EXECUTION_ROLE_ARN = 'arn:aws:iam::<account id>:role/<role>'\n",
+    "\n",
     "\n",
     "# Offline store role (dedicated role for Feature Store S3 access)\n",
     "# Replace with your dedicated offline store role ARN\n",
     "# https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store-adding-policies.html\n",
-    "OFFLINE_STORE_ROLE_ARN = \"arn:aws:iam::<aws account id>:role/<role name>\"\n",
+    "OFFLINE_STORE_ROLE_ARN = \"arn:aws:iam::<account id>:role/<role>\"\n",
+    "\n",
+    "\n",
+    "boto_session = assume_role(EXECUTION_ROLE_ARN)\n",
+    "sagemaker_session = SageMakerSession(boto_session=boto_session)\n",
+    "sts = boto_session.client('sts')\n",
+    "\n",
+    "S3_BUCKET = sagemaker_session.default_bucket()\n",
+    "REGION = sagemaker_session.boto_session.region_name\n",
+    "\n",
     "\n",
     "print(f\"S3 Bucket: {S3_BUCKET}\")\n",
-    "print(f\"Execution Role ARN: {EXECUTION_ROLE_ARN}\")\n",
+    "print(f\"Execution Role ARN:{sts.get_caller_identity()['Arn']}\")\n",
     "print(f\"Offline Store Role ARN: {OFFLINE_STORE_ROLE_ARN}\")\n",
     "print(f\"Region: {REGION}\")"
    ]
@@ -572,12 +617,10 @@
    ]
   },
   {
-   "cell_type": "code",
-   "execution_count": null,
+   "cell_type": "markdown",
    "metadata": {},
-   "outputs": [],
    "source": [
-    "fg_workflow2 = FeatureGroup.refresh()"
+    "Here you can optionally assume a different role with just datalake permissions and describe Feature Group permission"
    ]
   },
   {
@@ -593,10 +636,9 @@
     "print(\"  2. Grant permissions to execution role\")\n",
     "print(\"  3. Revoke IAMAllowedPrincipal permissions\")\n",
     "print()\n",
-    "\n",
+    "fg_workflow2 = FeatureGroup.get(FG_NAME_WORKFLOW2)\n",
     "result = fg_workflow2.enable_lake_formation( # new method\n",
     "    use_service_linked_role=True,\n",
-    "    session=boto_session\n",
     ")\n",
     "\n",
     "print(f\"\\nLake Formation setup results:\")\n",
@@ -645,7 +687,7 @@
     "print(f\"Status: {fg_workflow2.feature_group_status}\")\n",
     "print(f\"ARN: {fg_workflow2.feature_group_arn}\")\n",
     "DataCatalogTable = fg_workflow2.offline_store_config.data_catalog_config.table_name\n",
-    "print(f\"{DataCatalogTable}\")"
+    "print(f\"Table Name: {DataCatalogTable}\")"
    ]
   },
   {
@@ -715,7 +757,7 @@
    "outputs": [],
    "source": [
     "# Uncomment to delete the Feature Groups\n",
-    "# cleanup_feature_group(fg_workflow1)\n",
+    "cleanup_feature_group(fg_workflow1)\n",
     "cleanup_feature_group(fg_workflow2)"
    ]
   },

From 07da9e7d7a4988216772f64efd92472d6b6308f8 Mon Sep 17 00:00:00 2001
From: BassemHalim <bassemamir459@gmail.com>
Date: Fri, 20 Feb 2026 11:10:59 -0800
Subject: [PATCH 08/22] add lf-multiaccount-demo + fix LakeformationConfig
 constructor

---
 .../mlops/feature_store/feature_group.py      |   2 +-
 .../FS-lakeformation-cross-account.ipynb      | 580 ++++++++++++++++++
 .../imgs/fs-lf-cross-account1.png             | Bin 0 -> 476328 bytes
 3 files changed, 581 insertions(+), 1 deletion(-)
 create mode 100644 v3-examples/ml-ops-examples/FS-lakeformation-cross-account.ipynb
 create mode 100644 v3-examples/ml-ops-examples/imgs/fs-lf-cross-account1.png

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
index dd193471eb..d4cff70988 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
@@ -26,7 +26,7 @@
 logger = logging.getLogger(__name__)
 
 
-class LakeFormationConfig:
+class LakeFormationConfig(Base):
     """Configuration for Lake Formation governance on Feature Group offline stores.
 
     Attributes:
diff --git a/v3-examples/ml-ops-examples/FS-lakeformation-cross-account.ipynb b/v3-examples/ml-ops-examples/FS-lakeformation-cross-account.ipynb
new file mode 100644
index 0000000000..59f7920998
--- /dev/null
+++ b/v3-examples/ml-ops-examples/FS-lakeformation-cross-account.ipynb
@@ -0,0 +1,580 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "4e7cc789-55ea-4460-a07e-a57ffe6ee4e6",
+   "metadata": {},
+   "source": [
+    "1. Create Feature Group in central account with Lakeformation enabled"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "id": "d8f0e80d-bc9b-4c5e-b545-32fff784b8b5",
+   "metadata": {},
+   "source": [
+    "# Cross Account Lakeformation governed Feature Group Demo\n",
+    "\n",
+    "This is a demo to showcase how cross account access would work with lakeformation(LF) governed Feature Group(FG)\n",
+    "\n",
+    "[simpler single account demo](./v3-feature-store-lake-formation.ipynb)  \n",
+    "\n",
+    "The following scenario will be setup where you have a central account that owns the FG and then you have a producer account to ingest into the FG and another one reading from the FG\n",
+    "\n",
+    "![image.png](./imgs/fs-lf-cross-account1.png)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "f0c347d3-2736-4acf-8aff-bc6c9cc7a990",
+   "metadata": {},
+   "source": [
+    "## Helper Methods"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "d30e0db4-122c-4da4-b33d-6ed3c3a40a3c",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import boto3\n",
+    "import os\n",
+    "\n",
+    "boto3.DEFAULT_SESSION = None\n",
+    "def assume_role(role_arn, session_name=\"AssumedRoleSession\"):\n",
+    "    \"\"\"\n",
+    "    Assume an AWS IAM role and return temporary credentials.\n",
+    "    \n",
+    "    Args:\n",
+    "        role_arn: The ARN of the role to assume\n",
+    "        session_name: A name for the assumed role session\n",
+    "    \n",
+    "    Returns:\n",
+    "        A boto3 session with the assumed role credentials\n",
+    "    \"\"\"\n",
+    "    sts_client = boto3.client('sts')\n",
+    "    \n",
+    "    response = sts_client.assume_role(\n",
+    "        RoleArn=role_arn,\n",
+    "        RoleSessionName=session_name\n",
+    "    )\n",
+    "    \n",
+    "    credentials = response['Credentials']\n",
+    "    \n",
+    "    # Create a new session with the temporary credentials\n",
+    "    session = boto3.Session(\n",
+    "        aws_access_key_id=credentials['AccessKeyId'],\n",
+    "        aws_secret_access_key=credentials['SecretAccessKey'],\n",
+    "        aws_session_token=credentials['SessionToken']\n",
+    "    )\n",
+    "    \n",
+    "    return session"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "bf42a253-bf5e-49f3-96cc-744606cda4f4",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from sagemaker.core.helper.session_helper import Session"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "afc7f261-e7fe-4abc-88c3-cd3b1aa61dd2",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "central_account  = \"account-1\"\n",
+    "producer_account = \"account-2\"\n",
+    "consumer_account = \"account-3\"\n",
+    "\n",
+    "acc_to_role_arn = {\n",
+    "    central_account: f\"arn:aws:iam::{central_account}:role/admin\",\n",
+    "    producer_account: f\"arn:aws:iam::{producer_account}:role/Admin\",\n",
+    "    consumer_account: f\"arn:aws:iam::{consumer_account}:role/Admin\"\n",
+    "}\n",
+    "\n",
+    "central_acc_boto_session = assume_role(acc_to_role_arn[central_account])\n",
+    "central_acc_sagemaker_session = Session(boto_session=central_acc_boto_session)\n",
+    "\n",
+    "producer_acc_boto_session = assume_role(acc_to_role_arn[producer_account])\n",
+    "producer_acc_sagemaker_session = Session(boto_session=producer_acc_boto_session)\n",
+    "\n",
+    "consumer_acc_boto_session = assume_role(acc_to_role_arn[consumer_account])\n",
+    "consumer_acc_sagemaker_session = Session(boto_session=consumer_acc_boto_session)\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "28a96af6-409a-4756-8cb7-60850342c955",
+   "metadata": {},
+   "source": [
+    "## 1. Create Feature Group in central account and enable Lakeformation"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "4f6a2639-2640-4a51-8fad-886b4d7226da",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import json\n",
+    "import boto3\n",
+    "from botocore.exceptions import ClientError\n",
+    "# Import the FeatureGroup with Lake Formation support\n",
+    "from sagemaker.mlops.feature_store.feature_group import FeatureGroup, LakeFormationConfig\n",
+    "from sagemaker.core.shapes import (\n",
+    "    FeatureDefinition,\n",
+    "    FeatureValue,\n",
+    "    OfflineStoreConfig,\n",
+    "    OnlineStoreConfig,\n",
+    "    S3StorageConfig,\n",
+    ")\n",
+    "from sagemaker.core.helper.session_helper import Session as SageMakerSession, get_execution_role\n",
+    "\n",
+    "feature_definitions = [\n",
+    "    FeatureDefinition(feature_name=\"customer_id\", feature_type=\"String\"),\n",
+    "    FeatureDefinition(feature_name=\"event_time\", feature_type=\"String\"),\n",
+    "    FeatureDefinition(feature_name=\"age\", feature_type=\"Integral\"),\n",
+    "    FeatureDefinition(feature_name=\"total_purchases\", feature_type=\"Integral\"),\n",
+    "    FeatureDefinition(feature_name=\"avg_order_value\", feature_type=\"Fractional\"),\n",
+    "]\n",
+    "\n",
+    "# Offline store role (dedicated role for Feature Store S3 access)\n",
+    "# https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store-adding-policies.html\n",
+    "OFFLINE_STORE_ROLE_ARN = \"your-offline-store-role-arn\"\n",
+    "\n",
+    "S3_BUCKET = central_acc_sagemaker_session.default_bucket()\n",
+    "REGION = central_acc_boto_session.region_name\n",
+    "\n",
+    "\n",
+    "# Configure online and offline stores\n",
+    "FEATURE_GROUP_NAME='lakeformation-managed-fg-2'\n",
+    "\n",
+    "online_store_config = OnlineStoreConfig(enable_online_store=True)\n",
+    "\n",
+    "offline_store_config = OfflineStoreConfig(\n",
+    "    s3_storage_config=S3StorageConfig(\n",
+    "        s3_uri=f\"s3://{S3_BUCKET}/feature-store-demo/\"\n",
+    "    )\n",
+    ")\n",
+    "\n",
+    "# Configure Lake Formation - enabled at creation\n",
+    "lake_formation_config = LakeFormationConfig(\n",
+    "    enabled=True\n",
+    ")\n",
+    "\n",
+    "# create FG in central account and enable LF\n",
+    "feature_group = FeatureGroup.create(\n",
+    "    feature_group_name=FEATURE_GROUP_NAME,\n",
+    "    record_identifier_feature_name=\"customer_id\",\n",
+    "    event_time_feature_name=\"event_time\",\n",
+    "    feature_definitions=feature_definitions,\n",
+    "    online_store_config=online_store_config,\n",
+    "    offline_store_config=offline_store_config,\n",
+    "    role_arn=OFFLINE_STORE_ROLE_ARN,\n",
+    "    description=\"Feature Group with lakeformation enabled\",\n",
+    "    lake_formation_config=lake_formation_config, # new parameter\n",
+    "    session=central_acc_boto_session \n",
+    ")\n",
+    "\n",
+    "print(f\"\\nFeature Group created: {feature_group.feature_group_name}\")\n",
+    "# feature_group = FeatureGroup.get(FEATURE_GROUP_NAME)\n",
+    "central_acc_sagemaker_session.describe_feature_group(FEATURE_GROUP_NAME)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "956b3ed3-7ede-4486-af44-46845b683a09",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "feature_group.refresh()\n",
+    "feature_group_arn = feature_group.feature_group_arn\n",
+    "data_catalog_config = feature_group.offline_store_config.data_catalog_config\n",
+    "database_name = str(data_catalog_config.database)\n",
+    "table_name = str(data_catalog_config.table_name)\n",
+    "catalog_id = str(data_catalog_config.catalog)\n",
+    "print(f\"Feature Group ARN: {feature_group_arn}\")\n",
+    "print(f\"Database: {database_name}\")\n",
+    "print(f\"Table: {table_name}\")\n",
+    "print(f\"Catalog: {catalog_id}\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "4708e998-6ac4-454c-a3ab-3a1f4fd71bc4",
+   "metadata": {},
+   "source": [
+    "## 2. Share Feature Group with producer account"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "6ea63cc0-7418-440f-8784-9108ca244e6c",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ram_client = central_acc_boto_session.client(\"ram\")\n",
+    "response = ram_client.create_resource_share(\n",
+    "    name='producer-account-fg-share',\n",
+    "    resourceArns=[\n",
+    "        feature_group_arn\n",
+    "    ],\n",
+    "    principals=[\n",
+    "        str(producer_account)\n",
+    "    ],\n",
+    "    permissionArns=[\n",
+    "        \"arn:aws:ram::aws:permission/AWSRAMPermissionSageMakerFeatureGroupReadWrite\"\n",
+    "    ]\n",
+    ")\n",
+    "response"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "18df5f35-8efe-4b02-bfbf-d4bcbb6cb9cd",
+   "metadata": {},
+   "source": [
+    "### Producer Accepts the RAM share"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "2360602b-fdc4-45ea-958e-9dbec0efdd52",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Producer account accepts the RAM invitation\n",
+    "ram_client_producer = producer_acc_boto_session.client('ram')\n",
+    "\n",
+    "response = ram_client_producer.get_resource_share_invitations()\n",
+    "pending = [\n",
+    "    inv for inv in response['resourceShareInvitations']\n",
+    "    if inv['status'] == 'PENDING' and inv['senderAccountId'] == str(central_account)\n",
+    "]\n",
+    "\n",
+    "for inv in pending:\n",
+    "    ram_client_producer.accept_resource_share_invitation(\n",
+    "        resourceShareInvitationArn=inv['resourceShareInvitationArn']\n",
+    "    )\n",
+    "    print(f\"Accepted: {inv['resourceShareInvitationArn']}\")\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "2b59161c-5016-41ac-b70f-b0375067cdbc",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Test ingest from producer\n",
+    "\n",
+    "from datetime import datetime\n",
+    "\n",
+    "# Use the producer session to call PutRecord on the shared Feature Group\n",
+    "sm_runtime = producer_acc_boto_session.client('sagemaker-featurestore-runtime')\n",
+    "\n",
+    "sm_runtime.put_record(\n",
+    "    FeatureGroupName=feature_group_arn,\n",
+    "    Record=[\n",
+    "        {'FeatureName': 'customer_id', 'ValueAsString': 'CUST-001'},\n",
+    "        {'FeatureName': 'event_time', 'ValueAsString': datetime.utcnow().isoformat() + 'Z'},\n",
+    "        {'FeatureName': 'age', 'ValueAsString': '35'},\n",
+    "        {'FeatureName': 'total_purchases', 'ValueAsString': '12'},\n",
+    "        {'FeatureName': 'avg_order_value', 'ValueAsString': '49.99'},\n",
+    "    ]\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "486142f8-de45-4029-a08c-e0e1457cb3ea",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Test getRecord\n",
+    "sm_runtime.get_record(\n",
+    "    FeatureGroupName=feature_group_arn,\n",
+    "    RecordIdentifierValueAsString='CUST-001'\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5f531d4a-b668-42a8-a725-94a165ba76f8",
+   "metadata": {},
+   "source": [
+    "## 3. Share Glue Table with consumer account using LF"
+   ]
+  },
+  {
+   "attachments": {
+    "d1f0c7d4-d102-42f3-a1fc-b26eeb94a2bf.png": {
+     "image/png": "iVBORw0KGgoAAAANSUhEUgAABqAAAALOCAYAAADGG9JtAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAGoKADAAQAAAABAAACzgAAAADCWs0rAABAAElEQVR4AezdB5gUVdaA4TN5BoaccxIQSaKoGDCvAdOimNNizrprWuE3ryzmsIY1Z1xFUNewpnUVA4oIkkRAcs4ypIk9/znVU93VzfTEnp7ume8+T9s1XVW3br1VjV116p6b1HPA0GKhIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIBAlgeQo1UM1CCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCDgCBKA4ERBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBKIqQAAqqpxUhgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggQACKcwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCCqAgSgospJZQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgSgOAcQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSiKkAAKqqcVIYAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIEAAinMAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAgqgIEoKLKSWUIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIEoDgHEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEoipAACqqnFSGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBAAIpzAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAIKoCBKCiykllCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACBKA4BxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBKIqQAAqqpxUhgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggQACKcwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCCqAgSgospJZQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgSgOAcQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSiKkAAKqqcVIYAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIEAAinMAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAgqgIEoKLKSWUIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIEoDgHEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEoipAACqqnFSGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBAAIpzAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAIKoCBKCiykllCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACBKA4BxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBKIqQAAqqpxUhgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggQACKcwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCCqAgSgospJZQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgSgOAcQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSiKkAAKqqcVIYAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIEAAinMAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAgqgIEoKLKSWUIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIEoDgHEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEoipAACqqnFSGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBAAIpzAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAIKoCBKCiykllCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACBKA4BxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBKIqQAAqqpxUhgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggQACKcwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCCqAgSgospJZQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgSgOAcQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSiKkAAKqqcVIYA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br7+slhz9ZWzO2eed1m88NJrM3mq7l9af9014vhjDs868ubbA2P33/257neqlnqQhk/bbbt57N53h1h5pRVmqDWdXfPQI09ls6Leeuf9Ge4X7UIaBF1+4enJDLHuFV177Y134tCjTqix5QnTZfTuufXaaNNm2vKIaX37HnBkTJky679NtNKKyyV7Vl1Tsb/XAYceE88+/3JFu30gQIAAAQKlKmAGVKmOjHYRIECAAAECBAgQIFBdAQFUdeWUq7MCdyd/qN19hWXrbPur0/B0r6s+u+1XnaLzfZl09lM6a65Xzy2iZYsWM3h88umguLXffckMncdi9JixM9wvyoV0qcLTTzom+vTauqJL6fJ2Bx12bHz6+eCKa/PywwbrrhnXXXl+1K9fL3vtTbfeHf88++LZVnHaiX+N3ZLwMD2+/GpIbLfzvpEu5ecgQIAAAQKlLCCAKuXR0TYCBAgQIECAAAECBKojYAm+6qgpU6cFdt25V7ZEV53uRBUb/92w4XHHXQ9UsZTHU4ERI36KZ54bEDfcclcM+fa75NfOgtFxwQ4VOB06tItNNlw3frdX30hn7Xz/w4j4fvgPFfeL8iFdqvDxp56PdPbXOmutns0wat26VfTZfutIQ7gvvvx6nnf1q2++zepbf501snf3WGn5+HrIt/HRJ5/Psq63330/0n/P05lsbZMZVJMmTY50BpWDAAECBAiUsoAl+Ep5dLSNAAECBAgQIECAAIHqCJgBVR01Zeq0wKYbrRcn/P3waNGieZ3ux5w2fkwyK+eMcy+Lp597aU6LeG42Aisu3y2bFbXdNptH8+YzbhSezji75Y57s/2Hfvll2obis3llnbqd/jt04dknVfw7VFY2Nc696Mq4/obba6Qfl5x3amy71abZu9MAbI/fHRIDP/h4lnXtsUvvOPWEo7Nnxo8fH9v02Se+HTpslmXcJECAAAECeQqYAZWnvroJECBAgAABAgQIEKgJAQFUTah6JwEC84VAGmKmM4B269srluu29Ax9Hjv2l7j/ocfjtmSJvg8//myG+3X5Qrell4yrLz0rm/VV3o977n8kTjztvHm+3F2zZk2j303XRLelu2ZVpUHSTnscED/+9HN51TP8rF+/fqTLba6w3DLZvcefei4O+csJMzznAgECBAgQKBUBAVSpjIR2ECBAgAABAgQIECAwrwQswTevJL2H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6gsBAgQIECBAgAABAgQIVCYwduSgePORPSu7Xen1ssm/ZPd+GvJivDm86uUrfXEt3Zg04cdaqkk1BEpfQABV+mOkhQQIECBQIAHLDhRoMHWFAAECBAgQIECAAAECBCoXmDo5Jo3/ofL7s7lTVjYhysZPmM1TbhMgUMoCluAr5dHRNgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAHRQwA6oODpomEyBAgEDdErDsQN0aL60lQIAAAQIECBAgQIAAAQIECBCYewEB1NwbegMBAgQIEJi1gGUHZu3jLgECBAgQIECAAAECBAgQIECAQOEELMFXuCHVIQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAvgICqHz91U6AAAECBAgQIECAAAECBAgQIECAAAECBAgQKJyAAKpwQ6pDBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF8BQRQ+fqrnQABAgQIECBAgAABAgQIECBAgAABAgQIECBQOAEBVOGGVIcIECBAgAABAgQIECBAgAABAgQIECBAgAABAvkKCKDy9Vc7AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKBwAgKowg2pDhEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE8hUQQOXrr3YCBAgQIECAAAECBAgQIECAAAECBAgQIECAQOEEBFCFG1IdIkCAAAECBAgQIECAAAECBAgQIECAAAECBAjkKyCAytdf7QQIECBAgAABAgQIECBAgAABAgQIECBAgACBwgkIoAo3pDpEgAABAgQIECBAgAABAgQIECBAgAABAgQIEMhXQACVr7/aCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKFExBAFW5IdYgAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgkK+AACpff7UTIECAAAECBAgQIECAAAECBAgQIECAAAECBAonIIAq3JDqEAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgXwEBVL7+aidAgAABAgQIECBAgAABAgQIECBAgAABAgQIFE5AAFW4IdUhAgQIECBAgAABAgQIECBAgAABAgQIECBAgEC+AgKofP3VToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAonIAAqnBDqkMECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgXwFBFD5+qudAAECBAgQIECAAAECBAgQIECAAAECBAgQIFA4AQFU4YZUhwgQIECAAAECBAgQIECAAAECBAgQIECAAAEC+QoIoPL1VzsBAgQIECBAgAABAgQIECBAgAABAgQIECBAoHACAqjCDakOESBAgAABAgQIECBAgAABAgQIECBAgAABAgTyFRBA5euvdgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA4QQEUIUbUh0iQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECOQrIIDK11/tBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHCCQigCjekOkSAAAECBAgQIECAAAECBAgQIECAAAECBAgQyFdAAJWvv9oJECBAgAABAgQIECBAgAABAgQIECBAgAABAoUTEEAVbkh1iAABAgQIECBAgAABAgQIECBAgAABAgQIECCQr4AAKl9/tRMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECicggCrckOoQAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCBfAQFUvv5qJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgUTkAAVbgh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL4CAqh8/dVOgAABAgQIECBAgAABAgQIECBAgAABAgQIECicgACqcEOqQwQIECBAgAABAgQIECBAgAABAgQIECBAgACBfAUEUPn6q50AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgUDgBAVThhlSHCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQL5Cgig8vVXOwECBAgQIECAAAECBAgQIECAAAECBAgQIECgcAICqMINqQ4RIECAAAECBAgQIECAAAECBAgQIECAAAECBPIVEEDl6692AgQIECBAgAABAgQIECBAgAABAgQIECBAgEDhBARQhRtSHSJAgAABAgQIECBAgAABAgQIECBAgAABAgQI5CsggMrXX+0ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgcIJCKAKN6Q6RIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDIV0AAla+/2gkQIECAAAECBAgQIECAAAECBAgQIECAAAEChRMQQBVuSHWIAAECBAgQIECAAAECBAgQIECAAAECBAgQIJCvgAAqX3+1EyBAgAABAgQIECBAgAABAgQIECBAgAABAgQKJyCAKtyQ6hABAgQIECBAgAABAgQIECBAgAABAgQIECBAIF8BAVS+/monQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBROQABVuCHVIQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAvgICqHz91U6AAAECBAgQIECAAAECBAgQIECAAAECBAgQKJyAAKpwQ6pDBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF8BQRQ+fqrnQABAgQIECBAgAABAgQIECBAgAABAgQIECBQOAEBVOGGVIcIECBAgAABAgQIECBAgAABAgQIECBAgAABAvkKCKDy9Vc7AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKBwAgKowg2pDhEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE8hUQQOXrr3YCBAgQIECAAAECBAgQIECAAAECBAgQIECAQOEEBFCFG1IdIkCAAAECBAgQIECAAAECBAgQIECAAAECBAjkKyCAytdf7QQIECBAgAABAgQIECBAgAABAgQIECBAgACBwgkIoAo3pDpEgAABAgQIECBAgAABAgQIECBAgAABAgQIEMhXQACVr7/aCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKFExBAFW5IdYgAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgkK+AACpff7UTIECAAAECBAgQIECAAAECBAgQIECAAAECBAonIIAq3JDqEAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgXwEBVL7+aidAgAABAgQIECBAgAABAgQIECBAgAABAgQIFE5AAFW4IdUhAgQIECBAgAABAgQIECBAgAABAgQIECBAgEC+AgKofP3VToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAonIAAqnBDqkMECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgXwFBFD5+qudAAECBAgQIECAAAECBAgQIECAAAECBAgQIFA4AQFU4YZUhwgQIECAAAECBAgQIECAAAECBAgQIECAAAEC+QoIoPL1VzsBAgQIECBAgAABAgQIECBAgAABAgQIECBAoHACAqjCDakOESBAgAABAgQIECBAgAABAgQIECBAgAABAgTyFRBA5euvdgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA4QQEUIUbUh0iQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECOQrIIDK11/tBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHCCQigCjekOkSAAAECBAgQIECAAAECBAgQIECAAAECBAgQyFdAAJWvv9oJECBAgAABAgQIECBAgAABAgQIECBAgAABAoUTEEAVbkh1iAABAgQIECBAgAABAgQIECBAgAABAgQIECCQr4AAKl9/tRMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECicggCrckOoQAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCBfAQFUvv5qJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgUTkAAVbgh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL4CAqh8/dVOgAABAgQIECBAgAABAgQIECBAgAABAgQIECicgACqcEOqQwQIECBAgAABAgQIECBAgAABAgQIECBAgACBfAUEUPn6q50AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgUDgBAVThhlSHCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQL5Cgig8vVXOwECBAgQIECAAAECBAgQIECAAAECBAgQIECgcAICqMINqQ4RIECAAAECBAgQIECAAAECBAgQIECAAAECBPIVEEDl6692AgQIECBAgAABAgQIECBAgAABAgQIECBAgEDhBARQhRtSHSJAgAABAgQIECBAgAABAgQIECBAgAABAgQI5CsggMrXX+0ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgcIJCKAKN6Q6RIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDIV0AAla+/2gkQIECAAAECBAgQIECAAAECBAgQIECAAAEChRMQQBVuSHWIAAECBAgQIECAAAECBAgQIECAAAECBAgQIJCvgAAqX3+1EyBAgAABAgQIECBAgAABAgQIECBAgAABAgQKJyCAKtyQ6hABAgQIECBAgAABAgQIECBAgAABAgQIECBAIF8BAVS+/monQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBROQABVuCHVIQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAvgICqHz91U6AAAECBAgQIECAAAECBAgQIECAAAECBAgQKJyAAKpwQ6pDBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF8BQRQ+fqrnQABAgQIECBAgAABAgQIECBAgAABAgQIECBQOAEBVOGGVIcIECBAgAABAgQIECBAgAABAgQIECBAgAABAvkKCKDy9Vc7AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKBwAgKowg2pDhEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE8hUQQOXrr3YCBAgQIECAAAECBAgQIECAAAECBAgQIECAQOEEBFCFG1IdIkCAAAECBAgQIECAAAECBAgQIECAAAECBAjkKyCAytdf7QQIECBAgAABAgQIECBAgAABAgQIECBAgACBwgkIoAo3pDpEgAABAgQIECBAgAABAgQIECBAgAABAgQIEMhXQACVr7/aCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKFExBAFW5IdYgAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgkK+AACpff7UTIECAAAECBAgQIECAAAECBAgQIECAAAECBAonIIAq3JDqEAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgXwEBVL7+aidAgAABAgQIECBAgAABAgQIECBAgAABAgQIFE5AAFW4IdUhAgQIECBAgAABAgQIECBAgAABAgQIECBAgEC+AgKofP3VToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAonIAAqnBDqkMECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgXwFBFD5+qudAAECBAgQIECAAAECBAgQIECAAAECBAgQIFA4AQFU4YZUhwgQIECAAAECBAgQIECAAAECBAgQIECAAAEC+QoIoPL1VzsBAgQIECBAgAABAgQIECBAgAABAgQIECBAoHACAqjCDakOESBAgAABAgQIECBAgAABAgQIECBAgAABAgTyFRBA5euvdgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA4QQEUIUbUh0iQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECOQrIIDK11/tBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHCCQigCjekOkSAAAECBAgQIECAAAECBAgQIECAAAECBAgQyFdAAJWvv9oJECBAgAABAgQIECBAgAABAgQIECBAgAABAoUTEEAVbkh1iAABAgQIECBAgAABAgQIECBAgAABAgQIECCQr4AAKl9/tRMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECicggCrckOoQAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCBfAQFUvv5qJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgUTkAAVbgh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL4CAqh8/dVOgAABAgQIECBAgAABAgQIECBAgAABAgQIECicgACqcEOqQwQIECBAgAABAgQIECBAgAABAgQIECBAgACBfAUEUPn6q50AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgUDgBAVThhlSHCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQL5Cgig8vVXOwECBAgQIECAAAECBAgQIECAAAECBAgQIECgcAICqMINqQ4RIECAAAECBAgQIECAAAECBAgQIECAAAECBPIVEEDl6692AgQIECBAgAABAgQIECBAgAABAgQIECBAgEDhBARQhRtSHSJAgAABAgQIECBAgAABAgQIECBAgAABAgQI5CsggMrXX+0ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgcIJCKAKN6Q6RIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDIV6DeMj02nJpvE9ROgAABAgQIECBAgAABAgQIECBAgAABAgQIECBQJAEzoIo0mvpCgAABAgQIECBAgAABAgQIECBAgAABAgQIECgBAQFUCQyCJhAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEiiQggCrSaOoLAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKAEBARQJTAImkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQKJKAAKpIo6kvBAgQIECAAAECBAgQIECAAAECBAgQIECAAIESEBBAlcAgaAIBAgQIECBAgAABAgQIECBAgAABAgQIECBAoEgCAqgijaa+ECBAgAABAgQIECBAgAABAgQIECBAgAABAgRKQEAAVQKDoAkECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgSIJCKCKNJr6QoAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAoAQEBVAkMgiYQIECAAAECBAgQIECAAAECBAgQIECAAAECBIokIIAq0mjqCwECBAgQIECAAAECBAgQIECAAAECBAgQIECgBAQEUCUwCJpAgAABAgQIECBAgAABAgQIECBAgAABAgQIECiSgACqSKOpLwQIECBAgAABAgQIECBAgAABAgQIECBAgACBEhAQQJXAIGgCAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKBIAgKoIo2mvhAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIESkBAAFUCg6AJBAgQIECAAAECBAgQIECAAAECBAgQIECAAIEiCQigijSa+kKAAAECBAgQIECAAAECBAgQIECAAAECBAgQKAEBAVQJDIImECBAgAABAgQIECBAgAABAgQIECBAgAABAgSKJCCAKtJo6gsBAgQIECBAgAABAgQIECBAgAABAgQIECBAoAQEBFAlMAiaQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAoksD/AxNWEy9iPvIAAAAAAElFTkSuQmCC"
+    }
+   },
+   "cell_type": "markdown",
+   "id": "ad9e20ae-934a-4b98-b6ab-091c77572c61",
+   "metadata": {},
+   "source": [
+    "The central account has an LF tag  `data_classification:dev` which we will first add to glue table and grant consumer role permissions to that tag\n",
+    "\n",
+    "![image.png](attachment:d1f0c7d4-d102-42f3-a1fc-b26eeb94a2bf.png)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5506c39d-5b59-436f-82ca-ba1934e60c4d",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "lf_client_central = central_acc_boto_session.client('lakeformation')\n",
+    "lf_client_central.get_data_lake_settings()\n",
+    "\n",
+    "lf_client_central.add_lf_tags_to_resource(\n",
+    "    Resource={\n",
+    "        'Table': {\n",
+    "            'CatalogId': str(central_account),\n",
+    "            'DatabaseName': database_name,\n",
+    "            'Name': table_name\n",
+    "        }\n",
+    "    },\n",
+    "    LFTags=[\n",
+    "        {\n",
+    "            'CatalogId': str(central_account),\n",
+    "            'TagKey': 'data_classification',\n",
+    "            'TagValues': ['dev']\n",
+    "        }\n",
+    "    ]\n",
+    ")\n",
+    "print(f\"Tagged table {database_name}.{table_name} with SharedAccess=consumer\")\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c0bfc0ff-95be-47a5-b49a-028adc23a8c9",
+   "metadata": {},
+   "source": [
+    "Now we need to grant the role in consumer account permissions to the LF tag"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "c069580b-6254-4173-a618-2bdf2fbd2889",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "lf_client_central.grant_permissions(\n",
+    "    Principal={\n",
+    "        'DataLakePrincipalIdentifier': acc_to_role_arn[consumer_account]\n",
+    "    },\n",
+    "    Resource={\n",
+    "        'LFTagPolicy': {\n",
+    "            'CatalogId': str(central_account),\n",
+    "            'ResourceType': 'TABLE',\n",
+    "            'Expression': [\n",
+    "                {\n",
+    "                    'TagKey': 'data_classification',\n",
+    "                    'TagValues': ['dev']\n",
+    "                }\n",
+    "            ]\n",
+    "        }\n",
+    "    },\n",
+    "    Permissions=['SELECT', 'DESCRIBE'],\n",
+    "    PermissionsWithGrantOption=[]\n",
+    ")\n",
+    "\n",
+    "\n",
+    "print(f\"Granted LF-tag based SELECT/DESCRIBE to consumer account {consumer_account}\")\n",
+    "\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "8508880e-a856-4574-8c8a-edbc972c9326",
+   "metadata": {},
+   "source": [
+    "Cross account lakeformation grant permissions automatically creates a RAM share so we need to accept that in consumer account"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "df5665a2-1817-4366-97a6-7370bb3ebf44",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Producer account accepts the RAM invitation\n",
+    "ram_client_consumer = consumer_acc_boto_session.client('ram')\n",
+    "\n",
+    "response = ram_client_consumer.get_resource_share_invitations()\n",
+    "pending = [\n",
+    "    inv for inv in response['resourceShareInvitations']\n",
+    "    if inv['status'] == 'PENDING' and inv['senderAccountId'] == str(central_account)\n",
+    "]\n",
+    "for inv in pending:\n",
+    "    ram_client_consumer.accept_resource_share_invitation(\n",
+    "        resourceShareInvitationArn=inv['resourceShareInvitationArn']\n",
+    "    )\n",
+    "    print(f\"Accepted: {inv['resourceShareInvitationArn']}\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "305acbb5-80b4-4890-adb0-954beba91995",
+   "metadata": {},
+   "source": [
+    "## 4. Consumer reads data from the glue table using Athena"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "3fa4fe66-4e03-4197-80b5-116f1c591183",
+   "metadata": {},
+   "source": [
+    "create a link between glue table in central and the consumer account"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b089a0cf-e69d-461a-91ab-39d3fc17dc7e",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "glue_client_consumer = consumer_acc_boto_session.client('glue')\n",
+    "\n",
+    "CONSUMER_DB_NAME = 'shared_feature_store_db'\n",
+    "try:\n",
+    "    glue_client_consumer.create_database(\n",
+    "        DatabaseInput={'Name': CONSUMER_DB_NAME}\n",
+    "    )\n",
+    "    print(f\"Created database: {CONSUMER_DB_NAME}\")\n",
+    "except glue_client_consumer.exceptions.AlreadyExistsException:\n",
+    "    print(f\"Database {CONSUMER_DB_NAME} already exists\")\n",
+    "\n",
+    "try:\n",
+    "    glue_client_consumer.create_table(\n",
+    "        DatabaseName=CONSUMER_DB_NAME,\n",
+    "        TableInput={\n",
+    "            'Name': f'{table_name}_link',\n",
+    "            'TargetTable': {\n",
+    "                'CatalogId': str(central_account),\n",
+    "                'DatabaseName': database_name,\n",
+    "                'Name': table_name\n",
+    "            }\n",
+    "        }\n",
+    "    )\n",
+    "    print(f\"Created resource link: {CONSUMER_DB_NAME}.{table_name}_link\")\n",
+    "except glue_client_consumer.exceptions.AlreadyExistsException:\n",
+    "    print(\"Resource link already exists\")\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "4be3b18e-9682-4edd-bfd1-603932622b0b",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import time\n",
+    "\n",
+    "athena_client = consumer_acc_boto_session.client('athena')\n",
+    "CONSUMER_S3_BUCKET = consumer_acc_sagemaker_session.default_bucket()\n",
+    "\n",
+    "query = f'SELECT * FROM {CONSUMER_DB_NAME}.{table_name}_link LIMIT 10'\n",
+    "\n",
+    "response = athena_client.start_query_execution(\n",
+    "    QueryString=query,\n",
+    "    ResultConfiguration={\n",
+    "        'OutputLocation': f's3://{CONSUMER_S3_BUCKET}/athena-results/'\n",
+    "    }\n",
+    ")\n",
+    "\n",
+    "query_id = response['QueryExecutionId']\n",
+    "print(f\"Query started: {query_id}\")\n",
+    "\n",
+    "while True:\n",
+    "    status = athena_client.get_query_execution(QueryExecutionId=query_id)\n",
+    "    state = status['QueryExecution']['Status']['State']\n",
+    "    if state in ['SUCCEEDED', 'FAILED', 'CANCELLED']:\n",
+    "        break\n",
+    "    print(f\"Status: {state}...\")\n",
+    "    time.sleep(2)\n",
+    "\n",
+    "if state == 'SUCCEEDED':\n",
+    "    results = athena_client.get_query_results(QueryExecutionId=query_id)\n",
+    "    for row in results['ResultSet']['Rows']:\n",
+    "        print([col.get('VarCharValue', '') for col in row['Data']])\n",
+    "else:\n",
+    "    reason = status['QueryExecution']['Status'].get('StateChangeReason', 'unknown')\n",
+    "    print(f\"Query {state}: {reason}\")\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b54072b5-eed0-41de-b238-a79f8884d1e6",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "py3.10.14",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.10.14"
+  },
+  "widgets": {
+   "application/vnd.jupyter.widget-state+json": {
+    "state": {
+     "15d7159da97842f289a6eae80d88f367": {
+      "model_module": "@jupyter-widgets/base",
+      "model_module_version": "2.0.0",
+      "model_name": "LayoutModel",
+      "state": {}
+     },
+     "16cf8427b8774feabe06a535381438ef": {
+      "model_module": "@jupyter-widgets/base",
+      "model_module_version": "2.0.0",
+      "model_name": "LayoutModel",
+      "state": {}
+     }
+    },
+    "version_major": 2,
+    "version_minor": 0
+   }
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/v3-examples/ml-ops-examples/imgs/fs-lf-cross-account1.png b/v3-examples/ml-ops-examples/imgs/fs-lf-cross-account1.png
new file mode 100644
index 0000000000000000000000000000000000000000..a126d2e207d268e65a7e03515a3b6dfde8c7ad67
GIT binary patch

From 914f0fd16321e765accdfe6f174915554769a854 Mon Sep 17 00:00:00 2001
From: BassemHalim <bassemamir459@gmail.com>
Date: Wed, 4 Mar 2026 13:17:02 -0800
Subject: [PATCH 09/22] reusing clients + bug fixes

---
 .../mlops/feature_store/feature_group.py      | 39 +++++++++++++------
 1 file changed, 28 insertions(+), 11 deletions(-)

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
index d4cff70988..8b8db82164 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
@@ -2,6 +2,7 @@
 # Licensed under the Apache License, Version 2.0
 """FeatureGroup with Lake Formation support."""
 
+import json
 import logging
 from typing import List, Optional
 
@@ -132,6 +133,7 @@ def _generate_s3_deny_policy(
         s3_prefix: str,
         lake_formation_role_arn: str,
         feature_store_role_arn: str,
+        region: Optional[str] = None,
     ) -> dict:
         """
         Generate an S3 deny policy for Lake Formation governance.
@@ -144,6 +146,8 @@ def _generate_s3_deny_policy(
             s3_prefix: S3 prefix path (without bucket name).
             lake_formation_role_arn: Lake Formation registration role ARN.
             feature_store_role_arn: Feature Store execution role ARN.
+            region: AWS region name (e.g., 'us-west-2'). Used to determine the correct
+                partition for S3 ARNs. If not provided, defaults to 'aws' partition.
 
         Returns:
             S3 bucket policy as a dict with valid JSON structure containing:
@@ -152,6 +156,8 @@ def _generate_s3_deny_policy(
               1. Deny GetObject, PutObject, DeleteObject on data prefix except allowed principals
               2. Deny ListBucket on bucket with prefix condition except allowed principals
         """
+        partition = aws_partition(region) if region else "aws"
+
         policy = {
             "Version": "2012-10-17",
             "Statement": [
@@ -160,7 +166,7 @@ def _generate_s3_deny_policy(
                     "Effect": "Deny",
                     "Principal": "*",
                     "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
-                    "Resource": f"arn:aws:s3:::{bucket_name}/{s3_prefix}/*",
+                    "Resource": f"arn:{partition}:s3:::{bucket_name}/{s3_prefix}/*",
                     "Condition": {
                         "StringNotEquals": {
                             "aws:PrincipalArn": [
@@ -175,7 +181,7 @@ def _generate_s3_deny_policy(
                     "Effect": "Deny",
                     "Principal": "*",
                     "Action": "s3:ListBucket",
-                    "Resource": f"arn:aws:s3:::{bucket_name}",
+                    "Resource": f"arn:{partition}:s3:::{bucket_name}",
                     "Condition": {
                         "StringLike": {"s3:prefix": f"{s3_prefix}/*"},
                         "StringNotEquals": {
@@ -196,7 +202,11 @@ def _get_lake_formation_client(
         region: Optional[str] = None,
     ):
         """
-        Get a Lake Formation client.
+        Get a Lake Formation client, reusing a cached client when possible.
+
+        The client is cached on the instance keyed by (session, region). Subsequent
+        calls with the same arguments return the existing client instead of creating
+        a new one.
 
         Args:
             session: Boto3 session. If not provided, a new session will be created.
@@ -205,9 +215,17 @@ def _get_lake_formation_client(
         Returns:
             A boto3 Lake Formation client.
         """
-        # TODO: don't create w new client for each call
-        boto_session = session or Session()
-        return boto_session.client("lakeformation", region_name=region)
+        cache_key = (id(session), region)
+        if not hasattr(self, "_lf_client_cache"):
+            self._lf_client_cache: dict = {}
+
+        if cache_key not in self._lf_client_cache:
+            boto_session = session or Session()
+            self._lf_client_cache[cache_key] = boto_session.client(
+                "lakeformation", region_name=region
+            )
+
+        return self._lf_client_cache[cache_key]
 
     def _register_s3_with_lake_formation(
         self,
@@ -242,7 +260,7 @@ def _register_s3_with_lake_formation(
 
         # Get region from session if not provided
         if region is None and session is not None:
-            region = session.region_name()
+            region = session.region_name
 
         client = self._get_lake_formation_client(session, region)
         resource_arn = self._s3_uri_to_arn(s3_location, region)
@@ -288,7 +306,7 @@ def _revoke_iam_allowed_principal(
         """
         # Get region from session if not provided
         if region is None and session is not None:
-            region = session.region_name()
+            region = session.region_name
 
         client = self._get_lake_formation_client(session, region)
 
@@ -341,7 +359,7 @@ def _grant_lake_formation_permissions(
         """
         # Get region from session if not provided
         if region is None and session is not None:
-            region = session.region_name()
+            region = session.region_name
 
         client = self._get_lake_formation_client(session, region)
         permissions = ["SELECT", "INSERT", "DELETE", "DESCRIBE", "ALTER"]
@@ -569,11 +587,10 @@ def enable_lake_formation(
                 s3_prefix=s3_prefix,
                 lake_formation_role_arn=lf_role_arn,
                 feature_store_role_arn=role_arn_str,
+                region=region,
             )
 
             # Print policy with clear instructions
-            import json
-
             print("\n" + "=" * 80)
             print("S3 Bucket Policy Update recommended")
             print("=" * 80)

From d5934884dc86542da4e4a7e315517c0b7b7b209f Mon Sep 17 00:00:00 2001
From: BassemHalim <bassemamir459@gmail.com>
Date: Thu, 5 Mar 2026 09:05:40 -0800
Subject: [PATCH 10/22] feat: add disable_hybrid_access_mode + update tests

---
 .../mlops/feature_store/feature_group.py      |  48 +++--
 .../mlops/feature_store/test_lakeformation.py | 178 ++++++++++++++++++
 2 files changed, 211 insertions(+), 15 deletions(-)

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
index 8b8db82164..97863c3f04 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
@@ -42,12 +42,17 @@ class LakeFormationConfig(Base):
         show_s3_policy: If True, prints the S3 deny policy to the console after successful
             Lake Formation setup. This policy should be added to your S3 bucket to restrict
             access to only the allowed principals. Default is False.
+        disable_hybrid_access_mode: If True, revokes IAMAllowedPrincipal permissions from
+            the Glue table, moving it to Lake Formation-only access mode. If False, keeps
+            hybrid access mode where both IAM and Lake Formation control access.
+            Default is True (LF-only mode).
     """
 
     enabled: bool = False
     use_service_linked_role: bool = True
     registration_role_arn: Optional[str] = None
     show_s3_policy: bool = False
+    disable_hybrid_access_mode: bool = True
 
 
 class FeatureGroup(CoreFeatureGroup):
@@ -395,6 +400,7 @@ def enable_lake_formation(
         registration_role_arn: Optional[str] = None,
         wait_for_active: bool = False,
         show_s3_policy: bool = False,
+        disable_hybrid_access_mode: bool = True,
     ) -> dict:
         """
         Enable Lake Formation governance for this Feature Group's offline store.
@@ -404,7 +410,8 @@ def enable_lake_formation(
         2. Validates Feature Group status is 'Created'
         3. Registers the offline store S3 location as data lake location
         4. Grants the execution role permissions on the Glue table
-        5. Revokes IAMAllowedPrincipal permissions from the Glue table
+        5. Optionally revokes IAMAllowedPrincipal permissions from the Glue table
+           (controlled by disable_hybrid_access_mode)
 
         The role ARN is automatically extracted from the Feature Group's configuration.
         Each phase depends on the success of the previous phase - if any phase fails,
@@ -424,11 +431,15 @@ def enable_lake_formation(
             show_s3_policy: If True, prints the S3 deny policy to the console after successful
                 Lake Formation setup. This policy should be added to your S3 bucket to restrict
                 access to only the allowed principals. Default is False.
+            disable_hybrid_access_mode: If True, revokes IAMAllowedPrincipal permissions from
+                the Glue table, moving it to Lake Formation-only access mode. If False, keeps
+                hybrid access mode where both IAM and Lake Formation control access.
+                Default is True.
 
         Returns:
             Dict with status of each Lake Formation operation:
             - s3_registration: bool
-            - iam_principal_revoked: bool
+            - iam_principal_revoked: bool or None (None when disable_hybrid_access_mode=False)
             - permissions_granted: bool
 
         Raises:
@@ -548,19 +559,25 @@ def enable_lake_formation(
                 f"Subsequent phases skipped. Results: {results}"
             )
 
-        # Phase 3: Revoke IAMAllowedPrincipal permissions
-        try:
-            results["iam_principal_revoked"] = self._revoke_iam_allowed_principal(
-                database_name_str, table_name_str, session, region
-            )
-        except Exception as e:
-            raise RuntimeError(
-                f"Failed to revoke IAMAllowedPrincipal permissions. Results: {results}. Error: {e}"
-            ) from e
-
-        if not results["iam_principal_revoked"]:
-            raise RuntimeError(
-                f"Failed to revoke IAMAllowedPrincipal permissions. Results: {results}"
+        # Phase 3: Revoke IAMAllowedPrincipal permissions (if disabling hybrid access mode)
+        if disable_hybrid_access_mode:
+            try:
+                results["iam_principal_revoked"] = self._revoke_iam_allowed_principal(
+                    database_name_str, table_name_str, session, region
+                )
+            except Exception as e:
+                raise RuntimeError(
+                    f"Failed to revoke IAMAllowedPrincipal permissions. Results: {results}. Error: {e}"
+                ) from e
+
+            if not results["iam_principal_revoked"]:
+                raise RuntimeError(
+                    f"Failed to revoke IAMAllowedPrincipal permissions. Results: {results}"
+                )
+        else:
+            results["iam_principal_revoked"] = None
+            logger.info(
+                "Skipping IAMAllowedPrincipal revocation - hybrid access mode preserved."
             )
 
         logger.info(f"Lake Formation setup complete for {self.feature_group_name}: {results}")
@@ -724,5 +741,6 @@ def create(
                 use_service_linked_role=lake_formation_config.use_service_linked_role,
                 registration_role_arn=lake_formation_config.registration_role_arn,
                 show_s3_policy=lake_formation_config.show_s3_policy,
+                disable_hybrid_access_mode=lake_formation_config.disable_hybrid_access_mode,
             )
         return feature_group
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py
index e4d44df37a..534d4a6406 100644
--- a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py
@@ -69,6 +69,37 @@ def test_creates_client_with_provided_session(self):
         mock_session.client.assert_called_with("lakeformation", region_name="us-west-2")
         assert client == mock_client
 
+    def test_caches_client_for_same_session_and_region(self):
+        """Test that repeated calls with the same session and region reuse the cached client."""
+        mock_session = MagicMock()
+        mock_client = MagicMock()
+        mock_session.client.return_value = mock_client
+
+        fg = MagicMock(spec=FeatureGroup)
+        fg._get_lake_formation_client = FeatureGroup._get_lake_formation_client.__get__(fg)
+
+        client1 = fg._get_lake_formation_client(session=mock_session, region="us-west-2")
+        client2 = fg._get_lake_formation_client(session=mock_session, region="us-west-2")
+
+        assert client1 is client2
+        mock_session.client.assert_called_once()
+
+    def test_creates_new_client_for_different_region(self):
+        """Test that a different region produces a new client."""
+        mock_session = MagicMock()
+        mock_client_west = MagicMock()
+        mock_client_east = MagicMock()
+        mock_session.client.side_effect = [mock_client_west, mock_client_east]
+
+        fg = MagicMock(spec=FeatureGroup)
+        fg._get_lake_formation_client = FeatureGroup._get_lake_formation_client.__get__(fg)
+
+        client1 = fg._get_lake_formation_client(session=mock_session, region="us-west-2")
+        client2 = fg._get_lake_formation_client(session=mock_session, region="us-east-1")
+
+        assert client1 is not client2
+        assert mock_session.client.call_count == 2
+
 
 class TestRegisterS3WithLakeFormation:
     """Tests for _register_s3_with_lake_formation method."""
@@ -942,6 +973,7 @@ def test_enable_lake_formation_called_when_enabled(
             use_service_linked_role=True,
             registration_role_arn=None,
             show_s3_policy=False,
+            disable_hybrid_access_mode=True,
         )
         # Verify the feature group was returned
         assert result == mock_fg
@@ -1150,11 +1182,157 @@ def test_use_service_linked_role_extraction_from_config(
             use_service_linked_role=use_slr,
             registration_role_arn=expected_registration_role,
             show_s3_policy=False,
+            disable_hybrid_access_mode=True,
         )
         # Verify the feature group was returned
         assert result == mock_fg
 
 
+class TestDisableHybridAccessMode:
+    """Tests for disable_hybrid_access_mode parameter in enable_lake_formation."""
+
+    def setup_method(self):
+        """Set up test fixtures."""
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        self.fg = FeatureGroup(feature_group_name="test-fg")
+        self.fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(
+                s3_uri="s3://test-bucket/path",
+                resolved_output_s3_uri="s3://test-bucket/resolved-path",
+            ),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+        )
+        self.fg.role_arn = "arn:aws:iam::123456789012:role/TestRole"
+        self.fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
+        self.fg.feature_group_status = "Created"
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    def test_revoke_called_when_disable_hybrid_access_mode_true(
+        self, mock_revoke, mock_grant, mock_register, mock_refresh
+    ):
+        """Test that IAMAllowedPrincipal is revoked when disable_hybrid_access_mode=True (default)."""
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+
+        result = self.fg.enable_lake_formation(disable_hybrid_access_mode=True)
+
+        mock_revoke.assert_called_once()
+        assert result["iam_principal_revoked"] is True
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    def test_revoke_skipped_when_disable_hybrid_access_mode_false(
+        self, mock_revoke, mock_grant, mock_register, mock_refresh
+    ):
+        """Test that IAMAllowedPrincipal revocation is skipped when disable_hybrid_access_mode=False."""
+        mock_register.return_value = True
+        mock_grant.return_value = True
+
+        result = self.fg.enable_lake_formation(disable_hybrid_access_mode=False)
+
+        mock_revoke.assert_not_called()
+        assert result["iam_principal_revoked"] is None
+        assert result["s3_registration"] is True
+        assert result["permissions_granted"] is True
+
+    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    def test_default_disable_hybrid_access_mode_is_true(
+        self, mock_revoke, mock_grant, mock_register, mock_refresh
+    ):
+        """Test that disable_hybrid_access_mode defaults to True (revoke is called by default)."""
+        mock_register.return_value = True
+        mock_grant.return_value = True
+        mock_revoke.return_value = True
+
+        # Call without specifying disable_hybrid_access_mode
+        result = self.fg.enable_lake_formation()
+
+        mock_revoke.assert_called_once()
+        assert result["iam_principal_revoked"] is True
+
+
+class TestCreateWithLakeFormationDisableHybridAccessMode:
+    """Tests for disable_hybrid_access_mode passed through create() via LakeFormationConfig."""
+
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    @patch.object(FeatureGroup, "get")
+    @patch.object(FeatureGroup, "wait_for_status")
+    @patch.object(FeatureGroup, "enable_lake_formation")
+    def test_disable_hybrid_access_mode_false_passed_through_create(
+        self, mock_enable_lf, mock_wait, mock_get, mock_get_client
+    ):
+        """Test that disable_hybrid_access_mode=False is passed through create() to enable_lake_formation."""
+        from sagemaker.core.shapes import FeatureDefinition, OfflineStoreConfig, S3StorageConfig
+
+        mock_client = MagicMock()
+        mock_client.create_feature_group.return_value = {
+            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test"
+        }
+        mock_get_client.return_value = mock_client
+
+        mock_fg = MagicMock(spec=FeatureGroup)
+        mock_fg.wait_for_status = mock_wait
+        mock_fg.enable_lake_formation = mock_enable_lf
+        mock_get.return_value = mock_fg
+
+        feature_definitions = [
+            FeatureDefinition(feature_name="record_id", feature_type="String"),
+            FeatureDefinition(feature_name="event_time", feature_type="String"),
+        ]
+
+        lf_config = LakeFormationConfig()
+        lf_config.enabled = True
+        lf_config.disable_hybrid_access_mode = False
+
+        FeatureGroup.create(
+            feature_group_name="test-fg",
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=feature_definitions,
+            offline_store_config=OfflineStoreConfig(
+                s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/path")
+            ),
+            role_arn="arn:aws:iam::123456789012:role/TestRole",
+            lake_formation_config=lf_config,
+        )
+
+        mock_enable_lf.assert_called_once_with(
+            session=None,
+            region=None,
+            use_service_linked_role=True,
+            registration_role_arn=None,
+            show_s3_policy=False,
+            disable_hybrid_access_mode=False,
+        )
+
+
+class TestLakeFormationConfigDefaults:
+    """Tests for LakeFormationConfig default values."""
+
+    def test_disable_hybrid_access_mode_defaults_to_true(self):
+        """Test that LakeFormationConfig.disable_hybrid_access_mode defaults to True."""
+        config = LakeFormationConfig()
+        assert config.disable_hybrid_access_mode is True
+
+    def test_disable_hybrid_access_mode_can_be_set_to_false(self):
+        """Test that LakeFormationConfig.disable_hybrid_access_mode can be set to False."""
+        config = LakeFormationConfig()
+        config.disable_hybrid_access_mode = False
+        assert config.disable_hybrid_access_mode is False
+
+
 class TestExtractAccountIdFromArn:
     """Tests for _extract_account_id_from_arn static method."""
 

From 4ef9451e0e3f133967345cb1b0e3bbdcf3bcf930 Mon Sep 17 00:00:00 2001
From: BassemHalim <bassemamir459@gmail.com>
Date: Tue, 10 Mar 2026 12:48:24 -0700
Subject: [PATCH 11/22] refactor: replace print() with logger.info() for S3
 deny policy display

Replace 10 bare print() calls with a single logger.info() call for the
S3 deny policy output in enable_lake_formation(). This makes the policy
display consistent with the rest of the LF workflow which uses logger.

Update 12 tests to mock the logger instead of builtins.print.

---
X-AI-Prompt: replace print with logger.info for s3 bucket policy display in enable_lake_formation
X-AI-Tool: kiro-cli
---
 .../mlops/feature_store/feature_group.py      |  31 ++--
 .../mlops/feature_store/test_lakeformation.py | 164 ++++++++----------
 2 files changed, 91 insertions(+), 104 deletions(-)

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
index 97863c3f04..ded890a397 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
@@ -607,23 +607,22 @@ def enable_lake_formation(
                 region=region,
             )
 
-            # Print policy with clear instructions
-            print("\n" + "=" * 80)
-            print("S3 Bucket Policy Update recommended")
-            print("=" * 80)
-            print(
-                "\nTo complete Lake Formation setup, add the following deny policy to your S3 bucket."
+            # Log policy with clear instructions
+            policy_json = json.dumps(policy, indent=2)
+            policy_message = (
+                "\n" + "=" * 50
+                + "\nS3 Bucket Policy Update recommended"
+                + "\n" + "=" * 50
+                + "\n\nTo complete Lake Formation setup, add the following"
+                + "\ndeny policy to your S3 bucket."
+                + "\nThis restricts access to the offline store data to"
+                + "\nonly the allowed principals."
+                + f"\n\nBucket: {bucket_name}"
+                + f"\n\nPolicy to add:\n{policy_json}"
+                + "\n\nNote: Merge this with your existing bucket policy if one exists."
+                + "\n" + "=" * 50 + "\n"
             )
-            print(
-                "This policy restricts access to the offline store data to only the allowed principals."
-            )
-            print("\nBucket:", bucket_name)
-            print("\nPolicy to add:")
-            print("-" * 40)
-            print(json.dumps(policy, indent=2))
-            print("-" * 40)
-            print("\nNote: Merge this with your existing bucket policy if one exists.")
-            print("=" * 80 + "\n")
+            logger.info(policy_message)
 
         return results
 
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py
index 534d4a6406..b882c97e95 100644
--- a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py
@@ -1609,10 +1609,8 @@ class TestEnableLakeFormationServiceLinkedRoleInPolicy:
     @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
     @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
     @patch.object(FeatureGroup, "_generate_s3_deny_policy")
-    @patch("builtins.print")
     def test_uses_service_linked_role_arn_when_use_service_linked_role_true(
         self,
-        mock_print,
         mock_generate_policy,
         mock_revoke,
         mock_grant,
@@ -1660,10 +1658,8 @@ def test_uses_service_linked_role_arn_when_use_service_linked_role_true(
     @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
     @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
     @patch.object(FeatureGroup, "_generate_s3_deny_policy")
-    @patch("builtins.print")
     def test_uses_service_linked_role_arn_by_default(
         self,
-        mock_print,
         mock_generate_policy,
         mock_revoke,
         mock_grant,
@@ -1710,10 +1706,8 @@ def test_uses_service_linked_role_arn_by_default(
     @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
     @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
     @patch.object(FeatureGroup, "_generate_s3_deny_policy")
-    @patch("builtins.print")
     def test_service_linked_role_arn_uses_correct_account_id(
         self,
-        mock_print,
         mock_generate_policy,
         mock_revoke,
         mock_grant,
@@ -1768,10 +1762,8 @@ class TestRegistrationRoleArnUsedWhenServiceLinkedRoleFalse:
     @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
     @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
     @patch.object(FeatureGroup, "_generate_s3_deny_policy")
-    @patch("builtins.print")
     def test_uses_registration_role_arn_when_use_service_linked_role_false(
         self,
-        mock_print,
         mock_generate_policy,
         mock_revoke,
         mock_grant,
@@ -1829,10 +1821,8 @@ def test_uses_registration_role_arn_when_use_service_linked_role_false(
     @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
     @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
     @patch.object(FeatureGroup, "_generate_s3_deny_policy")
-    @patch("builtins.print")
     def test_registration_role_arn_passed_to_s3_registration(
         self,
-        mock_print,
         mock_generate_policy,
         mock_revoke,
         mock_grant,
@@ -1887,10 +1877,8 @@ def test_registration_role_arn_passed_to_s3_registration(
     @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
     @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
     @patch.object(FeatureGroup, "_generate_s3_deny_policy")
-    @patch("builtins.print")
     def test_different_registration_role_arns_produce_different_policies(
         self,
-        mock_print,
         mock_generate_policy,
         mock_revoke,
         mock_grant,
@@ -1966,17 +1954,17 @@ class TestPolicyPrintedWithClearInstructions:
     @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
     @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
     @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch("builtins.print")
+    @patch("sagemaker.mlops.feature_store.feature_group.logger")
     def test_policy_printed_with_header_and_instructions(
         self,
-        mock_print,
+        mock_logger,
         mock_revoke,
         mock_grant,
         mock_register,
         mock_refresh,
     ):
         """
-        Test that enable_lake_formation prints the S3 deny policy with clear
+        Test that enable_lake_formation logs the S3 deny policy with clear
         header and instructions for the user.
         """
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
@@ -2004,42 +1992,42 @@ def test_policy_printed_with_header_and_instructions(
         # Call enable_lake_formation with show_s3_policy=True
         fg.enable_lake_formation(show_s3_policy=True)
 
-        # Collect all print calls
-        print_calls = [str(call) for call in mock_print.call_args_list]
-        all_printed_text = " ".join(print_calls)
+        # Collect all logger.info calls
+        log_calls = [str(call) for call in mock_logger.info.call_args_list]
+        all_logged_text = " ".join(log_calls)
 
-        # Verify header is printed
-        assert "S3 Bucket Policy" in all_printed_text, "Header should mention 'S3 Bucket Policy'"
+        # Verify header is logged
+        assert "S3 Bucket Policy" in all_logged_text, "Header should mention 'S3 Bucket Policy'"
 
-        # Verify instructions are printed
+        # Verify instructions are logged
         assert (
-            "Lake Formation" in all_printed_text
-            or "deny policy" in all_printed_text
+            "Lake Formation" in all_logged_text
+            or "deny policy" in all_logged_text
         ), "Instructions should mention Lake Formation or deny policy"
 
-        # Verify bucket name is printed
-        assert "test-bucket" in all_printed_text, "Bucket name should be printed"
+        # Verify bucket name is logged
+        assert "test-bucket" in all_logged_text, "Bucket name should be logged"
 
-        # Verify note about merging with existing policy is printed
+        # Verify note about merging with existing policy is logged
         assert (
-            "Merge" in all_printed_text or "existing" in all_printed_text
-        ), "Note about merging with existing policy should be printed"
+            "Merge" in all_logged_text or "existing" in all_logged_text
+        ), "Note about merging with existing policy should be logged"
 
     @patch.object(FeatureGroup, "refresh")
     @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
     @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
     @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch("builtins.print")
+    @patch("sagemaker.mlops.feature_store.feature_group.logger")
     def test_policy_json_is_printed(
         self,
-        mock_print,
+        mock_logger,
         mock_revoke,
         mock_grant,
         mock_register,
         mock_refresh,
     ):
         """
-        Test that the S3 deny policy JSON is printed to the console when show_s3_policy=True.
+        Test that the S3 deny policy JSON is logged to the console when show_s3_policy=True.
         """
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
@@ -2066,31 +2054,31 @@ def test_policy_json_is_printed(
         # Call enable_lake_formation with show_s3_policy=True
         fg.enable_lake_formation(show_s3_policy=True)
 
-        # Collect all print calls
-        print_calls = [str(call) for call in mock_print.call_args_list]
-        all_printed_text = " ".join(print_calls)
+        # Collect all logger.info calls
+        log_calls = [str(call) for call in mock_logger.info.call_args_list]
+        all_logged_text = " ".join(log_calls)
 
-        # Verify policy JSON structure elements are printed
-        assert "Version" in all_printed_text, "Policy JSON should contain 'Version'"
-        assert "Statement" in all_printed_text, "Policy JSON should contain 'Statement'"
-        assert "Effect" in all_printed_text, "Policy JSON should contain 'Effect'"
-        assert "Deny" in all_printed_text, "Policy JSON should contain 'Deny' effect"
+        # Verify policy JSON structure elements are logged
+        assert "Version" in all_logged_text, "Policy JSON should contain 'Version'"
+        assert "Statement" in all_logged_text, "Policy JSON should contain 'Statement'"
+        assert "Effect" in all_logged_text, "Policy JSON should contain 'Effect'"
+        assert "Deny" in all_logged_text, "Policy JSON should contain 'Deny' effect"
 
     @patch.object(FeatureGroup, "refresh")
     @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
     @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
     @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch("builtins.print")
+    @patch("sagemaker.mlops.feature_store.feature_group.logger")
     def test_policy_printed_only_after_successful_setup(
         self,
-        mock_print,
+        mock_logger,
         mock_revoke,
         mock_grant,
         mock_register,
         mock_refresh,
     ):
         """
-        Test that the S3 deny policy is only printed after all Lake Formation
+        Test that the S3 deny policy is only logged after all Lake Formation
         phases complete successfully.
         """
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
@@ -2119,15 +2107,15 @@ def test_policy_printed_only_after_successful_setup(
         with pytest.raises(RuntimeError):
             fg.enable_lake_formation(show_s3_policy=True)
 
-        # Collect all print calls
-        print_calls = [str(call) for call in mock_print.call_args_list]
-        all_printed_text = " ".join(print_calls)
+        # Collect all logger.info calls
+        log_calls = [str(call) for call in mock_logger.info.call_args_list]
+        all_logged_text = " ".join(log_calls)
 
-        # Verify policy was NOT printed when setup failed
-        assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed when setup fails"
+        # Verify policy was NOT logged when setup failed
+        assert "S3 Bucket Policy" not in all_logged_text, "Policy should not be logged when setup fails"
 
         # Reset mocks
-        mock_print.reset_mock()
+        mock_logger.reset_mock()
         mock_register.reset_mock()
         mock_register.side_effect = None
         mock_register.return_value = True
@@ -2139,15 +2127,15 @@ def test_policy_printed_only_after_successful_setup(
         with pytest.raises(RuntimeError):
             fg.enable_lake_formation(show_s3_policy=True)
 
-        # Collect all print calls
-        print_calls = [str(call) for call in mock_print.call_args_list]
-        all_printed_text = " ".join(print_calls)
+        # Collect all logger.info calls
+        log_calls = [str(call) for call in mock_logger.info.call_args_list]
+        all_logged_text = " ".join(log_calls)
 
-        # Verify policy was NOT printed when setup fails at Phase 2
-        assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed when Phase 2 fails"
+        # Verify policy was NOT logged when setup fails at Phase 2
+        assert "S3 Bucket Policy" not in all_logged_text, "Policy should not be logged when Phase 2 fails"
 
         # Reset mocks
-        mock_print.reset_mock()
+        mock_logger.reset_mock()
         mock_grant.reset_mock()
         mock_grant.side_effect = None
         mock_grant.return_value = True
@@ -2159,28 +2147,28 @@ def test_policy_printed_only_after_successful_setup(
         with pytest.raises(RuntimeError):
             fg.enable_lake_formation(show_s3_policy=True)
 
-        # Collect all print calls
-        print_calls = [str(call) for call in mock_print.call_args_list]
-        all_printed_text = " ".join(print_calls)
+        # Collect all logger.info calls
+        log_calls = [str(call) for call in mock_logger.info.call_args_list]
+        all_logged_text = " ".join(log_calls)
 
-        # Verify policy was NOT printed when setup fails at Phase 3
-        assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed when Phase 3 fails"
+        # Verify policy was NOT logged when setup fails at Phase 3
+        assert "S3 Bucket Policy" not in all_logged_text, "Policy should not be logged when Phase 3 fails"
 
     @patch.object(FeatureGroup, "refresh")
     @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
     @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
     @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch("builtins.print")
+    @patch("sagemaker.mlops.feature_store.feature_group.logger")
     def test_policy_includes_both_allowed_principals(
         self,
-        mock_print,
+        mock_logger,
         mock_revoke,
         mock_grant,
         mock_register,
         mock_refresh,
     ):
         """
-        Test that the printed policy includes both the Lake Formation role
+        Test that the logged policy includes both the Lake Formation role
         and the Feature Store execution role as allowed principals.
         """
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
@@ -2209,32 +2197,32 @@ def test_policy_includes_both_allowed_principals(
         # Call enable_lake_formation with service-linked role and show_s3_policy=True
         fg.enable_lake_formation(use_service_linked_role=True, show_s3_policy=True)
 
-        # Collect all print calls
-        print_calls = [str(call) for call in mock_print.call_args_list]
-        all_printed_text = " ".join(print_calls)
+        # Collect all logger.info calls
+        log_calls = [str(call) for call in mock_logger.info.call_args_list]
+        all_logged_text = " ".join(log_calls)
 
-        # Verify Feature Store role is in the printed output
-        assert feature_store_role in all_printed_text, "Feature Store role should be in printed policy"
+        # Verify Feature Store role is in the logged output
+        assert feature_store_role in all_logged_text, "Feature Store role should be in logged policy"
 
-        # Verify Lake Formation service-linked role pattern is in the printed output
-        assert "AWSServiceRoleForLakeFormationDataAccess" in all_printed_text, \
-            "Lake Formation service-linked role should be in printed policy"
+        # Verify Lake Formation service-linked role pattern is in the logged output
+        assert "AWSServiceRoleForLakeFormationDataAccess" in all_logged_text, \
+            "Lake Formation service-linked role should be in logged policy"
 
     @patch.object(FeatureGroup, "refresh")
     @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
     @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
     @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch("builtins.print")
+    @patch("sagemaker.mlops.feature_store.feature_group.logger")
     def test_policy_not_printed_when_show_s3_policy_false(
         self,
-        mock_print,
+        mock_logger,
         mock_revoke,
         mock_grant,
         mock_register,
         mock_refresh,
     ):
         """
-        Test that the S3 deny policy is NOT printed when show_s3_policy=False (default).
+        Test that the S3 deny policy is NOT logged when show_s3_policy=False (default).
         """
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
@@ -2261,29 +2249,29 @@ def test_policy_not_printed_when_show_s3_policy_false(
         # Call enable_lake_formation with show_s3_policy=False (default)
         fg.enable_lake_formation(show_s3_policy=False)
 
-        # Collect all print calls
-        print_calls = [str(call) for call in mock_print.call_args_list]
-        all_printed_text = " ".join(print_calls)
+        # Collect all logger.info calls
+        log_calls = [str(call) for call in mock_logger.info.call_args_list]
+        all_logged_text = " ".join(log_calls)
 
-        # Verify policy was NOT printed
-        assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed when show_s3_policy=False"
-        assert "Version" not in all_printed_text, "Policy JSON should not be printed when show_s3_policy=False"
+        # Verify policy was NOT logged
+        assert "S3 Bucket Policy" not in all_logged_text, "Policy should not be logged when show_s3_policy=False"
+        assert "Version" not in all_logged_text, "Policy JSON should not be logged when show_s3_policy=False"
 
     @patch.object(FeatureGroup, "refresh")
     @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
     @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
     @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch("builtins.print")
+    @patch("sagemaker.mlops.feature_store.feature_group.logger")
     def test_policy_not_printed_by_default(
         self,
-        mock_print,
+        mock_logger,
         mock_revoke,
         mock_grant,
         mock_register,
         mock_refresh,
     ):
         """
-        Test that the S3 deny policy is NOT printed by default (when show_s3_policy is not specified).
+        Test that the S3 deny policy is NOT logged by default (when show_s3_policy is not specified).
         """
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
@@ -2310,10 +2298,10 @@ def test_policy_not_printed_by_default(
         # Call enable_lake_formation without specifying show_s3_policy (should default to False)
         fg.enable_lake_formation()
 
-        # Collect all print calls
-        print_calls = [str(call) for call in mock_print.call_args_list]
-        all_printed_text = " ".join(print_calls)
+        # Collect all logger.info calls
+        log_calls = [str(call) for call in mock_logger.info.call_args_list]
+        all_logged_text = " ".join(log_calls)
 
-        # Verify policy was NOT printed
-        assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed by default"
-        assert "Version" not in all_printed_text, "Policy JSON should not be printed by default"
+        # Verify policy was NOT logged
+        assert "S3 Bucket Policy" not in all_logged_text, "Policy should not be logged by default"
+        assert "Version" not in all_logged_text, "Policy JSON should not be logged by default"

From a6f40657cc24772320a87578ecf434828ccf5e73 Mon Sep 17 00:00:00 2001
From: BassemHalim <bassemamir459@gmail.com>
Date: Wed, 11 Mar 2026 14:56:22 -0700
Subject: [PATCH 12/22] update integ tests

---
 .../integ/test_featureStore_lakeformation.py  | 62 +++++++++----------
 1 file changed, 28 insertions(+), 34 deletions(-)

diff --git a/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py b/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py
index dc6f12181a..60d87b37dc 100644
--- a/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py
+++ b/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py
@@ -9,6 +9,7 @@
 Run with: pytest tests/integ/test_featureStore_lakeformation.py -v -m integ
 """
 
+import logging
 import uuid
 
 import boto3
@@ -447,8 +448,9 @@ def test_enable_lake_formation_fails_with_nonexistent_role(
     """
     fg = shared_feature_group_for_negative_tests
 
-    # Generate a nonexistent role ARN by appending a random string to the current role
-    nonexistent_role = f"{role}-nonexistent-{uuid.uuid4().hex[:8]}"
+    # Build a short nonexistent role ARN using the account ID from the real role
+    account_id = role.split(":")[4]
+    nonexistent_role = f"arn:aws:iam::{account_id}:role/non-existent-role"
 
     with pytest.raises(RuntimeError) as exc_info:
         fg.enable_lake_formation(
@@ -470,7 +472,7 @@ def test_enable_lake_formation_fails_with_nonexistent_role(
 
 @pytest.mark.serial
 @pytest.mark.slow_test
-def test_enable_lake_formation_full_flow_with_policy_output(s3_uri, role, region, capsys):
+def test_enable_lake_formation_full_flow_with_policy_output(s3_uri, role, region, caplog):
     """
     Test the full Lake Formation flow with S3 deny policy output.
 
@@ -478,7 +480,7 @@ def test_enable_lake_formation_full_flow_with_policy_output(s3_uri, role, region
     1. Creates a FeatureGroup with offline store
     2. Enables Lake Formation with show_s3_policy=True
     3. Verifies all Lake Formation phases complete successfully
-    4. Verifies the S3 deny policy is printed to the console
+    4. Verifies the S3 deny policy is logged
     5. Verifies the policy structure contains expected elements
 
     This validates Requirements 6.1-6.9 from the design document.
@@ -496,25 +498,19 @@ def test_enable_lake_formation_full_flow_with_policy_output(s3_uri, role, region
         assert fg.feature_group_status == "Created"
 
         # Enable Lake Formation governance with policy output
-        result = fg.enable_lake_formation(show_s3_policy=True)
+        with caplog.at_level(logging.INFO, logger="sagemaker.mlops.feature_store.feature_group"):
+            result = fg.enable_lake_formation(show_s3_policy=True)
 
         # Verify all phases completed successfully
         assert result["s3_registration"] is True
         assert result["permissions_granted"] is True
         assert result["iam_principal_revoked"] is True
 
-        # Capture the printed output
-        captured = capsys.readouterr()
-        output = captured.out
+        output = caplog.text
 
-        # Re-print the output so it's visible in terminal with -s flag
-        print(output)
-
-        # Verify the policy header is printed
+        # Verify the policy header is logged
         assert "S3 Bucket Policy Update recommended" in output
-        assert "=" * 80 in output
-
-        # Verify bucket information is printed
+        # Verify bucket information is logged
         # Extract bucket name from s3_uri (s3://bucket/path -> bucket)
         expected_bucket = s3_uri.replace("s3://", "").split("/")[0]
         assert f"Bucket: {expected_bucket}" in output
@@ -541,7 +537,7 @@ def test_enable_lake_formation_full_flow_with_policy_output(s3_uri, role, region
         # Verify the service-linked role pattern is present (default use_service_linked_role=True)
         assert "aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess" in output
 
-        # Verify instructions are printed
+        # Verify instructions are logged
         assert "Merge this with your existing bucket policy" in output
 
     finally:
@@ -552,15 +548,15 @@ def test_enable_lake_formation_full_flow_with_policy_output(s3_uri, role, region
 
 @pytest.mark.serial
 @pytest.mark.slow_test
-def test_enable_lake_formation_no_policy_output_by_default(s3_uri, role, region, capsys):
+def test_enable_lake_formation_no_policy_output_by_default(s3_uri, role, region, caplog):
     """
-    Test that S3 deny policy is NOT printed when show_s3_policy=False (default).
+    Test that S3 deny policy is NOT logged when show_s3_policy=False (default).
 
     This test verifies:
     1. Creates a FeatureGroup with offline store
     2. Enables Lake Formation without show_s3_policy (defaults to False)
     3. Verifies all Lake Formation phases complete successfully
-    4. Verifies the S3 deny policy is NOT printed to the console
+    4. Verifies the S3 deny policy is NOT logged
 
     This validates Requirement 6.2 from the design document.
     """
@@ -577,18 +573,17 @@ def test_enable_lake_formation_no_policy_output_by_default(s3_uri, role, region,
         assert fg.feature_group_status == "Created"
 
         # Enable Lake Formation governance WITHOUT policy output (default)
-        result = fg.enable_lake_formation()
+        with caplog.at_level(logging.INFO, logger="sagemaker.mlops.feature_store.feature_group"):
+            result = fg.enable_lake_formation()
 
         # Verify all phases completed successfully
         assert result["s3_registration"] is True
         assert result["permissions_granted"] is True
         assert result["iam_principal_revoked"] is True
 
-        # Capture the printed output
-        captured = capsys.readouterr()
-        output = captured.out
+        output = caplog.text
 
-        # Verify the policy is NOT printed
+        # Verify the policy is NOT logged
         assert "S3 Bucket Policy Update recommended" not in output
         assert '"Version": "2012-10-17"' not in output
         assert "s3:GetObject" not in output
@@ -601,7 +596,7 @@ def test_enable_lake_formation_no_policy_output_by_default(s3_uri, role, region,
 
 @pytest.mark.serial
 @pytest.mark.slow_test
-def test_enable_lake_formation_with_custom_role_policy_output(s3_uri, role, region, capsys):
+def test_enable_lake_formation_with_custom_role_policy_output(s3_uri, role, region, caplog):
     """
     Test the full Lake Formation flow with custom registration role and policy output.
 
@@ -629,22 +624,21 @@ def test_enable_lake_formation_with_custom_role_policy_output(s3_uri, role, regi
 
         # Enable Lake Formation with custom registration role and policy output
         # Using the same role for both execution and registration for test simplicity
-        result = fg.enable_lake_formation(
-            use_service_linked_role=False,
-            registration_role_arn=role,
-            show_s3_policy=True,
-        )
+        with caplog.at_level(logging.INFO, logger="sagemaker.mlops.feature_store.feature_group"):
+            result = fg.enable_lake_formation(
+                use_service_linked_role=False,
+                registration_role_arn=role,
+                show_s3_policy=True,
+            )
 
         # Verify all phases completed successfully
         assert result["s3_registration"] is True
         assert result["permissions_granted"] is True
         assert result["iam_principal_revoked"] is True
 
-        # Capture the printed output
-        captured = capsys.readouterr()
-        output = captured.out
+        output = caplog.text
 
-        # Verify the policy header is printed
+        # Verify the policy header is logged
         assert "S3 Bucket Policy Update recommended" in output
 
         # Verify the custom role ARN is used in the policy (appears twice - once for each principal)

From d21ca67ab723cf5fcef9e6e1090efcd643e1ded3 Mon Sep 17 00:00:00 2001
From: BassemHalim <bassemamir459@gmail.com>
Date: Mon, 16 Mar 2026 15:39:09 -0700
Subject: [PATCH 13/22] refactor: rename FeatureGroup to FeatureGroupManager

Rename the mlops FeatureGroup class to FeatureGroupManager to
distinguish it from the core FeatureGroup base class. Update all
references in unit and integration lake formation tests. Fix missing
comma in __init__.py __all__ list.
---
X-AI-Prompt: rename FeatureGroup to FeatureGroupManager and update lakeformation tests
X-AI-Tool: kiro-cli
---
 .../sagemaker/mlops/feature_store/__init__.py |   4 +-
 ...ture_group.py => feature_group_manager.py} |  27 +-
 .../integ/test_featureStore_lakeformation.py  |  94 ++---
 .../mlops/feature_store/test_lakeformation.py | 352 +++++++++---------
 4 files changed, 247 insertions(+), 230 deletions(-)
 rename sagemaker-mlops/src/sagemaker/mlops/feature_store/{feature_group.py => feature_group_manager.py} (96%)

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
index 1b635df2a7..36494f0d79 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
@@ -3,7 +3,8 @@
 """SageMaker FeatureStore V3 - powered by sagemaker-core."""
 
 # FeatureGroup with Lake Formation support (local subclass)
-from sagemaker.mlops.feature_store.feature_group import FeatureGroup, LakeFormationConfig
+from sagemaker.core.resources import FeatureGroup, FeatureMetadata
+from sagemaker.mlops.feature_store.feature_group_manager import FeatureGroupManager, LakeFormationConfig
 
 # Resources from core
 from sagemaker.core.resources import FeatureMetadata
@@ -76,6 +77,7 @@
 __all__ = [
     # Resources
     "FeatureGroup",
+    "FeatureGroupManager",
     "FeatureMetadata",
     # Shapes
     "DataCatalogConfig",
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
similarity index 96%
rename from sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
rename to sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
index ded890a397..46ee26c123 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
@@ -8,7 +8,7 @@
 
 import botocore.exceptions
 
-from sagemaker.core.resources import FeatureGroup as CoreFeatureGroup
+from sagemaker.core.resources import FeatureGroup
 from sagemaker.core.resources import Base
 from sagemaker.core.shapes import (
     FeatureDefinition,
@@ -55,11 +55,11 @@ class LakeFormationConfig(Base):
     disable_hybrid_access_mode: bool = True
 
 
-class FeatureGroup(CoreFeatureGroup):
+class FeatureGroupManager(FeatureGroup):
 
     # Inherit parent docstring and append our additions
-    if CoreFeatureGroup.__doc__ and __doc__:
-        __doc__ = CoreFeatureGroup.__doc__
+    if FeatureGroup.__doc__ and __doc__:
+        __doc__ = FeatureGroup.__doc__
 
     @staticmethod
     def _s3_uri_to_arn(s3_uri: str, region: Optional[str] = None) -> str:
@@ -326,7 +326,7 @@ def _revoke_iam_allowed_principal(
                 },
                 Permissions=["ALL"],
             )
-            logger.info(f"Revoked IAMAllowedPrincipal from table: {database_name}.{table_name}")
+            logger.info(f"Disabled Lake Formation hybrid-access mode on table: {database_name}.{table_name}")
             return True
         except botocore.exceptions.ClientError as e:
             # if the Table doesn't have that permission because the user already revoked it
@@ -514,6 +514,21 @@ def enable_lake_formation(
         table_name_str = str(table_name)
         role_arn_str = str(self.role_arn)
 
+        # Determine the actual S3 location to register with Lake Formation.
+        # For Iceberg tables, the Glue table's StorageDescriptor.Location is the parent
+        # path (without /data suffix), while resolved_output_s3_uri always ends with /data.
+        s3_location_to_register = resolved_s3_uri_str
+        if (
+            self.offline_store_config.table_format is not None
+            and str(self.offline_store_config.table_format) == "Iceberg"
+            and resolved_s3_uri_str.endswith("/data")
+        ):
+            s3_location_to_register = resolved_s3_uri_str[: -len("/data")]
+            logger.info(
+                f"Iceberg table format detected. Using parent S3 path for LF registration: "
+                f"{s3_location_to_register}"
+            )
+
         # Execute Lake Formation setup with fail-fast behavior
         results = {
             "s3_registration": False,
@@ -524,7 +539,7 @@ def enable_lake_formation(
         # Phase 1: Register S3 with Lake Formation
         try:
             results["s3_registration"] = self._register_s3_with_lake_formation(
-                resolved_s3_uri_str,
+                s3_location_to_register,
                 session,
                 region,
                 use_service_linked_role=use_service_linked_role,
diff --git a/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py b/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py
index 60d87b37dc..4aba769258 100644
--- a/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py
+++ b/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py
@@ -1,5 +1,5 @@
 """
-Integration tests for Lake Formation with FeatureGroup.
+Integration tests for Lake Formation with FeatureGroupManager.
 
 These tests require:
 - AWS credentials with Lake Formation and SageMaker permissions
@@ -18,7 +18,7 @@
 
 from sagemaker.core.helper.session_helper import Session, get_execution_role
 from sagemaker.mlops.feature_store import (
-    FeatureGroup,
+    FeatureGroupManager,
     LakeFormationConfig,
     OfflineStoreConfig,
     OnlineStoreConfig,
@@ -58,7 +58,7 @@ def region():
 @pytest.fixture(scope="module")
 def shared_feature_group_for_negative_tests(s3_uri, role, region):
     """
-    Create a single FeatureGroup for negative tests that only need to verify
+    Create a single FeatureGroupManager for negative tests that only need to verify
     error conditions without modifying the resource.
 
     This fixture is module-scoped to be created once and shared across tests,
@@ -81,12 +81,12 @@ def generate_feature_group_name():
     return f"test-lf-fg-{uuid.uuid4().hex[:8]}"
 
 
-def create_test_feature_group(name: str, s3_uri: str, role_arn: str, region: str) -> FeatureGroup:
-    """Create a FeatureGroup with offline store for testing."""
+def create_test_feature_group(name: str, s3_uri: str, role_arn: str, region: str) -> FeatureGroupManager:
+    """Create a FeatureGroupManager with offline store for testing."""
 
     offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri))
 
-    fg = FeatureGroup.create(
+    fg = FeatureGroupManager.create(
         feature_group_name=name,
         record_identifier_feature_name="record_id",
         event_time_feature_name="event_time",
@@ -99,12 +99,12 @@ def create_test_feature_group(name: str, s3_uri: str, role_arn: str, region: str
     return fg
 
 
-def cleanup_feature_group(fg: FeatureGroup):
+def cleanup_feature_group(fg: FeatureGroupManager):
     """
-    Delete a FeatureGroup and its associated Glue table.
+    Delete a FeatureGroupManager and its associated Glue table.
 
     Args:
-        fg: The FeatureGroup to delete.
+        fg: The FeatureGroupManager to delete.
     """
     try:
         # Delete the Glue table if it exists
@@ -128,7 +128,7 @@ def cleanup_feature_group(fg: FeatureGroup):
                 # Don't fail cleanup if Glue table deletion fails
                 pass
 
-        # Delete the FeatureGroup
+        # Delete the FeatureGroupManager
         fg.delete()
     except ClientError:
         # Don't fail cleanup if Glue table deletion fails
@@ -139,20 +139,20 @@ def cleanup_feature_group(fg: FeatureGroup):
 @pytest.mark.slow_test
 def test_create_feature_group_and_enable_lake_formation(s3_uri, role, region):
     """
-    Test creating a FeatureGroup and enabling Lake Formation governance.
+    Test creating a FeatureGroupManager and enabling Lake Formation governance.
 
     This test:
-    1. Creates a new FeatureGroup with offline store
+    1. Creates a new FeatureGroupManager with offline store
     2. Waits for it to reach Created status
     3. Enables Lake Formation governance (registers S3, grants permissions, revokes IAM principals)
-    4. Cleans up the FeatureGroup
+    4. Cleans up the FeatureGroupManager
     """
 
     fg_name = generate_feature_group_name()
     fg = None
 
     try:
-        # Create the FeatureGroup
+        # Create the FeatureGroupManager
         fg = create_test_feature_group(fg_name, s3_uri, role, region)
         assert fg is not None
 
@@ -179,26 +179,26 @@ def test_create_feature_group_and_enable_lake_formation(s3_uri, role, region):
 @pytest.mark.slow_test
 def test_create_feature_group_with_lake_formation_enabled(s3_uri, role, region):
     """
-    Test creating a FeatureGroup with lake_formation_config.enabled=True.
+    Test creating a FeatureGroupManager with lake_formation_config.enabled=True.
 
     This test verifies the integrated workflow where Lake Formation is enabled
-    automatically during FeatureGroup creation:
-    1. Creates a new FeatureGroup with lake_formation_config.enabled=True
-    2. Verifies the FeatureGroup is created and Lake Formation is configured
-    3. Cleans up the FeatureGroup
+    automatically during FeatureGroupManager creation:
+    1. Creates a new FeatureGroupManager with lake_formation_config.enabled=True
+    2. Verifies the FeatureGroupManager is created and Lake Formation is configured
+    3. Cleans up the FeatureGroupManager
     """
 
     fg_name = generate_feature_group_name()
     fg = None
 
     try:
-        # Create the FeatureGroup with Lake Formation enabled
+        # Create the FeatureGroupManager with Lake Formation enabled
 
         offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri))
         lake_formation_config = LakeFormationConfig()
         lake_formation_config.enabled = True
 
-        fg = FeatureGroup.create(
+        fg = FeatureGroupManager.create(
             feature_group_name=fg_name,
             record_identifier_feature_name="record_id",
             event_time_feature_name="event_time",
@@ -208,7 +208,7 @@ def test_create_feature_group_with_lake_formation_enabled(s3_uri, role, region):
             lake_formation_config=lake_formation_config,
         )
 
-        # Verify the FeatureGroup was created
+        # Verify the FeatureGroupManager was created
         assert fg is not None
         assert fg.feature_group_name == fg_name
         assert fg.feature_group_status == "Created"
@@ -226,24 +226,24 @@ def test_create_feature_group_with_lake_formation_enabled(s3_uri, role, region):
 @pytest.mark.serial
 def test_create_feature_group_without_lake_formation(s3_uri, role, region):
     """
-    Test creating a FeatureGroup without Lake Formation enabled.
+    Test creating a FeatureGroupManager without Lake Formation enabled.
 
     This test verifies that when lake_formation_config is not provided or enabled=False,
-    the FeatureGroup is created successfully without any Lake Formation operations:
-    1. Creates a new FeatureGroup without lake_formation_config
-    2. Verifies the FeatureGroup is created successfully
+    the FeatureGroupManager is created successfully without any Lake Formation operations:
+    1. Creates a new FeatureGroupManager without lake_formation_config
+    2. Verifies the FeatureGroupManager is created successfully
     3. Verifies no Lake Formation operations were performed
-    4. Cleans up the FeatureGroup
+    4. Cleans up the FeatureGroupManager
     """
     fg_name = generate_feature_group_name()
     fg = None
 
     try:
-        # Create the FeatureGroup without Lake Formation
+        # Create the FeatureGroupManager without Lake Formation
         offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri))
 
         # Create without lake_formation_config (default behavior)
-        fg = FeatureGroup.create(
+        fg = FeatureGroupManager.create(
             feature_group_name=fg_name,
             record_identifier_feature_name="record_id",
             event_time_feature_name="event_time",
@@ -252,7 +252,7 @@ def test_create_feature_group_without_lake_formation(s3_uri, role, region):
             role_arn=role,
         )
 
-        # Verify the FeatureGroup was created
+        # Verify the FeatureGroupManager was created
         assert fg is not None
         assert fg.feature_group_name == fg_name
 
@@ -278,7 +278,7 @@ def test_create_feature_group_without_lake_formation(s3_uri, role, region):
 
 def test_create_feature_group_with_lake_formation_fails_without_offline_store(role, region):
     """
-    Test that creating a FeatureGroup with enable_lake_formation=True fails
+    Test that creating a FeatureGroupManager with enable_lake_formation=True fails
     when no offline store is configured.
 
     Expected behavior: ValueError should be raised indicating offline store is required.
@@ -290,7 +290,7 @@ def test_create_feature_group_with_lake_formation_fails_without_offline_store(ro
 
     # Attempt to create without offline store but with Lake Formation enabled
     with pytest.raises(ValueError) as exc_info:
-        FeatureGroup.create(
+        FeatureGroupManager.create(
             feature_group_name=fg_name,
             record_identifier_feature_name="record_id",
             event_time_feature_name="event_time",
@@ -307,7 +307,7 @@ def test_create_feature_group_with_lake_formation_fails_without_offline_store(ro
 
 def test_create_feature_group_with_lake_formation_fails_without_role(s3_uri, region):
     """
-    Test that creating a FeatureGroup with lake_formation_config.enabled=True fails
+    Test that creating a FeatureGroupManager with lake_formation_config.enabled=True fails
     when no role_arn is provided.
 
     Expected behavior: ValueError should be raised indicating role_arn is required.
@@ -320,7 +320,7 @@ def test_create_feature_group_with_lake_formation_fails_without_role(s3_uri, reg
 
     # Attempt to create without role_arn but with Lake Formation enabled
     with pytest.raises(ValueError) as exc_info:
-        FeatureGroup.create(
+        FeatureGroupManager.create(
             feature_group_name=fg_name,
             record_identifier_feature_name="record_id",
             event_time_feature_name="event_time",
@@ -335,20 +335,20 @@ def test_create_feature_group_with_lake_formation_fails_without_role(s3_uri, reg
 
 def test_enable_lake_formation_fails_for_non_created_status(s3_uri, role, region):
     """
-    Test that enable_lake_formation() fails when called on a FeatureGroup
+    Test that enable_lake_formation() fails when called on a FeatureGroupManager
     that is not in 'Created' status.
 
     Expected behavior: ValueError should be raised indicating the Feature Group
     must be in 'Created' status.
 
-    Note: This test creates its own FeatureGroup because it needs to test
+    Note: This test creates its own FeatureGroupManager because it needs to test
     behavior during the 'Creating' status, which requires a fresh resource.
     """
     fg_name = generate_feature_group_name()
     fg = None
 
     try:
-        # Create the FeatureGroup
+        # Create the FeatureGroupManager
         fg = create_test_feature_group(fg_name, s3_uri, role, region)
         assert fg is not None
 
@@ -370,22 +370,22 @@ def test_enable_lake_formation_fails_for_non_created_status(s3_uri, role, region
 
 def test_enable_lake_formation_without_offline_store(role, region):
     """
-    Test that enable_lake_formation() fails when called on a FeatureGroup
+    Test that enable_lake_formation() fails when called on a FeatureGroupManager
     without an offline store configured.
 
     Expected behavior: ValueError should be raised indicating offline store is required.
 
-    Note: This test creates a FeatureGroup with only online store, which is a valid
+    Note: This test creates a FeatureGroupManager with only online store, which is a valid
     configuration, but Lake Formation cannot be enabled for it.
     """
     fg_name = generate_feature_group_name()
     fg = None
 
     try:
-        # Create a FeatureGroup with only online store (no offline store)
+        # Create a FeatureGroupManager with only online store (no offline store)
         online_store_config = OnlineStoreConfig(enable_online_store=True)
 
-        fg = FeatureGroup.create(
+        fg = FeatureGroupManager.create(
             feature_group_name=fg_name,
             record_identifier_feature_name="record_id",
             event_time_feature_name="event_time",
@@ -477,7 +477,7 @@ def test_enable_lake_formation_full_flow_with_policy_output(s3_uri, role, region
     Test the full Lake Formation flow with S3 deny policy output.
 
     This test verifies:
-    1. Creates a FeatureGroup with offline store
+    1. Creates a FeatureGroupManager with offline store
     2. Enables Lake Formation with show_s3_policy=True
     3. Verifies all Lake Formation phases complete successfully
     4. Verifies the S3 deny policy is logged
@@ -489,7 +489,7 @@ def test_enable_lake_formation_full_flow_with_policy_output(s3_uri, role, region
     fg = None
 
     try:
-        # Create the FeatureGroup
+        # Create the FeatureGroupManager
         fg = create_test_feature_group(fg_name, s3_uri, role, region)
         assert fg is not None
 
@@ -553,7 +553,7 @@ def test_enable_lake_formation_no_policy_output_by_default(s3_uri, role, region,
     Test that S3 deny policy is NOT logged when show_s3_policy=False (default).
 
     This test verifies:
-    1. Creates a FeatureGroup with offline store
+    1. Creates a FeatureGroupManager with offline store
     2. Enables Lake Formation without show_s3_policy (defaults to False)
     3. Verifies all Lake Formation phases complete successfully
     4. Verifies the S3 deny policy is NOT logged
@@ -564,7 +564,7 @@ def test_enable_lake_formation_no_policy_output_by_default(s3_uri, role, region,
     fg = None
 
     try:
-        # Create the FeatureGroup
+        # Create the FeatureGroupManager
         fg = create_test_feature_group(fg_name, s3_uri, role, region)
         assert fg is not None
 
@@ -601,7 +601,7 @@ def test_enable_lake_formation_with_custom_role_policy_output(s3_uri, role, regi
     Test the full Lake Formation flow with custom registration role and policy output.
 
     This test verifies:
-    1. Creates a FeatureGroup with offline store
+    1. Creates a FeatureGroupManager with offline store
     2. Enables Lake Formation with use_service_linked_role=False and a custom registration_role_arn
     3. Verifies the S3 deny policy uses the custom role ARN instead of service-linked role
 
@@ -614,7 +614,7 @@ def test_enable_lake_formation_with_custom_role_policy_output(s3_uri, role, regi
     fg = None
 
     try:
-        # Create the FeatureGroup
+        # Create the FeatureGroupManager
         fg = create_test_feature_group(fg_name, s3_uri, role, region)
         assert fg is not None
 
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py
index b882c97e95..d378dd1753 100644
--- a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py
@@ -1,10 +1,10 @@
-"""Unit tests for Lake Formation integration with FeatureGroup."""
+"""Unit tests for Lake Formation integration with FeatureGroupManager."""
 from unittest.mock import MagicMock, patch
 
 import botocore.exceptions
 import pytest
 
-from sagemaker.mlops.feature_store import FeatureGroup, LakeFormationConfig
+from sagemaker.mlops.feature_store import FeatureGroupManager, LakeFormationConfig
 
 
 class TestS3UriToArn:
@@ -13,25 +13,25 @@ class TestS3UriToArn:
     def test_converts_s3_uri_to_arn(self):
         """Test S3 URI is converted to ARN format."""
         uri = "s3://my-bucket/my-prefix/data"
-        result = FeatureGroup._s3_uri_to_arn(uri)
+        result = FeatureGroupManager._s3_uri_to_arn(uri)
         assert result == "arn:aws:s3:::my-bucket/my-prefix/data"
 
     def test_handles_bucket_only_uri(self):
         """Test S3 URI with bucket only."""
         uri = "s3://my-bucket"
-        result = FeatureGroup._s3_uri_to_arn(uri)
+        result = FeatureGroupManager._s3_uri_to_arn(uri)
         assert result == "arn:aws:s3:::my-bucket"
 
     def test_returns_arn_unchanged(self):
         """Test ARN input is returned unchanged (idempotent)."""
         arn = "arn:aws:s3:::my-bucket/path"
-        result = FeatureGroup._s3_uri_to_arn(arn)
+        result = FeatureGroupManager._s3_uri_to_arn(arn)
         assert result == arn
 
     def test_uses_region_for_partition(self):
         """Test that region is used to determine partition."""
         uri = "s3://my-bucket/path"
-        result = FeatureGroup._s3_uri_to_arn(uri, region="cn-north-1")
+        result = FeatureGroupManager._s3_uri_to_arn(uri, region="cn-north-1")
         assert result.startswith("arn:aws-cn:s3:::")
 
 
@@ -39,7 +39,7 @@ def test_uses_region_for_partition(self):
 class TestGetLakeFormationClient:
     """Tests for _get_lake_formation_client method."""
 
-    @patch("sagemaker.mlops.feature_store.feature_group.Session")
+    @patch("sagemaker.mlops.feature_store.feature_group_manager.Session")
     def test_creates_client_with_default_session(self, mock_session_class):
         """Test client creation with default session."""
         mock_session = MagicMock()
@@ -47,8 +47,8 @@ def test_creates_client_with_default_session(self, mock_session_class):
         mock_session.client.return_value = mock_client
         mock_session_class.return_value = mock_session
 
-        fg = MagicMock(spec=FeatureGroup)
-        fg._get_lake_formation_client = FeatureGroup._get_lake_formation_client.__get__(fg)
+        fg = MagicMock(spec=FeatureGroupManager)
+        fg._get_lake_formation_client = FeatureGroupManager._get_lake_formation_client.__get__(fg)
 
         client = fg._get_lake_formation_client(region="us-west-2")
 
@@ -61,8 +61,8 @@ def test_creates_client_with_provided_session(self):
         mock_client = MagicMock()
         mock_session.client.return_value = mock_client
 
-        fg = MagicMock(spec=FeatureGroup)
-        fg._get_lake_formation_client = FeatureGroup._get_lake_formation_client.__get__(fg)
+        fg = MagicMock(spec=FeatureGroupManager)
+        fg._get_lake_formation_client = FeatureGroupManager._get_lake_formation_client.__get__(fg)
 
         client = fg._get_lake_formation_client(session=mock_session, region="us-west-2")
 
@@ -75,8 +75,8 @@ def test_caches_client_for_same_session_and_region(self):
         mock_client = MagicMock()
         mock_session.client.return_value = mock_client
 
-        fg = MagicMock(spec=FeatureGroup)
-        fg._get_lake_formation_client = FeatureGroup._get_lake_formation_client.__get__(fg)
+        fg = MagicMock(spec=FeatureGroupManager)
+        fg._get_lake_formation_client = FeatureGroupManager._get_lake_formation_client.__get__(fg)
 
         client1 = fg._get_lake_formation_client(session=mock_session, region="us-west-2")
         client2 = fg._get_lake_formation_client(session=mock_session, region="us-west-2")
@@ -91,8 +91,8 @@ def test_creates_new_client_for_different_region(self):
         mock_client_east = MagicMock()
         mock_session.client.side_effect = [mock_client_west, mock_client_east]
 
-        fg = MagicMock(spec=FeatureGroup)
-        fg._get_lake_formation_client = FeatureGroup._get_lake_formation_client.__get__(fg)
+        fg = MagicMock(spec=FeatureGroupManager)
+        fg._get_lake_formation_client = FeatureGroupManager._get_lake_formation_client.__get__(fg)
 
         client1 = fg._get_lake_formation_client(session=mock_session, region="us-west-2")
         client2 = fg._get_lake_formation_client(session=mock_session, region="us-east-1")
@@ -106,10 +106,10 @@ class TestRegisterS3WithLakeFormation:
 
     def setup_method(self):
         """Set up test fixtures."""
-        self.fg = MagicMock(spec=FeatureGroup)
-        self.fg._s3_uri_to_arn = FeatureGroup._s3_uri_to_arn
+        self.fg = MagicMock(spec=FeatureGroupManager)
+        self.fg._s3_uri_to_arn = FeatureGroupManager._s3_uri_to_arn
         self.fg._register_s3_with_lake_formation = (
-            FeatureGroup._register_s3_with_lake_formation.__get__(self.fg)
+            FeatureGroupManager._register_s3_with_lake_formation.__get__(self.fg)
         )
         self.mock_client = MagicMock()
         self.fg._get_lake_formation_client = MagicMock(return_value=self.mock_client)
@@ -191,8 +191,8 @@ class TestRevokeIamAllowedPrincipal:
 
     def setup_method(self):
         """Set up test fixtures."""
-        self.fg = MagicMock(spec=FeatureGroup)
-        self.fg._revoke_iam_allowed_principal = FeatureGroup._revoke_iam_allowed_principal.__get__(
+        self.fg = MagicMock(spec=FeatureGroupManager)
+        self.fg._revoke_iam_allowed_principal = FeatureGroupManager._revoke_iam_allowed_principal.__get__(
             self.fg
         )
         self.mock_client = MagicMock()
@@ -268,9 +268,9 @@ class TestGrantLakeFormationPermissions:
 
     def setup_method(self):
         """Set up test fixtures."""
-        self.fg = MagicMock(spec=FeatureGroup)
+        self.fg = MagicMock(spec=FeatureGroupManager)
         self.fg._grant_lake_formation_permissions = (
-            FeatureGroup._grant_lake_formation_permissions.__get__(self.fg)
+            FeatureGroupManager._grant_lake_formation_permissions.__get__(self.fg)
         )
         self.mock_client = MagicMock()
         self.fg._get_lake_formation_client = MagicMock(return_value=self.mock_client)
@@ -351,10 +351,10 @@ def test_passes_session_and_region_to_client(self):
 class TestEnableLakeFormationValidation:
     """Tests for enable_lake_formation validation logic."""
 
-    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroupManager, "refresh")
     def test_raises_error_when_no_offline_store(self, mock_refresh):
         """Test that enable_lake_formation raises ValueError when no offline store is configured."""
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = None
         fg.feature_group_status = "Created"
 
@@ -364,12 +364,12 @@ def test_raises_error_when_no_offline_store(self, mock_refresh):
         # Verify refresh was called
         mock_refresh.assert_called_once()
 
-    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroupManager, "refresh")
     def test_raises_error_when_no_role_arn(self, mock_refresh):
         """Test that enable_lake_formation raises ValueError when no role_arn is configured."""
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -388,12 +388,12 @@ def test_raises_error_when_no_role_arn(self, mock_refresh):
         # Verify refresh was called
         mock_refresh.assert_called_once()
 
-    @patch.object(FeatureGroup, "refresh")
+    @patch.object(FeatureGroupManager, "refresh")
     def test_raises_error_when_invalid_status(self, mock_refresh):
         """Test enable_lake_formation raises ValueError when Feature Group not in Created status."""
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -412,18 +412,18 @@ def test_raises_error_when_invalid_status(self, mock_refresh):
         # Verify refresh was called
         mock_refresh.assert_called_once()
 
-    @patch.object(FeatureGroup, "wait_for_status")
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroupManager, "wait_for_status")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
     def test_wait_for_active_calls_wait_for_status(
         self, mock_revoke, mock_grant, mock_register, mock_refresh, mock_wait
     ):
         """Test that wait_for_active=True calls wait_for_status with 'Created' target."""
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -450,18 +450,18 @@ def test_wait_for_active_calls_wait_for_status(
         # Verify refresh was called after wait
         mock_refresh.assert_called_once()
 
-    @patch.object(FeatureGroup, "wait_for_status")
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroupManager, "wait_for_status")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
     def test_wait_for_active_false_does_not_call_wait(
         self, mock_revoke, mock_grant, mock_register, mock_refresh, mock_wait
     ):
         """Test that wait_for_active=False does not call wait_for_status."""
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -521,10 +521,10 @@ def test_wait_for_active_false_does_not_call_wait(
             ),
         ],
     )
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
     def test_fail_fast_phase_execution(
         self,
         mock_revoke,
@@ -546,7 +546,7 @@ def test_fail_fast_phase_execution(
         """
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
-        fg = FeatureGroup(feature_group_name=feature_group_name)
+        fg = FeatureGroupManager(feature_group_name=feature_group_name)
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri=f"s3://test-bucket/{s3_uri}",
@@ -626,9 +626,9 @@ def test_register_s3_propagates_unhandled_exceptions(self):
         AlreadyExistsException, the error should be propagated to the caller unchanged.
 
         """
-        fg = MagicMock(spec=FeatureGroup)
-        fg._s3_uri_to_arn = FeatureGroup._s3_uri_to_arn
-        fg._register_s3_with_lake_formation = FeatureGroup._register_s3_with_lake_formation.__get__(
+        fg = MagicMock(spec=FeatureGroupManager)
+        fg._s3_uri_to_arn = FeatureGroupManager._s3_uri_to_arn
+        fg._register_s3_with_lake_formation = FeatureGroupManager._register_s3_with_lake_formation.__get__(
             fg
         )
         mock_client = MagicMock()
@@ -662,8 +662,8 @@ def test_revoke_iam_principal_propagates_unhandled_exceptions(self):
         InvalidInputException, the error should be propagated to the caller unchanged.
 
         """
-        fg = MagicMock(spec=FeatureGroup)
-        fg._revoke_iam_allowed_principal = FeatureGroup._revoke_iam_allowed_principal.__get__(fg)
+        fg = MagicMock(spec=FeatureGroupManager)
+        fg._revoke_iam_allowed_principal = FeatureGroupManager._revoke_iam_allowed_principal.__get__(fg)
         mock_client = MagicMock()
         fg._get_lake_formation_client = MagicMock(return_value=mock_client)
 
@@ -695,9 +695,9 @@ def test_grant_permissions_propagates_unhandled_exceptions(self):
         InvalidInputException, the error should be propagated to the caller unchanged.
 
         """
-        fg = MagicMock(spec=FeatureGroup)
+        fg = MagicMock(spec=FeatureGroupManager)
         fg._grant_lake_formation_permissions = (
-            FeatureGroup._grant_lake_formation_permissions.__get__(fg)
+            FeatureGroupManager._grant_lake_formation_permissions.__get__(fg)
         )
         mock_client = MagicMock()
         fg._get_lake_formation_client = MagicMock(return_value=mock_client)
@@ -729,14 +729,14 @@ def test_handled_exceptions_do_not_propagate(self):
         Verify that specifically handled exceptions (AlreadyExistsException, InvalidInputException)
         do NOT propagate but return True instead, while all other exceptions are propagated.
         """
-        fg = MagicMock(spec=FeatureGroup)
-        fg._s3_uri_to_arn = FeatureGroup._s3_uri_to_arn
-        fg._register_s3_with_lake_formation = FeatureGroup._register_s3_with_lake_formation.__get__(
+        fg = MagicMock(spec=FeatureGroupManager)
+        fg._s3_uri_to_arn = FeatureGroupManager._s3_uri_to_arn
+        fg._register_s3_with_lake_formation = FeatureGroupManager._register_s3_with_lake_formation.__get__(
             fg
         )
-        fg._revoke_iam_allowed_principal = FeatureGroup._revoke_iam_allowed_principal.__get__(fg)
+        fg._revoke_iam_allowed_principal = FeatureGroupManager._revoke_iam_allowed_principal.__get__(fg)
         fg._grant_lake_formation_permissions = (
-            FeatureGroup._grant_lake_formation_permissions.__get__(fg)
+            FeatureGroupManager._grant_lake_formation_permissions.__get__(fg)
         )
         mock_client = MagicMock()
         fg._get_lake_formation_client = MagicMock(return_value=mock_client)
@@ -787,9 +787,9 @@ class TestCreateWithLakeFormation:
         ],
     )
     @patch("sagemaker.core.resources.Base.get_sagemaker_client")
-    @patch.object(FeatureGroup, "get")
-    @patch.object(FeatureGroup, "wait_for_status")
-    @patch.object(FeatureGroup, "enable_lake_formation")
+    @patch.object(FeatureGroupManager, "get")
+    @patch.object(FeatureGroupManager, "wait_for_status")
+    @patch.object(FeatureGroupManager, "enable_lake_formation")
     def test_no_lake_formation_operations_when_disabled(
         self,
         mock_enable_lf,
@@ -803,7 +803,7 @@ def test_no_lake_formation_operations_when_disabled(
         """
         No Lake Formation Operations When Disabled
 
-        For any call to FeatureGroup.create() where lake_formation_config is None or has enabled=False,
+        For any call to FeatureGroupManager.create() where lake_formation_config is None or has enabled=False,
         no Lake Formation client methods should be invoked.
 
         """
@@ -817,7 +817,7 @@ def test_no_lake_formation_operations_when_disabled(
         mock_get_client.return_value = mock_client
 
         # Mock the get method to return a feature group
-        mock_fg = MagicMock(spec=FeatureGroup)
+        mock_fg = MagicMock(spec=FeatureGroupManager)
         mock_fg.feature_group_name = feature_group_name
         mock_get.return_value = mock_fg
 
@@ -830,7 +830,7 @@ def test_no_lake_formation_operations_when_disabled(
         # Test 1: lake_formation_config with enabled=False (explicit)
         lf_config = LakeFormationConfig()
         lf_config.enabled = False
-        result = FeatureGroup.create(
+        result = FeatureGroupManager.create(
             feature_group_name=feature_group_name,
             record_identifier_feature_name=record_id_feature,
             event_time_feature_name=event_time_feature,
@@ -852,7 +852,7 @@ def test_no_lake_formation_operations_when_disabled(
         mock_get.return_value = mock_fg
 
         # Test 2: lake_formation_config not specified (defaults to None)
-        result = FeatureGroup.create(
+        result = FeatureGroupManager.create(
             feature_group_name=feature_group_name,
             record_identifier_feature_name=record_id_feature,
             event_time_feature_name=event_time_feature,
@@ -892,9 +892,9 @@ def test_no_lake_formation_operations_when_disabled(
         ],
     )
     @patch("sagemaker.core.resources.Base.get_sagemaker_client")
-    @patch.object(FeatureGroup, "get")
-    @patch.object(FeatureGroup, "wait_for_status")
-    @patch.object(FeatureGroup, "enable_lake_formation")
+    @patch.object(FeatureGroupManager, "get")
+    @patch.object(FeatureGroupManager, "wait_for_status")
+    @patch.object(FeatureGroupManager, "enable_lake_formation")
     def test_enable_lake_formation_called_when_enabled(
         self,
         mock_enable_lf,
@@ -929,7 +929,7 @@ def test_enable_lake_formation_called_when_enabled(
         mock_get_client.return_value = mock_client
 
         # Mock the get method to return a feature group
-        mock_fg = MagicMock(spec=FeatureGroup)
+        mock_fg = MagicMock(spec=FeatureGroupManager)
         mock_fg.feature_group_name = feature_group_name
         mock_fg.wait_for_status = mock_wait
         mock_fg.enable_lake_formation = mock_enable_lf
@@ -954,7 +954,7 @@ def test_enable_lake_formation_called_when_enabled(
         lf_config.enabled = True
 
         # Create with lake_formation_config enabled=True
-        result = FeatureGroup.create(
+        result = FeatureGroupManager.create(
             feature_group_name=feature_group_name,
             record_identifier_feature_name=record_id_feature,
             event_time_feature_name=event_time_feature,
@@ -1012,7 +1012,7 @@ def test_validation_error_when_lake_formation_enabled_without_offline_store(
             ValueError,
             match="lake_formation_config with enabled=True requires offline_store_config to be configured",
         ):
-            FeatureGroup.create(
+            FeatureGroupManager.create(
                 feature_group_name=feature_group_name,
                 record_identifier_feature_name=record_id_feature,
                 event_time_feature_name=event_time_feature,
@@ -1074,7 +1074,7 @@ def test_validation_error_when_lake_formation_enabled_without_role_arn(
         with pytest.raises(
             ValueError, match="lake_formation_config with enabled=True requires role_arn to be specified"
         ):
-            FeatureGroup.create(
+            FeatureGroupManager.create(
                 feature_group_name=feature_group_name,
                 record_identifier_feature_name=record_id_feature,
                 event_time_feature_name=event_time_feature,
@@ -1094,9 +1094,9 @@ def test_validation_error_when_lake_formation_enabled_without_role_arn(
         ],
     )
     @patch("sagemaker.core.resources.Base.get_sagemaker_client")
-    @patch.object(FeatureGroup, "get")
-    @patch.object(FeatureGroup, "wait_for_status")
-    @patch.object(FeatureGroup, "enable_lake_formation")
+    @patch.object(FeatureGroupManager, "get")
+    @patch.object(FeatureGroupManager, "wait_for_status")
+    @patch.object(FeatureGroupManager, "enable_lake_formation")
     def test_use_service_linked_role_extraction_from_config(
         self,
         mock_enable_lf,
@@ -1134,7 +1134,7 @@ def test_use_service_linked_role_extraction_from_config(
         mock_get_client.return_value = mock_client
 
         # Mock the get method to return a feature group
-        mock_fg = MagicMock(spec=FeatureGroup)
+        mock_fg = MagicMock(spec=FeatureGroupManager)
         mock_fg.feature_group_name = feature_group_name
         mock_fg.wait_for_status = mock_wait
         mock_fg.enable_lake_formation = mock_enable_lf
@@ -1165,7 +1165,7 @@ def test_use_service_linked_role_extraction_from_config(
             expected_registration_role = "arn:aws:iam::123456789012:role/LFRegistrationRole"
 
         # Create with lake_formation_config
-        result = FeatureGroup.create(
+        result = FeatureGroupManager.create(
             feature_group_name=feature_group_name,
             record_identifier_feature_name=record_id_feature,
             event_time_feature_name=event_time_feature,
@@ -1195,7 +1195,7 @@ def setup_method(self):
         """Set up test fixtures."""
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
-        self.fg = FeatureGroup(feature_group_name="test-fg")
+        self.fg = FeatureGroupManager(feature_group_name="test-fg")
         self.fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -1209,10 +1209,10 @@ def setup_method(self):
         self.fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
         self.fg.feature_group_status = "Created"
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
     def test_revoke_called_when_disable_hybrid_access_mode_true(
         self, mock_revoke, mock_grant, mock_register, mock_refresh
     ):
@@ -1226,10 +1226,10 @@ def test_revoke_called_when_disable_hybrid_access_mode_true(
         mock_revoke.assert_called_once()
         assert result["iam_principal_revoked"] is True
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
     def test_revoke_skipped_when_disable_hybrid_access_mode_false(
         self, mock_revoke, mock_grant, mock_register, mock_refresh
     ):
@@ -1244,10 +1244,10 @@ def test_revoke_skipped_when_disable_hybrid_access_mode_false(
         assert result["s3_registration"] is True
         assert result["permissions_granted"] is True
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
     def test_default_disable_hybrid_access_mode_is_true(
         self, mock_revoke, mock_grant, mock_register, mock_refresh
     ):
@@ -1267,9 +1267,9 @@ class TestCreateWithLakeFormationDisableHybridAccessMode:
     """Tests for disable_hybrid_access_mode passed through create() via LakeFormationConfig."""
 
     @patch("sagemaker.core.resources.Base.get_sagemaker_client")
-    @patch.object(FeatureGroup, "get")
-    @patch.object(FeatureGroup, "wait_for_status")
-    @patch.object(FeatureGroup, "enable_lake_formation")
+    @patch.object(FeatureGroupManager, "get")
+    @patch.object(FeatureGroupManager, "wait_for_status")
+    @patch.object(FeatureGroupManager, "enable_lake_formation")
     def test_disable_hybrid_access_mode_false_passed_through_create(
         self, mock_enable_lf, mock_wait, mock_get, mock_get_client
     ):
@@ -1282,7 +1282,7 @@ def test_disable_hybrid_access_mode_false_passed_through_create(
         }
         mock_get_client.return_value = mock_client
 
-        mock_fg = MagicMock(spec=FeatureGroup)
+        mock_fg = MagicMock(spec=FeatureGroupManager)
         mock_fg.wait_for_status = mock_wait
         mock_fg.enable_lake_formation = mock_enable_lf
         mock_get.return_value = mock_fg
@@ -1296,7 +1296,7 @@ def test_disable_hybrid_access_mode_false_passed_through_create(
         lf_config.enabled = True
         lf_config.disable_hybrid_access_mode = False
 
-        FeatureGroup.create(
+        FeatureGroupManager.create(
             feature_group_name="test-fg",
             record_identifier_feature_name="record_id",
             event_time_feature_name="event_time",
@@ -1339,34 +1339,34 @@ class TestExtractAccountIdFromArn:
     def test_extracts_account_id_from_sagemaker_arn(self):
         """Test extracting account ID from a SageMaker Feature Group ARN."""
         arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/my-feature-group"
-        result = FeatureGroup._extract_account_id_from_arn(arn)
+        result = FeatureGroupManager._extract_account_id_from_arn(arn)
         assert result == "123456789012"
 
     def test_raises_value_error_for_invalid_arn_too_few_parts(self):
         """Test that ValueError is raised for ARN with fewer than 5 colon-separated parts."""
         invalid_arn = "arn:aws:sagemaker:us-west-2"  # Only 4 parts
         with pytest.raises(ValueError, match="Invalid ARN format"):
-            FeatureGroup._extract_account_id_from_arn(invalid_arn)
+            FeatureGroupManager._extract_account_id_from_arn(invalid_arn)
 
     def test_raises_value_error_for_empty_string(self):
         """Test that ValueError is raised for empty string."""
         with pytest.raises(ValueError, match="Invalid ARN format"):
-            FeatureGroup._extract_account_id_from_arn("")
+            FeatureGroupManager._extract_account_id_from_arn("")
 
     def test_raises_value_error_for_non_arn_string(self):
         """Test that ValueError is raised for non-ARN string."""
         with pytest.raises(ValueError, match="Invalid ARN format"):
-            FeatureGroup._extract_account_id_from_arn("not-an-arn")
+            FeatureGroupManager._extract_account_id_from_arn("not-an-arn")
 
     def test_raises_value_error_for_s3_uri(self):
         """Test that ValueError is raised for S3 URI (not ARN)."""
         with pytest.raises(ValueError, match="Invalid ARN format"):
-            FeatureGroup._extract_account_id_from_arn("s3://my-bucket/my-prefix")
+            FeatureGroupManager._extract_account_id_from_arn("s3://my-bucket/my-prefix")
 
     def test_handles_arn_with_resource_path(self):
         """Test extracting account ID from ARN with complex resource path."""
         arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/my-fg/version/1"
-        result = FeatureGroup._extract_account_id_from_arn(arn)
+        result = FeatureGroupManager._extract_account_id_from_arn(arn)
         assert result == "123456789012"
 
 
@@ -1376,14 +1376,14 @@ class TestGetLakeFormationServiceLinkedRoleArn:
     def test_generates_correct_service_linked_role_arn(self):
         """Test that the method generates the correct service-linked role ARN format."""
         account_id = "123456789012"
-        result = FeatureGroup._get_lake_formation_service_linked_role_arn(account_id)
+        result = FeatureGroupManager._get_lake_formation_service_linked_role_arn(account_id)
         expected = "arn:aws:iam::123456789012:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess"
         assert result == expected
 
     def test_uses_region_for_partition(self):
         """Test that region is used to determine partition."""
         account_id = "123456789012"
-        result = FeatureGroup._get_lake_formation_service_linked_role_arn(account_id, region="cn-north-1")
+        result = FeatureGroupManager._get_lake_formation_service_linked_role_arn(account_id, region="cn-north-1")
         assert result.startswith("arn:aws-cn:iam::")
 
 
@@ -1393,8 +1393,8 @@ class TestGenerateS3DenyPolicy:
 
     def setup_method(self):
         """Set up test fixtures."""
-        self.fg = MagicMock(spec=FeatureGroup)
-        self.fg._generate_s3_deny_policy = FeatureGroup._generate_s3_deny_policy.__get__(self.fg)
+        self.fg = MagicMock(spec=FeatureGroupManager)
+        self.fg._generate_s3_deny_policy = FeatureGroupManager._generate_s3_deny_policy.__get__(self.fg)
 
     def test_policy_includes_correct_bucket_arn_in_object_statement(self):
         """Test that the policy includes correct bucket ARN and prefix in object actions statement."""
@@ -1604,11 +1604,11 @@ def test_policy_has_correct_actions_in_each_statement(self):
 class TestEnableLakeFormationServiceLinkedRoleInPolicy:
     """Tests for service-linked role ARN usage in S3 deny policy generation."""
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch.object(FeatureGroup, "_generate_s3_deny_policy")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroupManager, "_generate_s3_deny_policy")
     def test_uses_service_linked_role_arn_when_use_service_linked_role_true(
         self,
         mock_generate_policy,
@@ -1623,7 +1623,7 @@ def test_uses_service_linked_role_arn_when_use_service_linked_role_true(
         """
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -1653,11 +1653,11 @@ def test_uses_service_linked_role_arn_when_use_service_linked_role_true(
         assert call_kwargs["lake_formation_role_arn"] == expected_slr_arn
         assert call_kwargs["feature_store_role_arn"] == fg.role_arn
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch.object(FeatureGroup, "_generate_s3_deny_policy")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroupManager, "_generate_s3_deny_policy")
     def test_uses_service_linked_role_arn_by_default(
         self,
         mock_generate_policy,
@@ -1672,7 +1672,7 @@ def test_uses_service_linked_role_arn_by_default(
         """
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -1701,11 +1701,11 @@ def test_uses_service_linked_role_arn_by_default(
         call_kwargs = mock_generate_policy.call_args[1]
         assert call_kwargs["lake_formation_role_arn"] == expected_slr_arn
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch.object(FeatureGroup, "_generate_s3_deny_policy")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroupManager, "_generate_s3_deny_policy")
     def test_service_linked_role_arn_uses_correct_account_id(
         self,
         mock_generate_policy,
@@ -1722,7 +1722,7 @@ def test_service_linked_role_arn_uses_correct_account_id(
 
         # Use a specific account ID to verify it's extracted correctly
         account_id = "111222333444"
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -1757,11 +1757,11 @@ def test_service_linked_role_arn_uses_correct_account_id(
 class TestRegistrationRoleArnUsedWhenServiceLinkedRoleFalse:
     """Tests for verifying registration_role_arn is used when use_service_linked_role=False."""
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch.object(FeatureGroup, "_generate_s3_deny_policy")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroupManager, "_generate_s3_deny_policy")
     def test_uses_registration_role_arn_when_use_service_linked_role_false(
         self,
         mock_generate_policy,
@@ -1777,7 +1777,7 @@ def test_uses_registration_role_arn_when_use_service_linked_role_false(
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
         # Set up Feature Group with required configuration
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -1816,11 +1816,11 @@ def test_uses_registration_role_arn_when_use_service_linked_role_false(
         service_linked_role_pattern = "aws-service-role/lakeformation.amazonaws.com"
         assert service_linked_role_pattern not in call_kwargs["lake_formation_role_arn"]
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch.object(FeatureGroup, "_generate_s3_deny_policy")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroupManager, "_generate_s3_deny_policy")
     def test_registration_role_arn_passed_to_s3_registration(
         self,
         mock_generate_policy,
@@ -1836,7 +1836,7 @@ def test_registration_role_arn_passed_to_s3_registration(
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
         # Set up Feature Group with required configuration
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -1872,11 +1872,11 @@ def test_registration_role_arn_passed_to_s3_registration(
         assert call_args[1]["use_service_linked_role"] == False
         assert call_args[1]["role_arn"] == custom_registration_role
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch.object(FeatureGroup, "_generate_s3_deny_policy")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
+    @patch.object(FeatureGroupManager, "_generate_s3_deny_policy")
     def test_different_registration_role_arns_produce_different_policies(
         self,
         mock_generate_policy,
@@ -1892,7 +1892,7 @@ def test_different_registration_role_arns_produce_different_policies(
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
         # Set up Feature Group with required configuration
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -1950,11 +1950,11 @@ def test_different_registration_role_arns_produce_different_policies(
 class TestPolicyPrintedWithClearInstructions:
     """Tests for verifying the S3 deny policy is printed with clear instructions."""
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch("sagemaker.mlops.feature_store.feature_group.logger")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
+    @patch("sagemaker.mlops.feature_store.feature_group_manager.logger")
     def test_policy_printed_with_header_and_instructions(
         self,
         mock_logger,
@@ -1970,7 +1970,7 @@ def test_policy_printed_with_header_and_instructions(
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
         # Set up Feature Group with required configuration
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -2013,11 +2013,11 @@ def test_policy_printed_with_header_and_instructions(
             "Merge" in all_logged_text or "existing" in all_logged_text
         ), "Note about merging with existing policy should be logged"
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch("sagemaker.mlops.feature_store.feature_group.logger")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
+    @patch("sagemaker.mlops.feature_store.feature_group_manager.logger")
     def test_policy_json_is_printed(
         self,
         mock_logger,
@@ -2032,7 +2032,7 @@ def test_policy_json_is_printed(
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
         # Set up Feature Group with required configuration
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -2064,11 +2064,11 @@ def test_policy_json_is_printed(
         assert "Effect" in all_logged_text, "Policy JSON should contain 'Effect'"
         assert "Deny" in all_logged_text, "Policy JSON should contain 'Deny' effect"
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch("sagemaker.mlops.feature_store.feature_group.logger")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
+    @patch("sagemaker.mlops.feature_store.feature_group_manager.logger")
     def test_policy_printed_only_after_successful_setup(
         self,
         mock_logger,
@@ -2084,7 +2084,7 @@ def test_policy_printed_only_after_successful_setup(
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
         # Set up Feature Group with required configuration
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -2154,11 +2154,11 @@ def test_policy_printed_only_after_successful_setup(
         # Verify policy was NOT logged when setup fails at Phase 3
         assert "S3 Bucket Policy" not in all_logged_text, "Policy should not be logged when Phase 3 fails"
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch("sagemaker.mlops.feature_store.feature_group.logger")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
+    @patch("sagemaker.mlops.feature_store.feature_group_manager.logger")
     def test_policy_includes_both_allowed_principals(
         self,
         mock_logger,
@@ -2174,7 +2174,7 @@ def test_policy_includes_both_allowed_principals(
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
         # Set up Feature Group with required configuration
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -2208,11 +2208,11 @@ def test_policy_includes_both_allowed_principals(
         assert "AWSServiceRoleForLakeFormationDataAccess" in all_logged_text, \
             "Lake Formation service-linked role should be in logged policy"
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch("sagemaker.mlops.feature_store.feature_group.logger")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
+    @patch("sagemaker.mlops.feature_store.feature_group_manager.logger")
     def test_policy_not_printed_when_show_s3_policy_false(
         self,
         mock_logger,
@@ -2227,7 +2227,7 @@ def test_policy_not_printed_when_show_s3_policy_false(
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
         # Set up Feature Group with required configuration
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",
@@ -2257,11 +2257,11 @@ def test_policy_not_printed_when_show_s3_policy_false(
         assert "S3 Bucket Policy" not in all_logged_text, "Policy should not be logged when show_s3_policy=False"
         assert "Version" not in all_logged_text, "Policy JSON should not be logged when show_s3_policy=False"
 
-    @patch.object(FeatureGroup, "refresh")
-    @patch.object(FeatureGroup, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroup, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroup, "_revoke_iam_allowed_principal")
-    @patch("sagemaker.mlops.feature_store.feature_group.logger")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
+    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
+    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
+    @patch("sagemaker.mlops.feature_store.feature_group_manager.logger")
     def test_policy_not_printed_by_default(
         self,
         mock_logger,
@@ -2276,7 +2276,7 @@ def test_policy_not_printed_by_default(
         from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
 
         # Set up Feature Group with required configuration
-        fg = FeatureGroup(feature_group_name="test-fg")
+        fg = FeatureGroupManager(feature_group_name="test-fg")
         fg.offline_store_config = OfflineStoreConfig(
             s3_storage_config=S3StorageConfig(
                 s3_uri="s3://test-bucket/path",

From 62a1e7328340a0a15cff24ee1c4f2b74717500a9 Mon Sep 17 00:00:00 2001
From: Alexander Young <youngag@amazon.com>
Date: Thu, 19 Mar 2026 20:57:14 +0000
Subject: [PATCH 14/22] Basic functionality of iceberg property changing and
 retrieval in create, update, get functions

---
 .../feature_store/feature_group_manager.py    | 393 +++++++--
 .../feature_store/test_iceberg_properties.py  | 762 ++++++++++++++++++
 2 files changed, 1083 insertions(+), 72 deletions(-)
 create mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
index 46ee26c123..5e01d104a4 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
@@ -4,18 +4,21 @@
 
 import json
 import logging
-from typing import List, Optional
+from typing import Dict, List, Optional
 
 import botocore.exceptions
 
 from sagemaker.core.resources import FeatureGroup
 from sagemaker.core.resources import Base
 from sagemaker.core.shapes import (
+    AddOnlineStoreReplicaAction,
     FeatureDefinition,
     OfflineStoreConfig,
     OnlineStoreConfig,
+    OnlineStoreConfigUpdate,
     Tag,
     ThroughputConfig,
+    ThroughputConfigUpdate,
 )
 from sagemaker.core.shapes import Unassigned
 from sagemaker.core.helper.pipeline_variable import StrPipeVar
@@ -27,6 +30,23 @@
 logger = logging.getLogger(__name__)
 
 
+class IcebergProperties(Base):
+    """Configuration for Iceberg table properties in a Feature Group offline store.
+
+    Use this to customize Iceberg table behavior such as compaction settings,
+    snapshot retention, and other Iceberg-specific configurations.
+
+    Attributes:
+        properties: A dictionary mapping Iceberg property names to their values.
+            Common properties include:
+            - 'write.target-file-size-bytes': Target size for data files
+            - 'commit.manifest.min-count-to-merge': Min manifests before merging
+            - 'history.expire.max-snapshot-age-ms': Max age for snapshot expiration
+    """
+
+    properties: Optional[Dict[str, str]] = None
+
+
 class LakeFormationConfig(Base):
     """Configuration for Lake Formation governance on Feature Group offline stores.
 
@@ -57,6 +77,9 @@ class LakeFormationConfig(Base):
 
 class FeatureGroupManager(FeatureGroup):
 
+    # Attribute for Iceberg table properties (populated by get() when include_iceberg_properties=True)
+    iceberg_properties: Optional[IcebergProperties] = None
+
     # Inherit parent docstring and append our additions
     if FeatureGroup.__doc__ and __doc__:
         __doc__ = FeatureGroup.__doc__
@@ -641,66 +664,239 @@ def enable_lake_formation(
 
         return results
 
+    def _get_iceberg_properties(
+        self,
+        session: Optional[Session] = None,
+        region: Optional[StrPipeVar] = None,
+    ) -> Dict[str, any]:
+        """
+        Fetch the current Glue table definition for the Feature Group's Iceberg offline store.
+
+        Validates that the Feature Group has an Iceberg-formatted offline store,
+        retrieves the Glue table, and strips non-TableInput fields.
+
+        Parameters:
+            session: Optional boto3 session. If not provided, uses default credentials.
+            region: Optional AWS region. If not provided, uses default region.
+
+        Returns:
+            Dict with keys:
+            - 'database_name': The Glue database name
+            - 'table_name': The Glue table name
+            - 'table_input': The cleaned Glue TableInput dict
+            - 'glue_client': The Glue client used for the request
+
+        Raises:
+            ValueError: If offline_store_config is not configured or table_format is not Iceberg.
+            RuntimeError: If the Glue get_table call fails.
+        """
+        # Validate offline store is configured
+        if self.offline_store_config is None or self.offline_store_config == Unassigned():
+            raise ValueError(
+                "Cannot update Iceberg properties: offline_store_config is not configured"
+            )
+
+        # Validate table format is Iceberg
+        if (
+            self.offline_store_config.table_format is None
+            or str(self.offline_store_config.table_format) != "Iceberg"
+        ):
+            raise ValueError(
+                "Cannot update Iceberg properties: table_format must be 'Iceberg'"
+            )
+
+        # Get database and table name from data_catalog_config
+        data_catalog_config = self.offline_store_config.data_catalog_config
+        if data_catalog_config is None:
+            raise ValueError(
+                "Cannot update Iceberg properties: data_catalog_config is not available"
+            )
+
+        database_name = str(data_catalog_config.database)
+        table_name = str(data_catalog_config.table_name)
+
+        # Get Glue client
+        if session is None:
+            session = Session()
+
+        region_str = str(region) if region else session.region_name
+        glue_client = session.client("glue", region_name=region_str)
+
+        try:
+            # Get current table definition
+            response = glue_client.get_table(
+                DatabaseName=database_name,
+                Name=table_name,
+            )
+            table_input = response["Table"]
+
+            # Remove fields that shouldn't be in TableInput
+            fields_to_remove = [
+                "DatabaseName",
+                "CreateTime",
+                "UpdateTime",
+                "CreatedBy",
+                "IsRegisteredWithLakeFormation",
+                "CatalogId",
+                "VersionId",
+                "FederatedTable",
+            ]
+            for field in fields_to_remove:
+                table_input.pop(field, None)
+
+            return {
+                "database_name": database_name,
+                "table_name": table_name,
+                "table_input": table_input,
+                "glue_client": glue_client,
+            }
+
+        except botocore.exceptions.ClientError as e:
+            error_code = e.response.get("Error", {}).get("Code", "Unknown")
+            error_message = e.response.get("Error", {}).get("Message", str(e))
+            raise RuntimeError(
+                f"Failed to update Iceberg properties for {self.feature_group_name}: "
+                f"[{error_code}] {error_message}"
+            ) from e
+
+    def _update_iceberg_properties(
+        self,
+        iceberg_properties: IcebergProperties,
+        session: Optional[Session] = None,
+        region: Optional[StrPipeVar] = None,
+    ) -> Dict[str, any]:
+        """
+        Update Iceberg table properties for the Feature Group's offline store.
+
+        This method updates the Glue table properties for an Iceberg-formatted
+        offline store. The Feature Group must have an offline store configured
+        with table_format='Iceberg'.
+
+        Parameters:
+            iceberg_properties: IcebergProperties object containing the properties to set.
+            session: Optional boto3 session. If not provided, uses default credentials.
+            region: Optional AWS region. If not provided, uses default region.
+
+        Returns:
+            Dict containing the update results with keys:
+            - 'database': The Glue database name
+            - 'table': The Glue table name
+            - 'properties_updated': The properties that were updated
+
+        Raises:
+            ValueError: If offline_store_config is not configured or table_format is not Iceberg.
+            RuntimeError: If the Glue table update fails.
+        """
+        # Validate iceberg_properties has properties to update
+        if iceberg_properties is None or not iceberg_properties.properties:
+            raise ValueError(
+                "iceberg_properties must contain at least one property to update"
+            )
+
+        result = self._get_iceberg_properties(session=session, region=region)
+        database_name = result["database_name"]
+        table_name = result["table_name"]
+        table_input = result["table_input"]
+        glue_client = result["glue_client"]
+
+        logger.info(
+            f"Updating Iceberg properties for {self.feature_group_name} "
+            f"(database={database_name}, table={table_name})"
+        )
+
+        try:
+            # Update parameters with new Iceberg properties
+            if "Parameters" not in table_input:
+                table_input["Parameters"] = {}
+
+            for key, value in iceberg_properties.properties.items():
+                table_input["Parameters"][key] = value
+
+            # Update the table
+            glue_client.update_table(
+                DatabaseName=database_name,
+                TableInput=table_input,
+            )
+
+            logger.info(
+                f"Successfully updated Iceberg properties for {self.feature_group_name}"
+            )
+
+            return {
+                "database": database_name,
+                "table": table_name,
+                "properties_updated": iceberg_properties.properties,
+            }
+
+        except botocore.exceptions.ClientError as e:
+            error_code = e.response.get("Error", {}).get("Code", "Unknown")
+            error_message = e.response.get("Error", {}).get("Message", str(e))
+            raise RuntimeError(
+                f"Failed to update Iceberg properties for {self.feature_group_name}: "
+                f"[{error_code}] {error_message}"
+            ) from e
+
+    @classmethod
+    def get(
+        cls,
+        *args,
+        include_iceberg_properties: bool = False,
+        **kwargs,
+    ) -> Optional["FeatureGroup"]:
+        """
+        Get a FeatureGroup resource with optional Iceberg property retrieval.
+
+        Accepts all parameters from FeatureGroup.get(), plus:
+
+        Parameters:
+            include_iceberg_properties: If True, fetches Iceberg table properties
+                from Glue and stores them in the iceberg_properties attribute.
+                Only applies to Feature Groups with table_format='Iceberg'.
+
+        Returns:
+            The FeatureGroup resource.
+        """
+        session = kwargs.get("session")
+        region = kwargs.get("region")
+
+        feature_group = super().get(*args, **kwargs)
+
+        if include_iceberg_properties:
+            result = feature_group._get_iceberg_properties(session=session, region=region)
+            feature_group.iceberg_properties = IcebergProperties(
+                properties=result["table_input"].get("Parameters", {})
+            )
+
+        return feature_group
+
     @classmethod
-    @Base.add_validate_call
     def create(
         cls,
-        feature_group_name: StrPipeVar,
-        record_identifier_feature_name: StrPipeVar,
-        event_time_feature_name: StrPipeVar,
-        feature_definitions: List[FeatureDefinition],
-        online_store_config: Optional[OnlineStoreConfig] = None,
-        offline_store_config: Optional[OfflineStoreConfig] = None,
-        throughput_config: Optional[ThroughputConfig] = None,
-        role_arn: Optional[StrPipeVar] = None,
-        description: Optional[StrPipeVar] = None,
-        tags: Optional[List[Tag]] = None,
-        use_pre_prod_offline_store_replicator_lambda: Optional[bool] = None,
+        *args,
         lake_formation_config: Optional[LakeFormationConfig] = None,
-        session: Optional[Session] = None,
-        region: Optional[StrPipeVar] = None,
+        iceberg_properties: Optional[IcebergProperties] = None,
+        **kwargs,
     ) -> Optional["FeatureGroup"]:
         """
-        Create a FeatureGroup resource with optional Lake Formation governance.
+        Create a FeatureGroup resource with optional Lake Formation governance and Iceberg properties.
+
+        Accepts all parameters from FeatureGroup.create(), plus:
 
         Parameters:
-            feature_group_name: The name of the FeatureGroup.
-            record_identifier_feature_name: The name of the Feature whose value uniquely
-                identifies a Record.
-            event_time_feature_name: The name of the feature that stores the EventTime.
-            feature_definitions: A list of Feature names and types.
-            online_store_config: Configuration for the OnlineStore.
-            offline_store_config: Configuration for the OfflineStore.
-            throughput_config: Throughput configuration.
-            role_arn: IAM execution role ARN for the OfflineStore.
-            description: A free-form description of the FeatureGroup.
-            tags: Tags used to identify Features in each FeatureGroup.
-            use_pre_prod_offline_store_replicator_lambda: Pre-prod replicator flag.
             lake_formation_config: Optional LakeFormationConfig to configure Lake Formation
                 governance. When enabled=True, requires offline_store_config and role_arn.
-            session: Boto3 session.
-            region: Region name.
+            iceberg_properties: Optional IcebergProperties to configure Iceberg table
+                properties for the offline store. Requires offline_store_config with
+                table_format='Iceberg'.
 
         Returns:
             The FeatureGroup resource.
-
-        Raises:
-            botocore.exceptions.ClientError: This exception is raised for AWS service related errors.
-                The error message and error code can be parsed from the exception as follows:
-                ```
-                try:
-                    # AWS service call here
-                except botocore.exceptions.ClientError as e:
-                    error_message = e.response['Error']['Message']
-                    error_code = e.response['Error']['Code']
-                ```
-            ResourceInUse: Resource being accessed is in use.
-            ResourceLimitExceeded: You have exceeded an SageMaker resource limit.
-                For example, you might have too many training jobs created.
-            ConfigSchemaValidationError: Raised when a configuration file does not adhere to the schema
-            LocalConfigNotFoundError: Raised when a configuration file is not found in local file system
-            S3ConfigNotFoundError: Raised when a configuration file is not found in S3
         """
+        offline_store_config = kwargs.get("offline_store_config")
+        role_arn = kwargs.get("role_arn")
+        session = kwargs.get("session")
+        region = kwargs.get("region")
+
         # Validation for Lake Formation
         if lake_formation_config is not None and lake_formation_config.enabled:
             if offline_store_config is None:
@@ -720,31 +916,21 @@ def create(
                     "when use_service_linked_role is False"
                 )
 
-        # Build kwargs, only including non-None values so parent uses its defaults
-        create_kwargs = {
-            "feature_group_name": feature_group_name,
-            "record_identifier_feature_name": record_identifier_feature_name,
-            "event_time_feature_name": event_time_feature_name,
-            "feature_definitions": feature_definitions,
-            "session": session,
-            "region": region,
-        }
-        if online_store_config is not None:
-            create_kwargs["online_store_config"] = online_store_config
-        if offline_store_config is not None:
-            create_kwargs["offline_store_config"] = offline_store_config
-        if throughput_config is not None:
-            create_kwargs["throughput_config"] = throughput_config
-        if role_arn is not None:
-            create_kwargs["role_arn"] = role_arn
-        if description is not None:
-            create_kwargs["description"] = description
-        if tags is not None:
-            create_kwargs["tags"] = tags
-        if use_pre_prod_offline_store_replicator_lambda is not None:
-            create_kwargs["use_pre_prod_offline_store_replicator_lambda"] = use_pre_prod_offline_store_replicator_lambda
-
-        feature_group = super().create(**create_kwargs)
+        # Validation for Iceberg properties
+        if iceberg_properties is not None and iceberg_properties.properties:
+            if offline_store_config is None:
+                raise ValueError(
+                    "iceberg_properties requires offline_store_config to be configured"
+                )
+            if (
+                offline_store_config.table_format is None
+                or str(offline_store_config.table_format) != "Iceberg"
+            ):
+                raise ValueError(
+                    "iceberg_properties requires offline_store_config.table_format to be 'Iceberg'"
+                )
+
+        feature_group = super().create(*args, **kwargs)
 
         # Enable Lake Formation if requested
         if lake_formation_config is not None and lake_formation_config.enabled:
@@ -757,4 +943,67 @@ def create(
                 show_s3_policy=lake_formation_config.show_s3_policy,
                 disable_hybrid_access_mode=lake_formation_config.disable_hybrid_access_mode,
             )
+        
+        # Update Iceberg properties if requested
+        if iceberg_properties is not None and iceberg_properties.properties:
+            # Wait for feature group to be created before updating Iceberg properties
+            feature_group.wait_for_status(target_status="Created")
+            feature_group._update_iceberg_properties(
+                iceberg_properties=iceberg_properties,
+                session=session,
+                region=region,
+            )
+
         return feature_group
+
+    def update(
+        self,
+        *args,
+        iceberg_properties: Optional[IcebergProperties] = None,
+        session: Optional[Session] = None,
+        region: Optional[StrPipeVar] = None,
+        **kwargs,
+    ) -> Optional["FeatureGroup"]:
+        """
+        Update a FeatureGroup resource with optional Iceberg property updates.
+
+        Accepts all parameters from FeatureGroup.update(), plus:
+
+        Parameters:
+            iceberg_properties: Optional IcebergProperties to update Iceberg table
+                properties for the offline store. Requires offline_store_config with
+                table_format='Iceberg'.
+            session: Boto3 session for Iceberg property updates.
+            region: Region name for Iceberg property updates.
+
+        Returns:
+            The FeatureGroup resource.
+        """
+
+        offline_store_config = self.offline_store_config
+
+        # Validation for Iceberg properties
+        if iceberg_properties is not None and iceberg_properties.properties:
+            if offline_store_config is None or offline_store_config == Unassigned():
+                raise ValueError(
+                    "iceberg_properties requires offline_store_config to be configured"
+                )
+            if (
+                offline_store_config.table_format is None
+                or str(offline_store_config.table_format) != "Iceberg"
+            ):
+                raise ValueError(
+                    "iceberg_properties requires offline_store_config.table_format to be 'Iceberg'"
+                )
+
+        result = super().update(*args, **kwargs)
+
+        # Update Iceberg properties if requested
+        if iceberg_properties is not None and iceberg_properties.properties:
+            self._update_iceberg_properties(
+                iceberg_properties=iceberg_properties,
+                session=session,
+                region=region,
+            )
+
+        return result
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py
new file mode 100644
index 0000000000..861edd73ea
--- /dev/null
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py
@@ -0,0 +1,762 @@
+"""Unit tests for Iceberg properties in FeatureGroupManager."""
+from unittest.mock import MagicMock, patch
+
+import botocore.exceptions
+import pytest
+
+from boto3 import Session
+from sagemaker.mlops.feature_store import FeatureGroupManager
+from sagemaker.mlops.feature_store.feature_group_manager import IcebergProperties
+
+
+class TestIcebergPropertiesConfig:
+    """Tests for IcebergProperties default values."""
+
+    def test_properties_defaults_to_none(self):
+        """Test that properties defaults to None."""
+        config = IcebergProperties()
+        assert config.properties is None
+
+    def test_properties_can_be_set(self):
+        """Test that properties can be set with a dict."""
+        props = {"write.target-file-size-bytes": "536870912"}
+        config = IcebergProperties(properties=props)
+        assert config.properties == props
+
+
+class TestGetIcebergProperties:
+    """Tests for get_iceberg_properties method."""
+
+    def setup_method(self):
+        """Set up test fixtures."""
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        self.fg = MagicMock(spec=FeatureGroupManager)
+        self.fg._get_iceberg_properties = FeatureGroupManager._get_iceberg_properties.__get__(self.fg)
+        self.fg.feature_group_name = "test-fg"
+        self.fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(s3_uri="s3://test-bucket/path"),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+            ),
+            table_format="Iceberg",
+        )
+
+    def test_raises_error_when_no_offline_store_config(self):
+        """Test ValueError when offline_store_config is None."""
+        self.fg.offline_store_config = None
+
+        with pytest.raises(ValueError, match="offline_store_config is not configured"):
+            self.fg._get_iceberg_properties()
+
+    def test_raises_error_when_offline_store_config_is_unassigned(self):
+        """Test ValueError when offline_store_config is Unassigned()."""
+        from sagemaker.core.shapes import Unassigned
+
+        self.fg.offline_store_config = Unassigned()
+
+        with pytest.raises(ValueError, match="offline_store_config is not configured"):
+            self.fg._get_iceberg_properties()
+
+    def test_raises_error_when_table_format_not_iceberg(self):
+        """Test ValueError when table_format is not Iceberg."""
+        self.fg.offline_store_config.table_format = None
+
+        with pytest.raises(ValueError, match="table_format must be 'Iceberg'"):
+            self.fg._get_iceberg_properties()
+
+    def test_raises_error_when_no_data_catalog_config(self):
+        """Test ValueError when data_catalog_config is None."""
+        self.fg.offline_store_config.data_catalog_config = None
+
+        with pytest.raises(ValueError, match="data_catalog_config is not available"):
+            self.fg._get_iceberg_properties()
+
+    @patch("sagemaker.mlops.feature_store.feature_group_manager.Session")
+    def test_successful_get_table_and_field_stripping(self, mock_session_class):
+        """Test successful Glue get_table call strips non-TableInput fields."""
+        mock_session = MagicMock()
+        mock_glue_client = MagicMock()
+        mock_session.client.return_value = mock_glue_client
+        mock_session_class.return_value = mock_session
+
+        mock_glue_client.get_table.return_value = {
+            "Table": {
+                "Name": "test_table",
+                "Parameters": {"table_type": "ICEBERG"},
+                "DatabaseName": "test_db",
+                "CreateTime": "2024-01-01",
+                "UpdateTime": "2024-01-02",
+                "CreatedBy": "user",
+                "IsRegisteredWithLakeFormation": False,
+                "CatalogId": "123456789012",
+                "VersionId": "1",
+                "FederatedTable": {},
+            }
+        }
+
+        result = self.fg._get_iceberg_properties()
+
+        assert result["database_name"] == "test_db"
+        assert result["table_name"] == "test_table"
+        assert result["glue_client"] == mock_glue_client
+        # Verify stripped fields are not in table_input
+        for field in ["DatabaseName", "CreateTime", "UpdateTime", "CreatedBy",
+                      "IsRegisteredWithLakeFormation", "CatalogId", "VersionId", "FederatedTable"]:
+            assert field not in result["table_input"]
+        # Verify kept fields remain
+        assert result["table_input"]["Name"] == "test_table"
+        assert result["table_input"]["Parameters"] == {"table_type": "ICEBERG"}
+
+    def test_uses_provided_session_and_region(self):
+        """Test that provided session and region are used instead of defaults."""
+        mock_session = MagicMock()
+        mock_glue_client = MagicMock()
+        mock_session.client.return_value = mock_glue_client
+
+        mock_glue_client.get_table.return_value = {
+            "Table": {"Name": "test_table"}
+        }
+
+        result = self.fg._get_iceberg_properties(session=mock_session, region="eu-west-1")
+
+        mock_session.client.assert_called_once_with("glue", region_name="eu-west-1")
+
+    def test_uses_session_region_when_region_not_provided(self):
+        """Test that session.region_name is used when region is None."""
+        mock_session = MagicMock()
+        mock_session.region_name = "ap-southeast-1"
+        mock_glue_client = MagicMock()
+        mock_session.client.return_value = mock_glue_client
+
+        mock_glue_client.get_table.return_value = {
+            "Table": {"Name": "test_table"}
+        }
+
+        result = self.fg._get_iceberg_properties(session=mock_session)
+
+        mock_session.client.assert_called_once_with("glue", region_name="ap-southeast-1")
+
+    @patch("sagemaker.mlops.feature_store.feature_group_manager.Session")
+    def test_raises_runtime_error_on_client_error(self, mock_session_class):
+        """Test RuntimeError wrapping ClientError from Glue."""
+        mock_session = MagicMock()
+        mock_glue_client = MagicMock()
+        mock_session.client.return_value = mock_glue_client
+        mock_session_class.return_value = mock_session
+
+        mock_glue_client.get_table.side_effect = botocore.exceptions.ClientError(
+            {"Error": {"Code": "EntityNotFoundException", "Message": "Table not found"}},
+            "GetTable",
+        )
+
+        with pytest.raises(RuntimeError, match="Failed to update Iceberg properties"):
+            self.fg._get_iceberg_properties()
+
+
+class TestUpdateIcebergProperties:
+    """Tests for update_iceberg_properties method."""
+
+    def setup_method(self):
+        """Set up test fixtures."""
+        self.fg = MagicMock(spec=FeatureGroupManager)
+        self.fg._update_iceberg_properties = FeatureGroupManager._update_iceberg_properties.__get__(self.fg)
+        self.fg.feature_group_name = "test-fg"
+
+    def test_raises_error_when_iceberg_properties_is_none(self):
+        """Test ValueError when iceberg_properties is None."""
+        with pytest.raises(ValueError, match="must contain at least one property"):
+            self.fg._update_iceberg_properties(iceberg_properties=None)
+
+    def test_raises_error_when_properties_dict_is_empty(self):
+        """Test ValueError when properties dict is empty."""
+        props = IcebergProperties(properties={})
+
+        with pytest.raises(ValueError, match="must contain at least one property"):
+            self.fg._update_iceberg_properties(iceberg_properties=props)
+
+    def test_raises_error_when_properties_is_none_on_object(self):
+        """Test ValueError when IcebergProperties.properties is None."""
+        props = IcebergProperties()
+
+        with pytest.raises(ValueError, match="must contain at least one property"):
+            self.fg._update_iceberg_properties(iceberg_properties=props)
+
+    def test_successful_update_merges_properties(self):
+        """Test successful update merges properties and calls update_table."""
+        mock_glue_client = MagicMock()
+        self.fg._get_iceberg_properties.return_value = {
+            "database_name": "test_db",
+            "table_name": "test_table",
+            "table_input": {
+                "Name": "test_table",
+                "Parameters": {"table_type": "ICEBERG", "existing_key": "existing_value"},
+            },
+            "glue_client": mock_glue_client,
+        }
+
+        props = IcebergProperties(properties={"write.target-file-size-bytes": "536870912"})
+        result = self.fg._update_iceberg_properties(iceberg_properties=props)
+
+        # Verify update_table was called with merged parameters
+        call_args = mock_glue_client.update_table.call_args
+        updated_params = call_args[1]["TableInput"]["Parameters"]
+        assert updated_params["table_type"] == "ICEBERG"
+        assert updated_params["existing_key"] == "existing_value"
+        assert updated_params["write.target-file-size-bytes"] == "536870912"
+
+        assert result["database"] == "test_db"
+        assert result["table"] == "test_table"
+        assert result["properties_updated"] == props.properties
+
+    def test_creates_parameters_dict_when_missing(self):
+        """Test that Parameters dict is created when not present in table_input."""
+        mock_glue_client = MagicMock()
+        self.fg._get_iceberg_properties.return_value = {
+            "database_name": "test_db",
+            "table_name": "test_table",
+            "table_input": {"Name": "test_table"},
+            "glue_client": mock_glue_client,
+        }
+
+        props = IcebergProperties(properties={"key": "value"})
+        result = self.fg._update_iceberg_properties(iceberg_properties=props)
+
+        call_args = mock_glue_client.update_table.call_args
+        updated_params = call_args[1]["TableInput"]["Parameters"]
+        assert updated_params == {"key": "value"}
+
+    def test_raises_runtime_error_on_update_table_client_error(self):
+        """Test RuntimeError wrapping ClientError from Glue update_table."""
+        mock_glue_client = MagicMock()
+        self.fg._get_iceberg_properties.return_value = {
+            "database_name": "test_db",
+            "table_name": "test_table",
+            "table_input": {"Name": "test_table", "Parameters": {}},
+            "glue_client": mock_glue_client,
+        }
+        mock_glue_client.update_table.side_effect = botocore.exceptions.ClientError(
+            {"Error": {"Code": "AccessDeniedException", "Message": "Access denied"}},
+            "UpdateTable",
+        )
+
+        props = IcebergProperties(properties={"key": "value"})
+
+        with pytest.raises(RuntimeError, match="Failed to update Iceberg properties"):
+            self.fg._update_iceberg_properties(iceberg_properties=props)
+
+
+class TestCreateWithIcebergProperties:
+    """Tests for create() method with iceberg_properties parameter."""
+
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    @patch.object(FeatureGroupManager, "get")
+    def test_no_iceberg_operations_when_none(self, mock_get, mock_get_client):
+        """Test no iceberg operations when iceberg_properties is None."""
+        from sagemaker.core.shapes import FeatureDefinition
+
+        mock_client = MagicMock()
+        mock_client.create_feature_group.return_value = {
+            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test"
+        }
+        mock_get_client.return_value = mock_client
+
+        mock_fg = MagicMock(spec=FeatureGroupManager)
+        mock_get.return_value = mock_fg
+
+        feature_definitions = [
+            FeatureDefinition(feature_name="record_id", feature_type="String"),
+            FeatureDefinition(feature_name="event_time", feature_type="String"),
+        ]
+
+        FeatureGroupManager.create(
+            feature_group_name="test-fg",
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=feature_definitions,
+        )
+
+        mock_fg.wait_for_status.assert_not_called()
+        mock_fg._update_iceberg_properties.assert_not_called()
+
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    @patch.object(FeatureGroupManager, "get")
+    def test_no_iceberg_operations_when_properties_empty(self, mock_get, mock_get_client):
+        """Test no iceberg operations when iceberg_properties.properties is empty."""
+        from sagemaker.core.shapes import FeatureDefinition
+
+        mock_client = MagicMock()
+        mock_client.create_feature_group.return_value = {
+            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test"
+        }
+        mock_get_client.return_value = mock_client
+
+        mock_fg = MagicMock(spec=FeatureGroupManager)
+        mock_get.return_value = mock_fg
+
+        feature_definitions = [
+            FeatureDefinition(feature_name="record_id", feature_type="String"),
+            FeatureDefinition(feature_name="event_time", feature_type="String"),
+        ]
+
+        FeatureGroupManager.create(
+            feature_group_name="test-fg",
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=feature_definitions,
+            iceberg_properties=IcebergProperties(),
+        )
+
+        mock_fg._update_iceberg_properties.assert_not_called()
+
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_validation_error_without_offline_store_config(self, mock_get_client):
+        """Test ValueError when iceberg_properties provided without offline_store_config."""
+        from sagemaker.core.shapes import FeatureDefinition
+
+        mock_get_client.return_value = MagicMock()
+
+        feature_definitions = [
+            FeatureDefinition(feature_name="record_id", feature_type="String"),
+            FeatureDefinition(feature_name="event_time", feature_type="String"),
+        ]
+
+        with pytest.raises(ValueError, match="iceberg_properties requires offline_store_config"):
+            FeatureGroupManager.create(
+                feature_group_name="test-fg",
+                record_identifier_feature_name="record_id",
+                event_time_feature_name="event_time",
+                feature_definitions=feature_definitions,
+                iceberg_properties=IcebergProperties(properties={"key": "value"}),
+            )
+
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_validation_error_when_table_format_not_iceberg(self, mock_get_client):
+        """Test ValueError when table_format is not Iceberg."""
+        from sagemaker.core.shapes import FeatureDefinition, OfflineStoreConfig, S3StorageConfig
+
+        mock_get_client.return_value = MagicMock()
+
+        feature_definitions = [
+            FeatureDefinition(feature_name="record_id", feature_type="String"),
+            FeatureDefinition(feature_name="event_time", feature_type="String"),
+        ]
+
+        with pytest.raises(ValueError, match="table_format to be 'Iceberg'"):
+            FeatureGroupManager.create(
+                feature_group_name="test-fg",
+                record_identifier_feature_name="record_id",
+                event_time_feature_name="event_time",
+                feature_definitions=feature_definitions,
+                offline_store_config=OfflineStoreConfig(
+                    s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/path"),
+                ),
+                iceberg_properties=IcebergProperties(properties={"key": "value"}),
+            )
+
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_validation_error_when_table_format_is_glue(self, mock_get_client):
+        """Test ValueError when table_format is explicitly Glue."""
+        from sagemaker.core.shapes import FeatureDefinition, OfflineStoreConfig, S3StorageConfig
+
+        mock_get_client.return_value = MagicMock()
+
+        feature_definitions = [
+            FeatureDefinition(feature_name="record_id", feature_type="String"),
+            FeatureDefinition(feature_name="event_time", feature_type="String"),
+        ]
+
+        with pytest.raises(ValueError, match="table_format to be 'Iceberg'"):
+            FeatureGroupManager.create(
+                feature_group_name="test-fg",
+                record_identifier_feature_name="record_id",
+                event_time_feature_name="event_time",
+                feature_definitions=feature_definitions,
+                offline_store_config=OfflineStoreConfig(
+                    s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/path"),
+                    table_format="Glue",
+                ),
+                iceberg_properties=IcebergProperties(properties={"key": "value"}),
+            )
+
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    @patch.object(FeatureGroupManager, "get")
+    @patch.object(FeatureGroupManager, "wait_for_status")
+    @patch.object(FeatureGroupManager, "_update_iceberg_properties")
+    def test_update_called_after_create_with_properties(
+        self, mock_update, mock_wait, mock_get, mock_get_client
+    ):
+        """Test update_iceberg_properties called after create when properties provided."""
+        from sagemaker.core.shapes import (
+            FeatureDefinition,
+            OfflineStoreConfig,
+            S3StorageConfig,
+            DataCatalogConfig,
+        )
+
+        mock_client = MagicMock()
+        mock_client.create_feature_group.return_value = {
+            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test"
+        }
+        mock_get_client.return_value = mock_client
+
+        mock_fg = MagicMock(spec=FeatureGroupManager)
+        mock_fg.wait_for_status = mock_wait
+        mock_fg._update_iceberg_properties = mock_update
+        mock_get.return_value = mock_fg
+
+        feature_definitions = [
+            FeatureDefinition(feature_name="record_id", feature_type="String"),
+            FeatureDefinition(feature_name="event_time", feature_type="String"),
+        ]
+
+        iceberg_props = IcebergProperties(properties={"write.target-file-size-bytes": "536870912"})
+
+        result = FeatureGroupManager.create(
+            feature_group_name="test-fg",
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=feature_definitions,
+            offline_store_config=OfflineStoreConfig(
+                s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/path"),
+                data_catalog_config=DataCatalogConfig(
+                    catalog="AwsDataCatalog", database="test_db", table_name="test_table"
+                ),
+                table_format="Iceberg",
+            ),
+            iceberg_properties=iceberg_props,
+        )
+
+        # Verify wait_for_status called before update
+        mock_wait.assert_called_once_with(target_status="Created")
+        mock_update.assert_called_once_with(
+            iceberg_properties=iceberg_props,
+            session=None,
+            region=None,
+        )
+        assert result == mock_fg
+
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    @patch.object(FeatureGroupManager, "get")
+    @patch.object(FeatureGroupManager, "wait_for_status")
+    @patch.object(FeatureGroupManager, "_update_iceberg_properties")
+    def test_create_passes_session_and_region_to_update(
+        self, mock_update, mock_wait, mock_get, mock_get_client
+    ):
+        """Test that session and region are forwarded to _update_iceberg_properties."""
+        from sagemaker.core.shapes import (
+            FeatureDefinition,
+            OfflineStoreConfig,
+            S3StorageConfig,
+            DataCatalogConfig,
+        )
+
+        mock_client = MagicMock()
+        mock_client.create_feature_group.return_value = {
+            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test"
+        }
+        mock_get_client.return_value = mock_client
+
+        mock_fg = MagicMock(spec=FeatureGroupManager)
+        mock_fg.wait_for_status = mock_wait
+        mock_fg._update_iceberg_properties = mock_update
+        mock_get.return_value = mock_fg
+
+        mock_session = MagicMock(spec=Session)
+        iceberg_props = IcebergProperties(properties={"key": "val"})
+
+        FeatureGroupManager.create(
+            feature_group_name="test-fg",
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=[
+                FeatureDefinition(feature_name="record_id", feature_type="String"),
+                FeatureDefinition(feature_name="event_time", feature_type="String"),
+            ],
+            offline_store_config=OfflineStoreConfig(
+                s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/path"),
+                data_catalog_config=DataCatalogConfig(
+                    catalog="AwsDataCatalog", database="db", table_name="tbl"
+                ),
+                table_format="Iceberg",
+            ),
+            iceberg_properties=iceberg_props,
+            session=mock_session,
+            region="eu-west-1",
+        )
+
+        mock_update.assert_called_once_with(
+            iceberg_properties=iceberg_props,
+            session=mock_session,
+            region="eu-west-1",
+        )
+
+
+class TestUpdateWithIcebergProperties:
+    """Tests for update() method with iceberg_properties parameter."""
+
+    @patch.object(FeatureGroupManager, "_update_iceberg_properties")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_no_iceberg_operations_when_none(self, mock_get_client, mock_refresh, mock_update_iceberg):
+        """Test no iceberg operations when iceberg_properties is None."""
+        mock_client = MagicMock()
+        mock_client.update_feature_group.return_value = {}
+        mock_get_client.return_value = mock_client
+
+        fg = FeatureGroupManager(feature_group_name="test-fg")
+        fg.update(description="new description")
+
+        mock_update_iceberg.assert_not_called()
+
+    @patch.object(FeatureGroupManager, "_update_iceberg_properties")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_no_iceberg_operations_when_properties_empty(self, mock_get_client, mock_refresh, mock_update_iceberg):
+        """Test no iceberg operations when iceberg_properties.properties is None."""
+        mock_client = MagicMock()
+        mock_client.update_feature_group.return_value = {}
+        mock_get_client.return_value = mock_client
+
+        fg = FeatureGroupManager(feature_group_name="test-fg")
+        fg.update(iceberg_properties=IcebergProperties())
+
+        mock_update_iceberg.assert_not_called()
+
+    @patch.object(FeatureGroupManager, "_update_iceberg_properties")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_iceberg_update_called_with_properties(self, mock_get_client, mock_refresh, mock_update_iceberg):
+        """Test _update_iceberg_properties called when properties provided."""
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        mock_client = MagicMock()
+        mock_client.update_feature_group.return_value = {}
+        mock_get_client.return_value = mock_client
+
+        fg = FeatureGroupManager(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/path"),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="db", table_name="tbl"
+            ),
+            table_format="Iceberg",
+        )
+        iceberg_props = IcebergProperties(properties={"write.target-file-size-bytes": "536870912"})
+        fg.update(description="new description", iceberg_properties=iceberg_props, session=None, region=None)
+
+        mock_update_iceberg.assert_called_once_with(
+            iceberg_properties=iceberg_props,
+            session=None,
+            region=None,
+        )
+
+    @patch.object(FeatureGroupManager, "_update_iceberg_properties")
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_parent_update_receives_only_standard_params(self, mock_get_client, mock_refresh, mock_update_iceberg):
+        """Test that iceberg_properties is not passed to the parent update()."""
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
+
+        mock_client = MagicMock()
+        mock_client.update_feature_group.return_value = {}
+        mock_get_client.return_value = mock_client
+
+        fg = FeatureGroupManager(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/path"),
+            data_catalog_config=DataCatalogConfig(
+                catalog="AwsDataCatalog", database="db", table_name="tbl"
+            ),
+            table_format="Iceberg",
+        )
+        fg.update(
+            description="new desc",
+            iceberg_properties=IcebergProperties(properties={"key": "val"}),
+        )
+
+        # Verify the SageMaker API call does NOT contain iceberg_properties
+        call_args = mock_client.update_feature_group.call_args
+        assert "IcebergProperties" not in call_args[1]
+        assert "Description" in call_args[1]
+
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_validation_error_when_no_offline_store(self, mock_get_client, mock_refresh):
+        """Test ValueError when iceberg_properties provided without offline_store_config."""
+        mock_client = MagicMock()
+        mock_client.update_feature_group.return_value = {}
+        mock_get_client.return_value = mock_client
+
+        fg = FeatureGroupManager(feature_group_name="test-fg")
+        fg.offline_store_config = None
+
+        with pytest.raises(ValueError, match="iceberg_properties requires offline_store_config"):
+            fg.update(iceberg_properties=IcebergProperties(properties={"key": "val"}))
+
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_validation_error_when_offline_store_is_unassigned(self, mock_get_client, mock_refresh):
+        """Test ValueError when offline_store_config is Unassigned()."""
+        from sagemaker.core.shapes import Unassigned
+
+        mock_client = MagicMock()
+        mock_client.update_feature_group.return_value = {}
+        mock_get_client.return_value = mock_client
+
+        fg = FeatureGroupManager(feature_group_name="test-fg")
+        object.__setattr__(fg, "offline_store_config", Unassigned())
+
+        with pytest.raises(ValueError, match="iceberg_properties requires offline_store_config"):
+            fg.update(iceberg_properties=IcebergProperties(properties={"key": "val"}))
+
+    @patch.object(FeatureGroupManager, "refresh")
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_validation_error_when_table_format_not_iceberg(self, mock_get_client, mock_refresh):
+        """Test ValueError when table_format is not Iceberg."""
+        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig
+
+        mock_client = MagicMock()
+        mock_client.update_feature_group.return_value = {}
+        mock_get_client.return_value = mock_client
+
+        fg = FeatureGroupManager(feature_group_name="test-fg")
+        fg.offline_store_config = OfflineStoreConfig(
+            s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/path"),
+            table_format="Glue",
+        )
+
+        with pytest.raises(ValueError, match="table_format to be 'Iceberg'"):
+            fg.update(iceberg_properties=IcebergProperties(properties={"key": "val"}))
+
+
+class TestGetWithIcebergProperties:
+    """Tests for get() method with include_iceberg_properties flag."""
+
+    @patch.object(FeatureGroupManager, "_get_iceberg_properties")
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_no_iceberg_fetch_by_default(self, mock_get_client, mock_get_iceberg):
+        """Test that Iceberg properties are not fetched when flag is False (default)."""
+        from sagemaker.core.shapes import FeatureDefinition
+
+        mock_client = MagicMock()
+        mock_client.describe_feature_group.return_value = {
+            "FeatureGroupName": "test-fg",
+            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg",
+            "RecordIdentifierFeatureName": "record_id",
+            "EventTimeFeatureName": "event_time",
+            "FeatureDefinitions": [
+                {"FeatureName": "record_id", "FeatureType": "String"},
+            ],
+            "CreationTime": "2024-01-01T00:00:00Z",
+        }
+        mock_get_client.return_value = mock_client
+
+        result = FeatureGroupManager.get(feature_group_name="test-fg")
+
+        mock_get_iceberg.assert_not_called()
+
+    @patch.object(FeatureGroupManager, "_get_iceberg_properties")
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_iceberg_properties_fetched_when_flag_true(self, mock_get_client, mock_get_iceberg):
+        """Test that Iceberg properties are fetched and stored when flag is True."""
+        mock_client = MagicMock()
+        mock_client.describe_feature_group.return_value = {
+            "FeatureGroupName": "test-fg",
+            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg",
+            "RecordIdentifierFeatureName": "record_id",
+            "EventTimeFeatureName": "event_time",
+            "FeatureDefinitions": [
+                {"FeatureName": "record_id", "FeatureType": "String"},
+            ],
+            "CreationTime": "2024-01-01T00:00:00Z",
+        }
+        mock_get_client.return_value = mock_client
+
+        mock_get_iceberg.return_value = {
+            "database_name": "test_db",
+            "table_name": "test_table",
+            "table_input": {
+                "Parameters": {
+                    "table_type": "ICEBERG",
+                    "write.target-file-size-bytes": "536870912",
+                },
+            },
+            "glue_client": MagicMock(),
+        }
+
+        result = FeatureGroupManager.get(
+            feature_group_name="test-fg",
+            include_iceberg_properties=True,
+        )
+
+        mock_get_iceberg.assert_called_once_with(session=None, region=None)
+        assert result.iceberg_properties.properties == {
+            "table_type": "ICEBERG",
+            "write.target-file-size-bytes": "536870912",
+        }
+
+    @patch.object(FeatureGroupManager, "_get_iceberg_properties")
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_iceberg_properties_empty_parameters(self, mock_get_client, mock_get_iceberg):
+        """Test that empty Parameters dict results in empty properties."""
+        mock_client = MagicMock()
+        mock_client.describe_feature_group.return_value = {
+            "FeatureGroupName": "test-fg",
+            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg",
+            "RecordIdentifierFeatureName": "record_id",
+            "EventTimeFeatureName": "event_time",
+            "FeatureDefinitions": [
+                {"FeatureName": "record_id", "FeatureType": "String"},
+            ],
+            "CreationTime": "2024-01-01T00:00:00Z",
+        }
+        mock_get_client.return_value = mock_client
+
+        mock_get_iceberg.return_value = {
+            "database_name": "test_db",
+            "table_name": "test_table",
+            "table_input": {},
+            "glue_client": MagicMock(),
+        }
+
+        result = FeatureGroupManager.get(
+            feature_group_name="test-fg",
+            include_iceberg_properties=True,
+        )
+
+        assert result.iceberg_properties.properties == {}
+
+    @patch.object(FeatureGroupManager, "_get_iceberg_properties")
+    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
+    def test_passes_session_and_region_to_get_iceberg_properties(self, mock_get_client, mock_get_iceberg):
+        """Test that session and region kwargs are forwarded to _get_iceberg_properties."""
+        mock_client = MagicMock()
+        mock_client.describe_feature_group.return_value = {
+            "FeatureGroupName": "test-fg",
+            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg",
+            "RecordIdentifierFeatureName": "record_id",
+            "EventTimeFeatureName": "event_time",
+            "FeatureDefinitions": [
+                {"FeatureName": "record_id", "FeatureType": "String"},
+            ],
+            "CreationTime": "2024-01-01T00:00:00Z",
+        }
+        mock_get_client.return_value = mock_client
+
+        mock_session = MagicMock(spec=Session)
+        mock_get_iceberg.return_value = {
+            "database_name": "test_db",
+            "table_name": "test_table",
+            "table_input": {"Parameters": {"key": "val"}},
+            "glue_client": MagicMock(),
+        }
+
+        FeatureGroupManager.get(
+            feature_group_name="test-fg",
+            include_iceberg_properties=True,
+            session=mock_session,
+            region="us-east-1",
+        )
+
+        mock_get_iceberg.assert_called_once_with(session=mock_session, region="us-east-1")

From dd539114e8e16e5935c19d95200392a0e8264cf6 Mon Sep 17 00:00:00 2001
From: Alexander Young <youngag@amazon.com>
Date: Thu, 19 Mar 2026 21:43:03 +0000
Subject: [PATCH 15/22] Added validation of IcebergProperties with valid list

---
 .../feature_store/feature_group_manager.py    | 14 +++++
 .../mlops/feature_store/feature_utils.py      | 20 +++++++
 .../feature_store/test_iceberg_properties.py  | 59 ++++++++++++++-----
 3 files changed, 79 insertions(+), 14 deletions(-)

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
index 5e01d104a4..8856fdf5ea 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
@@ -7,6 +7,7 @@
 from typing import Dict, List, Optional
 
 import botocore.exceptions
+from pydantic import model_validator
 
 from sagemaker.core.resources import FeatureGroup
 from sagemaker.core.resources import Base
@@ -25,6 +26,7 @@
 from sagemaker.core.s3.utils import parse_s3_url
 from sagemaker.core.common_utils import aws_partition
 from boto3 import Session
+from sagemaker.mlops.feature_store.feature_utils import _APPROVED_ICEBERG_PROPERTIES
 
 
 logger = logging.getLogger(__name__)
@@ -46,6 +48,18 @@ class IcebergProperties(Base):
 
     properties: Optional[Dict[str, str]] = None
 
+    @model_validator(mode="after")
+    def validate_property_keys(self):
+        if self.properties is None:
+            return self
+        invalid_keys = set(self.properties.keys()) - _APPROVED_ICEBERG_PROPERTIES
+        if invalid_keys:
+            raise ValueError(
+                f"Invalid iceberg properties: {invalid_keys}. "
+                f"Approved properties are: {_APPROVED_ICEBERG_PROPERTIES}"
+            )
+        return self
+
 
 class LakeFormationConfig(Base):
     """Configuration for Lake Formation governance on Feature Group offline stores.
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py
index 5ee04780be..a809b0a8f3 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py
@@ -49,6 +49,26 @@
 _INTEGER_TYPES = {"int_", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64"}
 _FLOAT_TYPES = {"float_", "float16", "float32", "float64"}
 
+_APPROVED_ICEBERG_PROPERTIES = {
+    "write.metadata.delete-after-commit.enabled",
+    "write.metadata.previous-versions-max",
+    "history.expire.max-snapshot-age-ms",
+    "history.expire.min-snapshots-to-keep",
+    "write.parquet.row-group-size-bytes",
+    "read.split.target-size",
+    "read.split.metadata-target-size",
+    "write.delete.target-file-size-bytes",
+    "write.delete.mode",
+    "write.update.mode",
+    "write.delete.granularity",
+    "write.delete.isolation-level",
+    "write.update.isolation-level",
+    "write.merge.isolation-level",
+    "history.expire.max-ref-age-ms",
+    "read.split.open-file-cost",
+    "write.target-file-size-bytes"
+}
+
 
 def _get_athena_client(session: Session):
     """Get Athena client from session."""
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py
index 861edd73ea..ceaae90ce0 100644
--- a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py
@@ -23,6 +23,39 @@ def test_properties_can_be_set(self):
         config = IcebergProperties(properties=props)
         assert config.properties == props
 
+    def test_valid_approved_keys_accepted(self):
+        """Test that all approved keys are accepted."""
+        props = {
+            "write.target-file-size-bytes": "536870912",
+            "write.metadata.delete-after-commit.enabled": "true",
+            "history.expire.max-snapshot-age-ms": "432000000",
+        }
+        config = IcebergProperties(properties=props)
+        assert config.properties == props
+
+    def test_single_invalid_key_raises_error(self):
+        """Test that a single invalid key raises ValueError."""
+        with pytest.raises(ValueError, match="Invalid iceberg properties"):
+            IcebergProperties(properties={"not.a.valid.key": "value"})
+
+    def test_multiple_invalid_keys_raises_error(self):
+        """Test that multiple invalid keys raise ValueError."""
+        with pytest.raises(ValueError, match="Invalid iceberg properties"):
+            IcebergProperties(properties={"bad.key.one": "1", "bad.key.two": "2"})
+
+    def test_mix_valid_and_invalid_keys_raises_error(self):
+        """Test that a mix of valid and invalid keys raises ValueError."""
+        with pytest.raises(ValueError, match="Invalid iceberg properties"):
+            IcebergProperties(properties={
+                "write.target-file-size-bytes": "536870912",
+                "invalid.key": "value",
+            })
+
+    def test_error_message_contains_invalid_key_names(self):
+        """Test that the error message includes the invalid key names."""
+        with pytest.raises(ValueError, match="fake.property"):
+            IcebergProperties(properties={"fake.property": "value"})
+
 
 class TestGetIcebergProperties:
     """Tests for get_iceberg_properties method."""
@@ -219,12 +252,12 @@ def test_creates_parameters_dict_when_missing(self):
             "glue_client": mock_glue_client,
         }
 
-        props = IcebergProperties(properties={"key": "value"})
+        props = IcebergProperties(properties={"write.target-file-size-bytes": "value"})
         result = self.fg._update_iceberg_properties(iceberg_properties=props)
 
         call_args = mock_glue_client.update_table.call_args
         updated_params = call_args[1]["TableInput"]["Parameters"]
-        assert updated_params == {"key": "value"}
+        assert updated_params == {"write.target-file-size-bytes": "value"}
 
     def test_raises_runtime_error_on_update_table_client_error(self):
         """Test RuntimeError wrapping ClientError from Glue update_table."""
@@ -240,7 +273,7 @@ def test_raises_runtime_error_on_update_table_client_error(self):
             "UpdateTable",
         )
 
-        props = IcebergProperties(properties={"key": "value"})
+        props = IcebergProperties(properties={"write.target-file-size-bytes": "value"})
 
         with pytest.raises(RuntimeError, match="Failed to update Iceberg properties"):
             self.fg._update_iceberg_properties(iceberg_properties=props)
@@ -327,7 +360,7 @@ def test_validation_error_without_offline_store_config(self, mock_get_client):
                 record_identifier_feature_name="record_id",
                 event_time_feature_name="event_time",
                 feature_definitions=feature_definitions,
-                iceberg_properties=IcebergProperties(properties={"key": "value"}),
+                iceberg_properties=IcebergProperties(properties={"write.target-file-size-bytes": "value"}),
             )
 
     @patch("sagemaker.core.resources.Base.get_sagemaker_client")
@@ -351,7 +384,7 @@ def test_validation_error_when_table_format_not_iceberg(self, mock_get_client):
                 offline_store_config=OfflineStoreConfig(
                     s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/path"),
                 ),
-                iceberg_properties=IcebergProperties(properties={"key": "value"}),
+                iceberg_properties=IcebergProperties(properties={"write.target-file-size-bytes": "value"}),
             )
 
     @patch("sagemaker.core.resources.Base.get_sagemaker_client")
@@ -376,7 +409,7 @@ def test_validation_error_when_table_format_is_glue(self, mock_get_client):
                     s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/path"),
                     table_format="Glue",
                 ),
-                iceberg_properties=IcebergProperties(properties={"key": "value"}),
+                iceberg_properties=IcebergProperties(properties={"write.target-file-size-bytes": "value"}),
             )
 
     @patch("sagemaker.core.resources.Base.get_sagemaker_client")
@@ -463,7 +496,7 @@ def test_create_passes_session_and_region_to_update(
         mock_get.return_value = mock_fg
 
         mock_session = MagicMock(spec=Session)
-        iceberg_props = IcebergProperties(properties={"key": "val"})
+        iceberg_props = IcebergProperties(properties={"write.target-file-size-bytes": "val"})
 
         FeatureGroupManager.create(
             feature_group_name="test-fg",
@@ -572,7 +605,7 @@ def test_parent_update_receives_only_standard_params(self, mock_get_client, mock
         )
         fg.update(
             description="new desc",
-            iceberg_properties=IcebergProperties(properties={"key": "val"}),
+            iceberg_properties=IcebergProperties(properties={"write.target-file-size-bytes": "val"}),
         )
 
         # Verify the SageMaker API call does NOT contain iceberg_properties
@@ -592,7 +625,7 @@ def test_validation_error_when_no_offline_store(self, mock_get_client, mock_refr
         fg.offline_store_config = None
 
         with pytest.raises(ValueError, match="iceberg_properties requires offline_store_config"):
-            fg.update(iceberg_properties=IcebergProperties(properties={"key": "val"}))
+            fg.update(iceberg_properties=IcebergProperties(properties={"write.target-file-size-bytes": "val"}))
 
     @patch.object(FeatureGroupManager, "refresh")
     @patch("sagemaker.core.resources.Base.get_sagemaker_client")
@@ -608,7 +641,7 @@ def test_validation_error_when_offline_store_is_unassigned(self, mock_get_client
         object.__setattr__(fg, "offline_store_config", Unassigned())
 
         with pytest.raises(ValueError, match="iceberg_properties requires offline_store_config"):
-            fg.update(iceberg_properties=IcebergProperties(properties={"key": "val"}))
+            fg.update(iceberg_properties=IcebergProperties(properties={"write.target-file-size-bytes": "val"}))
 
     @patch.object(FeatureGroupManager, "refresh")
     @patch("sagemaker.core.resources.Base.get_sagemaker_client")
@@ -627,7 +660,7 @@ def test_validation_error_when_table_format_not_iceberg(self, mock_get_client, m
         )
 
         with pytest.raises(ValueError, match="table_format to be 'Iceberg'"):
-            fg.update(iceberg_properties=IcebergProperties(properties={"key": "val"}))
+            fg.update(iceberg_properties=IcebergProperties(properties={"write.target-file-size-bytes": "val"}))
 
 
 class TestGetWithIcebergProperties:
@@ -678,7 +711,6 @@ def test_iceberg_properties_fetched_when_flag_true(self, mock_get_client, mock_g
             "table_name": "test_table",
             "table_input": {
                 "Parameters": {
-                    "table_type": "ICEBERG",
                     "write.target-file-size-bytes": "536870912",
                 },
             },
@@ -692,7 +724,6 @@ def test_iceberg_properties_fetched_when_flag_true(self, mock_get_client, mock_g
 
         mock_get_iceberg.assert_called_once_with(session=None, region=None)
         assert result.iceberg_properties.properties == {
-            "table_type": "ICEBERG",
             "write.target-file-size-bytes": "536870912",
         }
 
@@ -748,7 +779,7 @@ def test_passes_session_and_region_to_get_iceberg_properties(self, mock_get_clie
         mock_get_iceberg.return_value = {
             "database_name": "test_db",
             "table_name": "test_table",
-            "table_input": {"Parameters": {"key": "val"}},
+            "table_input": {"Parameters": {"write.target-file-size-bytes": "val"}},
             "glue_client": MagicMock(),
         }
 

From 78b5bda73e84fab00b5287f0780fb3e0403cdcd8 Mon Sep 17 00:00:00 2001
From: Alexander Young <youngag@amazon.com>
Date: Tue, 24 Mar 2026 22:04:58 +0000
Subject: [PATCH 16/22] Added checking of only approved iceberg properties

---
 .../sagemaker/mlops/feature_store/feature_group_manager.py | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
index 8856fdf5ea..8828b5bbb1 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
@@ -807,6 +807,13 @@ def _update_iceberg_properties(
                 "iceberg_properties must contain at least one property to update"
             )
 
+        invalid_keys = set(iceberg_properties.properties.keys()) - _APPROVED_ICEBERG_PROPERTIES
+        if invalid_keys:
+            raise ValueError(
+                f"Invalid iceberg properties: {invalid_keys}. "
+                f"Approved properties are: {_APPROVED_ICEBERG_PROPERTIES}"
+            )
+
         result = self._get_iceberg_properties(session=session, region=region)
         database_name = result["database_name"]
         table_name = result["table_name"]

From 320e14fc34d4997c963adcb30202f3c831a8dd25 Mon Sep 17 00:00:00 2001
From: Alexander Young <youngag@amazon.com>
Date: Mon, 30 Mar 2026 17:56:40 +0000
Subject: [PATCH 17/22] Added checking of duplicate iceberg properties

---
 .../sagemaker/mlops/feature_store/feature_group_manager.py   | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
index 8828b5bbb1..15717a1095 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
@@ -58,6 +58,11 @@ def validate_property_keys(self):
                 f"Invalid iceberg properties: {invalid_keys}. "
                 f"Approved properties are: {_APPROVED_ICEBERG_PROPERTIES}"
             )
+        # Check for no duplicate keys
+        if len(set(self.properties.keys())) != len(self.properties.keys()):
+            raise ValueError(
+                f"Invalide duplicate properties. Please only have 1 of each property."
+            )
         return self
 
 

From 6d41abd6d4bae1de86c4821ec7a85e5b93c27a3f Mon Sep 17 00:00:00 2001
From: Alexander Young <youngag@amazon.com>
Date: Mon, 30 Mar 2026 18:15:15 +0000
Subject: [PATCH 18/22] Added additional checking of duplicate iceberg
 properties and testing

---
 .../feature_store/feature_group_manager.py    |  8 ++++-
 .../feature_store/test_iceberg_properties.py  | 32 +++++++++++++++++++
 2 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
index 15717a1095..4e66e6c16b 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
@@ -61,7 +61,7 @@ def validate_property_keys(self):
         # Check for no duplicate keys
         if len(set(self.properties.keys())) != len(self.properties.keys()):
             raise ValueError(
-                f"Invalide duplicate properties. Please only have 1 of each property."
+                f"Invalid duplicate properties. Please only have 1 of each property."
             )
         return self
 
@@ -819,6 +819,12 @@ def _update_iceberg_properties(
                 f"Approved properties are: {_APPROVED_ICEBERG_PROPERTIES}"
             )
 
+         # Check for no duplicate keys
+        if len(set(iceberg_properties.properties.keys())) != len(iceberg_properties.properties.keys()):
+            raise ValueError(
+                f"Invalid duplicate properties. Please only have 1 of each property."
+            )
+
         result = self._get_iceberg_properties(session=session, region=region)
         database_name = result["database_name"]
         table_name = result["table_name"]
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py
index ceaae90ce0..586f5e9161 100644
--- a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py
@@ -56,6 +56,24 @@ def test_error_message_contains_invalid_key_names(self):
         with pytest.raises(ValueError, match="fake.property"):
             IcebergProperties(properties={"fake.property": "value"})
 
+    def test_duplicate_keys_raises_error(self):
+        """Test that duplicate property keys raise ValueError."""
+        config = IcebergProperties(properties={"write.target-file-size-bytes": "536870912"})
+        mock_props = MagicMock()
+        mock_props.keys.return_value = [
+            "write.target-file-size-bytes",
+            "write.target-file-size-bytes",
+        ]
+        object.__setattr__(config, "properties", mock_props)
+        with pytest.raises(ValueError, match="Invalid duplicate properties"):
+            config.validate_property_keys()
+
+    def test_no_duplicate_keys_passes(self):
+        """Test that unique approved keys pass duplicate validation."""
+        config = IcebergProperties(properties={"write.target-file-size-bytes": "536870912"})
+        result = config.validate_property_keys()
+        assert result is config
+
 
 class TestGetIcebergProperties:
     """Tests for get_iceberg_properties method."""
@@ -278,6 +296,20 @@ def test_raises_runtime_error_on_update_table_client_error(self):
         with pytest.raises(RuntimeError, match="Failed to update Iceberg properties"):
             self.fg._update_iceberg_properties(iceberg_properties=props)
 
+    def test_raises_error_on_duplicate_keys(self):
+        """Test ValueError when iceberg_properties has duplicate keys."""
+        props = IcebergProperties(properties={"write.target-file-size-bytes": "536870912"})
+        mock_props = MagicMock()
+        mock_props.keys.return_value = [
+            "write.target-file-size-bytes",
+            "write.target-file-size-bytes",
+        ]
+        mock_props.__bool__ = lambda self: True
+        object.__setattr__(props, "properties", mock_props)
+
+        with pytest.raises(ValueError, match="Invalid duplicate properties"):
+            self.fg._update_iceberg_properties(iceberg_properties=props)
+
 
 class TestCreateWithIcebergProperties:
     """Tests for create() method with iceberg_properties parameter."""

From f0c84e3eab02a2975eac958a9a193d277fb6e495 Mon Sep 17 00:00:00 2001
From: Alexander Young <youngag@amazon.com>
Date: Tue, 31 Mar 2026 19:09:43 +0000
Subject: [PATCH 19/22] Removed excess LakeFormation code to isolate Iceberg
 Properties change

---
 .../sagemaker/mlops/feature_store/__init__.py |   5 +-
 .../feature_store/feature_group_manager.py    | 640 -------------
 .../integ/test_featureStore_lakeformation.py  | 654 --------------
 .../test_feature_store_iceberg_properties.py  | 229 +++++
 .../mlops/feature_store/test_athena_query.py  | 114 ---
 .../FS-lakeformation-cross-account.ipynb      | 580 ------------
 .../imgs/fs-lf-cross-account1.png             | Bin 476328 -> 0 bytes
 .../v3-feature-store-lake-formation.ipynb     | 851 ------------------
 8 files changed, 231 insertions(+), 2842 deletions(-)
 delete mode 100644 sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py
 create mode 100644 sagemaker-mlops/tests/integ/test_feature_store_iceberg_properties.py
 delete mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_athena_query.py
 delete mode 100644 v3-examples/ml-ops-examples/FS-lakeformation-cross-account.ipynb
 delete mode 100644 v3-examples/ml-ops-examples/imgs/fs-lf-cross-account1.png
 delete mode 100644 v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
index 36494f0d79..ad75442185 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py
@@ -2,9 +2,9 @@
 # Licensed under the Apache License, Version 2.0
 """SageMaker FeatureStore V3 - powered by sagemaker-core."""
 
-# FeatureGroup with Lake Formation support (local subclass)
+# FeatureGroup with additional operational support
 from sagemaker.core.resources import FeatureGroup, FeatureMetadata
-from sagemaker.mlops.feature_store.feature_group_manager import FeatureGroupManager, LakeFormationConfig
+from sagemaker.mlops.feature_store.feature_group_manager import FeatureGroupManager
 
 # Resources from core
 from sagemaker.core.resources import FeatureMetadata
@@ -84,7 +84,6 @@
     "FeatureParameter",
     "FeatureValue",
     "Filter",
-    "LakeFormationConfig",
     "OfflineStoreConfig",
     "OnlineStoreConfig",
     "OnlineStoreSecurityConfig",
diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
index 4e66e6c16b..30a22593cc 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
@@ -66,34 +66,6 @@ def validate_property_keys(self):
         return self
 
 
-class LakeFormationConfig(Base):
-    """Configuration for Lake Formation governance on Feature Group offline stores.
-
-    Attributes:
-        enabled: If True, enables Lake Formation governance for the offline store.
-            Requires offline_store_config and role_arn to be set on the Feature Group.
-        use_service_linked_role: Whether to use the Lake Formation service-linked role
-            for S3 registration. If True, Lake Formation uses its service-linked role.
-            If False, registration_role_arn must be provided. Default is True.
-        registration_role_arn: IAM role ARN to use for S3 registration with Lake Formation.
-            Required when use_service_linked_role is False. This can be different from the
-            Feature Group's execution role.
-        show_s3_policy: If True, prints the S3 deny policy to the console after successful
-            Lake Formation setup. This policy should be added to your S3 bucket to restrict
-            access to only the allowed principals. Default is False.
-        disable_hybrid_access_mode: If True, revokes IAMAllowedPrincipal permissions from
-            the Glue table, moving it to Lake Formation-only access mode. If False, keeps
-            hybrid access mode where both IAM and Lake Formation control access.
-            Default is True (LF-only mode).
-    """
-
-    enabled: bool = False
-    use_service_linked_role: bool = True
-    registration_role_arn: Optional[str] = None
-    show_s3_policy: bool = False
-    disable_hybrid_access_mode: bool = True
-
-
 class FeatureGroupManager(FeatureGroup):
 
     # Attribute for Iceberg table properties (populated by get() when include_iceberg_properties=True)
@@ -103,586 +75,6 @@ class FeatureGroupManager(FeatureGroup):
     if FeatureGroup.__doc__ and __doc__:
         __doc__ = FeatureGroup.__doc__
 
-    @staticmethod
-    def _s3_uri_to_arn(s3_uri: str, region: Optional[str] = None) -> str:
-        """
-        Convert S3 URI to S3 ARN format for Lake Formation.
-
-        Args:
-            s3_uri: S3 URI in format s3://bucket/path or already an ARN
-            region: AWS region name (e.g., 'us-west-2'). Used to determine the correct
-                partition for the ARN. If not provided, defaults to 'aws' partition.
-
-        Returns:
-            S3 ARN in format arn:{partition}:s3:::bucket/path
-
-        Note:
-            This format is specifically used for Lake Formation resource registration.
-            The triple colon (:::) after 's3' is correct - S3 ARNs don't include
-            region or account ID fields.
-        """
-        if s3_uri.startswith("arn:"):
-            return s3_uri
-        
-        # Determine partition based on region
-        partition = aws_partition(region) if region else "aws"
-        
-        bucket, key = parse_s3_url(s3_uri)
-        # Reconstruct as ARN - key may be empty string
-        s3_path = f"{bucket}/{key}" if key else bucket
-        return f"arn:{partition}:s3:::{s3_path}"
-
-    @staticmethod
-    def _extract_account_id_from_arn(arn: str) -> str:
-        """
-        Extract AWS account ID from an ARN.
-
-        Args:
-            arn: AWS ARN in format arn:aws:service:region:account:resource
-
-        Returns:
-            AWS account ID (the 5th colon-separated field)
-
-        Raises:
-            ValueError: If ARN format is invalid (fewer than 5 colon-separated parts)
-        """
-        parts = arn.split(":")
-        if len(parts) < 5:
-            raise ValueError(f"Invalid ARN format: {arn}")
-        return parts[4]
-
-    @staticmethod
-    def _get_lake_formation_service_linked_role_arn(
-        account_id: str, region: Optional[str] = None
-    ) -> str:
-        """
-        Generate the Lake Formation service-linked role ARN for an account.
-
-        Args:
-            account_id: AWS account ID
-            region: AWS region name (e.g., 'us-west-2'). Used to determine the correct
-                partition for the ARN. If not provided, defaults to 'aws' partition.
-
-        Returns:
-            Lake Formation service-linked role ARN in format:
-            arn:{partition}:iam::{account}:role/aws-service-role/lakeformation.amazonaws.com/
-            AWSServiceRoleForLakeFormationDataAccess
-        """
-        partition = aws_partition(region) if region else "aws"
-        return (
-            f"arn:{partition}:iam::{account_id}:role/aws-service-role/"
-            f"lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess"
-        )
-
-    def _generate_s3_deny_policy(
-        self,
-        bucket_name: str,
-        s3_prefix: str,
-        lake_formation_role_arn: str,
-        feature_store_role_arn: str,
-        region: Optional[str] = None,
-    ) -> dict:
-        """
-        Generate an S3 deny policy for Lake Formation governance.
-
-        This policy denies S3 access to the offline store data prefix except for
-        the Lake Formation role and Feature Store execution role.
-
-        Args:
-            bucket_name: S3 bucket name.
-            s3_prefix: S3 prefix path (without bucket name).
-            lake_formation_role_arn: Lake Formation registration role ARN.
-            feature_store_role_arn: Feature Store execution role ARN.
-            region: AWS region name (e.g., 'us-west-2'). Used to determine the correct
-                partition for S3 ARNs. If not provided, defaults to 'aws' partition.
-
-        Returns:
-            S3 bucket policy as a dict with valid JSON structure containing:
-            - Version: "2012-10-17"
-            - Statement: List with two deny statements:
-              1. Deny GetObject, PutObject, DeleteObject on data prefix except allowed principals
-              2. Deny ListBucket on bucket with prefix condition except allowed principals
-        """
-        partition = aws_partition(region) if region else "aws"
-
-        policy = {
-            "Version": "2012-10-17",
-            "Statement": [
-                {
-                    "Sid": "DenyAllAccessToFeatureStorePrefixExceptAllowedPrincipals",
-                    "Effect": "Deny",
-                    "Principal": "*",
-                    "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
-                    "Resource": f"arn:{partition}:s3:::{bucket_name}/{s3_prefix}/*",
-                    "Condition": {
-                        "StringNotEquals": {
-                            "aws:PrincipalArn": [
-                                lake_formation_role_arn,
-                                feature_store_role_arn,
-                            ]
-                        }
-                    },
-                },
-                {
-                    "Sid": "DenyListOnPrefixExceptAllowedPrincipals",
-                    "Effect": "Deny",
-                    "Principal": "*",
-                    "Action": "s3:ListBucket",
-                    "Resource": f"arn:{partition}:s3:::{bucket_name}",
-                    "Condition": {
-                        "StringLike": {"s3:prefix": f"{s3_prefix}/*"},
-                        "StringNotEquals": {
-                            "aws:PrincipalArn": [
-                                lake_formation_role_arn,
-                                feature_store_role_arn,
-                            ]
-                        },
-                    },
-                },
-            ],
-        }
-        return policy
-
-    def _get_lake_formation_client(
-        self,
-        session: Optional[Session] = None,
-        region: Optional[str] = None,
-    ):
-        """
-        Get a Lake Formation client, reusing a cached client when possible.
-
-        The client is cached on the instance keyed by (session, region). Subsequent
-        calls with the same arguments return the existing client instead of creating
-        a new one.
-
-        Args:
-            session: Boto3 session. If not provided, a new session will be created.
-            region: AWS region name.
-
-        Returns:
-            A boto3 Lake Formation client.
-        """
-        cache_key = (id(session), region)
-        if not hasattr(self, "_lf_client_cache"):
-            self._lf_client_cache: dict = {}
-
-        if cache_key not in self._lf_client_cache:
-            boto_session = session or Session()
-            self._lf_client_cache[cache_key] = boto_session.client(
-                "lakeformation", region_name=region
-            )
-
-        return self._lf_client_cache[cache_key]
-
-    def _register_s3_with_lake_formation(
-        self,
-        s3_location: str,
-        session: Optional[Session] = None,
-        region: Optional[str] = None,
-        use_service_linked_role: bool = True,
-        role_arn: Optional[str] = None,
-    ) -> bool:
-        """
-        Register an S3 location with Lake Formation.
-
-        Args:
-            s3_location: S3 URI or ARN to register.
-            session: Boto3 session.
-            region: AWS region. If not provided, will be inferred from the session.
-            use_service_linked_role: Whether to use the Lake Formation service-linked role.
-                If True, Lake Formation uses its service-linked role for registration.
-                If False, role_arn must be provided.
-            role_arn: IAM role ARN to use for registration. Required when
-                use_service_linked_role is False.
-
-        Returns:
-            True if registration succeeded or location already registered.
-
-        Raises:
-            ValueError: If use_service_linked_role is False but role_arn is not provided.
-            ClientError: If registration fails for unexpected reasons.
-        """
-        if not use_service_linked_role and not role_arn:
-            raise ValueError("role_arn must be provided when use_service_linked_role is False")
-
-        # Get region from session if not provided
-        if region is None and session is not None:
-            region = session.region_name
-
-        client = self._get_lake_formation_client(session, region)
-        resource_arn = self._s3_uri_to_arn(s3_location, region)
-
-        try:
-            register_params = {"ResourceArn": resource_arn}
-
-            if use_service_linked_role:
-                register_params["UseServiceLinkedRole"] = True
-            else:
-                register_params["RoleArn"] = role_arn
-
-            client.register_resource(**register_params)
-            logger.info(f"Successfully registered S3 location: {resource_arn}")
-            return True
-        except botocore.exceptions.ClientError as e:
-            if e.response["Error"]["Code"] == "AlreadyExistsException":
-                logger.info(f"S3 location already registered: {resource_arn}")
-                return True
-            raise
-
-    def _revoke_iam_allowed_principal(
-        self,
-        database_name: str,
-        table_name: str,
-        session: Optional[Session] = None,
-        region: Optional[str] = None,
-    ) -> bool:
-        """
-        Revoke IAMAllowedPrincipal permissions from a Glue table.
-
-        Args:
-            database_name: Glue database name.
-            table_name: Glue table name.
-            session: Boto3 session.
-            region: AWS region. If not provided, will be inferred from the session.
-
-        Returns:
-            True if revocation succeeded or permissions didn't exist.
-
-        Raises:
-            ClientError: If revocation fails for unexpected reasons.
-        """
-        # Get region from session if not provided
-        if region is None and session is not None:
-            region = session.region_name
-
-        client = self._get_lake_formation_client(session, region)
-
-        try:
-            client.revoke_permissions(
-                Principal={"DataLakePrincipalIdentifier": "IAM_ALLOWED_PRINCIPALS"},
-                Resource={
-                    "Table": {
-                        "DatabaseName": database_name,
-                        "Name": table_name,
-                    }
-                },
-                Permissions=["ALL"],
-            )
-            logger.info(f"Disabled Lake Formation hybrid-access mode on table: {database_name}.{table_name}")
-            return True
-        except botocore.exceptions.ClientError as e:
-            # if the Table doesn't have that permission because the user already revoked it
-            # then just return True
-            if e.response["Error"]["Code"] == "InvalidInputException":
-                logger.info(
-                    f"IAMAllowedPrincipal permissions may not exist on: {database_name}.{table_name}"
-                )
-                return True
-            raise
-
-    def _grant_lake_formation_permissions(
-        self,
-        role_arn: str,
-        database_name: str,
-        table_name: str,
-        session: Optional[Session] = None,
-        region: Optional[str] = None,
-    ) -> bool:
-        """
-        Grant permissions to a role on a Glue table via Lake Formation.
-
-        Args:
-            role_arn: IAM role ARN to grant permissions to.
-            database_name: Glue database name.
-            table_name: Glue table name.
-            session: Boto3 session.
-            region: AWS region. If not provided, will be inferred from the session.
-
-        Returns:
-            True if grant succeeded or permissions already exist.
-
-        Raises:
-            ClientError: If grant fails for unexpected reasons.
-        """
-        # Get region from session if not provided
-        if region is None and session is not None:
-            region = session.region_name
-
-        client = self._get_lake_formation_client(session, region)
-        permissions = ["SELECT", "INSERT", "DELETE", "DESCRIBE", "ALTER"]
-
-        try:
-            client.grant_permissions(
-                Principal={"DataLakePrincipalIdentifier": role_arn},
-                Resource={
-                    "Table": {
-                        "DatabaseName": database_name,
-                        "Name": table_name,
-                    }
-                },
-                Permissions=permissions,
-                PermissionsWithGrantOption=[],
-            )
-            logger.info(f"Granted permissions to {role_arn} on table: {database_name}.{table_name}")
-            return True
-        except botocore.exceptions.ClientError as e:
-            if e.response["Error"]["Code"] == "InvalidInputException":
-                logger.info(
-                    f"Permissions may already exist for {role_arn} on: {database_name}.{table_name}"
-                )
-                return True
-            raise
-
-    @Base.add_validate_call
-    def enable_lake_formation(
-        self,
-        session: Optional[Session] = None,
-        region: Optional[str] = None,
-        use_service_linked_role: bool = True,
-        registration_role_arn: Optional[str] = None,
-        wait_for_active: bool = False,
-        show_s3_policy: bool = False,
-        disable_hybrid_access_mode: bool = True,
-    ) -> dict:
-        """
-        Enable Lake Formation governance for this Feature Group's offline store.
-
-        This method:
-        1. Optionally waits for Feature Group to reach 'Created' status
-        2. Validates Feature Group status is 'Created'
-        3. Registers the offline store S3 location as data lake location
-        4. Grants the execution role permissions on the Glue table
-        5. Optionally revokes IAMAllowedPrincipal permissions from the Glue table
-           (controlled by disable_hybrid_access_mode)
-
-        The role ARN is automatically extracted from the Feature Group's configuration.
-        Each phase depends on the success of the previous phase - if any phase fails,
-        subsequent phases are not executed.
-
-        Parameters:
-            session: Boto3 session.
-            region: Region name.
-            use_service_linked_role: Whether to use the Lake Formation service-linked role
-                for S3 registration. If True, Lake Formation uses its service-linked role.
-                If False, registration_role_arn must be provided. Default is True.
-            registration_role_arn: IAM role ARN to use for S3 registration with Lake Formation.
-                Required when use_service_linked_role is False. This can be different from the
-                Feature Group's execution role (role_arn)
-            wait_for_active: If True, waits for the Feature Group to reach 'Created' status
-                before enabling Lake Formation. Default is False.
-            show_s3_policy: If True, prints the S3 deny policy to the console after successful
-                Lake Formation setup. This policy should be added to your S3 bucket to restrict
-                access to only the allowed principals. Default is False.
-            disable_hybrid_access_mode: If True, revokes IAMAllowedPrincipal permissions from
-                the Glue table, moving it to Lake Formation-only access mode. If False, keeps
-                hybrid access mode where both IAM and Lake Formation control access.
-                Default is True.
-
-        Returns:
-            Dict with status of each Lake Formation operation:
-            - s3_registration: bool
-            - iam_principal_revoked: bool or None (None when disable_hybrid_access_mode=False)
-            - permissions_granted: bool
-
-        Raises:
-            ValueError: If the Feature Group has no offline store configured,
-                if role_arn is not set on the Feature Group, if use_service_linked_role
-                is False but registration_role_arn is not provided, or if the Feature Group
-                is not in 'Created' status.
-            ClientError: If Lake Formation operations fail.
-            RuntimeError: If a phase fails and subsequent phases cannot proceed.
-        """
-        # Get region from session if not provided
-        if region is None and session is not None:
-            region = session.region_name
-
-        # Wait for Created status if requested
-        if wait_for_active:
-            self.wait_for_status(target_status="Created")
-
-        # Refresh to get latest state
-        self.refresh()
-
-        # Validate Feature Group status
-        if self.feature_group_status not in ["Created"]:
-            raise ValueError(
-                f"Feature Group '{self.feature_group_name}' must be in 'Created' status "
-                f"to enable Lake Formation. Current status: '{self.feature_group_status}'. "
-                f"Use wait_for_active=True to automatically wait for the Feature Group to be ready."
-            )
-
-        # Validate offline store exists
-        if self.offline_store_config is None or self.offline_store_config == Unassigned():
-            raise ValueError(
-                f"Feature Group '{self.feature_group_name}' does not have an offline store configured. "
-                "Lake Formation can only be enabled for Feature Groups with offline stores."
-            )
-
-        # Get role ARN from Feature Group config
-        if self.role_arn is None or self.role_arn == Unassigned():
-            raise ValueError(
-                f"Feature Group '{self.feature_group_name}' does not have a role_arn configured. "
-                "Lake Formation requires a role ARN to grant permissions."
-            )
-        if not use_service_linked_role and registration_role_arn is None:
-            raise ValueError(
-                "Either 'use_service_linked_role' must be True or 'registration_role_arn' must be provided."
-            )
-
-        # Extract required configuration
-        s3_config = self.offline_store_config.s3_storage_config
-        if s3_config is None:
-            raise ValueError("Offline store S3 configuration is missing")
-
-        resolved_s3_uri = s3_config.resolved_output_s3_uri
-        if resolved_s3_uri is None or resolved_s3_uri == Unassigned():
-            raise ValueError(
-                "Resolved S3 URI not available. Ensure the Feature Group is in 'Created' status."
-            )
-
-        data_catalog_config = self.offline_store_config.data_catalog_config
-        if data_catalog_config is None:
-            raise ValueError("Data catalog configuration is missing from offline store config")
-
-        database_name = data_catalog_config.database
-        table_name = data_catalog_config.table_name
-
-        if not database_name or not table_name:
-            raise ValueError("Database name and table name are required from data catalog config")
-
-        # Convert to str to handle PipelineVariable types
-        resolved_s3_uri_str = str(resolved_s3_uri)
-        database_name_str = str(database_name)
-        table_name_str = str(table_name)
-        role_arn_str = str(self.role_arn)
-
-        # Determine the actual S3 location to register with Lake Formation.
-        # For Iceberg tables, the Glue table's StorageDescriptor.Location is the parent
-        # path (without /data suffix), while resolved_output_s3_uri always ends with /data.
-        s3_location_to_register = resolved_s3_uri_str
-        if (
-            self.offline_store_config.table_format is not None
-            and str(self.offline_store_config.table_format) == "Iceberg"
-            and resolved_s3_uri_str.endswith("/data")
-        ):
-            s3_location_to_register = resolved_s3_uri_str[: -len("/data")]
-            logger.info(
-                f"Iceberg table format detected. Using parent S3 path for LF registration: "
-                f"{s3_location_to_register}"
-            )
-
-        # Execute Lake Formation setup with fail-fast behavior
-        results = {
-            "s3_registration": False,
-            "iam_principal_revoked": False,
-            "permissions_granted": False,
-        }
-
-        # Phase 1: Register S3 with Lake Formation
-        try:
-            results["s3_registration"] = self._register_s3_with_lake_formation(
-                s3_location_to_register,
-                session,
-                region,
-                use_service_linked_role=use_service_linked_role,
-                role_arn=registration_role_arn,
-            )
-        except Exception as e:
-            raise RuntimeError(
-                f"Failed to register S3 location with Lake Formation. "
-                f"Subsequent phases skipped. Results: {results}. Error: {e}"
-            ) from e
-
-        if not results["s3_registration"]:
-            raise RuntimeError(
-                f"Failed to register S3 location with Lake Formation. "
-                f"Subsequent phases skipped. Results: {results}"
-            )
-
-        # Phase 2: Grant Lake Formation permissions to the role
-        try:
-            results["permissions_granted"] = self._grant_lake_formation_permissions(
-                role_arn_str, database_name_str, table_name_str, session, region
-            )
-        except Exception as e:
-            raise RuntimeError(
-                f"Failed to grant Lake Formation permissions. "
-                f"Subsequent phases skipped. Results: {results}. Error: {e}"
-            ) from e
-
-        if not results["permissions_granted"]:
-            raise RuntimeError(
-                f"Failed to grant Lake Formation permissions. "
-                f"Subsequent phases skipped. Results: {results}"
-            )
-
-        # Phase 3: Revoke IAMAllowedPrincipal permissions (if disabling hybrid access mode)
-        if disable_hybrid_access_mode:
-            try:
-                results["iam_principal_revoked"] = self._revoke_iam_allowed_principal(
-                    database_name_str, table_name_str, session, region
-                )
-            except Exception as e:
-                raise RuntimeError(
-                    f"Failed to revoke IAMAllowedPrincipal permissions. Results: {results}. Error: {e}"
-                ) from e
-
-            if not results["iam_principal_revoked"]:
-                raise RuntimeError(
-                    f"Failed to revoke IAMAllowedPrincipal permissions. Results: {results}"
-                )
-        else:
-            results["iam_principal_revoked"] = None
-            logger.info(
-                "Skipping IAMAllowedPrincipal revocation - hybrid access mode preserved."
-            )
-
-        logger.info(f"Lake Formation setup complete for {self.feature_group_name}: {results}")
-
-        # Generate and optionally print S3 deny policy
-        if show_s3_policy:
-            # Extract bucket name and prefix from resolved S3 URI using core utility
-            bucket_name, s3_prefix = parse_s3_url(resolved_s3_uri_str)
-
-            # Extract account ID from Feature Group ARN
-            feature_group_arn_str = str(self.feature_group_arn) if self.feature_group_arn else ""
-            account_id = self._extract_account_id_from_arn(feature_group_arn_str)
-
-            # Determine Lake Formation role ARN based on use_service_linked_role flag
-            if use_service_linked_role:
-                lf_role_arn = self._get_lake_formation_service_linked_role_arn(account_id, region)
-            else:
-                # registration_role_arn is validated earlier when use_service_linked_role is False
-                lf_role_arn = str(registration_role_arn)
-
-            # Generate the S3 deny policy
-            policy = self._generate_s3_deny_policy(
-                bucket_name=bucket_name,
-                s3_prefix=s3_prefix,
-                lake_formation_role_arn=lf_role_arn,
-                feature_store_role_arn=role_arn_str,
-                region=region,
-            )
-
-            # Log policy with clear instructions
-            policy_json = json.dumps(policy, indent=2)
-            policy_message = (
-                "\n" + "=" * 50
-                + "\nS3 Bucket Policy Update recommended"
-                + "\n" + "=" * 50
-                + "\n\nTo complete Lake Formation setup, add the following"
-                + "\ndeny policy to your S3 bucket."
-                + "\nThis restricts access to the offline store data to"
-                + "\nonly the allowed principals."
-                + f"\n\nBucket: {bucket_name}"
-                + f"\n\nPolicy to add:\n{policy_json}"
-                + "\n\nNote: Merge this with your existing bucket policy if one exists."
-                + "\n" + "=" * 50 + "\n"
-            )
-            logger.info(policy_message)
-
-        return results
-
     def _get_iceberg_properties(
         self,
         session: Optional[Session] = None,
@@ -905,7 +297,6 @@ def get(
     def create(
         cls,
         *args,
-        lake_formation_config: Optional[LakeFormationConfig] = None,
         iceberg_properties: Optional[IcebergProperties] = None,
         **kwargs,
     ) -> Optional["FeatureGroup"]:
@@ -929,25 +320,6 @@ def create(
         session = kwargs.get("session")
         region = kwargs.get("region")
 
-        # Validation for Lake Formation
-        if lake_formation_config is not None and lake_formation_config.enabled:
-            if offline_store_config is None:
-                raise ValueError(
-                    "lake_formation_config with enabled=True requires offline_store_config to be configured"
-                )
-            if role_arn is None:
-                raise ValueError(
-                    "lake_formation_config with enabled=True requires role_arn to be specified"
-                )
-            if (
-                not lake_formation_config.use_service_linked_role
-                and not lake_formation_config.registration_role_arn
-            ):
-                raise ValueError(
-                    "registration_role_arn must be provided in lake_formation_config "
-                    "when use_service_linked_role is False"
-                )
-
         # Validation for Iceberg properties
         if iceberg_properties is not None and iceberg_properties.properties:
             if offline_store_config is None:
@@ -964,18 +336,6 @@ def create(
 
         feature_group = super().create(*args, **kwargs)
 
-        # Enable Lake Formation if requested
-        if lake_formation_config is not None and lake_formation_config.enabled:
-            feature_group.wait_for_status(target_status="Created")
-            feature_group.enable_lake_formation(
-                session=session,
-                region=region,
-                use_service_linked_role=lake_formation_config.use_service_linked_role,
-                registration_role_arn=lake_formation_config.registration_role_arn,
-                show_s3_policy=lake_formation_config.show_s3_policy,
-                disable_hybrid_access_mode=lake_formation_config.disable_hybrid_access_mode,
-            )
-        
         # Update Iceberg properties if requested
         if iceberg_properties is not None and iceberg_properties.properties:
             # Wait for feature group to be created before updating Iceberg properties
diff --git a/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py b/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py
deleted file mode 100644
index 4aba769258..0000000000
--- a/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py
+++ /dev/null
@@ -1,654 +0,0 @@
-"""
-Integration tests for Lake Formation with FeatureGroupManager.
-
-These tests require:
-- AWS credentials with Lake Formation and SageMaker permissions
-- An S3 bucket for offline store (uses default SageMaker bucket)
-- An IAM role for Feature Store (uses execution role)
-
-Run with: pytest tests/integ/test_featureStore_lakeformation.py -v -m integ
-"""
-
-import logging
-import uuid
-
-import boto3
-import pytest
-from botocore.exceptions import ClientError
-
-from sagemaker.core.helper.session_helper import Session, get_execution_role
-from sagemaker.mlops.feature_store import (
-    FeatureGroupManager,
-    LakeFormationConfig,
-    OfflineStoreConfig,
-    OnlineStoreConfig,
-    S3StorageConfig,
-    StringFeatureDefinition,
-    FractionalFeatureDefinition,
-)
-
-feature_definitions = [
-    StringFeatureDefinition(feature_name="record_id"),
-    StringFeatureDefinition(feature_name="event_time"),
-    FractionalFeatureDefinition(feature_name="feature_value"),
-]
-
-
-@pytest.fixture(scope="module")
-def sagemaker_session():
-    return Session()
-
-
-@pytest.fixture(scope="module")
-def role(sagemaker_session):
-    return get_execution_role(sagemaker_session)
-
-
-@pytest.fixture(scope="module")
-def s3_uri(sagemaker_session):
-    bucket = sagemaker_session.default_bucket()
-    return f"s3://{bucket}/feature-store-test"
-
-
-@pytest.fixture(scope="module")
-def region():
-    return "us-west-2"
-
-
-@pytest.fixture(scope="module")
-def shared_feature_group_for_negative_tests(s3_uri, role, region):
-    """
-    Create a single FeatureGroupManager for negative tests that only need to verify
-    error conditions without modifying the resource.
-
-    This fixture is module-scoped to be created once and shared across tests,
-    reducing test execution time.
-    """
-    fg_name = f"test-lf-negative-{uuid.uuid4().hex[:8]}"
-    fg = None
-
-    try:
-        fg = create_test_feature_group(fg_name, s3_uri, role, region)
-        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
-        yield fg
-    finally:
-        if fg:
-            cleanup_feature_group(fg)
-
-
-def generate_feature_group_name():
-    """Generate a unique feature group name for testing."""
-    return f"test-lf-fg-{uuid.uuid4().hex[:8]}"
-
-
-def create_test_feature_group(name: str, s3_uri: str, role_arn: str, region: str) -> FeatureGroupManager:
-    """Create a FeatureGroupManager with offline store for testing."""
-
-    offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri))
-
-    fg = FeatureGroupManager.create(
-        feature_group_name=name,
-        record_identifier_feature_name="record_id",
-        event_time_feature_name="event_time",
-        feature_definitions=feature_definitions,
-        offline_store_config=offline_store_config,
-        role_arn=role_arn,
-        region=region,
-    )
-
-    return fg
-
-
-def cleanup_feature_group(fg: FeatureGroupManager):
-    """
-    Delete a FeatureGroupManager and its associated Glue table.
-
-    Args:
-        fg: The FeatureGroupManager to delete.
-    """
-    try:
-        # Delete the Glue table if it exists
-        if fg.offline_store_config is not None:
-            try:
-                fg.refresh()  # Ensure we have latest config
-                data_catalog_config = fg.offline_store_config.data_catalog_config
-                if data_catalog_config is not None:
-                    database_name = data_catalog_config.database
-                    table_name = data_catalog_config.table_name
-
-                    if database_name and table_name:
-                        glue_client = boto3.client("glue")
-                        try:
-                            glue_client.delete_table(DatabaseName=database_name, Name=table_name)
-                        except ClientError as e:
-                            # Ignore if table doesn't exist
-                            if e.response["Error"]["Code"] != "EntityNotFoundException":
-                                raise
-            except Exception:
-                # Don't fail cleanup if Glue table deletion fails
-                pass
-
-        # Delete the FeatureGroupManager
-        fg.delete()
-    except ClientError:
-        # Don't fail cleanup if Glue table deletion fails
-        pass
-
-
-@pytest.mark.serial
-@pytest.mark.slow_test
-def test_create_feature_group_and_enable_lake_formation(s3_uri, role, region):
-    """
-    Test creating a FeatureGroupManager and enabling Lake Formation governance.
-
-    This test:
-    1. Creates a new FeatureGroupManager with offline store
-    2. Waits for it to reach Created status
-    3. Enables Lake Formation governance (registers S3, grants permissions, revokes IAM principals)
-    4. Cleans up the FeatureGroupManager
-    """
-
-    fg_name = generate_feature_group_name()
-    fg = None
-
-    try:
-        # Create the FeatureGroupManager
-        fg = create_test_feature_group(fg_name, s3_uri, role, region)
-        assert fg is not None
-
-        # Wait for Created status
-        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
-        assert fg.feature_group_status == "Created"
-
-        # Enable Lake Formation governance
-        result = fg.enable_lake_formation()
-
-        # Verify all phases completed successfully
-        assert result["s3_registration"] is True
-        assert result["permissions_granted"] is True
-        assert result["iam_principal_revoked"] is True
-
-    finally:
-        print('done')
-        # Cleanup
-        if fg:
-            cleanup_feature_group(fg)
-
-
-@pytest.mark.serial
-@pytest.mark.slow_test
-def test_create_feature_group_with_lake_formation_enabled(s3_uri, role, region):
-    """
-    Test creating a FeatureGroupManager with lake_formation_config.enabled=True.
-
-    This test verifies the integrated workflow where Lake Formation is enabled
-    automatically during FeatureGroupManager creation:
-    1. Creates a new FeatureGroupManager with lake_formation_config.enabled=True
-    2. Verifies the FeatureGroupManager is created and Lake Formation is configured
-    3. Cleans up the FeatureGroupManager
-    """
-
-    fg_name = generate_feature_group_name()
-    fg = None
-
-    try:
-        # Create the FeatureGroupManager with Lake Formation enabled
-
-        offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri))
-        lake_formation_config = LakeFormationConfig()
-        lake_formation_config.enabled = True
-
-        fg = FeatureGroupManager.create(
-            feature_group_name=fg_name,
-            record_identifier_feature_name="record_id",
-            event_time_feature_name="event_time",
-            feature_definitions=feature_definitions,
-            offline_store_config=offline_store_config,
-            role_arn=role,
-            lake_formation_config=lake_formation_config,
-        )
-
-        # Verify the FeatureGroupManager was created
-        assert fg is not None
-        assert fg.feature_group_name == fg_name
-        assert fg.feature_group_status == "Created"
-
-        # Verify Lake Formation is configured by checking we can refresh without errors
-        fg.refresh()
-        assert fg.offline_store_config is not None
-
-    finally:
-        # Cleanup
-        if fg:
-            cleanup_feature_group(fg)
-
-
-@pytest.mark.serial
-def test_create_feature_group_without_lake_formation(s3_uri, role, region):
-    """
-    Test creating a FeatureGroupManager without Lake Formation enabled.
-
-    This test verifies that when lake_formation_config is not provided or enabled=False,
-    the FeatureGroupManager is created successfully without any Lake Formation operations:
-    1. Creates a new FeatureGroupManager without lake_formation_config
-    2. Verifies the FeatureGroupManager is created successfully
-    3. Verifies no Lake Formation operations were performed
-    4. Cleans up the FeatureGroupManager
-    """
-    fg_name = generate_feature_group_name()
-    fg = None
-
-    try:
-        # Create the FeatureGroupManager without Lake Formation
-        offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri))
-
-        # Create without lake_formation_config (default behavior)
-        fg = FeatureGroupManager.create(
-            feature_group_name=fg_name,
-            record_identifier_feature_name="record_id",
-            event_time_feature_name="event_time",
-            feature_definitions=feature_definitions,
-            offline_store_config=offline_store_config,
-            role_arn=role,
-        )
-
-        # Verify the FeatureGroupManager was created
-        assert fg is not None
-        assert fg.feature_group_name == fg_name
-
-        # Wait for Created status to ensure it's fully provisioned
-        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
-        assert fg.feature_group_status == "Created"
-
-        # Verify offline store is configured
-        fg.refresh()
-        assert fg.offline_store_config is not None
-        assert fg.offline_store_config.s3_storage_config is not None
-
-    finally:
-        # Cleanup
-        if fg:
-            cleanup_feature_group(fg)
-
-
-# ============================================================================
-# Negative Integration Tests
-# ============================================================================
-
-
-def test_create_feature_group_with_lake_formation_fails_without_offline_store(role, region):
-    """
-    Test that creating a FeatureGroupManager with enable_lake_formation=True fails
-    when no offline store is configured.
-
-    Expected behavior: ValueError should be raised indicating offline store is required.
-    """
-    fg_name = generate_feature_group_name()
-
-    lake_formation_config = LakeFormationConfig()
-    lake_formation_config.enabled = True
-
-    # Attempt to create without offline store but with Lake Formation enabled
-    with pytest.raises(ValueError) as exc_info:
-        FeatureGroupManager.create(
-            feature_group_name=fg_name,
-            record_identifier_feature_name="record_id",
-            event_time_feature_name="event_time",
-            feature_definitions=feature_definitions,
-            role_arn=role,
-            lake_formation_config=lake_formation_config,
-        )
-
-    # Verify error message mentions offline_store_config requirement
-    assert "lake_formation_config with enabled=True requires offline_store_config to be configured" in str(
-        exc_info.value
-    )
-
-
-def test_create_feature_group_with_lake_formation_fails_without_role(s3_uri, region):
-    """
-    Test that creating a FeatureGroupManager with lake_formation_config.enabled=True fails
-    when no role_arn is provided.
-
-    Expected behavior: ValueError should be raised indicating role_arn is required.
-    """
-    fg_name = generate_feature_group_name()
-
-    offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri))
-    lake_formation_config = LakeFormationConfig()
-    lake_formation_config.enabled = True
-
-    # Attempt to create without role_arn but with Lake Formation enabled
-    with pytest.raises(ValueError) as exc_info:
-        FeatureGroupManager.create(
-            feature_group_name=fg_name,
-            record_identifier_feature_name="record_id",
-            event_time_feature_name="event_time",
-            feature_definitions=feature_definitions,
-            offline_store_config=offline_store_config,
-            lake_formation_config=lake_formation_config,
-        )
-
-    # Verify error message mentions role_arn requirement
-    assert "lake_formation_config with enabled=True requires role_arn to be specified" in str(exc_info.value)
-
-
-def test_enable_lake_formation_fails_for_non_created_status(s3_uri, role, region):
-    """
-    Test that enable_lake_formation() fails when called on a FeatureGroupManager
-    that is not in 'Created' status.
-
-    Expected behavior: ValueError should be raised indicating the Feature Group
-    must be in 'Created' status.
-
-    Note: This test creates its own FeatureGroupManager because it needs to test
-    behavior during the 'Creating' status, which requires a fresh resource.
-    """
-    fg_name = generate_feature_group_name()
-    fg = None
-
-    try:
-        # Create the FeatureGroupManager
-        fg = create_test_feature_group(fg_name, s3_uri, role, region)
-        assert fg is not None
-
-        # Immediately try to enable Lake Formation without waiting for Created status
-        # The Feature Group will be in 'Creating' status
-        with pytest.raises(ValueError) as exc_info:
-            fg.enable_lake_formation(wait_for_active=False)
-
-        # Verify error message mentions status requirement
-        error_msg = str(exc_info.value)
-        assert "must be in 'Created' status to enable Lake Formation" in error_msg
-
-    finally:
-        # Cleanup
-        if fg:
-            fg.wait_for_status(target_status="Created", poll=30, timeout=300)
-            cleanup_feature_group(fg)
-
-
-def test_enable_lake_formation_without_offline_store(role, region):
-    """
-    Test that enable_lake_formation() fails when called on a FeatureGroupManager
-    without an offline store configured.
-
-    Expected behavior: ValueError should be raised indicating offline store is required.
-
-    Note: This test creates a FeatureGroupManager with only online store, which is a valid
-    configuration, but Lake Formation cannot be enabled for it.
-    """
-    fg_name = generate_feature_group_name()
-    fg = None
-
-    try:
-        # Create a FeatureGroupManager with only online store (no offline store)
-        online_store_config = OnlineStoreConfig(enable_online_store=True)
-
-        fg = FeatureGroupManager.create(
-            feature_group_name=fg_name,
-            record_identifier_feature_name="record_id",
-            event_time_feature_name="event_time",
-            feature_definitions=feature_definitions,
-            online_store_config=online_store_config,
-            role_arn=role,
-        )
-
-        # Wait for Created status
-        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
-
-        # Attempt to enable Lake Formation
-        with pytest.raises(ValueError) as exc_info:
-            fg.enable_lake_formation()
-        # Verify error message mentions offline store requirement
-        assert "does not have an offline store configured" in str(exc_info.value)
-
-    finally:
-        # Cleanup
-        if fg:
-            cleanup_feature_group(fg)
-
-
-def test_enable_lake_formation_fails_with_invalid_registration_role(
-    shared_feature_group_for_negative_tests,
-):
-    """
-    Test that enable_lake_formation() fails when use_service_linked_role=False
-    but no registration_role_arn is provided.
-
-    Expected behavior: ValueError should be raised indicating registration_role_arn
-    is required when not using service-linked role.
-    """
-    fg = shared_feature_group_for_negative_tests
-
-    # Attempt to enable Lake Formation without service-linked role and without registration_role_arn
-    with pytest.raises(ValueError) as exc_info:
-        fg.enable_lake_formation(
-            use_service_linked_role=False,
-            registration_role_arn=None,
-        )
-
-    # Verify error message mentions role requirement
-    error_msg = str(exc_info.value)
-    assert "registration_role_arn" in error_msg
-
-
-def test_enable_lake_formation_fails_with_nonexistent_role(
-    shared_feature_group_for_negative_tests, role
-):
-    """
-    Test that enable_lake_formation() properly bubbles errors when using
-    a nonexistent role ARN for Lake Formation registration.
-
-    Expected behavior: RuntimeError or ClientError should be raised with details
-    about the registration failure.
-
-    Note: This test uses a nonexistent role ARN (current role with random suffix)
-    to trigger an error during S3 registration with Lake Formation.
-    """
-    fg = shared_feature_group_for_negative_tests
-
-    # Build a short nonexistent role ARN using the account ID from the real role
-    account_id = role.split(":")[4]
-    nonexistent_role = f"arn:aws:iam::{account_id}:role/non-existent-role"
-
-    with pytest.raises(RuntimeError) as exc_info:
-        fg.enable_lake_formation(
-            use_service_linked_role=False,
-            registration_role_arn=nonexistent_role,
-        )
-
-    # Verify we got an appropriate error
-    error_msg = str(exc_info.value)
-    print(exc_info)
-    # Should mention role-related issues (not found, invalid, access denied, etc.)
-    assert "EntityNotFoundException" in error_msg
-
-
-# ============================================================================
-# Full Flow Integration Tests with Policy Output
-# ============================================================================
-
-
-@pytest.mark.serial
-@pytest.mark.slow_test
-def test_enable_lake_formation_full_flow_with_policy_output(s3_uri, role, region, caplog):
-    """
-    Test the full Lake Formation flow with S3 deny policy output.
-
-    This test verifies:
-    1. Creates a FeatureGroupManager with offline store
-    2. Enables Lake Formation with show_s3_policy=True
-    3. Verifies all Lake Formation phases complete successfully
-    4. Verifies the S3 deny policy is logged
-    5. Verifies the policy structure contains expected elements
-
-    This validates Requirements 6.1-6.9 from the design document.
-    """
-    fg_name = generate_feature_group_name()
-    fg = None
-
-    try:
-        # Create the FeatureGroupManager
-        fg = create_test_feature_group(fg_name, s3_uri, role, region)
-        assert fg is not None
-
-        # Wait for Created status
-        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
-        assert fg.feature_group_status == "Created"
-
-        # Enable Lake Formation governance with policy output
-        with caplog.at_level(logging.INFO, logger="sagemaker.mlops.feature_store.feature_group"):
-            result = fg.enable_lake_formation(show_s3_policy=True)
-
-        # Verify all phases completed successfully
-        assert result["s3_registration"] is True
-        assert result["permissions_granted"] is True
-        assert result["iam_principal_revoked"] is True
-
-        output = caplog.text
-
-        # Verify the policy header is logged
-        assert "S3 Bucket Policy Update recommended" in output
-        # Verify bucket information is logged
-        # Extract bucket name from s3_uri (s3://bucket/path -> bucket)
-        expected_bucket = s3_uri.replace("s3://", "").split("/")[0]
-        assert f"Bucket: {expected_bucket}" in output
-
-        # Verify policy structure elements are present
-        assert '"Version": "2012-10-17"' in output
-        assert '"Statement"' in output
-        assert '"Effect": "Deny"' in output
-        assert '"Principal": "*"' in output
-
-        # Verify the deny actions are present
-        assert "s3:GetObject" in output
-        assert "s3:PutObject" in output
-        assert "s3:DeleteObject" in output
-        assert "s3:ListBucket" in output
-
-        # Verify the condition structure is present
-        assert "StringNotEquals" in output
-        assert "aws:PrincipalArn" in output
-
-        # Verify the role ARN is in the allowed principals
-        assert role in output
-
-        # Verify the service-linked role pattern is present (default use_service_linked_role=True)
-        assert "aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess" in output
-
-        # Verify instructions are logged
-        assert "Merge this with your existing bucket policy" in output
-
-    finally:
-        # Cleanup
-        if fg:
-            cleanup_feature_group(fg)
-
-
-@pytest.mark.serial
-@pytest.mark.slow_test
-def test_enable_lake_formation_no_policy_output_by_default(s3_uri, role, region, caplog):
-    """
-    Test that S3 deny policy is NOT logged when show_s3_policy=False (default).
-
-    This test verifies:
-    1. Creates a FeatureGroupManager with offline store
-    2. Enables Lake Formation without show_s3_policy (defaults to False)
-    3. Verifies all Lake Formation phases complete successfully
-    4. Verifies the S3 deny policy is NOT logged
-
-    This validates Requirement 6.2 from the design document.
-    """
-    fg_name = generate_feature_group_name()
-    fg = None
-
-    try:
-        # Create the FeatureGroupManager
-        fg = create_test_feature_group(fg_name, s3_uri, role, region)
-        assert fg is not None
-
-        # Wait for Created status
-        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
-        assert fg.feature_group_status == "Created"
-
-        # Enable Lake Formation governance WITHOUT policy output (default)
-        with caplog.at_level(logging.INFO, logger="sagemaker.mlops.feature_store.feature_group"):
-            result = fg.enable_lake_formation()
-
-        # Verify all phases completed successfully
-        assert result["s3_registration"] is True
-        assert result["permissions_granted"] is True
-        assert result["iam_principal_revoked"] is True
-
-        output = caplog.text
-
-        # Verify the policy is NOT logged
-        assert "S3 Bucket Policy Update recommended" not in output
-        assert '"Version": "2012-10-17"' not in output
-        assert "s3:GetObject" not in output
-
-    finally:
-        # Cleanup
-        if fg:
-            cleanup_feature_group(fg)
-
-
-@pytest.mark.serial
-@pytest.mark.slow_test
-def test_enable_lake_formation_with_custom_role_policy_output(s3_uri, role, region, caplog):
-    """
-    Test the full Lake Formation flow with custom registration role and policy output.
-
-    This test verifies:
-    1. Creates a FeatureGroupManager with offline store
-    2. Enables Lake Formation with use_service_linked_role=False and a custom registration_role_arn
-    3. Verifies the S3 deny policy uses the custom role ARN instead of service-linked role
-
-    This validates Requirements 6.4, 6.5 from the design document.
-
-    Note: This test uses the same execution role as the registration role for simplicity.
-    In production, these would typically be different roles.
-    """
-    fg_name = generate_feature_group_name()
-    fg = None
-
-    try:
-        # Create the FeatureGroupManager
-        fg = create_test_feature_group(fg_name, s3_uri, role, region)
-        assert fg is not None
-
-        # Wait for Created status
-        fg.wait_for_status(target_status="Created", poll=30, timeout=300)
-        assert fg.feature_group_status == "Created"
-
-        # Enable Lake Formation with custom registration role and policy output
-        # Using the same role for both execution and registration for test simplicity
-        with caplog.at_level(logging.INFO, logger="sagemaker.mlops.feature_store.feature_group"):
-            result = fg.enable_lake_formation(
-                use_service_linked_role=False,
-                registration_role_arn=role,
-                show_s3_policy=True,
-            )
-
-        # Verify all phases completed successfully
-        assert result["s3_registration"] is True
-        assert result["permissions_granted"] is True
-        assert result["iam_principal_revoked"] is True
-
-        output = caplog.text
-
-        # Verify the policy header is logged
-        assert "S3 Bucket Policy Update recommended" in output
-
-        # Verify the custom role ARN is used in the policy (appears twice - once for each principal)
-        # The role should appear as both the Lake Formation role and the Feature Store role
-        assert output.count(role) >= 2
-
-        # Verify the service-linked role is NOT used
-        assert "aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess" not in output
-
-    finally:
-        # Cleanup
-        if fg:
-            cleanup_feature_group(fg)
diff --git a/sagemaker-mlops/tests/integ/test_feature_store_iceberg_properties.py b/sagemaker-mlops/tests/integ/test_feature_store_iceberg_properties.py
new file mode 100644
index 0000000000..2cd2b05369
--- /dev/null
+++ b/sagemaker-mlops/tests/integ/test_feature_store_iceberg_properties.py
@@ -0,0 +1,229 @@
+"""Integration tests for FeatureGroupManager iceberg property handling."""
+import time
+
+import boto3
+import pandas as pd
+import pytest
+
+from sagemaker.core.helper.session_helper import Session, get_execution_role
+from sagemaker.core.utils import unique_name_from_base
+from sagemaker.mlops.feature_store import (
+    OfflineStoreConfig,
+    S3StorageConfig,
+)
+from sagemaker.mlops.feature_store import FeatureGroupManager
+from sagemaker.mlops.feature_store.feature_group_manager import IcebergProperties
+from sagemaker.mlops.feature_store.feature_utils import (
+    load_feature_definitions_from_dataframe,
+)
+
+
+@pytest.fixture(scope="module")
+def sagemaker_session():
+    return Session()
+
+
+@pytest.fixture(scope="module")
+def role():
+    return get_execution_role()
+
+
+@pytest.fixture(scope="module")
+def region():
+    return boto3.Session().region_name
+
+
+@pytest.fixture(scope="module")
+def bucket(sagemaker_session):
+    return sagemaker_session.default_bucket()
+
+
+@pytest.fixture
+def feature_group_name():
+    return unique_name_from_base("integ-test-iceberg-fg")
+
+
+@pytest.fixture
+def sample_dataframe():
+    current_time = int(time.time())
+    return pd.DataFrame({
+        "record_id": [f"id-{i}" for i in range(10)],
+        "feature_1": [i * 1.5 for i in range(10)],
+        "feature_2": [i * 2 for i in range(10)],
+        "event_time": [float(current_time + i) for i in range(10)],
+    })
+
+
+def cleanup_feature_group(feature_group_name):
+    try:
+        fg = FeatureGroupManager.get(feature_group_name=feature_group_name)
+        fg.delete()
+        time.sleep(2)
+    except Exception:
+        pass
+
+
+def test_create_with_iceberg_properties(
+    feature_group_name, sample_dataframe, bucket, role
+):
+    try:
+        feature_definitions = load_feature_definitions_from_dataframe(sample_dataframe)
+        iceberg_props = IcebergProperties(properties={
+            "write.target-file-size-bytes": "536870912",
+            "history.expire.max-snapshot-age-ms": "432000000",
+        })
+
+        fg = FeatureGroupManager.create(
+            feature_group_name=feature_group_name,
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=feature_definitions,
+            role_arn=role,
+            offline_store_config=OfflineStoreConfig(
+                s3_storage_config=S3StorageConfig(s3_uri=f"s3://{bucket}/feature-store"),
+                table_format="Iceberg",
+            ),
+            iceberg_properties=iceberg_props,
+        )
+
+        fg.wait_for_status("Created")
+
+        retrieved = FeatureGroupManager.get(
+            feature_group_name=feature_group_name,
+            include_iceberg_properties=True,
+        )
+        assert retrieved.iceberg_properties is not None
+        assert retrieved.iceberg_properties.properties["write.target-file-size-bytes"] == "536870912"
+        assert retrieved.iceberg_properties.properties["history.expire.max-snapshot-age-ms"] == "432000000"
+    finally:
+        cleanup_feature_group(feature_group_name)
+
+
+def test_update_iceberg_properties(
+    feature_group_name, sample_dataframe, bucket, role
+):
+    try:
+        feature_definitions = load_feature_definitions_from_dataframe(sample_dataframe)
+
+        fg = FeatureGroupManager.create(
+            feature_group_name=feature_group_name,
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=feature_definitions,
+            role_arn=role,
+            offline_store_config=OfflineStoreConfig(
+                s3_storage_config=S3StorageConfig(s3_uri=f"s3://{bucket}/feature-store"),
+                table_format="Iceberg",
+            ),
+            iceberg_properties=IcebergProperties(properties={
+                "write.target-file-size-bytes": "536870912",
+            }),
+        )
+
+        fg.wait_for_status("Created")
+
+        fg.update(iceberg_properties=IcebergProperties(properties={
+            "write.target-file-size-bytes": "268435456",
+            "history.expire.min-snapshots-to-keep": "5",
+        }))
+
+        retrieved = FeatureGroupManager.get(
+            feature_group_name=feature_group_name,
+            include_iceberg_properties=True,
+        )
+        assert retrieved.iceberg_properties.properties["write.target-file-size-bytes"] == "268435456"
+        assert retrieved.iceberg_properties.properties["history.expire.min-snapshots-to-keep"] == "5"
+    finally:
+        cleanup_feature_group(feature_group_name)
+
+
+def test_get_with_include_iceberg_properties(
+    feature_group_name, sample_dataframe, bucket, role
+):
+    try:
+        feature_definitions = load_feature_definitions_from_dataframe(sample_dataframe)
+
+        fg = FeatureGroupManager.create(
+            feature_group_name=feature_group_name,
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=feature_definitions,
+            role_arn=role,
+            offline_store_config=OfflineStoreConfig(
+                s3_storage_config=S3StorageConfig(s3_uri=f"s3://{bucket}/feature-store"),
+                table_format="Iceberg",
+            ),
+            iceberg_properties=IcebergProperties(properties={
+                "write.metadata.delete-after-commit.enabled": "true",
+            }),
+        )
+
+        fg.wait_for_status("Created")
+
+        retrieved = FeatureGroupManager.get(
+            feature_group_name=feature_group_name,
+            include_iceberg_properties=True,
+        )
+        assert retrieved.iceberg_properties is not None
+        assert isinstance(retrieved.iceberg_properties.properties, dict)
+        assert retrieved.iceberg_properties.properties["write.metadata.delete-after-commit.enabled"] == "true"
+    finally:
+        cleanup_feature_group(feature_group_name)
+
+
+def test_create_with_iceberg_properties_none(
+    feature_group_name, sample_dataframe, bucket, role
+):
+    try:
+        feature_definitions = load_feature_definitions_from_dataframe(sample_dataframe)
+
+        fg = FeatureGroupManager.create(
+            feature_group_name=feature_group_name,
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=feature_definitions,
+            role_arn=role,
+            offline_store_config=OfflineStoreConfig(
+                s3_storage_config=S3StorageConfig(s3_uri=f"s3://{bucket}/feature-store"),
+                table_format="Iceberg",
+            ),
+            iceberg_properties=None,
+        )
+
+        fg.wait_for_status("Created")
+
+        assert fg.iceberg_properties is None
+    finally:
+        cleanup_feature_group(feature_group_name)
+
+
+def test_create_iceberg_properties_without_offline_store_raises():
+    with pytest.raises(ValueError, match="iceberg_properties requires offline_store_config"):
+        FeatureGroupManager.create(
+            feature_group_name="dummy-fg",
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=[],
+            role_arn="arn:aws:iam::000000000000:role/dummy",
+            iceberg_properties=IcebergProperties(properties={
+                "write.target-file-size-bytes": "536870912",
+            }),
+        )
+
+
+def test_create_iceberg_properties_with_non_iceberg_table_format_raises():
+    with pytest.raises(ValueError, match="table_format to be 'Iceberg'"):
+        FeatureGroupManager.create(
+            feature_group_name="dummy-fg",
+            record_identifier_feature_name="record_id",
+            event_time_feature_name="event_time",
+            feature_definitions=[],
+            role_arn="arn:aws:iam::000000000000:role/dummy",
+            offline_store_config=OfflineStoreConfig(
+                s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/prefix"),
+                table_format="Glue",
+            ),
+            iceberg_properties=IcebergProperties(properties={
+                "write.target-file-size-bytes": "536870912",
+            }),
+        )
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_athena_query.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_athena_query.py
deleted file mode 100644
index 5085ef9613..0000000000
--- a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_athena_query.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
-# Licensed under the Apache License, Version 2.0
-"""Unit tests for athena_query.py"""
-import os
-import pytest
-from unittest.mock import Mock, patch, MagicMock
-import pandas as pd
-
-from sagemaker.mlops.feature_store.athena_query import AthenaQuery
-
-
-class TestAthenaQuery:
-    @pytest.fixture
-    def mock_session(self):
-        session = Mock()
-        session.boto_session.client.return_value = Mock()
-        session.boto_region_name = "us-west-2"
-        session.sagemaker_config = {}
-        return session
-
-    @pytest.fixture
-    def athena_query(self, mock_session):
-        return AthenaQuery(
-            catalog="AwsDataCatalog",
-            database="sagemaker_featurestore",
-            table_name="my_feature_group",
-            sagemaker_session=mock_session,
-        )
-
-    def test_initialization(self, athena_query):
-        assert athena_query.catalog == "AwsDataCatalog"
-        assert athena_query.database == "sagemaker_featurestore"
-        assert athena_query.table_name == "my_feature_group"
-        assert athena_query._current_query_execution_id is None
-
-    @patch("sagemaker.mlops.feature_store.athena_query.start_query_execution")
-    def test_run_starts_query(self, mock_start, athena_query):
-        mock_start.return_value = {"QueryExecutionId": "query-123"}
-
-        result = athena_query.run(
-            query_string="SELECT * FROM table",
-            output_location="s3://bucket/output",
-        )
-
-        assert result == "query-123"
-        assert athena_query._current_query_execution_id == "query-123"
-        assert athena_query._result_bucket == "bucket"
-        assert athena_query._result_file_prefix == "output"
-
-    @patch("sagemaker.mlops.feature_store.athena_query.start_query_execution")
-    def test_run_with_kms_key(self, mock_start, athena_query):
-        mock_start.return_value = {"QueryExecutionId": "query-123"}
-
-        athena_query.run(
-            query_string="SELECT * FROM table",
-            output_location="s3://bucket/output",
-            kms_key="arn:aws:kms:us-west-2:123:key/abc",
-        )
-
-        mock_start.assert_called_once()
-        call_kwargs = mock_start.call_args[1]
-        assert call_kwargs["kms_key"] == "arn:aws:kms:us-west-2:123:key/abc"
-
-    @patch("sagemaker.mlops.feature_store.athena_query.wait_for_athena_query")
-    def test_wait_calls_helper(self, mock_wait, athena_query):
-        athena_query._current_query_execution_id = "query-123"
-
-        athena_query.wait()
-
-        mock_wait.assert_called_once_with(athena_query.sagemaker_session, "query-123")
-
-    @patch("sagemaker.mlops.feature_store.athena_query.get_query_execution")
-    def test_get_query_execution(self, mock_get, athena_query):
-        athena_query._current_query_execution_id = "query-123"
-        mock_get.return_value = {"QueryExecution": {"Status": {"State": "SUCCEEDED"}}}
-
-        result = athena_query.get_query_execution()
-
-        assert result["QueryExecution"]["Status"]["State"] == "SUCCEEDED"
-
-    @patch("sagemaker.mlops.feature_store.athena_query.get_query_execution")
-    @patch("sagemaker.mlops.feature_store.athena_query.download_athena_query_result")
-    @patch("pandas.read_csv")
-    @patch("os.path.join")
-    def test_as_dataframe_success(self, mock_join, mock_read_csv, mock_download, mock_get, athena_query):
-        athena_query._current_query_execution_id = "query-123"
-        athena_query._result_bucket = "bucket"
-        athena_query._result_file_prefix = "prefix"
-
-        mock_get.return_value = {"QueryExecution": {"Status": {"State": "SUCCEEDED"}}}
-        mock_join.return_value = "/tmp/query-123.csv"
-        mock_read_csv.return_value = pd.DataFrame({"col": [1, 2, 3]})
-
-        with patch("tempfile.gettempdir", return_value="/tmp"):
-            with patch("os.remove"):
-                df = athena_query.as_dataframe()
-
-        assert len(df) == 3
-
-    @patch("sagemaker.mlops.feature_store.athena_query.get_query_execution")
-    def test_as_dataframe_raises_when_running(self, mock_get, athena_query):
-        athena_query._current_query_execution_id = "query-123"
-        mock_get.return_value = {"QueryExecution": {"Status": {"State": "RUNNING"}}}
-
-        with pytest.raises(RuntimeError, match="still executing"):
-            athena_query.as_dataframe()
-
-    @patch("sagemaker.mlops.feature_store.athena_query.get_query_execution")
-    def test_as_dataframe_raises_when_failed(self, mock_get, athena_query):
-        athena_query._current_query_execution_id = "query-123"
-        mock_get.return_value = {"QueryExecution": {"Status": {"State": "FAILED"}}}
-
-        with pytest.raises(RuntimeError, match="failed"):
-            athena_query.as_dataframe()
diff --git a/v3-examples/ml-ops-examples/FS-lakeformation-cross-account.ipynb b/v3-examples/ml-ops-examples/FS-lakeformation-cross-account.ipynb
deleted file mode 100644
index 59f7920998..0000000000
--- a/v3-examples/ml-ops-examples/FS-lakeformation-cross-account.ipynb
+++ /dev/null
@@ -1,580 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "id": "4e7cc789-55ea-4460-a07e-a57ffe6ee4e6",
-   "metadata": {},
-   "source": [
-    "1. Create Feature Group in central account with Lakeformation enabled"
-   ]
-  },
-  {
-   "attachments": {},
-   "cell_type": "markdown",
-   "id": "d8f0e80d-bc9b-4c5e-b545-32fff784b8b5",
-   "metadata": {},
-   "source": [
-    "# Cross Account Lakeformation governed Feature Group Demo\n",
-    "\n",
-    "This is a demo to showcase how cross account access would work with lakeformation(LF) governed Feature Group(FG)\n",
-    "\n",
-    "[simpler single account demo](./v3-feature-store-lake-formation.ipynb)  \n",
-    "\n",
-    "The following scenario will be setup where you have a central account that owns the FG and then you have a producer account to ingest into the FG and another one reading from the FG\n",
-    "\n",
-    "![image.png](./imgs/fs-lf-cross-account1.png)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "f0c347d3-2736-4acf-8aff-bc6c9cc7a990",
-   "metadata": {},
-   "source": [
-    "## Helper Methods"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "d30e0db4-122c-4da4-b33d-6ed3c3a40a3c",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import boto3\n",
-    "import os\n",
-    "\n",
-    "boto3.DEFAULT_SESSION = None\n",
-    "def assume_role(role_arn, session_name=\"AssumedRoleSession\"):\n",
-    "    \"\"\"\n",
-    "    Assume an AWS IAM role and return temporary credentials.\n",
-    "    \n",
-    "    Args:\n",
-    "        role_arn: The ARN of the role to assume\n",
-    "        session_name: A name for the assumed role session\n",
-    "    \n",
-    "    Returns:\n",
-    "        A boto3 session with the assumed role credentials\n",
-    "    \"\"\"\n",
-    "    sts_client = boto3.client('sts')\n",
-    "    \n",
-    "    response = sts_client.assume_role(\n",
-    "        RoleArn=role_arn,\n",
-    "        RoleSessionName=session_name\n",
-    "    )\n",
-    "    \n",
-    "    credentials = response['Credentials']\n",
-    "    \n",
-    "    # Create a new session with the temporary credentials\n",
-    "    session = boto3.Session(\n",
-    "        aws_access_key_id=credentials['AccessKeyId'],\n",
-    "        aws_secret_access_key=credentials['SecretAccessKey'],\n",
-    "        aws_session_token=credentials['SessionToken']\n",
-    "    )\n",
-    "    \n",
-    "    return session"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "bf42a253-bf5e-49f3-96cc-744606cda4f4",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from sagemaker.core.helper.session_helper import Session"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "afc7f261-e7fe-4abc-88c3-cd3b1aa61dd2",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "central_account  = \"account-1\"\n",
-    "producer_account = \"account-2\"\n",
-    "consumer_account = \"account-3\"\n",
-    "\n",
-    "acc_to_role_arn = {\n",
-    "    central_account: f\"arn:aws:iam::{central_account}:role/admin\",\n",
-    "    producer_account: f\"arn:aws:iam::{producer_account}:role/Admin\",\n",
-    "    consumer_account: f\"arn:aws:iam::{consumer_account}:role/Admin\"\n",
-    "}\n",
-    "\n",
-    "central_acc_boto_session = assume_role(acc_to_role_arn[central_account])\n",
-    "central_acc_sagemaker_session = Session(boto_session=central_acc_boto_session)\n",
-    "\n",
-    "producer_acc_boto_session = assume_role(acc_to_role_arn[producer_account])\n",
-    "producer_acc_sagemaker_session = Session(boto_session=producer_acc_boto_session)\n",
-    "\n",
-    "consumer_acc_boto_session = assume_role(acc_to_role_arn[consumer_account])\n",
-    "consumer_acc_sagemaker_session = Session(boto_session=consumer_acc_boto_session)\n"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "28a96af6-409a-4756-8cb7-60850342c955",
-   "metadata": {},
-   "source": [
-    "## 1. Create Feature Group in central account and enable Lakeformation"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "4f6a2639-2640-4a51-8fad-886b4d7226da",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import json\n",
-    "import boto3\n",
-    "from botocore.exceptions import ClientError\n",
-    "# Import the FeatureGroup with Lake Formation support\n",
-    "from sagemaker.mlops.feature_store.feature_group import FeatureGroup, LakeFormationConfig\n",
-    "from sagemaker.core.shapes import (\n",
-    "    FeatureDefinition,\n",
-    "    FeatureValue,\n",
-    "    OfflineStoreConfig,\n",
-    "    OnlineStoreConfig,\n",
-    "    S3StorageConfig,\n",
-    ")\n",
-    "from sagemaker.core.helper.session_helper import Session as SageMakerSession, get_execution_role\n",
-    "\n",
-    "feature_definitions = [\n",
-    "    FeatureDefinition(feature_name=\"customer_id\", feature_type=\"String\"),\n",
-    "    FeatureDefinition(feature_name=\"event_time\", feature_type=\"String\"),\n",
-    "    FeatureDefinition(feature_name=\"age\", feature_type=\"Integral\"),\n",
-    "    FeatureDefinition(feature_name=\"total_purchases\", feature_type=\"Integral\"),\n",
-    "    FeatureDefinition(feature_name=\"avg_order_value\", feature_type=\"Fractional\"),\n",
-    "]\n",
-    "\n",
-    "# Offline store role (dedicated role for Feature Store S3 access)\n",
-    "# https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store-adding-policies.html\n",
-    "OFFLINE_STORE_ROLE_ARN = \"your-offline-store-role-arn\"\n",
-    "\n",
-    "S3_BUCKET = central_acc_sagemaker_session.default_bucket()\n",
-    "REGION = central_acc_boto_session.region_name\n",
-    "\n",
-    "\n",
-    "# Configure online and offline stores\n",
-    "FEATURE_GROUP_NAME='lakeformation-managed-fg-2'\n",
-    "\n",
-    "online_store_config = OnlineStoreConfig(enable_online_store=True)\n",
-    "\n",
-    "offline_store_config = OfflineStoreConfig(\n",
-    "    s3_storage_config=S3StorageConfig(\n",
-    "        s3_uri=f\"s3://{S3_BUCKET}/feature-store-demo/\"\n",
-    "    )\n",
-    ")\n",
-    "\n",
-    "# Configure Lake Formation - enabled at creation\n",
-    "lake_formation_config = LakeFormationConfig(\n",
-    "    enabled=True\n",
-    ")\n",
-    "\n",
-    "# create FG in central account and enable LF\n",
-    "feature_group = FeatureGroup.create(\n",
-    "    feature_group_name=FEATURE_GROUP_NAME,\n",
-    "    record_identifier_feature_name=\"customer_id\",\n",
-    "    event_time_feature_name=\"event_time\",\n",
-    "    feature_definitions=feature_definitions,\n",
-    "    online_store_config=online_store_config,\n",
-    "    offline_store_config=offline_store_config,\n",
-    "    role_arn=OFFLINE_STORE_ROLE_ARN,\n",
-    "    description=\"Feature Group with lakeformation enabled\",\n",
-    "    lake_formation_config=lake_formation_config, # new parameter\n",
-    "    session=central_acc_boto_session \n",
-    ")\n",
-    "\n",
-    "print(f\"\\nFeature Group created: {feature_group.feature_group_name}\")\n",
-    "# feature_group = FeatureGroup.get(FEATURE_GROUP_NAME)\n",
-    "central_acc_sagemaker_session.describe_feature_group(FEATURE_GROUP_NAME)\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "956b3ed3-7ede-4486-af44-46845b683a09",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "feature_group.refresh()\n",
-    "feature_group_arn = feature_group.feature_group_arn\n",
-    "data_catalog_config = feature_group.offline_store_config.data_catalog_config\n",
-    "database_name = str(data_catalog_config.database)\n",
-    "table_name = str(data_catalog_config.table_name)\n",
-    "catalog_id = str(data_catalog_config.catalog)\n",
-    "print(f\"Feature Group ARN: {feature_group_arn}\")\n",
-    "print(f\"Database: {database_name}\")\n",
-    "print(f\"Table: {table_name}\")\n",
-    "print(f\"Catalog: {catalog_id}\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "4708e998-6ac4-454c-a3ab-3a1f4fd71bc4",
-   "metadata": {},
-   "source": [
-    "## 2. Share Feature Group with producer account"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "6ea63cc0-7418-440f-8784-9108ca244e6c",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "ram_client = central_acc_boto_session.client(\"ram\")\n",
-    "response = ram_client.create_resource_share(\n",
-    "    name='producer-account-fg-share',\n",
-    "    resourceArns=[\n",
-    "        feature_group_arn\n",
-    "    ],\n",
-    "    principals=[\n",
-    "        str(producer_account)\n",
-    "    ],\n",
-    "    permissionArns=[\n",
-    "        \"arn:aws:ram::aws:permission/AWSRAMPermissionSageMakerFeatureGroupReadWrite\"\n",
-    "    ]\n",
-    ")\n",
-    "response"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "18df5f35-8efe-4b02-bfbf-d4bcbb6cb9cd",
-   "metadata": {},
-   "source": [
-    "### Producer Accepts the RAM share"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "2360602b-fdc4-45ea-958e-9dbec0efdd52",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Producer account accepts the RAM invitation\n",
-    "ram_client_producer = producer_acc_boto_session.client('ram')\n",
-    "\n",
-    "response = ram_client_producer.get_resource_share_invitations()\n",
-    "pending = [\n",
-    "    inv for inv in response['resourceShareInvitations']\n",
-    "    if inv['status'] == 'PENDING' and inv['senderAccountId'] == str(central_account)\n",
-    "]\n",
-    "\n",
-    "for inv in pending:\n",
-    "    ram_client_producer.accept_resource_share_invitation(\n",
-    "        resourceShareInvitationArn=inv['resourceShareInvitationArn']\n",
-    "    )\n",
-    "    print(f\"Accepted: {inv['resourceShareInvitationArn']}\")\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "2b59161c-5016-41ac-b70f-b0375067cdbc",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Test ingest from producer\n",
-    "\n",
-    "from datetime import datetime\n",
-    "\n",
-    "# Use the producer session to call PutRecord on the shared Feature Group\n",
-    "sm_runtime = producer_acc_boto_session.client('sagemaker-featurestore-runtime')\n",
-    "\n",
-    "sm_runtime.put_record(\n",
-    "    FeatureGroupName=feature_group_arn,\n",
-    "    Record=[\n",
-    "        {'FeatureName': 'customer_id', 'ValueAsString': 'CUST-001'},\n",
-    "        {'FeatureName': 'event_time', 'ValueAsString': datetime.utcnow().isoformat() + 'Z'},\n",
-    "        {'FeatureName': 'age', 'ValueAsString': '35'},\n",
-    "        {'FeatureName': 'total_purchases', 'ValueAsString': '12'},\n",
-    "        {'FeatureName': 'avg_order_value', 'ValueAsString': '49.99'},\n",
-    "    ]\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "486142f8-de45-4029-a08c-e0e1457cb3ea",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Test getRecord\n",
-    "sm_runtime.get_record(\n",
-    "    FeatureGroupName=feature_group_arn,\n",
-    "    RecordIdentifierValueAsString='CUST-001'\n",
-    ")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "5f531d4a-b668-42a8-a725-94a165ba76f8",
-   "metadata": {},
-   "source": [
-    "## 3. Share Glue Table with consumer account using LF"
-   ]
-  },
-  {
-   "attachments": {
-    "d1f0c7d4-d102-42f3-a1fc-b26eeb94a2bf.png": {
-     "image/png": "iVBORw0KGgoAAAANSUhEUgAABqAAAALOCAYAAADGG9JtAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAGoKADAAQAAAABAAACzgAAAADCWs0rAABAAElEQVR4AezdB5gUVdaA4TN5BoaccxIQSaKoGDCvAdOimNNizrprWuE3ryzmsIY1Z1xFUNewpnUVA4oIkkRAcs4ypIk9/znVU93VzfTEnp7ume8+T9s1XVW3br1VjV116p6b1HPA0GKhIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIBAlgeQo1UM1CCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCDgCBKA4ERBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBKIqQAAqqpxUhgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggQACKcwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCCqAgSgospJZQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgSgOAcQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSiKkAAKqqcVIYAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIEAAinMAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAgqgIEoKLKSWUIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIEoDgHEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEoipAACqqnFSGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBAAIpzAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAIKoCBKCiykllCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACBKA4BxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBKIqQAAqqpxUhgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggQACKcwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCCqAgSgospJZQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgSgOAcQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSiKkAAKqqcVIYAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIEAAinMAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAgqgIEoKLKSWUIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIEoDgHEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEoipAACqqnFSGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBAAIpzAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAIKoCBKCiykllCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACBKA4BxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBKIqQAAqqpxUhgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggQACKcwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCCqAgSgospJZQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgSgOAcQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSiKkAAKqqcVIYAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIEAAinMAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAgqgIEoKLKSWUIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIEoDgHEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEoipAACqqnFSGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBAAIpzAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAIKoCBKCiykllCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACBKA4BxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBKIqQAAqqpxUhgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggQACKcwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCCqAgSgospJZQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgSgOAcQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSiKkAAKqqcVIYA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br7+slhz9ZWzO2eed1m88NJrM3mq7l9af9014vhjDs868ubbA2P33/257neqlnqQhk/bbbt57N53h1h5pRVmqDWdXfPQI09ls6Leeuf9Ge4X7UIaBF1+4enJDLHuFV177Y134tCjTqix5QnTZfTuufXaaNNm2vKIaX37HnBkTJky679NtNKKyyV7Vl1Tsb/XAYceE88+/3JFu30gQIAAAQKlKmAGVKmOjHYRIECAAAECBAgQIFBdAQFUdeWUq7MCdyd/qN19hWXrbPur0/B0r6s+u+1XnaLzfZl09lM6a65Xzy2iZYsWM3h88umguLXffckMncdi9JixM9wvyoV0qcLTTzom+vTauqJL6fJ2Bx12bHz6+eCKa/PywwbrrhnXXXl+1K9fL3vtTbfeHf88++LZVnHaiX+N3ZLwMD2+/GpIbLfzvpEu5ecgQIAAAQKlLCCAKuXR0TYCBAgQIECAAAECBKojYAm+6qgpU6cFdt25V7ZEV53uRBUb/92w4XHHXQ9UsZTHU4ERI36KZ54bEDfcclcM+fa75NfOgtFxwQ4VOB06tItNNlw3frdX30hn7Xz/w4j4fvgPFfeL8iFdqvDxp56PdPbXOmutns0wat26VfTZfutIQ7gvvvx6nnf1q2++zepbf501snf3WGn5+HrIt/HRJ5/Psq63330/0n/P05lsbZMZVJMmTY50BpWDAAECBAiUsoAl+Ep5dLSNAAECBAgQIECAAIHqCJgBVR01Zeq0wKYbrRcn/P3waNGieZ3ux5w2fkwyK+eMcy+Lp597aU6LeG42Aisu3y2bFbXdNptH8+YzbhSezji75Y57s/2Hfvll2obis3llnbqd/jt04dknVfw7VFY2Nc696Mq4/obba6Qfl5x3amy71abZu9MAbI/fHRIDP/h4lnXtsUvvOPWEo7Nnxo8fH9v02Se+HTpslmXcJECAAAECeQqYAZWnvroJECBAgAABAgQIEKgJAQFUTah6JwEC84VAGmKmM4B269srluu29Ax9Hjv2l7j/ocfjtmSJvg8//myG+3X5Qrell4yrLz0rm/VV3o977n8kTjztvHm+3F2zZk2j303XRLelu2ZVpUHSTnscED/+9HN51TP8rF+/fqTLba6w3DLZvcefei4O+csJMzznAgECBAgQKBUBAVSpjIR2ECBAgAABAgQIECAwrwQswTevJL2H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6gsBAgQIECBAgAABAgQIVCYwduSgePORPSu7Xen1ssm/ZPd+GvJivDm86uUrfXEt3Zg04cdaqkk1BEpfQABV+mOkhQQIECBQIAHLDhRoMHWFAAECBAgQIECAAAECBCoXmDo5Jo3/ofL7s7lTVjYhysZPmM1TbhMgUMoCluAr5dHRNgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAHRQwA6oODpomEyBAgEDdErDsQN0aL60lQIAAAQIECBAgQIAAAQIECBCYewEB1NwbegMBAgQIEJi1gGUHZu3jLgECBAgQIECAAAECBAgQIECAQOEELMFXuCHVIQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAvgICqHz91U6AAAECBAgQIECAAAECBAgQIECAAAECBAgQKJyAAKpwQ6pDBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF8BQRQ+fqrnQABAgQIECBAgAABAgQIECBAgAABAgQIECBQOAEBVOGGVIcIECBAgAABAgQIECBAgAABAgQIECBAgAABAvkKCKDy9Vc7AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKBwAgKowg2pDhEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE8hUQQOXrr3YCBAgQIECAAAECBAgQIECAAAECBAgQIECAQOEEBFCFG1IdIkCAAAECBAgQIECAAAECBAgQIECAAAECBAjkKyCAytdf7QQIECBAgAABAgQIECBAgAABAgQIECBAgACBwgkIoAo3pDpEgAABAgQIECBAgAABAgQIECBAgAABAgQIEMhXQACVr7/aCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKFExBAFW5IdYgAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgkK+AACpff7UTIECAAAECBAgQIECAAAECBAgQIECAAAECBAonIIAq3JDqEAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgXwEBVL7+aidAgAABAgQIECBAgAABAgQIECBAgAABAgQIFE5AAFW4IdUhAgQIECBAgAABAgQIECBAgAABAgQIECBAgEC+AgKofP3VToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAonIAAqnBDqkMECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgXwFBFD5+qudAAECBAgQIECAAAECBAgQIECAAAECBAgQIFA4AQFU4YZUhwgQIECAAAECBAgQIECAAAECBAgQIECAAAEC+QoIoPL1VzsBAgQIECBAgAABAgQIECBAgAABAgQIECBAoHACAqjCDakOESBAgAABAgQIECBAgAABAgQIECBAgAABAgTyFRBA5euvdgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA4QQEUIUbUh0iQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECOQrIIDK11/tBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHCCQigCjekOkSAAAECBAgQIECAAAECBAgQIECAAAECBAgQyFdAAJWvv9oJECBAgAABAgQIECBAgAABAgQIECBAgAABAoUTEEAVbkh1iAABAgQIECBAgAABAgQIECBAgAABAgQIECCQr4AAKl9/tRMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECicggCrckOoQAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCBfAQFUvv5qJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgUTkAAVbgh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL4CAqh8/dVOgAABAgQIECBAgAABAgQIECBAgAABAgQIECicgACqcEOqQwQIECBAgAABAgQIECBAgAABAgQIECBAgACBfAUEUPn6q50AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgUDgBAVThhlSHCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQL5Cgig8vVXOwECBAgQIECAAAECBAgQIECAAAECBAgQIECgcAICqMINqQ4RIECAAAECBAgQIECAAAECBAgQIECAAAECBPIVEEDl6692AgQIECBAgAABAgQIECBAgAABAgQIECBAgEDhBARQhRtSHSJAgAABAgQIECBAgAABAgQIECBAgAABAgQI5CsggMrXX+0ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgcIJCKAKN6Q6RIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDIV0AAla+/2gkQIECAAAECBAgQIECAAAECBAgQIECAAAEChRMQQBVuSHWIAAECBAgQIECAAAECBAgQIECAAAECBAgQIJCvgAAqX3+1EyBAgAABAgQIECBAgAABAgQIECBAgAABAgQKJyCAKtyQ6hABAgQIECBAgAABAgQIECBAgAABAgQIECBAIF8BAVS+/monQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBROQABVuCHVIQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAvgICqHz91U6AAAECBAgQIECAAAECBAgQIECAAAECBAgQKJyAAKpwQ6pDBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF8BQRQ+fqrnQABAgQIECBAgAABAgQIECBAgAABAgQIECBQOAEBVOGGVIcIECBAgAABAgQIECBAgAABAgQIECBAgAABAvkKCKDy9Vc7AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKBwAgKowg2pDhEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE8hUQQOXrr3YCBAgQIECAAAECBAgQIECAAAECBAgQIECAQOEEBFCFG1IdIkCAAAECBAgQIECAAAECBAgQIECAAAECBAjkKyCAytdf7QQIECBAgAABAgQIECBAgAABAgQIECBAgACBwgkIoAo3pDpEgAABAgQIECBAgAABAgQIECBAgAABAgQIEMhXQACVr7/aCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKFExBAFW5IdYgAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgkK+AACpff7UTIECAAAECBAgQIECAAAECBAgQIECAAAECBAonIIAq3JDqEAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgXwEBVL7+aidAgAABAgQIECBAgAABAgQIECBAgAABAgQIFE5AAFW4IdUhAgQIECBAgAABAgQIECBAgAABAgQIECBAgEC+AgKofP3VToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAonIAAqnBDqkMECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgXwFBFD5+qudAAECBAgQIECAAAECBAgQIECAAAECBAgQIFA4AQFU4YZUhwgQIECAAAECBAgQIECAAAECBAgQIECAAAEC+QoIoPL1VzsBAgQIECBAgAABAgQIECBAgAABAgQIECBAoHACAqjCDakOESBAgAABAgQIECBAgAABAgQIECBAgAABAgTyFRBA5euvdgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA4QQEUIUbUh0iQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECOQrIIDK11/tBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHCCQigCjekOkSAAAECBAgQIECAAAECBAgQIECAAAECBAgQyFdAAJWvv9oJECBAgAABAgQIECBAgAABAgQIECBAgAABAoUTEEAVbkh1iAABAgQIECBAgAABAgQIECBAgAABAgQIECCQr4AAKl9/tRMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECicggCrckOoQAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCBfAQFUvv5qJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgUTkAAVbgh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL4CAqh8/dVOgAABAgQIECBAgAABAgQIECBAgAABAgQIECicgACqcEOqQwQIECBAgAABAgQIECBAgAABAgQIECBAgACBfAUEUPn6q50AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgUDgBAVThhlSHCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQL5Cgig8vVXOwECBAgQIECAAAECBAgQIECAAAECBAgQIECgcAICqMINqQ4RIECAAAECBAgQIECAAAECBAgQIECAAAECBPIVEEDl6692AgQIECBAgAABAgQIECBAgAABAgQIECBAgEDhBARQhRtSHSJAgAABAgQIECBAgAABAgQIECBAgAABAgQI5CsggMrXX+0ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgcIJCKAKN6Q6RIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDIV0AAla+/2gkQIECAAAECBAgQIECAAAECBAgQIECAAAEChRMQQBVuSHWIAAECBAgQIECAAAECBAgQIECAAAECBAgQIJCvgAAqX3+1EyBAgAABAgQIECBAgAABAgQIECBAgAABAgQKJyCAKtyQ6hABAgQIECBAgAABAgQIECBAgAABAgQIECBAIF8BAVS+/monQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBROQABVuCHVIQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAvgICqHz91U6AAAECBAgQIECAAAECBAgQIECAAAECBAgQKJyAAKpwQ6pDBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF8BQRQ+fqrnQABAgQIECBAgAABAgQIECBAgAABAgQIECBQOAEBVOGGVIcIECBAgAABAgQIECBAgAABAgQIECBAgAABAvkKCKDy9Vc7AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKBwAgKowg2pDhEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE8hUQQOXrr3YCBAgQIECAAAECBAgQIECAAAECBAgQIECAQOEEBFCFG1IdIkCAAAECBAgQIECAAAECBAgQIECAAAECBAjkKyCAytdf7QQIECBAgAABAgQIECBAgAABAgQIECBAgACBwgkIoAo3pDpEgAABAgQIECBAgAABAgQIECBAgAABAgQIEMhXQACVr7/aCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKFExBAFW5IdYgAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgkK+AACpff7UTIECAAAECBAgQIECAAAECBAgQIECAAAECBAonIIAq3JDqEAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgXwEBVL7+aidAgAABAgQIECBAgAABAgQIECBAgAABAgQIFE5AAFW4IdUhAgQIECBAgAABAgQIECBAgAABAgQIECBAgEC+AgKofP3VToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAonIAAqnBDqkMECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgXwFBFD5+qudAAECBAgQIECAAAECBAgQIECAAAECBAgQIFA4AQFU4YZUhwgQIECAAAECBAgQIECAAAECBAgQIECAAAEC+QoIoPL1VzsBAgQIECBAgAABAgQIECBAgAABAgQIECBAoHACAqjCDakOESBAgAABAgQIECBAgAABAgQIECBAgAABAgTyFRBA5euvdgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA4QQEUIUbUh0iQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECOQrIIDK11/tBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHCCQigCjekOkSAAAECBAgQIECAAAECBAgQIECAAAECBAgQyFdAAJWvv9oJECBAgAABAgQIECBAgAABAgQIECBAgAABAoUTEEAVbkh1iAABAgQIECBAgAABAgQIECBAgAABAgQIECCQr4AAKl9/tRMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECicggCrckOoQAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCBfAQFUvv5qJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgUTkAAVbgh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL4CAqh8/dVOgAABAgQIECBAgAABAgQIECBAgAABAgQIECicgACqcEOqQwQIECBAgAABAgQIECBAgAABAgQIECBAgACBfAUEUPn6q50AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgUDgBAVThhlSHCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQL5Cgig8vVXOwECBAgQIECAAAECBAgQIECAAAECBAgQIECgcAICqMINqQ4RIECAAAECBAgQIECAAAECBAgQIECAAAECBPIVEEDl6692AgQIECBAgAABAgQIECBAgAABAgQIECBAgEDhBARQhRtSHSJAgAABAgQIECBAgAABAgQIECBAgAABAgQI5CsggMrXX+0ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgcIJCKAKN6Q6RIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDIV6DeMj02nJpvE9ROgAABAgQIECBAgAABAgQIECBAgAABAgQIECBQJAEzoIo0mvpCgAABAgQIECBAgAABAgQIECBAgAABAgQIECgBAQFUCQyCJhAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEiiQggCrSaOoLAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKAEBARQJTAImkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQKJKAAKpIo6kvBAgQIECAAAECBAgQIECAAAECBAgQIECAAIESEBBAlcAgaAIBAgQIECBAgAABAgQIECBAgAABAgQIECBAoEgCAqgijaa+ECBAgAABAgQIECBAgAABAgQIECBAgAABAgRKQEAAVQKDoAkECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgSIJCKCKNJr6QoAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAoAQEBVAkMgiYQIECAAAECBAgQIECAAAECBAgQIECAAAECBIokIIAq0mjqCwECBAgQIECAAAECBAgQIECAAAECBAgQIECgBAQEUCUwCJpAgAABAgQIECBAgAABAgQIECBAgAABAgQIECiSgACqSKOpLwQIECBAgAABAgQIECBAgAABAgQIECBAgACBEhAQQJXAIGgCAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKBIAgKoIo2mvhAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIESkBAAFUCg6AJBAgQIECAAAECBAgQIECAAAECBAgQIECAAIEiCQigijSa+kKAAAECBAgQIECAAAECBAgQIECAAAECBAgQKAEBAVQJDIImECBAgAABAgQIECBAgAABAgQIECBAgAABAgSKJCCAKtJo6gsBAgQIECBAgAABAgQIECBAgAABAgQIECBAoAQEBFAlMAiaQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAoksD/AxNWEy9iPvIAAAAAAElFTkSuQmCC"
-    }
-   },
-   "cell_type": "markdown",
-   "id": "ad9e20ae-934a-4b98-b6ab-091c77572c61",
-   "metadata": {},
-   "source": [
-    "The central account has an LF tag  `data_classification:dev` which we will first add to glue table and grant consumer role permissions to that tag\n",
-    "\n",
-    "![image.png](attachment:d1f0c7d4-d102-42f3-a1fc-b26eeb94a2bf.png)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "5506c39d-5b59-436f-82ca-ba1934e60c4d",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "lf_client_central = central_acc_boto_session.client('lakeformation')\n",
-    "lf_client_central.get_data_lake_settings()\n",
-    "\n",
-    "lf_client_central.add_lf_tags_to_resource(\n",
-    "    Resource={\n",
-    "        'Table': {\n",
-    "            'CatalogId': str(central_account),\n",
-    "            'DatabaseName': database_name,\n",
-    "            'Name': table_name\n",
-    "        }\n",
-    "    },\n",
-    "    LFTags=[\n",
-    "        {\n",
-    "            'CatalogId': str(central_account),\n",
-    "            'TagKey': 'data_classification',\n",
-    "            'TagValues': ['dev']\n",
-    "        }\n",
-    "    ]\n",
-    ")\n",
-    "print(f\"Tagged table {database_name}.{table_name} with SharedAccess=consumer\")\n"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "c0bfc0ff-95be-47a5-b49a-028adc23a8c9",
-   "metadata": {},
-   "source": [
-    "Now we need to grant the role in consumer account permissions to the LF tag"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "c069580b-6254-4173-a618-2bdf2fbd2889",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "lf_client_central.grant_permissions(\n",
-    "    Principal={\n",
-    "        'DataLakePrincipalIdentifier': acc_to_role_arn[consumer_account]\n",
-    "    },\n",
-    "    Resource={\n",
-    "        'LFTagPolicy': {\n",
-    "            'CatalogId': str(central_account),\n",
-    "            'ResourceType': 'TABLE',\n",
-    "            'Expression': [\n",
-    "                {\n",
-    "                    'TagKey': 'data_classification',\n",
-    "                    'TagValues': ['dev']\n",
-    "                }\n",
-    "            ]\n",
-    "        }\n",
-    "    },\n",
-    "    Permissions=['SELECT', 'DESCRIBE'],\n",
-    "    PermissionsWithGrantOption=[]\n",
-    ")\n",
-    "\n",
-    "\n",
-    "print(f\"Granted LF-tag based SELECT/DESCRIBE to consumer account {consumer_account}\")\n",
-    "\n",
-    "\n"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "8508880e-a856-4574-8c8a-edbc972c9326",
-   "metadata": {},
-   "source": [
-    "Cross account lakeformation grant permissions automatically creates a RAM share so we need to accept that in consumer account"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "df5665a2-1817-4366-97a6-7370bb3ebf44",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Producer account accepts the RAM invitation\n",
-    "ram_client_consumer = consumer_acc_boto_session.client('ram')\n",
-    "\n",
-    "response = ram_client_consumer.get_resource_share_invitations()\n",
-    "pending = [\n",
-    "    inv for inv in response['resourceShareInvitations']\n",
-    "    if inv['status'] == 'PENDING' and inv['senderAccountId'] == str(central_account)\n",
-    "]\n",
-    "for inv in pending:\n",
-    "    ram_client_consumer.accept_resource_share_invitation(\n",
-    "        resourceShareInvitationArn=inv['resourceShareInvitationArn']\n",
-    "    )\n",
-    "    print(f\"Accepted: {inv['resourceShareInvitationArn']}\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "305acbb5-80b4-4890-adb0-954beba91995",
-   "metadata": {},
-   "source": [
-    "## 4. Consumer reads data from the glue table using Athena"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "3fa4fe66-4e03-4197-80b5-116f1c591183",
-   "metadata": {},
-   "source": [
-    "create a link between glue table in central and the consumer account"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "b089a0cf-e69d-461a-91ab-39d3fc17dc7e",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "glue_client_consumer = consumer_acc_boto_session.client('glue')\n",
-    "\n",
-    "CONSUMER_DB_NAME = 'shared_feature_store_db'\n",
-    "try:\n",
-    "    glue_client_consumer.create_database(\n",
-    "        DatabaseInput={'Name': CONSUMER_DB_NAME}\n",
-    "    )\n",
-    "    print(f\"Created database: {CONSUMER_DB_NAME}\")\n",
-    "except glue_client_consumer.exceptions.AlreadyExistsException:\n",
-    "    print(f\"Database {CONSUMER_DB_NAME} already exists\")\n",
-    "\n",
-    "try:\n",
-    "    glue_client_consumer.create_table(\n",
-    "        DatabaseName=CONSUMER_DB_NAME,\n",
-    "        TableInput={\n",
-    "            'Name': f'{table_name}_link',\n",
-    "            'TargetTable': {\n",
-    "                'CatalogId': str(central_account),\n",
-    "                'DatabaseName': database_name,\n",
-    "                'Name': table_name\n",
-    "            }\n",
-    "        }\n",
-    "    )\n",
-    "    print(f\"Created resource link: {CONSUMER_DB_NAME}.{table_name}_link\")\n",
-    "except glue_client_consumer.exceptions.AlreadyExistsException:\n",
-    "    print(\"Resource link already exists\")\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "4be3b18e-9682-4edd-bfd1-603932622b0b",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import time\n",
-    "\n",
-    "athena_client = consumer_acc_boto_session.client('athena')\n",
-    "CONSUMER_S3_BUCKET = consumer_acc_sagemaker_session.default_bucket()\n",
-    "\n",
-    "query = f'SELECT * FROM {CONSUMER_DB_NAME}.{table_name}_link LIMIT 10'\n",
-    "\n",
-    "response = athena_client.start_query_execution(\n",
-    "    QueryString=query,\n",
-    "    ResultConfiguration={\n",
-    "        'OutputLocation': f's3://{CONSUMER_S3_BUCKET}/athena-results/'\n",
-    "    }\n",
-    ")\n",
-    "\n",
-    "query_id = response['QueryExecutionId']\n",
-    "print(f\"Query started: {query_id}\")\n",
-    "\n",
-    "while True:\n",
-    "    status = athena_client.get_query_execution(QueryExecutionId=query_id)\n",
-    "    state = status['QueryExecution']['Status']['State']\n",
-    "    if state in ['SUCCEEDED', 'FAILED', 'CANCELLED']:\n",
-    "        break\n",
-    "    print(f\"Status: {state}...\")\n",
-    "    time.sleep(2)\n",
-    "\n",
-    "if state == 'SUCCEEDED':\n",
-    "    results = athena_client.get_query_results(QueryExecutionId=query_id)\n",
-    "    for row in results['ResultSet']['Rows']:\n",
-    "        print([col.get('VarCharValue', '') for col in row['Data']])\n",
-    "else:\n",
-    "    reason = status['QueryExecution']['Status'].get('StateChangeReason', 'unknown')\n",
-    "    print(f\"Query {state}: {reason}\")\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "b54072b5-eed0-41de-b238-a79f8884d1e6",
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "py3.10.14",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.10.14"
-  },
-  "widgets": {
-   "application/vnd.jupyter.widget-state+json": {
-    "state": {
-     "15d7159da97842f289a6eae80d88f367": {
-      "model_module": "@jupyter-widgets/base",
-      "model_module_version": "2.0.0",
-      "model_name": "LayoutModel",
-      "state": {}
-     },
-     "16cf8427b8774feabe06a535381438ef": {
-      "model_module": "@jupyter-widgets/base",
-      "model_module_version": "2.0.0",
-      "model_name": "LayoutModel",
-      "state": {}
-     }
-    },
-    "version_major": 2,
-    "version_minor": 0
-   }
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/v3-examples/ml-ops-examples/imgs/fs-lf-cross-account1.png b/v3-examples/ml-ops-examples/imgs/fs-lf-cross-account1.png
deleted file mode 100644
index a126d2e207d268e65a7e03515a3b6dfde8c7ad67..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb b/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb
deleted file mode 100644
index 5f689a3c0d..0000000000
--- a/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb
+++ /dev/null
@@ -1,851 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "# Feature Group Lake Formation Governance "
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "This Demo builds on sagemaker v3 features which is not out yet so we need to tell pip to use local version \n",
-    "\n",
-    "1. install `pyenv` following the instructions here https://github.com/pyenv/pyenv?tab=readme-ov-file#a-getting-pyenv\n",
-    "2. setup your shell env for pyenv https://github.com/pyenv/pyenv?tab=readme-ov-file#b-set-up-your-shell-environment-for-pyenv\n",
-    "3. install and activate python for example (this code was tested on python 3.10.14)\n",
-    "```\n",
-    "pyenv install 3.10.14\n",
-    "pyenv virtualenv 3.10.14 py3.10.14\n",
-    "pyenv activate py3.10.14\n",
-    "```\n",
-    "3. You will then need to run `pip install -e ./sagemaker-mlops` before starting the jupyter notebook to use the local packages\n",
-    "4. `pip install jupyter notebook`\n",
-    "5. `jupyter notebook`"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## New SDK API Changes\n",
-    "\n",
-    "This release introduces Lake Formation integration through the following additions:\n",
-    "\n",
-    "### New Class: `LakeFormationConfig`\n",
-    "\n",
-    "A configuration class for Lake Formation governance settings:\n",
-    "\n",
-    "```python\n",
-    "from sagemaker.mlops.feature_store.feature_group import LakeFormationConfig\n",
-    "\n",
-    "lake_formation_config = LakeFormationConfig()\n",
-    "lake_formation_config.enabled = True                    # Enable Lake Formation governance\n",
-    "lake_formation_config.use_service_linked_role = True    # Use LF service-linked role (default)\n",
-    "lake_formation_config.registration_role_arn = None      # This is the role used by LF to access your Resources\n",
-    "lake_formation_config.show_s3_policy = True             # Print recommended S3 deny policy\n",
-    "```\n",
-    "\n",
-    "### New Parameter in FeatureGroup.create(): lake_formation_config\n",
-    "Pass a LakeFormationConfig object to enable Lake Formation at creation time:\n",
-    "```python\n",
-    "fg = FeatureGroup.create(\n",
-    "    feature_group_name=\"my-feature-group\",\n",
-    "    # ... other parameters ...\n",
-    "    lake_formation_config=lake_formation_config,  # OPTIONAL NEW PARAMETER\n",
-    ")\n",
-    "```\n",
-    "\n",
-    "### New Method: FeatureGroup.enable_lake_formation()\n",
-    "Enable Lake Formation on an existing Feature Group:\n",
-    "```python\n",
-    "fg.enable_lake_formation(\n",
-    "    use_service_linked_role=True,      # Use LF service-linked role (default)\n",
-    "    registration_role_arn=None,        # Custom role ARN (if not using SLR)\n",
-    "    wait_for_active=False,             # Wait for Feature Group to be Created\n",
-    "    show_s3_policy=False,              # Print recommended S3 deny policy\n",
-    ")\n",
-    "```\n"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Lake Formation Setup Process\n",
-    "\n",
-    "When you enable Lake Formation governance (either at creation time or via `enable_lake_formation()`), the SDK performs the following steps automatically:\n",
-    "\n",
-    "### Step 1: Register S3 Location with Lake Formation\n",
-    "\n",
-    "The offline store's S3 location is registered as a Lake Formation data lake location. This allows Lake Formation to manage access to the underlying data files.\n",
-    "\n",
-    "- Uses either the Lake Formation service-linked role (default) or a custom registration role\n",
-    "- If the location is already registered, this step is skipped\n",
-    "\n",
-    "### Step 2: Grant Lake Formation Permissions\n",
-    "\n",
-    "The Feature Group's `role_arn` (offline store role) is granted the following permissions on the Glue table via Lake Formation:\n",
-    "\n",
-    "- `SELECT` - Read data from the table\n",
-    "- `INSERT` - Write new records\n",
-    "- `DELETE` - Remove records\n",
-    "- `DESCRIBE` - View table metadata\n",
-    "- `ALTER` - Modify table schema\n",
-    "\n",
-    "### Step 3: Revoke IAMAllowedPrincipal Permissions\n",
-    "\n",
-    "By default, Glue tables allow access to any IAM principal with appropriate IAM permissions (`IAMAllowedPrincipal`). This step revokes that default permission, ensuring that:\n",
-    "\n",
-    "- Access is now controlled exclusively through Lake Formation\n",
-    "- Only principals explicitly granted permissions via Lake Formation can access the data\n",
-    "\n",
-    "### Optional: S3 Deny Policy\n",
-    "\n",
-    "When `show_s3_policy=True`, the SDK prints a recommended S3 bucket policy. This policy adds an additional layer of protection by denying direct S3 access to all principals except:\n",
-    "\n",
-    "- The Lake Formation service-linked role\n",
-    "- The Feature Store offline store role\n",
-    "\n",
-    "**Note:** The S3 policy is not applied automatically—you must manually add it to your bucket policy if desired.\n"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    " \n",
-    "This notebook demonstrates two workflows for using SageMaker Feature Store with Lake Formation governance:\n",
-    "\n",
-    "1. **Example 1**: Create Feature Group with Lake Formation enabled at creation time\n",
-    "2. **Example 2**: Create Feature Group first, then enable Lake Formation separately\n",
-    "\n",
-    "Both workflows include record ingestion to verify everything works end-to-end.\n",
-    "\n",
-    "## Prerequisites\n",
-    "\n",
-    "- AWS credentials configured with permissions for SageMaker, S3, Glue, and Lake Formation\n",
-    "- An S3 bucket for the offline store\n",
-    "- An IAM role with Feature Store permissions\n",
-    "\n",
-    "## Required IAM Permissions\n",
-    "\n",
-    "This notebook uses two separate IAM roles:\n",
-    "1. **Execution Role**: The SageMaker execution role running this notebook. It requires having Lakeformation Data lake admin permissions and Feature store permissions\n",
-    "2. **Offline Store Role**: A dedicated role for Feature Store S3 access\n",
-    "\n",
-    "## Lake Formation Admin Requirements\n",
-    "\n",
-    "The person enabling Lake Formation governance must be a **Data Lake Administrator** in Lake Formation. There are two options for enabling lakeformation governance depending on your organization's setup:\n",
-    "\n",
-    "### Option 1: Single Role (Data Lake Admin + Feature Store Admin)\n",
-    "\n",
-    "If the caller has both:\n",
-    "- Data Lake Administrator privileges in Lake Formation\n",
-    "- Permissions to create Feature Groups in SageMaker\n",
-    "\n",
-    "Then they can use `FeatureGroup.create()` with `lake_formation_config` to enable governance at creation time (Example 1).\n",
-    "\n",
-    "### Option 2: Separate Roles (ML Engineer + Data Lake Admin)\n",
-    "\n",
-    "If the person creating the Feature Group is different from the Data Lake Administrator:\n",
-    "\n",
-    "1. **ML Engineer** creates the Feature Group without Lake Formation using `FeatureGroup.create()`\n",
-    "2. **Data Lake Admin** later enables governance by calling `enable_lake_formation()` on the existing Feature Group (Example 2)\n",
-    "\n",
-    "\n",
-    "### Execution Role Policy\n",
-    "\n",
-    "You can assume a role with the following policy to run this notebook\n",
-    "Make sure to update the policy to use the offline store role\n",
-    "\n",
-    "```json\n",
-    "{\n",
-    "    \"Version\": \"2012-10-17\",\n",
-    "    \"Statement\": [\n",
-    "        {\n",
-    "            \"Sid\": \"FeatureGroupManagement\",\n",
-    "            \"Effect\": \"Allow\",\n",
-    "            \"Action\": [\n",
-    "                \"sagemaker:*\"\n",
-    "            ],\n",
-    "            \"Resource\": \"arn:aws:sagemaker:*:*:feature-group/*\"\n",
-    "        },\n",
-    "        {\n",
-    "            \"Sid\": \"LakeFormation\",\n",
-    "            \"Effect\": \"Allow\",\n",
-    "            \"Action\": [\n",
-    "                \"lakeformation:RegisterResource\",\n",
-    "                \"lakeformation:DeregisterResource\",\n",
-    "                \"lakeformation:GrantPermissions\",\n",
-    "                \"lakeformation:RevokePermissions\"\n",
-    "            ],\n",
-    "            \"Resource\": \"*\"\n",
-    "        },\n",
-    "        {\n",
-    "            \"Sid\": \"GlueCatalogRead\",\n",
-    "            \"Effect\": \"Allow\",\n",
-    "            \"Action\": [\n",
-    "                \"glue:GetTable\",\n",
-    "                \"glue:GetDatabase\",\n",
-    "                \"glue:DeleteTable\"\n",
-    "            ],\n",
-    "            \"Resource\": [\n",
-    "                \"arn:aws:glue:*:*:catalog\",\n",
-    "                \"arn:aws:glue:*:*:database/sagemaker_featurestore\",\n",
-    "                \"arn:aws:glue:*:*:table/sagemaker_featurestore/*\"\n",
-    "            ]\n",
-    "        },\n",
-    "        {\n",
-    "            \"Sid\": \"PassOfflineStoreRole\",\n",
-    "            \"Effect\": \"Allow\",\n",
-    "            \"Action\": \"iam:PassRole\",\n",
-    "            \"Resource\": \"arn:aws:iam::*:role/<your offline store role>\"\n",
-    "        },\n",
-    "        {\n",
-    "            \"Sid\": \"LakeFormationServiceLinkedRole\",\n",
-    "            \"Effect\": \"Allow\",\n",
-    "            \"Action\": [\n",
-    "                \"iam:GetRole\",\n",
-    "                \"iam:PutRolePolicy\",\n",
-    "                \"iam:GetRolePolicy\"\n",
-    "            ],\n",
-    "            \"Resource\": \"arn:aws:iam::*:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess\"\n",
-    "        },\n",
-    "        {\n",
-    "            \"Sid\": \"S3SagemakerDefaultBucket\",\n",
-    "            \"Effect\": \"Allow\",\n",
-    "            \"Action\": [\n",
-    "                \"s3:CreateBucket\",\n",
-    "                \"s3:GetBucketAcl\",\n",
-    "                \"s3:ListBucket\"\n",
-    "            ],\n",
-    "            \"Resource\": [\n",
-    "                \"arn:aws:s3:::sagemaker-*\"\n",
-    "            ]\n",
-    "        },\n",
-    "        {\n",
-    "            \"Sid\": \"CreateGlueTable\",\n",
-    "            \"Effect\": \"Allow\",\n",
-    "            \"Action\": [\n",
-    "                \"glue:CreateTable\"\n",
-    "            ],\n",
-    "            \"Resource\": [\n",
-    "                \"*\"\n",
-    "            ]\n",
-    "        }\n",
-    "    ]\n",
-    "}\n",
-    "```"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Setup"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import boto3\n",
-    "import os\n",
-    "\n",
-    "boto3.DEFAULT_SESSION = None\n",
-    "def assume_role(role_arn, session_name=\"AssumedRoleSession\"):\n",
-    "    \"\"\"\n",
-    "    Assume an AWS IAM role and return temporary credentials.\n",
-    "    \n",
-    "    Args:\n",
-    "        role_arn: The ARN of the role to assume\n",
-    "        session_name: A name for the assumed role session\n",
-    "    \n",
-    "    Returns:\n",
-    "        A boto3 session with the assumed role credentials\n",
-    "    \"\"\"\n",
-    "    sts_client = boto3.client('sts')\n",
-    "    \n",
-    "    response = sts_client.assume_role(\n",
-    "        RoleArn=role_arn,\n",
-    "        RoleSessionName=session_name\n",
-    "    )\n",
-    "    \n",
-    "    credentials = response['Credentials']\n",
-    "    \n",
-    "    # Create a new session with the temporary credentials\n",
-    "    session = boto3.Session(\n",
-    "        aws_access_key_id=credentials['AccessKeyId'],\n",
-    "        aws_secret_access_key=credentials['SecretAccessKey'],\n",
-    "        aws_session_token=credentials['SessionToken']\n",
-    "    )\n",
-    "    \n",
-    "    return session"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import time\n",
-    "from datetime import datetime\n",
-    "from datetime import timezone\n",
-    "\n",
-    "import boto3\n",
-    "from botocore.exceptions import ClientError\n",
-    "\n",
-    "# Import the FeatureGroup with Lake Formation support\n",
-    "from sagemaker.mlops.feature_store.feature_group import FeatureGroup, LakeFormationConfig\n",
-    "from sagemaker.core.shapes import (\n",
-    "    FeatureDefinition,\n",
-    "    FeatureValue,\n",
-    "    OfflineStoreConfig,\n",
-    "    OnlineStoreConfig,\n",
-    "    S3StorageConfig,\n",
-    ")\n",
-    "from sagemaker.core.helper.session_helper import Session as SageMakerSession, get_execution_role"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Configuration"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Use SageMaker session to get default bucket and execution role\n",
-    "\n",
-    "# Execution role (for running this notebook)\n",
-    "EXECUTION_ROLE_ARN = 'arn:aws:iam::<account id>:role/<role>'\n",
-    "\n",
-    "\n",
-    "# Offline store role (dedicated role for Feature Store S3 access)\n",
-    "# Replace with your dedicated offline store role ARN\n",
-    "# https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store-adding-policies.html\n",
-    "OFFLINE_STORE_ROLE_ARN = \"arn:aws:iam::<account id>:role/<role>\"\n",
-    "\n",
-    "\n",
-    "boto_session = assume_role(EXECUTION_ROLE_ARN)\n",
-    "sagemaker_session = SageMakerSession(boto_session=boto_session)\n",
-    "sts = boto_session.client('sts')\n",
-    "\n",
-    "S3_BUCKET = sagemaker_session.default_bucket()\n",
-    "REGION = sagemaker_session.boto_session.region_name\n",
-    "\n",
-    "\n",
-    "print(f\"S3 Bucket: {S3_BUCKET}\")\n",
-    "print(f\"Execution Role ARN:{sts.get_caller_identity()['Arn']}\")\n",
-    "print(f\"Offline Store Role ARN: {OFFLINE_STORE_ROLE_ARN}\")\n",
-    "print(f\"Region: {REGION}\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Common Feature Definitions"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "feature_definitions = [\n",
-    "    FeatureDefinition(feature_name=\"customer_id\", feature_type=\"String\"),\n",
-    "    FeatureDefinition(feature_name=\"event_time\", feature_type=\"String\"),\n",
-    "    FeatureDefinition(feature_name=\"age\", feature_type=\"Integral\"),\n",
-    "    FeatureDefinition(feature_name=\"total_purchases\", feature_type=\"Integral\"),\n",
-    "    FeatureDefinition(feature_name=\"avg_order_value\", feature_type=\"Fractional\"),\n",
-    "]\n",
-    "\n",
-    "print(\"Feature Definitions:\")\n",
-    "for fd in feature_definitions:\n",
-    "    print(f\"  - {fd.feature_name}: {fd.feature_type}\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Helper Function: Ingest Records"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "def ingest_sample_records(feature_group, num_records=3):\n",
-    "    \"\"\"\n",
-    "    Ingest sample records into the Feature Group.\n",
-    "    \n",
-    "    Args:\n",
-    "        feature_group: The FeatureGroup to ingest records into\n",
-    "        num_records: Number of sample records to ingest\n",
-    "    \"\"\"\n",
-    "    print(f\"\\nIngesting {num_records} sample records...\")\n",
-    "    \n",
-    "    for i in range(num_records):\n",
-    "        event_time = datetime.now(timezone.utc).isoformat()\n",
-    "        record = [\n",
-    "            FeatureValue(feature_name=\"customer_id\", value_as_string=f\"cust_{i+1}\"),\n",
-    "            FeatureValue(feature_name=\"event_time\", value_as_string=event_time),\n",
-    "            FeatureValue(feature_name=\"age\", value_as_string=str(25 + i * 5)),\n",
-    "            FeatureValue(feature_name=\"total_purchases\", value_as_string=str(10 + i * 3)),\n",
-    "            FeatureValue(feature_name=\"avg_order_value\", value_as_string=str(50.0 + i * 10.5)),\n",
-    "        ]\n",
-    "        \n",
-    "        feature_group.put_record(record=record)\n",
-    "        print(f\"  Ingested record for customer: cust_{i+1}\")\n",
-    "    \n",
-    "    print(f\"Successfully ingested {num_records} records!\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "---\n",
-    "# Example 1: Create Feature Group with Lake Formation Enabled\n",
-    "\n",
-    "This example creates a Feature Group with Lake Formation governance enabled at creation time using `LakeFormationConfig`."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Generate unique name for example 1\n",
-    "timestamp = datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
-    "FG_NAME_WORKFLOW1 = f\"lf-demo-workflow1-{timestamp}\"\n",
-    "\n",
-    "print(f\"Example 1 Feature Group: {FG_NAME_WORKFLOW1}\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Configure online and offline stores\n",
-    "online_store_config = OnlineStoreConfig(enable_online_store=True)\n",
-    "\n",
-    "offline_store_config_1 = OfflineStoreConfig(\n",
-    "    s3_storage_config=S3StorageConfig(\n",
-    "        s3_uri=f\"s3://{S3_BUCKET}/feature-store-demo/\"\n",
-    "    )\n",
-    ")\n",
-    "\n",
-    "# Configure Lake Formation - enabled at creation\n",
-    "lake_formation_config = LakeFormationConfig()\n",
-    "lake_formation_config.enabled = True\n",
-    "lake_formation_config.use_service_linked_role = True\n",
-    "lake_formation_config.show_s3_policy = True\n",
-    "\n",
-    "print(\"Store Config:\")\n",
-    "print(f\"  Online Store: enabled\")\n",
-    "print(f\"  Offline Store S3: s3://{S3_BUCKET}/feature-store-demo/\")\n",
-    "print(\"\\nLake Formation Config:\")\n",
-    "print(f\"  enabled: {lake_formation_config.enabled}\")\n",
-    "print(f\"  use_service_linked_role: {lake_formation_config.use_service_linked_role}\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Create Feature Group with Lake Formation enabled\n",
-    "print(\"Creating Feature Group with Lake Formation enabled...\")\n",
-    "print(\"This will:\")\n",
-    "print(\"  1. Create the Feature Group with online + offline stores\")\n",
-    "print(\"  2. Wait for 'Created' status\")\n",
-    "print(\"  3. Register S3 with Lake Formation\")\n",
-    "print(\"  4. Grant permissions to execution role\")\n",
-    "print(\"  5. Revoke IAMAllowedPrincipal permissions\")\n",
-    "print()\n",
-    "\n",
-    "fg_workflow1 = FeatureGroup.create(\n",
-    "    feature_group_name=FG_NAME_WORKFLOW1,\n",
-    "    record_identifier_feature_name=\"customer_id\",\n",
-    "    event_time_feature_name=\"event_time\",\n",
-    "    feature_definitions=feature_definitions,\n",
-    "    online_store_config=online_store_config,\n",
-    "    offline_store_config=offline_store_config_1,\n",
-    "    role_arn=OFFLINE_STORE_ROLE_ARN,\n",
-    "    description=\"Workflow 1: Lake Formation enabled at creation\",\n",
-    "    lake_formation_config=lake_formation_config, # new parameter\n",
-    "    region=REGION,\n",
-    "    session=boto_session\n",
-    ")\n",
-    "\n",
-    "print(f\"\\nFeature Group created: {fg_workflow1.feature_group_name}\")\n",
-    "print(f\"Status: {fg_workflow1.feature_group_status}\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Verify Feature Group status\n",
-    "fg_workflow1.refresh()\n",
-    "print(f\"Feature Group: {fg_workflow1.feature_group_name}\")\n",
-    "print(f\"Status: {fg_workflow1.feature_group_status}\")\n",
-    "print(f\"ARN: {fg_workflow1.feature_group_arn}\")\n",
-    "\n",
-    "DataCatalogConfig = fg_workflow1.offline_store_config.data_catalog_config\n",
-    "print(f'Table Name: {DataCatalogConfig.table_name}')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Ingest sample records to verify everything works\n",
-    "ingest_sample_records(fg_workflow1, num_records=10)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Retrieve a sample record from the online store\n",
-    "print(\"Retrieving record for customer 'cust_1' from online store...\")\n",
-    "response = fg_workflow1.get_record(record_identifier_value_as_string=\"cust_3\")\n",
-    "\n",
-    "print(f\"\\nRecord retrieved successfully!\")\n",
-    "print(f\"Features:\")\n",
-    "for feature in response.record:\n",
-    "    print(f\"  {feature.feature_name}: {feature.value_as_string}\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "---\n",
-    "# Example 2: Create Feature Group, Then Enable Lake Formation\n",
-    "\n",
-    "This example creates a Feature Group first without Lake Formation, then enables it separately using `enable_lake_formation()`."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Generate unique name for example 2\n",
-    "timestamp = datetime.now().strftime(\"%Y%m%d%H%M%S\")\n",
-    "FG_NAME_WORKFLOW2 = f\"lf-demo-workflow2-{timestamp}\"\n",
-    "\n",
-    "print(f\"Example 2 Feature Group: {FG_NAME_WORKFLOW2}\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Configure online and offline stores\n",
-    "online_store_config_2 = OnlineStoreConfig(enable_online_store=True)\n",
-    "\n",
-    "offline_store_config_2 = OfflineStoreConfig(\n",
-    "    s3_storage_config=S3StorageConfig(\n",
-    "        s3_uri=f\"s3://{S3_BUCKET}/feature-store-demo/\"\n",
-    "    ),\n",
-    "    table_format=\"Iceberg\"\n",
-    ")\n",
-    "\n",
-    "# Step 1: Create Feature Group WITHOUT Lake Formation\n",
-    "print(\"Step 1: Creating Feature Group without Lake Formation...\")\n",
-    "\n",
-    "fg_workflow2 = FeatureGroup.create(\n",
-    "    feature_group_name=FG_NAME_WORKFLOW2,\n",
-    "    record_identifier_feature_name=\"customer_id\",\n",
-    "    event_time_feature_name=\"event_time\",\n",
-    "    feature_definitions=feature_definitions,\n",
-    "    online_store_config=online_store_config_2,\n",
-    "    offline_store_config=offline_store_config_2,\n",
-    "    role_arn=OFFLINE_STORE_ROLE_ARN,\n",
-    "    description=\"Workflow 2: Lake Formation enabled after creation\",\n",
-    "    region=REGION,\n",
-    "    session=boto_session\n",
-    ")\n",
-    "\n",
-    "print(f\"Feature Group created: {fg_workflow2.feature_group_name}\")\n",
-    "print(f\"Status: {fg_workflow2.feature_group_status}\")\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Step 2: Wait for Feature Group to be ready\n",
-    "print(\"Step 2: Waiting for Feature Group to reach 'Created' status...\")\n",
-    "fg_workflow2.wait_for_status(target_status=\"Created\", poll=10, timeout=300)\n",
-    "print(f\"Status: {fg_workflow2.feature_group_status}\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Here you can optionally assume a different role with just datalake permissions and describe Feature Group permission"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Step 3: Enable Lake Formation governance\n",
-    "print(\"Step 3: Enabling Lake Formation governance...\")\n",
-    "print(\"This will:\")\n",
-    "print(\"  1. Register S3 with Lake Formation\")\n",
-    "print(\"  2. Grant permissions to execution role\")\n",
-    "print(\"  3. Revoke IAMAllowedPrincipal permissions\")\n",
-    "print()\n",
-    "fg_workflow2 = FeatureGroup.get(FG_NAME_WORKFLOW2)\n",
-    "result = fg_workflow2.enable_lake_formation( # new method\n",
-    "    use_service_linked_role=True,\n",
-    ")\n",
-    "\n",
-    "print(f\"\\nLake Formation setup results:\")\n",
-    "print(f\"  s3_registration: {result['s3_registration']}\")\n",
-    "print(f\"  permissions_granted: {result['permissions_granted']}\")\n",
-    "print(f\"  iam_principal_revoked: {result['iam_principal_revoked']}\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Step 4: Ingest sample records to verify everything works\n",
-    "# This is still using the first role\n",
-    "print(\"Step 4: Ingesting records to verify Lake Formation setup...\")\n",
-    "ingest_sample_records(fg_workflow2, num_records=4)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Step 5: Retrieve a sample record from the online store\n",
-    "print(\"Step 5: Retrieving record for customer 'cust_1' from online store...\")\n",
-    "response = fg_workflow2.get_record(record_identifier_value_as_string=\"cust_1\")\n",
-    "\n",
-    "print(f\"\\nRecord retrieved successfully!\")\n",
-    "print(f\"Features:\")\n",
-    "for feature in response.record:\n",
-    "    print(f\"  {feature.feature_name}: {feature.value_as_string}\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Verify Feature Group status\n",
-    "fg_workflow2.refresh()\n",
-    "print(f\"Feature Group: {fg_workflow2.feature_group_name}\")\n",
-    "print(f\"Status: {fg_workflow2.feature_group_status}\")\n",
-    "print(f\"ARN: {fg_workflow2.feature_group_arn}\")\n",
-    "DataCatalogTable = fg_workflow2.offline_store_config.data_catalog_config.table_name\n",
-    "print(f\"Table Name: {DataCatalogTable}\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "---\n",
-    "# Cleanup\n",
-    "\n",
-    "Delete the Feature Groups and **associated Glue tables** created in this demo."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Helper Function: Cleanup"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "def cleanup_feature_group(fg):\n",
-    "    \"\"\"\n",
-    "    Delete a FeatureGroup and its associated Glue table.\n",
-    "    \n",
-    "    Args:\n",
-    "        fg: The FeatureGroup to delete.\n",
-    "    \"\"\"\n",
-    "    try:\n",
-    "        # Delete the Glue table if it exists\n",
-    "        if fg.offline_store_config is not None:\n",
-    "            try:\n",
-    "                fg.refresh()  # Ensure we have latest config\n",
-    "                data_catalog_config = fg.offline_store_config.data_catalog_config\n",
-    "                if data_catalog_config is not None:\n",
-    "                    database_name = data_catalog_config.database\n",
-    "                    table_name = data_catalog_config.table_name\n",
-    "\n",
-    "                    if database_name and table_name:\n",
-    "                        glue_client = boto3.client(\"glue\")\n",
-    "                        try:\n",
-    "                            glue_client.delete_table(DatabaseName=database_name, Name=table_name)\n",
-    "                            print(f\"Deleted Glue table: {database_name}.{table_name}\")\n",
-    "                        except ClientError as e:\n",
-    "                            # Ignore if table doesn't exist\n",
-    "                            if e.response[\"Error\"][\"Code\"] != \"EntityNotFoundException\":\n",
-    "                                raise\n",
-    "            except Exception as e:\n",
-    "                # Don't fail cleanup if Glue table deletion fails\n",
-    "                print(f\"Warning: Could not delete Glue table: {e}\")\n",
-    "\n",
-    "        # Delete the FeatureGroup\n",
-    "        fg.delete()\n",
-    "        print(f\"Deleted Feature Group: {fg.feature_group_name}\")\n",
-    "    except ClientError as e:\n",
-    "        print(f\"Error during cleanup: {e}\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Uncomment to delete the Feature Groups\n",
-    "cleanup_feature_group(fg_workflow1)\n",
-    "cleanup_feature_group(fg_workflow2)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "---\n",
-    "# Summary\n",
-    "\n",
-    "This notebook demonstrated two workflows:\n",
-    "\n",
-    "**Example 1: Enable Lake Formation Governance at Creation**\n",
-    "- Use `LakeFormationConfig` with `enabled=True` in `FeatureGroup.create()`\n",
-    "- Lake Formation is automatically configured after Feature Group creation\n",
-    "- Both online and offline stores enabled\n",
-    "\n",
-    "**Example 2: Enable Lake Formation Later**\n",
-    "- Create Feature Group normally without Lake Formation\n",
-    "- Call `enable_lake_formation()` method after creation\n",
-    "- More control over when Lake Formation is enabled\n"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "---\n",
-    "# FAQ:\n",
-    "\n",
-    "## What is the S3 deny policy for?\n",
-    "\n",
-    "When you enable Lake Formation governance, you control access to data through Lake Formation permissions. However, **IAM roles that already have direct S3 access will continue to have access** to the underlying data files, bypassing Lake Formation entirely.\n",
-    "\n",
-    "The S3 deny policy closes this access path by explicitly denying S3 access to all principals except:\n",
-    "- The Lake Formation service-linked role (for data access)\n",
-    "- The Feature Store offline store role provided during Feature Group creation\n",
-    "\n",
-    "## Why don't we apply the S3 deny policy automatically?\n",
-    "\n",
-    "We provide the policy as a **recommendation** rather than applying it automatically for several important reasons:\n",
-    "\n",
-    "### 1. Protect existing SageMaker workflows from breaking\n",
-    "\n",
-    "Many customers already have SageMaker training and processing jobs wired directly to S3 URIs. An automatic S3 deny could cause those jobs to fail the moment governance is enabled on a table.\n",
-    "\n",
-    "### 2. Support different personas and trust levels\n",
-    "\n",
-    "Different users have different access needs:\n",
-    "- **Analysts / BI users** - should only see data through governed surfaces (Lake Formation tables, Athena, Redshift, etc.)\n",
-    "- **ML / Data engineers** - often need raw S3 access for training, feature engineering, and debugging\n",
-    "\n",
-    "### 3. Enable gradual migration to stronger governance\n",
-    "\n",
-    "Many customers want to phase in Lake Formation governance:\n",
-    "1. Start by governing table access only\n",
-    "2. Later tighten S3 access once they've refactored jobs and validated behavior\n",
-    "\n",
-    "### 4. Avoid breaking existing bucket policies\n",
-    "\n",
-    "Automatically modifying bucket policies could:\n",
-    "- Conflict with existing policy statements\n",
-    "- Lock out users or services unexpectedly\n",
-    "- Cause cascading failures across multiple applications sharing the bucket\n",
-    "\n",
-    "Therefore, the S3 policy is provided as a starting point that should be validated by the user. \n"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3 (ipykernel)",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.10.14"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 4
-}

From bdcbcf789116cdac3faa2bbf1bf56691d4b97734 Mon Sep 17 00:00:00 2001
From: Alexander Young <youngag@amazon.com>
Date: Tue, 31 Mar 2026 19:18:35 +0000
Subject: [PATCH 20/22] Removed excess LakeFormation tests and readded Athena
 Query tests

---
 .../mlops/feature_store/test_athena_query.py  |  114 +
 .../mlops/feature_store/test_lakeformation.py | 2307 -----------------
 2 files changed, 114 insertions(+), 2307 deletions(-)
 create mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_athena_query.py
 delete mode 100644 sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py

diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_athena_query.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_athena_query.py
new file mode 100644
index 0000000000..5085ef9613
--- /dev/null
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_athena_query.py
@@ -0,0 +1,114 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0
+"""Unit tests for athena_query.py"""
+import os
+import pytest
+from unittest.mock import Mock, patch, MagicMock
+import pandas as pd
+
+from sagemaker.mlops.feature_store.athena_query import AthenaQuery
+
+
+class TestAthenaQuery:
+    @pytest.fixture
+    def mock_session(self):
+        session = Mock()
+        session.boto_session.client.return_value = Mock()
+        session.boto_region_name = "us-west-2"
+        session.sagemaker_config = {}
+        return session
+
+    @pytest.fixture
+    def athena_query(self, mock_session):
+        return AthenaQuery(
+            catalog="AwsDataCatalog",
+            database="sagemaker_featurestore",
+            table_name="my_feature_group",
+            sagemaker_session=mock_session,
+        )
+
+    def test_initialization(self, athena_query):
+        assert athena_query.catalog == "AwsDataCatalog"
+        assert athena_query.database == "sagemaker_featurestore"
+        assert athena_query.table_name == "my_feature_group"
+        assert athena_query._current_query_execution_id is None
+
+    @patch("sagemaker.mlops.feature_store.athena_query.start_query_execution")
+    def test_run_starts_query(self, mock_start, athena_query):
+        mock_start.return_value = {"QueryExecutionId": "query-123"}
+
+        result = athena_query.run(
+            query_string="SELECT * FROM table",
+            output_location="s3://bucket/output",
+        )
+
+        assert result == "query-123"
+        assert athena_query._current_query_execution_id == "query-123"
+        assert athena_query._result_bucket == "bucket"
+        assert athena_query._result_file_prefix == "output"
+
+    @patch("sagemaker.mlops.feature_store.athena_query.start_query_execution")
+    def test_run_with_kms_key(self, mock_start, athena_query):
+        mock_start.return_value = {"QueryExecutionId": "query-123"}
+
+        athena_query.run(
+            query_string="SELECT * FROM table",
+            output_location="s3://bucket/output",
+            kms_key="arn:aws:kms:us-west-2:123:key/abc",
+        )
+
+        mock_start.assert_called_once()
+        call_kwargs = mock_start.call_args[1]
+        assert call_kwargs["kms_key"] == "arn:aws:kms:us-west-2:123:key/abc"
+
+    @patch("sagemaker.mlops.feature_store.athena_query.wait_for_athena_query")
+    def test_wait_calls_helper(self, mock_wait, athena_query):
+        athena_query._current_query_execution_id = "query-123"
+
+        athena_query.wait()
+
+        mock_wait.assert_called_once_with(athena_query.sagemaker_session, "query-123")
+
+    @patch("sagemaker.mlops.feature_store.athena_query.get_query_execution")
+    def test_get_query_execution(self, mock_get, athena_query):
+        athena_query._current_query_execution_id = "query-123"
+        mock_get.return_value = {"QueryExecution": {"Status": {"State": "SUCCEEDED"}}}
+
+        result = athena_query.get_query_execution()
+
+        assert result["QueryExecution"]["Status"]["State"] == "SUCCEEDED"
+
+    @patch("sagemaker.mlops.feature_store.athena_query.get_query_execution")
+    @patch("sagemaker.mlops.feature_store.athena_query.download_athena_query_result")
+    @patch("pandas.read_csv")
+    @patch("os.path.join")
+    def test_as_dataframe_success(self, mock_join, mock_read_csv, mock_download, mock_get, athena_query):
+        athena_query._current_query_execution_id = "query-123"
+        athena_query._result_bucket = "bucket"
+        athena_query._result_file_prefix = "prefix"
+
+        mock_get.return_value = {"QueryExecution": {"Status": {"State": "SUCCEEDED"}}}
+        mock_join.return_value = "/tmp/query-123.csv"
+        mock_read_csv.return_value = pd.DataFrame({"col": [1, 2, 3]})
+
+        with patch("tempfile.gettempdir", return_value="/tmp"):
+            with patch("os.remove"):
+                df = athena_query.as_dataframe()
+
+        assert len(df) == 3
+
+    @patch("sagemaker.mlops.feature_store.athena_query.get_query_execution")
+    def test_as_dataframe_raises_when_running(self, mock_get, athena_query):
+        athena_query._current_query_execution_id = "query-123"
+        mock_get.return_value = {"QueryExecution": {"Status": {"State": "RUNNING"}}}
+
+        with pytest.raises(RuntimeError, match="still executing"):
+            athena_query.as_dataframe()
+
+    @patch("sagemaker.mlops.feature_store.athena_query.get_query_execution")
+    def test_as_dataframe_raises_when_failed(self, mock_get, athena_query):
+        athena_query._current_query_execution_id = "query-123"
+        mock_get.return_value = {"QueryExecution": {"Status": {"State": "FAILED"}}}
+
+        with pytest.raises(RuntimeError, match="failed"):
+            athena_query.as_dataframe()
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py
deleted file mode 100644
index d378dd1753..0000000000
--- a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py
+++ /dev/null
@@ -1,2307 +0,0 @@
-"""Unit tests for Lake Formation integration with FeatureGroupManager."""
-from unittest.mock import MagicMock, patch
-
-import botocore.exceptions
-import pytest
-
-from sagemaker.mlops.feature_store import FeatureGroupManager, LakeFormationConfig
-
-
-class TestS3UriToArn:
-    """Tests for _s3_uri_to_arn static method."""
-
-    def test_converts_s3_uri_to_arn(self):
-        """Test S3 URI is converted to ARN format."""
-        uri = "s3://my-bucket/my-prefix/data"
-        result = FeatureGroupManager._s3_uri_to_arn(uri)
-        assert result == "arn:aws:s3:::my-bucket/my-prefix/data"
-
-    def test_handles_bucket_only_uri(self):
-        """Test S3 URI with bucket only."""
-        uri = "s3://my-bucket"
-        result = FeatureGroupManager._s3_uri_to_arn(uri)
-        assert result == "arn:aws:s3:::my-bucket"
-
-    def test_returns_arn_unchanged(self):
-        """Test ARN input is returned unchanged (idempotent)."""
-        arn = "arn:aws:s3:::my-bucket/path"
-        result = FeatureGroupManager._s3_uri_to_arn(arn)
-        assert result == arn
-
-    def test_uses_region_for_partition(self):
-        """Test that region is used to determine partition."""
-        uri = "s3://my-bucket/path"
-        result = FeatureGroupManager._s3_uri_to_arn(uri, region="cn-north-1")
-        assert result.startswith("arn:aws-cn:s3:::")
-
-
-
-class TestGetLakeFormationClient:
-    """Tests for _get_lake_formation_client method."""
-
-    @patch("sagemaker.mlops.feature_store.feature_group_manager.Session")
-    def test_creates_client_with_default_session(self, mock_session_class):
-        """Test client creation with default session."""
-        mock_session = MagicMock()
-        mock_client = MagicMock()
-        mock_session.client.return_value = mock_client
-        mock_session_class.return_value = mock_session
-
-        fg = MagicMock(spec=FeatureGroupManager)
-        fg._get_lake_formation_client = FeatureGroupManager._get_lake_formation_client.__get__(fg)
-
-        client = fg._get_lake_formation_client(region="us-west-2")
-
-        mock_session.client.assert_called_with("lakeformation", region_name="us-west-2")
-        assert client == mock_client
-
-    def test_creates_client_with_provided_session(self):
-        """Test client creation with provided session."""
-        mock_session = MagicMock()
-        mock_client = MagicMock()
-        mock_session.client.return_value = mock_client
-
-        fg = MagicMock(spec=FeatureGroupManager)
-        fg._get_lake_formation_client = FeatureGroupManager._get_lake_formation_client.__get__(fg)
-
-        client = fg._get_lake_formation_client(session=mock_session, region="us-west-2")
-
-        mock_session.client.assert_called_with("lakeformation", region_name="us-west-2")
-        assert client == mock_client
-
-    def test_caches_client_for_same_session_and_region(self):
-        """Test that repeated calls with the same session and region reuse the cached client."""
-        mock_session = MagicMock()
-        mock_client = MagicMock()
-        mock_session.client.return_value = mock_client
-
-        fg = MagicMock(spec=FeatureGroupManager)
-        fg._get_lake_formation_client = FeatureGroupManager._get_lake_formation_client.__get__(fg)
-
-        client1 = fg._get_lake_formation_client(session=mock_session, region="us-west-2")
-        client2 = fg._get_lake_formation_client(session=mock_session, region="us-west-2")
-
-        assert client1 is client2
-        mock_session.client.assert_called_once()
-
-    def test_creates_new_client_for_different_region(self):
-        """Test that a different region produces a new client."""
-        mock_session = MagicMock()
-        mock_client_west = MagicMock()
-        mock_client_east = MagicMock()
-        mock_session.client.side_effect = [mock_client_west, mock_client_east]
-
-        fg = MagicMock(spec=FeatureGroupManager)
-        fg._get_lake_formation_client = FeatureGroupManager._get_lake_formation_client.__get__(fg)
-
-        client1 = fg._get_lake_formation_client(session=mock_session, region="us-west-2")
-        client2 = fg._get_lake_formation_client(session=mock_session, region="us-east-1")
-
-        assert client1 is not client2
-        assert mock_session.client.call_count == 2
-
-
-class TestRegisterS3WithLakeFormation:
-    """Tests for _register_s3_with_lake_formation method."""
-
-    def setup_method(self):
-        """Set up test fixtures."""
-        self.fg = MagicMock(spec=FeatureGroupManager)
-        self.fg._s3_uri_to_arn = FeatureGroupManager._s3_uri_to_arn
-        self.fg._register_s3_with_lake_formation = (
-            FeatureGroupManager._register_s3_with_lake_formation.__get__(self.fg)
-        )
-        self.mock_client = MagicMock()
-        self.fg._get_lake_formation_client = MagicMock(return_value=self.mock_client)
-
-    def test_successful_registration_returns_true(self):
-        """Test successful S3 registration returns True."""
-        self.mock_client.register_resource.return_value = {}
-
-        result = self.fg._register_s3_with_lake_formation("s3://test-bucket/prefix")
-
-        assert result is True
-        self.mock_client.register_resource.assert_called_with(
-            ResourceArn="arn:aws:s3:::test-bucket/prefix",
-            UseServiceLinkedRole=True,
-        )
-
-    def test_already_exists_exception_returns_true(self):
-        """Test AlreadyExistsException is handled gracefully."""
-        self.mock_client.register_resource.side_effect = botocore.exceptions.ClientError(
-            {"Error": {"Code": "AlreadyExistsException", "Message": "Already exists"}},
-            "RegisterResource",
-        )
-
-        result = self.fg._register_s3_with_lake_formation("s3://test-bucket/prefix")
-
-        assert result is True
-
-    def test_other_exceptions_are_propagated(self):
-        """Test non-AlreadyExistsException errors are propagated."""
-        self.mock_client.register_resource.side_effect = botocore.exceptions.ClientError(
-            {"Error": {"Code": "AccessDeniedException", "Message": "Access denied"}},
-            "RegisterResource",
-        )
-
-        with pytest.raises(botocore.exceptions.ClientError) as exc_info:
-            self.fg._register_s3_with_lake_formation("s3://test-bucket/prefix")
-
-        assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException"
-
-    def test_uses_service_linked_role(self):
-        """Test UseServiceLinkedRole is set to True."""
-        self.mock_client.register_resource.return_value = {}
-
-        self.fg._register_s3_with_lake_formation("s3://bucket/path")
-
-        call_args = self.mock_client.register_resource.call_args
-        assert call_args[1]["UseServiceLinkedRole"] is True
-
-    def test_uses_custom_role_arn_when_service_linked_role_disabled(self):
-        """Test custom role ARN is used when use_service_linked_role is False."""
-        self.mock_client.register_resource.return_value = {}
-        custom_role = "arn:aws:iam::123456789012:role/CustomLakeFormationRole"
-
-        self.fg._register_s3_with_lake_formation(
-            "s3://bucket/path",
-            use_service_linked_role=False,
-            role_arn=custom_role,
-        )
-
-        call_args = self.mock_client.register_resource.call_args
-        assert call_args[1]["RoleArn"] == custom_role
-        assert "UseServiceLinkedRole" not in call_args[1]
-
-    def test_raises_error_when_role_arn_missing_and_service_linked_role_disabled(self):
-        """Test ValueError when use_service_linked_role is False but role_arn not provided."""
-        with pytest.raises(ValueError) as exc_info:
-            self.fg._register_s3_with_lake_formation(
-                "s3://bucket/path", use_service_linked_role=False
-            )
-
-        assert "role_arn must be provided when use_service_linked_role is False" in str(
-            exc_info.value
-        )
-
-
-
-class TestRevokeIamAllowedPrincipal:
-    """Tests for _revoke_iam_allowed_principal method."""
-
-    def setup_method(self):
-        """Set up test fixtures."""
-        self.fg = MagicMock(spec=FeatureGroupManager)
-        self.fg._revoke_iam_allowed_principal = FeatureGroupManager._revoke_iam_allowed_principal.__get__(
-            self.fg
-        )
-        self.mock_client = MagicMock()
-        self.fg._get_lake_formation_client = MagicMock(return_value=self.mock_client)
-
-    def test_successful_revocation_returns_true(self):
-        """Test successful revocation returns True."""
-        self.mock_client.revoke_permissions.return_value = {}
-
-        result = self.fg._revoke_iam_allowed_principal("test_database", "test_table")
-
-        assert result is True
-        self.mock_client.revoke_permissions.assert_called_once()
-
-    def test_revoke_permissions_call_structure(self):
-        """Test that revoke_permissions is called with correct parameters."""
-        self.mock_client.revoke_permissions.return_value = {}
-        database_name = "my_database"
-        table_name = "my_table"
-
-        self.fg._revoke_iam_allowed_principal(database_name, table_name)
-
-        call_args = self.mock_client.revoke_permissions.call_args
-        assert call_args[1]["Principal"] == {
-            "DataLakePrincipalIdentifier": "IAM_ALLOWED_PRINCIPALS"
-        }
-        assert call_args[1]["Permissions"] == ["ALL"]
-        assert call_args[1]["Resource"] == {
-            "Table": {
-                "DatabaseName": database_name,
-                "Name": table_name,
-            }
-        }
-
-    def test_invalid_input_exception_returns_true(self):
-        """Test InvalidInputException is handled gracefully (permissions may not exist)."""
-        self.mock_client.revoke_permissions.side_effect = botocore.exceptions.ClientError(
-            {"Error": {"Code": "InvalidInputException", "Message": "Permissions not found"}},
-            "RevokePermissions",
-        )
-
-        result = self.fg._revoke_iam_allowed_principal("test_database", "test_table")
-
-        assert result is True
-
-    def test_other_exceptions_are_propagated(self):
-        """Test non-InvalidInputException errors are propagated."""
-        self.mock_client.revoke_permissions.side_effect = botocore.exceptions.ClientError(
-            {"Error": {"Code": "AccessDeniedException", "Message": "Access denied"}},
-            "RevokePermissions",
-        )
-
-        with pytest.raises(botocore.exceptions.ClientError) as exc_info:
-            self.fg._revoke_iam_allowed_principal("test_database", "test_table")
-
-        assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException"
-
-    def test_passes_session_and_region_to_client(self):
-        """Test session and region are passed to get_lake_formation_client."""
-        self.mock_client.revoke_permissions.return_value = {}
-        mock_session = MagicMock()
-
-        self.fg._revoke_iam_allowed_principal(
-            "test_database", "test_table", session=mock_session, region="us-west-2"
-        )
-
-        self.fg._get_lake_formation_client.assert_called_with(mock_session, "us-west-2")
-
-
-
-class TestGrantLakeFormationPermissions:
-    """Tests for _grant_lake_formation_permissions method."""
-
-    def setup_method(self):
-        """Set up test fixtures."""
-        self.fg = MagicMock(spec=FeatureGroupManager)
-        self.fg._grant_lake_formation_permissions = (
-            FeatureGroupManager._grant_lake_formation_permissions.__get__(self.fg)
-        )
-        self.mock_client = MagicMock()
-        self.fg._get_lake_formation_client = MagicMock(return_value=self.mock_client)
-
-    def test_successful_grant_returns_true(self):
-        """Test successful permission grant returns True."""
-        self.mock_client.grant_permissions.return_value = {}
-
-        result = self.fg._grant_lake_formation_permissions(
-            "arn:aws:iam::123456789012:role/TestRole", "test_database", "test_table"
-        )
-
-        assert result is True
-        self.mock_client.grant_permissions.assert_called_once()
-
-    def test_grant_permissions_call_structure(self):
-        """Test that grant_permissions is called with correct parameters."""
-        self.mock_client.grant_permissions.return_value = {}
-        role_arn = "arn:aws:iam::123456789012:role/MyExecutionRole"
-
-        self.fg._grant_lake_formation_permissions(role_arn, "my_database", "my_table")
-
-        call_args = self.mock_client.grant_permissions.call_args
-        assert call_args[1]["Principal"] == {"DataLakePrincipalIdentifier": role_arn}
-        assert call_args[1]["Resource"] == {
-            "Table": {
-                "DatabaseName": "my_database",
-                "Name": "my_table",
-            }
-        }
-        assert call_args[1]["Permissions"] == ["SELECT", "INSERT", "DELETE", "DESCRIBE", "ALTER"]
-        assert call_args[1]["PermissionsWithGrantOption"] == []
-
-    def test_invalid_input_exception_returns_true(self):
-        """Test InvalidInputException is handled gracefully (permissions may exist)."""
-        self.mock_client.grant_permissions.side_effect = botocore.exceptions.ClientError(
-            {"Error": {"Code": "InvalidInputException", "Message": "Permissions already exist"}},
-            "GrantPermissions",
-        )
-
-        result = self.fg._grant_lake_formation_permissions(
-            "arn:aws:iam::123456789012:role/TestRole", "test_database", "test_table"
-        )
-
-        assert result is True
-
-    def test_other_exceptions_are_propagated(self):
-        """Test non-InvalidInputException errors are propagated."""
-        self.mock_client.grant_permissions.side_effect = botocore.exceptions.ClientError(
-            {"Error": {"Code": "AccessDeniedException", "Message": "Access denied"}},
-            "GrantPermissions",
-        )
-
-        with pytest.raises(botocore.exceptions.ClientError) as exc_info:
-            self.fg._grant_lake_formation_permissions(
-                "arn:aws:iam::123456789012:role/TestRole", "test_database", "test_table"
-            )
-
-        assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException"
-
-    def test_passes_session_and_region_to_client(self):
-        """Test session and region are passed to get_lake_formation_client."""
-        self.mock_client.grant_permissions.return_value = {}
-        mock_session = MagicMock()
-
-        self.fg._grant_lake_formation_permissions(
-            "arn:aws:iam::123456789012:role/TestRole",
-            "test_database",
-            "test_table",
-            session=mock_session,
-            region="us-west-2",
-        )
-
-        self.fg._get_lake_formation_client.assert_called_with(mock_session, "us-west-2")
-
-
-
-class TestEnableLakeFormationValidation:
-    """Tests for enable_lake_formation validation logic."""
-
-    @patch.object(FeatureGroupManager, "refresh")
-    def test_raises_error_when_no_offline_store(self, mock_refresh):
-        """Test that enable_lake_formation raises ValueError when no offline store is configured."""
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = None
-        fg.feature_group_status = "Created"
-
-        with pytest.raises(ValueError, match="does not have an offline store configured"):
-            fg.enable_lake_formation()
-
-        # Verify refresh was called
-        mock_refresh.assert_called_once()
-
-    @patch.object(FeatureGroupManager, "refresh")
-    def test_raises_error_when_no_role_arn(self, mock_refresh):
-        """Test that enable_lake_formation raises ValueError when no role_arn is configured."""
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = None
-        fg.feature_group_status = "Created"
-
-        with pytest.raises(ValueError, match="does not have a role_arn configured"):
-            fg.enable_lake_formation()
-
-        # Verify refresh was called
-        mock_refresh.assert_called_once()
-
-    @patch.object(FeatureGroupManager, "refresh")
-    def test_raises_error_when_invalid_status(self, mock_refresh):
-        """Test enable_lake_formation raises ValueError when Feature Group not in Created status."""
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = "arn:aws:iam::123456789012:role/TestRole"
-        fg.feature_group_status = "Creating"
-
-        with pytest.raises(ValueError, match="must be in 'Created' status"):
-            fg.enable_lake_formation()
-
-        # Verify refresh was called
-        mock_refresh.assert_called_once()
-
-    @patch.object(FeatureGroupManager, "wait_for_status")
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    def test_wait_for_active_calls_wait_for_status(
-        self, mock_revoke, mock_grant, mock_register, mock_refresh, mock_wait
-    ):
-        """Test that wait_for_active=True calls wait_for_status with 'Created' target."""
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = "arn:aws:iam::123456789012:role/TestRole"
-        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock successful Lake Formation operations
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-
-        # Call with wait_for_active=True
-        fg.enable_lake_formation(wait_for_active=True)
-
-        # Verify wait_for_status was called with "Created"
-        mock_wait.assert_called_once_with(target_status="Created")
-        # Verify refresh was called after wait
-        mock_refresh.assert_called_once()
-
-    @patch.object(FeatureGroupManager, "wait_for_status")
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    def test_wait_for_active_false_does_not_call_wait(
-        self, mock_revoke, mock_grant, mock_register, mock_refresh, mock_wait
-    ):
-        """Test that wait_for_active=False does not call wait_for_status."""
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = "arn:aws:iam::123456789012:role/TestRole"
-        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock successful Lake Formation operations
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-
-        # Call with wait_for_active=False (default)
-        fg.enable_lake_formation(wait_for_active=False)
-
-        # Verify wait_for_status was NOT called
-        mock_wait.assert_not_called()
-        # Verify refresh was still called
-        mock_refresh.assert_called_once()
-
-
-    @pytest.mark.parametrize(
-        "feature_group_name,role_arn,s3_uri,database_name,table_name",
-        [
-            ("test-fg", "TestRole", "path1", "db1", "table1"),
-            ("my_feature_group", "ExecutionRole", "data/features", "feature_db", "feature_table"),
-            ("fg123", "MyRole123", "ml/features/v1", "analytics", "features_v1"),
-            ("simple", "SimpleRole", "simple-path", "simple_db", "simple_table"),
-            (
-                "complex-name",
-                "ComplexExecutionRole",
-                "complex/path/structure",
-                "complex_database",
-                "complex_table_name",
-            ),
-            (
-                "underscore_name",
-                "Underscore_Role",
-                "underscore_path",
-                "underscore_db",
-                "underscore_table",
-            ),
-            ("mixed-123", "Mixed123Role", "mixed/path/123", "mixed_db_123", "mixed_table_123"),
-            ("x", "XRole", "x", "x", "x"),
-            (
-                "very-long-name",
-                "VeryLongRoleName",
-                "very/long/path/structure",
-                "very_long_database_name",
-                "very_long_table_name",
-            ),
-        ],
-    )
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    def test_fail_fast_phase_execution(
-        self,
-        mock_revoke,
-        mock_grant,
-        mock_register,
-        mock_refresh,
-        feature_group_name,
-        role_arn,
-        s3_uri,
-        database_name,
-        table_name,
-    ):
-        """
-        Test fail-fast behavior for Lake Formation phases.
-
-        If Phase 1 (S3 registration) fails, Phase 2 and 3 should not execute.
-        If Phase 2 fails, Phase 3 should not execute.
-        RuntimeError should indicate which phase failed.
-        """
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        fg = FeatureGroupManager(feature_group_name=feature_group_name)
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri=f"s3://test-bucket/{s3_uri}",
-                resolved_output_s3_uri=f"s3://test-bucket/resolved-{s3_uri}",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database=database_name, table_name=table_name
-            ),
-        )
-        fg.role_arn = f"arn:aws:iam::123456789012:role/{role_arn}"
-        fg.feature_group_status = "Created"
-
-        # Test Phase 1 failure - subsequent phases should not be called
-        mock_register.side_effect = Exception("Phase 1 failed")
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-
-        with pytest.raises(
-            RuntimeError, match="Failed to register S3 location with Lake Formation"
-        ):
-            fg.enable_lake_formation()
-
-        # Verify Phase 1 was called but Phase 2 and 3 were not
-        mock_register.assert_called_once()
-        mock_grant.assert_not_called()
-        mock_revoke.assert_not_called()
-
-        # Reset mocks for Phase 2 failure test
-        mock_register.reset_mock()
-        mock_grant.reset_mock()
-        mock_revoke.reset_mock()
-
-        # Test Phase 2 failure - Phase 3 should not be called
-        mock_register.side_effect = None
-        mock_register.return_value = True
-        mock_grant.side_effect = Exception("Phase 2 failed")
-        mock_revoke.return_value = True
-
-        with pytest.raises(RuntimeError, match="Failed to grant Lake Formation permissions"):
-            fg.enable_lake_formation()
-
-        # Verify Phase 1 and 2 were called but Phase 3 was not
-        mock_register.assert_called_once()
-        mock_grant.assert_called_once()
-        mock_revoke.assert_not_called()
-
-        # Reset mocks for Phase 3 failure test
-        mock_register.reset_mock()
-        mock_grant.reset_mock()
-        mock_revoke.reset_mock()
-
-        # Test Phase 3 failure - all phases should be called
-        mock_register.side_effect = None
-        mock_register.return_value = True
-        mock_grant.side_effect = None
-        mock_grant.return_value = True
-        mock_revoke.side_effect = Exception("Phase 3 failed")
-
-        with pytest.raises(RuntimeError, match="Failed to revoke IAMAllowedPrincipal permissions"):
-            fg.enable_lake_formation()
-
-        # Verify all phases were called
-        mock_register.assert_called_once()
-        mock_grant.assert_called_once()
-        mock_revoke.assert_called_once()
-
-
-
-class TestUnhandledExceptionPropagation:
-    """Tests for proper propagation of unhandled boto3 exceptions."""
-
-    def test_register_s3_propagates_unhandled_exceptions(self):
-        """
-        Non-AlreadyExists Errors Propagate from S3 Registration
-
-        For any error from Lake Formation's register_resource API that is not
-        AlreadyExistsException, the error should be propagated to the caller unchanged.
-
-        """
-        fg = MagicMock(spec=FeatureGroupManager)
-        fg._s3_uri_to_arn = FeatureGroupManager._s3_uri_to_arn
-        fg._register_s3_with_lake_formation = FeatureGroupManager._register_s3_with_lake_formation.__get__(
-            fg
-        )
-        mock_client = MagicMock()
-        fg._get_lake_formation_client = MagicMock(return_value=mock_client)
-
-        # Configure mock to raise an unhandled error
-        mock_client.register_resource.side_effect = botocore.exceptions.ClientError(
-            {
-                "Error": {
-                    "Code": "AccessDeniedException",
-                    "Message": "User does not have permission",
-                }
-            },
-            "RegisterResource",
-        )
-
-        # Verify the exception is propagated unchanged
-        with pytest.raises(botocore.exceptions.ClientError) as exc_info:
-            fg._register_s3_with_lake_formation("s3://test-bucket/path")
-
-        # Verify error details are preserved
-        assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException"
-        assert exc_info.value.response["Error"]["Message"] == "User does not have permission"
-        assert exc_info.value.operation_name == "RegisterResource"
-
-    def test_revoke_iam_principal_propagates_unhandled_exceptions(self):
-        """
-        Non-InvalidInput Errors Propagate from IAM Principal Revocation
-
-        For any error from Lake Formation's revoke_permissions API that is not
-        InvalidInputException, the error should be propagated to the caller unchanged.
-
-        """
-        fg = MagicMock(spec=FeatureGroupManager)
-        fg._revoke_iam_allowed_principal = FeatureGroupManager._revoke_iam_allowed_principal.__get__(fg)
-        mock_client = MagicMock()
-        fg._get_lake_formation_client = MagicMock(return_value=mock_client)
-
-        # Configure mock to raise an unhandled error
-        mock_client.revoke_permissions.side_effect = botocore.exceptions.ClientError(
-            {
-                "Error": {
-                    "Code": "AccessDeniedException",
-                    "Message": "User does not have permission",
-                }
-            },
-            "RevokePermissions",
-        )
-
-        # Verify the exception is propagated unchanged
-        with pytest.raises(botocore.exceptions.ClientError) as exc_info:
-            fg._revoke_iam_allowed_principal("test_database", "test_table")
-
-        # Verify error details are preserved
-        assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException"
-        assert exc_info.value.response["Error"]["Message"] == "User does not have permission"
-        assert exc_info.value.operation_name == "RevokePermissions"
-
-    def test_grant_permissions_propagates_unhandled_exceptions(self):
-        """
-        Non-InvalidInput Errors Propagate from Permission Grant
-
-        For any error from Lake Formation's grant_permissions API that is not
-        InvalidInputException, the error should be propagated to the caller unchanged.
-
-        """
-        fg = MagicMock(spec=FeatureGroupManager)
-        fg._grant_lake_formation_permissions = (
-            FeatureGroupManager._grant_lake_formation_permissions.__get__(fg)
-        )
-        mock_client = MagicMock()
-        fg._get_lake_formation_client = MagicMock(return_value=mock_client)
-
-        # Configure mock to raise an unhandled error
-        mock_client.grant_permissions.side_effect = botocore.exceptions.ClientError(
-            {
-                "Error": {
-                    "Code": "AccessDeniedException",
-                    "Message": "User does not have permission",
-                }
-            },
-            "GrantPermissions",
-        )
-
-        # Verify the exception is propagated unchanged
-        with pytest.raises(botocore.exceptions.ClientError) as exc_info:
-            fg._grant_lake_formation_permissions(
-                "arn:aws:iam::123456789012:role/TestRole", "test_database", "test_table"
-            )
-
-        # Verify error details are preserved
-        assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException"
-        assert exc_info.value.response["Error"]["Message"] == "User does not have permission"
-        assert exc_info.value.operation_name == "GrantPermissions"
-
-    def test_handled_exceptions_do_not_propagate(self):
-        """
-        Verify that specifically handled exceptions (AlreadyExistsException, InvalidInputException)
-        do NOT propagate but return True instead, while all other exceptions are propagated.
-        """
-        fg = MagicMock(spec=FeatureGroupManager)
-        fg._s3_uri_to_arn = FeatureGroupManager._s3_uri_to_arn
-        fg._register_s3_with_lake_formation = FeatureGroupManager._register_s3_with_lake_formation.__get__(
-            fg
-        )
-        fg._revoke_iam_allowed_principal = FeatureGroupManager._revoke_iam_allowed_principal.__get__(fg)
-        fg._grant_lake_formation_permissions = (
-            FeatureGroupManager._grant_lake_formation_permissions.__get__(fg)
-        )
-        mock_client = MagicMock()
-        fg._get_lake_formation_client = MagicMock(return_value=mock_client)
-
-        # Test AlreadyExistsException is handled (not propagated)
-        mock_client.register_resource.side_effect = botocore.exceptions.ClientError(
-            {"Error": {"Code": "AlreadyExistsException", "Message": "Already exists"}},
-            "RegisterResource",
-        )
-        result = fg._register_s3_with_lake_formation("s3://test-bucket/path")
-        assert result is True  # Should return True, not raise
-
-        # Test InvalidInputException is handled for revoke (not propagated)
-        mock_client.revoke_permissions.side_effect = botocore.exceptions.ClientError(
-            {"Error": {"Code": "InvalidInputException", "Message": "Invalid input"}},
-            "RevokePermissions",
-        )
-        result = fg._revoke_iam_allowed_principal("db", "table")
-        assert result is True  # Should return True, not raise
-
-        # Test InvalidInputException is handled for grant (not propagated)
-        mock_client.grant_permissions.side_effect = botocore.exceptions.ClientError(
-            {"Error": {"Code": "InvalidInputException", "Message": "Invalid input"}},
-            "GrantPermissions",
-        )
-        result = fg._grant_lake_formation_permissions(
-            "arn:aws:iam::123456789012:role/TestRole", "db", "table"
-        )
-        assert result is True  # Should return True, not raise
-
-
-
-class TestCreateWithLakeFormation:
-    """Tests for create() method with Lake Formation integration."""
-
-    @pytest.mark.parametrize(
-        "feature_group_name,record_id_feature,event_time_feature",
-        [
-            ("test-fg", "record_id", "event_time"),
-            ("my_feature_group", "id", "timestamp"),
-            ("fg123", "identifier", "time"),
-            ("simple", "rec_id", "evt_time"),
-            ("complex-name", "record_identifier", "event_timestamp"),
-            ("underscore_name", "record_id_field", "event_time_field"),
-            ("mixed-123", "id_123", "time_123"),
-            ("x", "x_id", "x_time"),
-            ("very-long-name", "very_long_record_id", "very_long_event_time"),
-        ],
-    )
-    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
-    @patch.object(FeatureGroupManager, "get")
-    @patch.object(FeatureGroupManager, "wait_for_status")
-    @patch.object(FeatureGroupManager, "enable_lake_formation")
-    def test_no_lake_formation_operations_when_disabled(
-        self,
-        mock_enable_lf,
-        mock_wait,
-        mock_get,
-        mock_get_client,
-        feature_group_name,
-        record_id_feature,
-        event_time_feature,
-    ):
-        """
-        No Lake Formation Operations When Disabled
-
-        For any call to FeatureGroupManager.create() where lake_formation_config is None or has enabled=False,
-        no Lake Formation client methods should be invoked.
-
-        """
-        from sagemaker.core.shapes import FeatureDefinition
-
-        # Mock the SageMaker client
-        mock_client = MagicMock()
-        mock_client.create_feature_group.return_value = {
-            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test"
-        }
-        mock_get_client.return_value = mock_client
-
-        # Mock the get method to return a feature group
-        mock_fg = MagicMock(spec=FeatureGroupManager)
-        mock_fg.feature_group_name = feature_group_name
-        mock_get.return_value = mock_fg
-
-        # Create feature definitions
-        feature_definitions = [
-            FeatureDefinition(feature_name=record_id_feature, feature_type="String"),
-            FeatureDefinition(feature_name=event_time_feature, feature_type="String"),
-        ]
-
-        # Test 1: lake_formation_config with enabled=False (explicit)
-        lf_config = LakeFormationConfig()
-        lf_config.enabled = False
-        result = FeatureGroupManager.create(
-            feature_group_name=feature_group_name,
-            record_identifier_feature_name=record_id_feature,
-            event_time_feature_name=event_time_feature,
-            feature_definitions=feature_definitions,
-            lake_formation_config=lf_config,
-        )
-
-        # Verify enable_lake_formation was NOT called
-        mock_enable_lf.assert_not_called()
-        # Verify wait_for_status was NOT called
-        mock_wait.assert_not_called()
-        # Verify the feature group was returned
-        assert result == mock_fg
-
-        # Reset mocks for next test
-        mock_enable_lf.reset_mock()
-        mock_wait.reset_mock()
-        mock_get.reset_mock()
-        mock_get.return_value = mock_fg
-
-        # Test 2: lake_formation_config not specified (defaults to None)
-        result = FeatureGroupManager.create(
-            feature_group_name=feature_group_name,
-            record_identifier_feature_name=record_id_feature,
-            event_time_feature_name=event_time_feature,
-            feature_definitions=feature_definitions,
-            # lake_formation_config not specified, should default to None
-        )
-
-        # Verify enable_lake_formation was NOT called
-        mock_enable_lf.assert_not_called()
-        # Verify wait_for_status was NOT called
-        mock_wait.assert_not_called()
-        # Verify the feature group was returned
-        assert result == mock_fg
-
-    @pytest.mark.parametrize(
-        "feature_group_name,record_id_feature,event_time_feature,role_arn,s3_uri,database,table",
-        [
-            ("test-fg", "record_id", "event_time", "TestRole", "path1", "db1", "table1"),
-            (
-                "my_feature_group",
-                "id",
-                "timestamp",
-                "ExecutionRole",
-                "data/features",
-                "feature_db",
-                "feature_table",
-            ),
-            (
-                "fg123",
-                "identifier",
-                "time",
-                "MyRole123",
-                "ml/features/v1",
-                "analytics",
-                "features_v1",
-            ),
-        ],
-    )
-    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
-    @patch.object(FeatureGroupManager, "get")
-    @patch.object(FeatureGroupManager, "wait_for_status")
-    @patch.object(FeatureGroupManager, "enable_lake_formation")
-    def test_enable_lake_formation_called_when_enabled(
-        self,
-        mock_enable_lf,
-        mock_wait,
-        mock_get,
-        mock_get_client,
-        feature_group_name,
-        record_id_feature,
-        event_time_feature,
-        role_arn,
-        s3_uri,
-        database,
-        table,
-    ):
-        """
-        Test that enable_lake_formation is called when lake_formation_config has enabled=True.
-
-        This verifies the integration between create() and enable_lake_formation().
-        """
-        from sagemaker.core.shapes import (
-            FeatureDefinition,
-            OfflineStoreConfig,
-            S3StorageConfig,
-            DataCatalogConfig,
-        )
-
-        # Mock the SageMaker client
-        mock_client = MagicMock()
-        mock_client.create_feature_group.return_value = {
-            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test"
-        }
-        mock_get_client.return_value = mock_client
-
-        # Mock the get method to return a feature group
-        mock_fg = MagicMock(spec=FeatureGroupManager)
-        mock_fg.feature_group_name = feature_group_name
-        mock_fg.wait_for_status = mock_wait
-        mock_fg.enable_lake_formation = mock_enable_lf
-        mock_get.return_value = mock_fg
-
-        # Create feature definitions
-        feature_definitions = [
-            FeatureDefinition(feature_name=record_id_feature, feature_type="String"),
-            FeatureDefinition(feature_name=event_time_feature, feature_type="String"),
-        ]
-
-        # Create offline store config
-        offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(s3_uri=f"s3://test-bucket/{s3_uri}"),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database=database, table_name=table
-            ),
-        )
-
-        # Create LakeFormationConfig with enabled=True
-        lf_config = LakeFormationConfig()
-        lf_config.enabled = True
-
-        # Create with lake_formation_config enabled=True
-        result = FeatureGroupManager.create(
-            feature_group_name=feature_group_name,
-            record_identifier_feature_name=record_id_feature,
-            event_time_feature_name=event_time_feature,
-            feature_definitions=feature_definitions,
-            offline_store_config=offline_store_config,
-            role_arn=f"arn:aws:iam::123456789012:role/{role_arn}",
-            lake_formation_config=lf_config,
-        )
-
-        # Verify wait_for_status was called with "Created"
-        mock_wait.assert_called_once_with(target_status="Created")
-        # Verify enable_lake_formation was called with default use_service_linked_role=True
-        mock_enable_lf.assert_called_once_with(
-            session=None,
-            region=None,
-            use_service_linked_role=True,
-            registration_role_arn=None,
-            show_s3_policy=False,
-            disable_hybrid_access_mode=True,
-        )
-        # Verify the feature group was returned
-        assert result == mock_fg
-
-    @pytest.mark.parametrize(
-        "feature_group_name,record_id_feature,event_time_feature",
-        [
-            ("test-fg", "record_id", "event_time"),
-            ("my_feature_group", "id", "timestamp"),
-            ("fg123", "identifier", "time"),
-        ],
-    )
-    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
-    def test_validation_error_when_lake_formation_enabled_without_offline_store(
-        self, mock_get_client, feature_group_name, record_id_feature, event_time_feature
-    ):
-        """Test create() raises ValueError when lake_formation_config enabled=True without offline_store."""
-        from sagemaker.core.shapes import FeatureDefinition
-
-        # Mock the SageMaker client
-        mock_client = MagicMock()
-        mock_get_client.return_value = mock_client
-
-        # Create feature definitions
-        feature_definitions = [
-            FeatureDefinition(feature_name=record_id_feature, feature_type="String"),
-            FeatureDefinition(feature_name=event_time_feature, feature_type="String"),
-        ]
-
-        # Create LakeFormationConfig with enabled=True
-        lf_config = LakeFormationConfig()
-        lf_config.enabled = True
-
-        # Test with lake_formation_config enabled=True but no offline_store_config
-        with pytest.raises(
-            ValueError,
-            match="lake_formation_config with enabled=True requires offline_store_config to be configured",
-        ):
-            FeatureGroupManager.create(
-                feature_group_name=feature_group_name,
-                record_identifier_feature_name=record_id_feature,
-                event_time_feature_name=event_time_feature,
-                feature_definitions=feature_definitions,
-                lake_formation_config=lf_config,
-                # offline_store_config not provided
-            )
-
-    @pytest.mark.parametrize(
-        "feature_group_name,record_id_feature,event_time_feature,s3_uri,database,table",
-        [
-            ("test-fg", "record_id", "event_time", "path1", "db1", "table1"),
-            ("my_feature_group", "id", "timestamp", "data/features", "feature_db", "feature_table"),
-            ("fg123", "identifier", "time", "ml/features/v1", "analytics", "features_v1"),
-        ],
-    )
-    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
-    def test_validation_error_when_lake_formation_enabled_without_role_arn(
-        self,
-        mock_get_client,
-        feature_group_name,
-        record_id_feature,
-        event_time_feature,
-        s3_uri,
-        database,
-        table,
-    ):
-        """Test create() raises ValueError when lake_formation_config enabled=True without role_arn."""
-        from sagemaker.core.shapes import (
-            FeatureDefinition,
-            OfflineStoreConfig,
-            S3StorageConfig,
-            DataCatalogConfig,
-        )
-
-        # Mock the SageMaker client
-        mock_client = MagicMock()
-        mock_get_client.return_value = mock_client
-
-        # Create feature definitions
-        feature_definitions = [
-            FeatureDefinition(feature_name=record_id_feature, feature_type="String"),
-            FeatureDefinition(feature_name=event_time_feature, feature_type="String"),
-        ]
-
-        # Create offline store config
-        offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(s3_uri=f"s3://test-bucket/{s3_uri}"),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database=database, table_name=table
-            ),
-        )
-
-        # Create LakeFormationConfig with enabled=True
-        lf_config = LakeFormationConfig()
-        lf_config.enabled = True
-
-        # Test with lake_formation_config enabled=True but no role_arn
-        with pytest.raises(
-            ValueError, match="lake_formation_config with enabled=True requires role_arn to be specified"
-        ):
-            FeatureGroupManager.create(
-                feature_group_name=feature_group_name,
-                record_identifier_feature_name=record_id_feature,
-                event_time_feature_name=event_time_feature,
-                feature_definitions=feature_definitions,
-                offline_store_config=offline_store_config,
-                lake_formation_config=lf_config,
-                # role_arn not provided
-            )
-
-
-    @pytest.mark.parametrize(
-        "feature_group_name,record_id_feature,event_time_feature,role_arn,s3_uri,database,table,use_slr",
-        [
-            ("test-fg", "record_id", "event_time", "TestRole", "path1", "db1", "table1", True),
-            ("my_feature_group", "id", "timestamp", "ExecutionRole", "data/features", "feature_db", "feature_table", False),
-            ("fg123", "identifier", "time", "MyRole123", "ml/features/v1", "analytics", "features_v1", True),
-        ],
-    )
-    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
-    @patch.object(FeatureGroupManager, "get")
-    @patch.object(FeatureGroupManager, "wait_for_status")
-    @patch.object(FeatureGroupManager, "enable_lake_formation")
-    def test_use_service_linked_role_extraction_from_config(
-        self,
-        mock_enable_lf,
-        mock_wait,
-        mock_get,
-        mock_get_client,
-        feature_group_name,
-        record_id_feature,
-        event_time_feature,
-        role_arn,
-        s3_uri,
-        database,
-        table,
-        use_slr,
-    ):
-        """
-        Test that use_service_linked_role is correctly extracted from lake_formation_config.
-
-        Verifies:
-        - use_service_linked_role defaults to True when not specified
-        - use_service_linked_role is passed correctly to enable_lake_formation()
-        """
-        from sagemaker.core.shapes import (
-            FeatureDefinition,
-            OfflineStoreConfig,
-            S3StorageConfig,
-            DataCatalogConfig,
-        )
-
-        # Mock the SageMaker client
-        mock_client = MagicMock()
-        mock_client.create_feature_group.return_value = {
-            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test"
-        }
-        mock_get_client.return_value = mock_client
-
-        # Mock the get method to return a feature group
-        mock_fg = MagicMock(spec=FeatureGroupManager)
-        mock_fg.feature_group_name = feature_group_name
-        mock_fg.wait_for_status = mock_wait
-        mock_fg.enable_lake_formation = mock_enable_lf
-        mock_get.return_value = mock_fg
-
-        # Create feature definitions
-        feature_definitions = [
-            FeatureDefinition(feature_name=record_id_feature, feature_type="String"),
-            FeatureDefinition(feature_name=event_time_feature, feature_type="String"),
-        ]
-
-        # Create offline store config
-        offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(s3_uri=f"s3://test-bucket/{s3_uri}"),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database=database, table_name=table
-            ),
-        )
-
-        # Build LakeFormationConfig with use_service_linked_role
-        lf_config = LakeFormationConfig()
-        lf_config.enabled = True
-        lf_config.use_service_linked_role = use_slr
-        # When use_service_linked_role is False, registration_role_arn is required
-        expected_registration_role = None
-        if not use_slr:
-            lf_config.registration_role_arn = "arn:aws:iam::123456789012:role/LFRegistrationRole"
-            expected_registration_role = "arn:aws:iam::123456789012:role/LFRegistrationRole"
-
-        # Create with lake_formation_config
-        result = FeatureGroupManager.create(
-            feature_group_name=feature_group_name,
-            record_identifier_feature_name=record_id_feature,
-            event_time_feature_name=event_time_feature,
-            feature_definitions=feature_definitions,
-            offline_store_config=offline_store_config,
-            role_arn=f"arn:aws:iam::123456789012:role/{role_arn}",
-            lake_formation_config=lf_config,
-        )
-
-        # Verify enable_lake_formation was called with correct use_service_linked_role value
-        mock_enable_lf.assert_called_once_with(
-            session=None,
-            region=None,
-            use_service_linked_role=use_slr,
-            registration_role_arn=expected_registration_role,
-            show_s3_policy=False,
-            disable_hybrid_access_mode=True,
-        )
-        # Verify the feature group was returned
-        assert result == mock_fg
-
-
-class TestDisableHybridAccessMode:
-    """Tests for disable_hybrid_access_mode parameter in enable_lake_formation."""
-
-    def setup_method(self):
-        """Set up test fixtures."""
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        self.fg = FeatureGroupManager(feature_group_name="test-fg")
-        self.fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        self.fg.role_arn = "arn:aws:iam::123456789012:role/TestRole"
-        self.fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
-        self.fg.feature_group_status = "Created"
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    def test_revoke_called_when_disable_hybrid_access_mode_true(
-        self, mock_revoke, mock_grant, mock_register, mock_refresh
-    ):
-        """Test that IAMAllowedPrincipal is revoked when disable_hybrid_access_mode=True (default)."""
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-
-        result = self.fg.enable_lake_formation(disable_hybrid_access_mode=True)
-
-        mock_revoke.assert_called_once()
-        assert result["iam_principal_revoked"] is True
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    def test_revoke_skipped_when_disable_hybrid_access_mode_false(
-        self, mock_revoke, mock_grant, mock_register, mock_refresh
-    ):
-        """Test that IAMAllowedPrincipal revocation is skipped when disable_hybrid_access_mode=False."""
-        mock_register.return_value = True
-        mock_grant.return_value = True
-
-        result = self.fg.enable_lake_formation(disable_hybrid_access_mode=False)
-
-        mock_revoke.assert_not_called()
-        assert result["iam_principal_revoked"] is None
-        assert result["s3_registration"] is True
-        assert result["permissions_granted"] is True
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    def test_default_disable_hybrid_access_mode_is_true(
-        self, mock_revoke, mock_grant, mock_register, mock_refresh
-    ):
-        """Test that disable_hybrid_access_mode defaults to True (revoke is called by default)."""
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-
-        # Call without specifying disable_hybrid_access_mode
-        result = self.fg.enable_lake_formation()
-
-        mock_revoke.assert_called_once()
-        assert result["iam_principal_revoked"] is True
-
-
-class TestCreateWithLakeFormationDisableHybridAccessMode:
-    """Tests for disable_hybrid_access_mode passed through create() via LakeFormationConfig."""
-
-    @patch("sagemaker.core.resources.Base.get_sagemaker_client")
-    @patch.object(FeatureGroupManager, "get")
-    @patch.object(FeatureGroupManager, "wait_for_status")
-    @patch.object(FeatureGroupManager, "enable_lake_formation")
-    def test_disable_hybrid_access_mode_false_passed_through_create(
-        self, mock_enable_lf, mock_wait, mock_get, mock_get_client
-    ):
-        """Test that disable_hybrid_access_mode=False is passed through create() to enable_lake_formation."""
-        from sagemaker.core.shapes import FeatureDefinition, OfflineStoreConfig, S3StorageConfig
-
-        mock_client = MagicMock()
-        mock_client.create_feature_group.return_value = {
-            "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test"
-        }
-        mock_get_client.return_value = mock_client
-
-        mock_fg = MagicMock(spec=FeatureGroupManager)
-        mock_fg.wait_for_status = mock_wait
-        mock_fg.enable_lake_formation = mock_enable_lf
-        mock_get.return_value = mock_fg
-
-        feature_definitions = [
-            FeatureDefinition(feature_name="record_id", feature_type="String"),
-            FeatureDefinition(feature_name="event_time", feature_type="String"),
-        ]
-
-        lf_config = LakeFormationConfig()
-        lf_config.enabled = True
-        lf_config.disable_hybrid_access_mode = False
-
-        FeatureGroupManager.create(
-            feature_group_name="test-fg",
-            record_identifier_feature_name="record_id",
-            event_time_feature_name="event_time",
-            feature_definitions=feature_definitions,
-            offline_store_config=OfflineStoreConfig(
-                s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/path")
-            ),
-            role_arn="arn:aws:iam::123456789012:role/TestRole",
-            lake_formation_config=lf_config,
-        )
-
-        mock_enable_lf.assert_called_once_with(
-            session=None,
-            region=None,
-            use_service_linked_role=True,
-            registration_role_arn=None,
-            show_s3_policy=False,
-            disable_hybrid_access_mode=False,
-        )
-
-
-class TestLakeFormationConfigDefaults:
-    """Tests for LakeFormationConfig default values."""
-
-    def test_disable_hybrid_access_mode_defaults_to_true(self):
-        """Test that LakeFormationConfig.disable_hybrid_access_mode defaults to True."""
-        config = LakeFormationConfig()
-        assert config.disable_hybrid_access_mode is True
-
-    def test_disable_hybrid_access_mode_can_be_set_to_false(self):
-        """Test that LakeFormationConfig.disable_hybrid_access_mode can be set to False."""
-        config = LakeFormationConfig()
-        config.disable_hybrid_access_mode = False
-        assert config.disable_hybrid_access_mode is False
-
-
-class TestExtractAccountIdFromArn:
-    """Tests for _extract_account_id_from_arn static method."""
-
-    def test_extracts_account_id_from_sagemaker_arn(self):
-        """Test extracting account ID from a SageMaker Feature Group ARN."""
-        arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/my-feature-group"
-        result = FeatureGroupManager._extract_account_id_from_arn(arn)
-        assert result == "123456789012"
-
-    def test_raises_value_error_for_invalid_arn_too_few_parts(self):
-        """Test that ValueError is raised for ARN with fewer than 5 colon-separated parts."""
-        invalid_arn = "arn:aws:sagemaker:us-west-2"  # Only 4 parts
-        with pytest.raises(ValueError, match="Invalid ARN format"):
-            FeatureGroupManager._extract_account_id_from_arn(invalid_arn)
-
-    def test_raises_value_error_for_empty_string(self):
-        """Test that ValueError is raised for empty string."""
-        with pytest.raises(ValueError, match="Invalid ARN format"):
-            FeatureGroupManager._extract_account_id_from_arn("")
-
-    def test_raises_value_error_for_non_arn_string(self):
-        """Test that ValueError is raised for non-ARN string."""
-        with pytest.raises(ValueError, match="Invalid ARN format"):
-            FeatureGroupManager._extract_account_id_from_arn("not-an-arn")
-
-    def test_raises_value_error_for_s3_uri(self):
-        """Test that ValueError is raised for S3 URI (not ARN)."""
-        with pytest.raises(ValueError, match="Invalid ARN format"):
-            FeatureGroupManager._extract_account_id_from_arn("s3://my-bucket/my-prefix")
-
-    def test_handles_arn_with_resource_path(self):
-        """Test extracting account ID from ARN with complex resource path."""
-        arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/my-fg/version/1"
-        result = FeatureGroupManager._extract_account_id_from_arn(arn)
-        assert result == "123456789012"
-
-
-class TestGetLakeFormationServiceLinkedRoleArn:
-    """Tests for _get_lake_formation_service_linked_role_arn static method."""
-
-    def test_generates_correct_service_linked_role_arn(self):
-        """Test that the method generates the correct service-linked role ARN format."""
-        account_id = "123456789012"
-        result = FeatureGroupManager._get_lake_formation_service_linked_role_arn(account_id)
-        expected = "arn:aws:iam::123456789012:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess"
-        assert result == expected
-
-    def test_uses_region_for_partition(self):
-        """Test that region is used to determine partition."""
-        account_id = "123456789012"
-        result = FeatureGroupManager._get_lake_formation_service_linked_role_arn(account_id, region="cn-north-1")
-        assert result.startswith("arn:aws-cn:iam::")
-
-
-
-class TestGenerateS3DenyPolicy:
-    """Tests for _generate_s3_deny_policy method."""
-
-    def setup_method(self):
-        """Set up test fixtures."""
-        self.fg = MagicMock(spec=FeatureGroupManager)
-        self.fg._generate_s3_deny_policy = FeatureGroupManager._generate_s3_deny_policy.__get__(self.fg)
-
-    def test_policy_includes_correct_bucket_arn_in_object_statement(self):
-        """Test that the policy includes correct bucket ARN and prefix in object actions statement."""
-        bucket_name = "my-feature-store-bucket"
-        s3_prefix = "feature-store/data/my-feature-group"
-        lf_role_arn = "arn:aws:iam::123456789012:role/LakeFormationRole"
-        fs_role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-
-        policy = self.fg._generate_s3_deny_policy(
-            bucket_name=bucket_name,
-            s3_prefix=s3_prefix,
-            lake_formation_role_arn=lf_role_arn,
-            feature_store_role_arn=fs_role_arn,
-        )
-
-        # Verify the object actions statement has correct Resource ARN
-        object_statement = policy["Statement"][0]
-        expected_resource = f"arn:aws:s3:::{bucket_name}/{s3_prefix}/*"
-        assert object_statement["Resource"] == expected_resource
-
-    def test_policy_includes_correct_bucket_arn_in_list_statement(self):
-        """Test that the policy includes correct bucket ARN in ListBucket statement."""
-        bucket_name = "my-feature-store-bucket"
-        s3_prefix = "feature-store/data/my-feature-group"
-        lf_role_arn = "arn:aws:iam::123456789012:role/LakeFormationRole"
-        fs_role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-
-        policy = self.fg._generate_s3_deny_policy(
-            bucket_name=bucket_name,
-            s3_prefix=s3_prefix,
-            lake_formation_role_arn=lf_role_arn,
-            feature_store_role_arn=fs_role_arn,
-        )
-
-        # Verify the ListBucket statement has correct Resource ARN (bucket only)
-        list_statement = policy["Statement"][1]
-        expected_resource = f"arn:aws:s3:::{bucket_name}"
-        assert list_statement["Resource"] == expected_resource
-
-    def test_policy_includes_correct_prefix_condition_in_list_statement(self):
-        """Test that the policy includes correct prefix condition in ListBucket statement."""
-        bucket_name = "my-feature-store-bucket"
-        s3_prefix = "feature-store/data/my-feature-group"
-        lf_role_arn = "arn:aws:iam::123456789012:role/LakeFormationRole"
-        fs_role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-
-        policy = self.fg._generate_s3_deny_policy(
-            bucket_name=bucket_name,
-            s3_prefix=s3_prefix,
-            lake_formation_role_arn=lf_role_arn,
-            feature_store_role_arn=fs_role_arn,
-        )
-
-        # Verify the ListBucket statement has correct prefix condition
-        list_statement = policy["Statement"][1]
-        expected_prefix = f"{s3_prefix}/*"
-        assert list_statement["Condition"]["StringLike"]["s3:prefix"] == expected_prefix
-
-    def test_policy_preserves_bucket_name_exactly(self):
-        """Test that bucket name is preserved exactly without modification."""
-        # Test with various bucket name formats
-        test_cases = [
-            "simple-bucket",
-            "bucket.with.dots",
-            "bucket-with-dashes-123",
-            "mybucket",
-            "a" * 63,  # Max bucket name length
-        ]
-
-        for bucket_name in test_cases:
-            policy = self.fg._generate_s3_deny_policy(
-                bucket_name=bucket_name,
-                s3_prefix="prefix",
-                lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole",
-                feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole",
-            )
-
-            # Verify bucket name is preserved in both statements
-            assert bucket_name in policy["Statement"][0]["Resource"]
-            assert bucket_name in policy["Statement"][1]["Resource"]
-
-    def test_policy_preserves_prefix_exactly(self):
-        """Test that S3 prefix is preserved exactly without modification."""
-        # Test with various prefix formats
-        test_cases = [
-            "simple-prefix",
-            "path/to/data",
-            "feature-store/account-id/region/feature-group-name",
-            "deep/nested/path/structure/data",
-            "prefix_with_underscores",
-            "prefix-with-dashes",
-        ]
-
-        for s3_prefix in test_cases:
-            policy = self.fg._generate_s3_deny_policy(
-                bucket_name="test-bucket",
-                s3_prefix=s3_prefix,
-                lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole",
-                feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole",
-            )
-
-            # Verify prefix is preserved in object statement Resource
-            assert f"{s3_prefix}/*" in policy["Statement"][0]["Resource"]
-            # Verify prefix is preserved in list statement Condition
-            assert policy["Statement"][1]["Condition"]["StringLike"]["s3:prefix"] == f"{s3_prefix}/*"
-
-    def test_policy_has_correct_s3_arn_format(self):
-        """Test that the policy uses correct S3 ARN format (arn:aws:s3:::bucket/path)."""
-        bucket_name = "test-bucket"
-        s3_prefix = "test/prefix"
-
-        policy = self.fg._generate_s3_deny_policy(
-            bucket_name=bucket_name,
-            s3_prefix=s3_prefix,
-            lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole",
-            feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole",
-        )
-
-        # Verify object statement Resource starts with correct ARN prefix
-        object_resource = policy["Statement"][0]["Resource"]
-        assert object_resource.startswith("arn:aws:s3:::")
-        assert object_resource == f"arn:aws:s3:::{bucket_name}/{s3_prefix}/*"
-
-        # Verify list statement Resource is bucket-only ARN
-        list_resource = policy["Statement"][1]["Resource"]
-        assert list_resource.startswith("arn:aws:s3:::")
-        assert list_resource == f"arn:aws:s3:::{bucket_name}"
-
-    def test_policy_structure_validation(self):
-        """Test that the policy has correct overall structure."""
-        policy = self.fg._generate_s3_deny_policy(
-            bucket_name="test-bucket",
-            s3_prefix="test/prefix",
-            lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole",
-            feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole",
-        )
-
-        # Verify policy version
-        assert policy["Version"] == "2012-10-17"
-
-        # Verify exactly two statements
-        assert len(policy["Statement"]) == 2
-
-        # Verify first statement structure (object actions)
-        object_statement = policy["Statement"][0]
-        assert object_statement["Sid"] == "DenyAllAccessToFeatureStorePrefixExceptAllowedPrincipals"
-        assert object_statement["Effect"] == "Deny"
-        assert object_statement["Principal"] == "*"
-        assert "Condition" in object_statement
-        assert "StringNotEquals" in object_statement["Condition"]
-
-        # Verify second statement structure (list bucket)
-        list_statement = policy["Statement"][1]
-        assert list_statement["Sid"] == "DenyListOnPrefixExceptAllowedPrincipals"
-        assert list_statement["Effect"] == "Deny"
-        assert list_statement["Principal"] == "*"
-        assert "Condition" in list_statement
-        assert "StringLike" in list_statement["Condition"]
-        assert "StringNotEquals" in list_statement["Condition"]
-
-    def test_policy_includes_both_principals_in_allowed_list(self):
-        """Test that both Lake Formation role and Feature Store role are in allowed principals."""
-        lf_role_arn = "arn:aws:iam::123456789012:role/LakeFormationRole"
-        fs_role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-
-        policy = self.fg._generate_s3_deny_policy(
-            bucket_name="test-bucket",
-            s3_prefix="test/prefix",
-            lake_formation_role_arn=lf_role_arn,
-            feature_store_role_arn=fs_role_arn,
-        )
-
-        # Verify both principals in object statement
-        object_principals = policy["Statement"][0]["Condition"]["StringNotEquals"]["aws:PrincipalArn"]
-        assert lf_role_arn in object_principals
-        assert fs_role_arn in object_principals
-        assert len(object_principals) == 2
-
-        # Verify both principals in list statement
-        list_principals = policy["Statement"][1]["Condition"]["StringNotEquals"]["aws:PrincipalArn"]
-        assert lf_role_arn in list_principals
-        assert fs_role_arn in list_principals
-        assert len(list_principals) == 2
-
-    def test_policy_has_correct_actions_in_each_statement(self):
-        """Test that each statement has the correct S3 actions."""
-        policy = self.fg._generate_s3_deny_policy(
-            bucket_name="test-bucket",
-            s3_prefix="test/prefix",
-            lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole",
-            feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole",
-        )
-
-        # Verify object statement has correct actions
-        object_actions = policy["Statement"][0]["Action"]
-        assert "s3:GetObject" in object_actions
-        assert "s3:PutObject" in object_actions
-        assert "s3:DeleteObject" in object_actions
-        assert len(object_actions) == 3
-
-        # Verify list statement has correct action
-        list_action = policy["Statement"][1]["Action"]
-        assert list_action == "s3:ListBucket"
-
-
-
-class TestEnableLakeFormationServiceLinkedRoleInPolicy:
-    """Tests for service-linked role ARN usage in S3 deny policy generation."""
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    @patch.object(FeatureGroupManager, "_generate_s3_deny_policy")
-    def test_uses_service_linked_role_arn_when_use_service_linked_role_true(
-        self,
-        mock_generate_policy,
-        mock_revoke,
-        mock_grant,
-        mock_register,
-        mock_refresh,
-    ):
-        """
-        Test that enable_lake_formation uses the auto-generated service-linked role ARN
-        when use_service_linked_role=True.
-        """
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock successful Lake Formation operations
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-        mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []}
-
-        # Call with use_service_linked_role=True (default)
-        fg.enable_lake_formation(use_service_linked_role=True, show_s3_policy=True)
-
-        # Verify _generate_s3_deny_policy was called with the service-linked role ARN
-        expected_slr_arn = "arn:aws:iam::123456789012:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess"
-        mock_generate_policy.assert_called_once()
-        call_kwargs = mock_generate_policy.call_args[1]
-        assert call_kwargs["lake_formation_role_arn"] == expected_slr_arn
-        assert call_kwargs["feature_store_role_arn"] == fg.role_arn
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    @patch.object(FeatureGroupManager, "_generate_s3_deny_policy")
-    def test_uses_service_linked_role_arn_by_default(
-        self,
-        mock_generate_policy,
-        mock_revoke,
-        mock_grant,
-        mock_register,
-        mock_refresh,
-    ):
-        """
-        Test that enable_lake_formation uses the service-linked role ARN by default
-        (when use_service_linked_role is not explicitly specified).
-        """
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = "arn:aws:iam::987654321098:role/MyFeatureStoreRole"
-        fg.feature_group_arn = "arn:aws:sagemaker:us-east-1:987654321098:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock successful Lake Formation operations
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-        mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []}
-
-        # Call without specifying use_service_linked_role (should default to True)
-        fg.enable_lake_formation(show_s3_policy=True)
-
-        # Verify _generate_s3_deny_policy was called with the service-linked role ARN
-        expected_slr_arn = "arn:aws:iam::987654321098:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess"
-        mock_generate_policy.assert_called_once()
-        call_kwargs = mock_generate_policy.call_args[1]
-        assert call_kwargs["lake_formation_role_arn"] == expected_slr_arn
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    @patch.object(FeatureGroupManager, "_generate_s3_deny_policy")
-    def test_service_linked_role_arn_uses_correct_account_id(
-        self,
-        mock_generate_policy,
-        mock_revoke,
-        mock_grant,
-        mock_register,
-        mock_refresh,
-    ):
-        """
-        Test that the service-linked role ARN is generated with the correct account ID
-        extracted from the Feature Group ARN.
-        """
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        # Use a specific account ID to verify it's extracted correctly
-        account_id = "111222333444"
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = f"arn:aws:iam::{account_id}:role/FeatureStoreRole"
-        fg.feature_group_arn = f"arn:aws:sagemaker:us-west-2:{account_id}:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock successful Lake Formation operations
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-        mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []}
-
-        # Call with use_service_linked_role=True
-        fg.enable_lake_formation(use_service_linked_role=True, show_s3_policy=True)
-
-        # Verify the service-linked role ARN contains the correct account ID
-        expected_slr_arn = f"arn:aws:iam::{account_id}:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess"
-        mock_generate_policy.assert_called_once()
-        call_kwargs = mock_generate_policy.call_args[1]
-        assert call_kwargs["lake_formation_role_arn"] == expected_slr_arn
-        assert account_id in call_kwargs["lake_formation_role_arn"]
-
-
-
-class TestRegistrationRoleArnUsedWhenServiceLinkedRoleFalse:
-    """Tests for verifying registration_role_arn is used when use_service_linked_role=False."""
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    @patch.object(FeatureGroupManager, "_generate_s3_deny_policy")
-    def test_uses_registration_role_arn_when_use_service_linked_role_false(
-        self,
-        mock_generate_policy,
-        mock_revoke,
-        mock_grant,
-        mock_register,
-        mock_refresh,
-    ):
-        """
-        Test that when use_service_linked_role=False, the registration_role_arn is used
-        in the S3 deny policy instead of the auto-generated service-linked role ARN.
-        """
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        # Set up Feature Group with required configuration
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock successful Lake Formation operations
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-        mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []}
-
-        # Custom registration role ARN
-        custom_registration_role = "arn:aws:iam::123456789012:role/CustomLakeFormationRole"
-
-        # Call with use_service_linked_role=False and registration_role_arn
-        fg.enable_lake_formation(
-            use_service_linked_role=False,
-            registration_role_arn=custom_registration_role,
-            show_s3_policy=True,
-        )
-
-        # Verify _generate_s3_deny_policy was called with the custom registration role ARN
-        mock_generate_policy.assert_called_once()
-        call_kwargs = mock_generate_policy.call_args[1]
-        assert call_kwargs["lake_formation_role_arn"] == custom_registration_role
-
-        # Verify it's NOT the service-linked role ARN
-        service_linked_role_pattern = "aws-service-role/lakeformation.amazonaws.com"
-        assert service_linked_role_pattern not in call_kwargs["lake_formation_role_arn"]
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    @patch.object(FeatureGroupManager, "_generate_s3_deny_policy")
-    def test_registration_role_arn_passed_to_s3_registration(
-        self,
-        mock_generate_policy,
-        mock_revoke,
-        mock_grant,
-        mock_register,
-        mock_refresh,
-    ):
-        """
-        Test that when use_service_linked_role=False, the registration_role_arn is also
-        passed to _register_s3_with_lake_formation.
-        """
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        # Set up Feature Group with required configuration
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock successful Lake Formation operations
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-        mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []}
-
-        # Custom registration role ARN
-        custom_registration_role = "arn:aws:iam::123456789012:role/CustomLakeFormationRole"
-
-        # Call with use_service_linked_role=False and registration_role_arn
-        fg.enable_lake_formation(
-            use_service_linked_role=False,
-            registration_role_arn=custom_registration_role,
-            show_s3_policy=True,
-        )
-
-        # Verify _register_s3_with_lake_formation was called with the correct parameters
-        mock_register.assert_called_once()
-        call_args = mock_register.call_args
-        assert call_args[1]["use_service_linked_role"] == False
-        assert call_args[1]["role_arn"] == custom_registration_role
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    @patch.object(FeatureGroupManager, "_generate_s3_deny_policy")
-    def test_different_registration_role_arns_produce_different_policies(
-        self,
-        mock_generate_policy,
-        mock_revoke,
-        mock_grant,
-        mock_register,
-        mock_refresh,
-    ):
-        """
-        Test that different registration_role_arn values result in different
-        lake_formation_role_arn values in the generated policy.
-        """
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        # Set up Feature Group with required configuration
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock successful Lake Formation operations
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-        mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []}
-
-        # First call with one registration role
-        first_role = "arn:aws:iam::123456789012:role/FirstLakeFormationRole"
-        fg.enable_lake_formation(
-            use_service_linked_role=False,
-            registration_role_arn=first_role,
-            show_s3_policy=True,
-        )
-
-        first_call_kwargs = mock_generate_policy.call_args[1]
-        first_lf_role = first_call_kwargs["lake_formation_role_arn"]
-
-        # Reset mocks
-        mock_generate_policy.reset_mock()
-        mock_register.reset_mock()
-        mock_grant.reset_mock()
-        mock_revoke.reset_mock()
-
-        # Second call with different registration role
-        second_role = "arn:aws:iam::123456789012:role/SecondLakeFormationRole"
-        fg.enable_lake_formation(
-            use_service_linked_role=False,
-            registration_role_arn=second_role,
-            show_s3_policy=True,
-        )
-
-        second_call_kwargs = mock_generate_policy.call_args[1]
-        second_lf_role = second_call_kwargs["lake_formation_role_arn"]
-
-        # Verify different roles were used
-        assert first_lf_role == first_role
-        assert second_lf_role == second_role
-        assert first_lf_role != second_lf_role
-
-
-
-class TestPolicyPrintedWithClearInstructions:
-    """Tests for verifying the S3 deny policy is printed with clear instructions."""
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    @patch("sagemaker.mlops.feature_store.feature_group_manager.logger")
-    def test_policy_printed_with_header_and_instructions(
-        self,
-        mock_logger,
-        mock_revoke,
-        mock_grant,
-        mock_register,
-        mock_refresh,
-    ):
-        """
-        Test that enable_lake_formation logs the S3 deny policy with clear
-        header and instructions for the user.
-        """
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        # Set up Feature Group with required configuration
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock successful Lake Formation operations
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-
-        # Call enable_lake_formation with show_s3_policy=True
-        fg.enable_lake_formation(show_s3_policy=True)
-
-        # Collect all logger.info calls
-        log_calls = [str(call) for call in mock_logger.info.call_args_list]
-        all_logged_text = " ".join(log_calls)
-
-        # Verify header is logged
-        assert "S3 Bucket Policy" in all_logged_text, "Header should mention 'S3 Bucket Policy'"
-
-        # Verify instructions are logged
-        assert (
-            "Lake Formation" in all_logged_text
-            or "deny policy" in all_logged_text
-        ), "Instructions should mention Lake Formation or deny policy"
-
-        # Verify bucket name is logged
-        assert "test-bucket" in all_logged_text, "Bucket name should be logged"
-
-        # Verify note about merging with existing policy is logged
-        assert (
-            "Merge" in all_logged_text or "existing" in all_logged_text
-        ), "Note about merging with existing policy should be logged"
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    @patch("sagemaker.mlops.feature_store.feature_group_manager.logger")
-    def test_policy_json_is_printed(
-        self,
-        mock_logger,
-        mock_revoke,
-        mock_grant,
-        mock_register,
-        mock_refresh,
-    ):
-        """
-        Test that the S3 deny policy JSON is logged to the console when show_s3_policy=True.
-        """
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        # Set up Feature Group with required configuration
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock successful Lake Formation operations
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-
-        # Call enable_lake_formation with show_s3_policy=True
-        fg.enable_lake_formation(show_s3_policy=True)
-
-        # Collect all logger.info calls
-        log_calls = [str(call) for call in mock_logger.info.call_args_list]
-        all_logged_text = " ".join(log_calls)
-
-        # Verify policy JSON structure elements are logged
-        assert "Version" in all_logged_text, "Policy JSON should contain 'Version'"
-        assert "Statement" in all_logged_text, "Policy JSON should contain 'Statement'"
-        assert "Effect" in all_logged_text, "Policy JSON should contain 'Effect'"
-        assert "Deny" in all_logged_text, "Policy JSON should contain 'Deny' effect"
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    @patch("sagemaker.mlops.feature_store.feature_group_manager.logger")
-    def test_policy_printed_only_after_successful_setup(
-        self,
-        mock_logger,
-        mock_revoke,
-        mock_grant,
-        mock_register,
-        mock_refresh,
-    ):
-        """
-        Test that the S3 deny policy is only logged after all Lake Formation
-        phases complete successfully.
-        """
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        # Set up Feature Group with required configuration
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock Phase 1 failure
-        mock_register.side_effect = Exception("Phase 1 failed")
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-
-        # Call enable_lake_formation with show_s3_policy=True - should fail
-        with pytest.raises(RuntimeError):
-            fg.enable_lake_formation(show_s3_policy=True)
-
-        # Collect all logger.info calls
-        log_calls = [str(call) for call in mock_logger.info.call_args_list]
-        all_logged_text = " ".join(log_calls)
-
-        # Verify policy was NOT logged when setup failed
-        assert "S3 Bucket Policy" not in all_logged_text, "Policy should not be logged when setup fails"
-
-        # Reset mocks
-        mock_logger.reset_mock()
-        mock_register.reset_mock()
-        mock_register.side_effect = None
-        mock_register.return_value = True
-
-        # Mock Phase 2 failure
-        mock_grant.side_effect = Exception("Phase 2 failed")
-
-        # Call enable_lake_formation with show_s3_policy=True - should fail
-        with pytest.raises(RuntimeError):
-            fg.enable_lake_formation(show_s3_policy=True)
-
-        # Collect all logger.info calls
-        log_calls = [str(call) for call in mock_logger.info.call_args_list]
-        all_logged_text = " ".join(log_calls)
-
-        # Verify policy was NOT logged when setup fails at Phase 2
-        assert "S3 Bucket Policy" not in all_logged_text, "Policy should not be logged when Phase 2 fails"
-
-        # Reset mocks
-        mock_logger.reset_mock()
-        mock_grant.reset_mock()
-        mock_grant.side_effect = None
-        mock_grant.return_value = True
-
-        # Mock Phase 3 failure
-        mock_revoke.side_effect = Exception("Phase 3 failed")
-
-        # Call enable_lake_formation with show_s3_policy=True - should fail
-        with pytest.raises(RuntimeError):
-            fg.enable_lake_formation(show_s3_policy=True)
-
-        # Collect all logger.info calls
-        log_calls = [str(call) for call in mock_logger.info.call_args_list]
-        all_logged_text = " ".join(log_calls)
-
-        # Verify policy was NOT logged when setup fails at Phase 3
-        assert "S3 Bucket Policy" not in all_logged_text, "Policy should not be logged when Phase 3 fails"
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    @patch("sagemaker.mlops.feature_store.feature_group_manager.logger")
-    def test_policy_includes_both_allowed_principals(
-        self,
-        mock_logger,
-        mock_revoke,
-        mock_grant,
-        mock_register,
-        mock_refresh,
-    ):
-        """
-        Test that the logged policy includes both the Lake Formation role
-        and the Feature Store execution role as allowed principals.
-        """
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        # Set up Feature Group with required configuration
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        feature_store_role = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-        fg.role_arn = feature_store_role
-        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock successful Lake Formation operations
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-
-        # Call enable_lake_formation with service-linked role and show_s3_policy=True
-        fg.enable_lake_formation(use_service_linked_role=True, show_s3_policy=True)
-
-        # Collect all logger.info calls
-        log_calls = [str(call) for call in mock_logger.info.call_args_list]
-        all_logged_text = " ".join(log_calls)
-
-        # Verify Feature Store role is in the logged output
-        assert feature_store_role in all_logged_text, "Feature Store role should be in logged policy"
-
-        # Verify Lake Formation service-linked role pattern is in the logged output
-        assert "AWSServiceRoleForLakeFormationDataAccess" in all_logged_text, \
-            "Lake Formation service-linked role should be in logged policy"
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    @patch("sagemaker.mlops.feature_store.feature_group_manager.logger")
-    def test_policy_not_printed_when_show_s3_policy_false(
-        self,
-        mock_logger,
-        mock_revoke,
-        mock_grant,
-        mock_register,
-        mock_refresh,
-    ):
-        """
-        Test that the S3 deny policy is NOT logged when show_s3_policy=False (default).
-        """
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        # Set up Feature Group with required configuration
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock successful Lake Formation operations
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-
-        # Call enable_lake_formation with show_s3_policy=False (default)
-        fg.enable_lake_formation(show_s3_policy=False)
-
-        # Collect all logger.info calls
-        log_calls = [str(call) for call in mock_logger.info.call_args_list]
-        all_logged_text = " ".join(log_calls)
-
-        # Verify policy was NOT logged
-        assert "S3 Bucket Policy" not in all_logged_text, "Policy should not be logged when show_s3_policy=False"
-        assert "Version" not in all_logged_text, "Policy JSON should not be logged when show_s3_policy=False"
-
-    @patch.object(FeatureGroupManager, "refresh")
-    @patch.object(FeatureGroupManager, "_register_s3_with_lake_formation")
-    @patch.object(FeatureGroupManager, "_grant_lake_formation_permissions")
-    @patch.object(FeatureGroupManager, "_revoke_iam_allowed_principal")
-    @patch("sagemaker.mlops.feature_store.feature_group_manager.logger")
-    def test_policy_not_printed_by_default(
-        self,
-        mock_logger,
-        mock_revoke,
-        mock_grant,
-        mock_register,
-        mock_refresh,
-    ):
-        """
-        Test that the S3 deny policy is NOT logged by default (when show_s3_policy is not specified).
-        """
-        from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig
-
-        # Set up Feature Group with required configuration
-        fg = FeatureGroupManager(feature_group_name="test-fg")
-        fg.offline_store_config = OfflineStoreConfig(
-            s3_storage_config=S3StorageConfig(
-                s3_uri="s3://test-bucket/path",
-                resolved_output_s3_uri="s3://test-bucket/resolved-path/data",
-            ),
-            data_catalog_config=DataCatalogConfig(
-                catalog="AwsDataCatalog", database="test_db", table_name="test_table"
-            ),
-        )
-        fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole"
-        fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg"
-        fg.feature_group_status = "Created"
-
-        # Mock successful Lake Formation operations
-        mock_register.return_value = True
-        mock_grant.return_value = True
-        mock_revoke.return_value = True
-
-        # Call enable_lake_formation without specifying show_s3_policy (should default to False)
-        fg.enable_lake_formation()
-
-        # Collect all logger.info calls
-        log_calls = [str(call) for call in mock_logger.info.call_args_list]
-        all_logged_text = " ".join(log_calls)
-
-        # Verify policy was NOT logged
-        assert "S3 Bucket Policy" not in all_logged_text, "Policy should not be logged by default"
-        assert "Version" not in all_logged_text, "Policy JSON should not be logged by default"

From c2426fe13e05ae76594c4d9a6376de52aa6049d5 Mon Sep 17 00:00:00 2001
From: Alexander Young <youngag@amazon.com>
Date: Tue, 31 Mar 2026 20:43:42 +0000
Subject: [PATCH 21/22] Fixed event_time format in integ tests

---
 .../tests/integ/test_feature_store_iceberg_properties.py    | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sagemaker-mlops/tests/integ/test_feature_store_iceberg_properties.py b/sagemaker-mlops/tests/integ/test_feature_store_iceberg_properties.py
index 2cd2b05369..cc3b201b55 100644
--- a/sagemaker-mlops/tests/integ/test_feature_store_iceberg_properties.py
+++ b/sagemaker-mlops/tests/integ/test_feature_store_iceberg_properties.py
@@ -2,6 +2,7 @@
 import time
 
 import boto3
+
 import pandas as pd
 import pytest
 
@@ -45,12 +46,13 @@ def feature_group_name():
 
 @pytest.fixture
 def sample_dataframe():
-    current_time = int(time.time())
+    from datetime import datetime, timezone, timedelta
+    base_time = datetime.now(timezone.utc)
     return pd.DataFrame({
         "record_id": [f"id-{i}" for i in range(10)],
         "feature_1": [i * 1.5 for i in range(10)],
         "feature_2": [i * 2 for i in range(10)],
-        "event_time": [float(current_time + i) for i in range(10)],
+        "event_time": [(base_time + timedelta(seconds=i)).strftime("%Y-%m-%dT%H:%M:%SZ") for i in range(10)],
     })
 
 

From 8158657a07554ec2321f3b7b40e805d9c40c6bbb Mon Sep 17 00:00:00 2001
From: Alexander Young <youngag@amazon.com>
Date: Tue, 31 Mar 2026 22:00:59 +0000
Subject: [PATCH 22/22] Removed excess fields from glue call in
 _get_iceberg_properties()

---
 .../sagemaker/mlops/feature_store/feature_group_manager.py   | 2 ++
 .../sagemaker/mlops/feature_store/test_iceberg_properties.py | 5 ++++-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
index 30a22593cc..a653779a15 100644
--- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
+++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group_manager.py
@@ -151,6 +151,8 @@ def _get_iceberg_properties(
                 "CatalogId",
                 "VersionId",
                 "FederatedTable",
+                "IsMultiDialectView",
+                "IsMaterializedView",
             ]
             for field in fields_to_remove:
                 table_input.pop(field, None)
diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py
index 586f5e9161..b264f251e5 100644
--- a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py
+++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_iceberg_properties.py
@@ -143,6 +143,8 @@ def test_successful_get_table_and_field_stripping(self, mock_session_class):
                 "CatalogId": "123456789012",
                 "VersionId": "1",
                 "FederatedTable": {},
+                "IsMultiDialectView": False,
+                "IsMaterializedView": False,
             }
         }
 
@@ -153,7 +155,8 @@ def test_successful_get_table_and_field_stripping(self, mock_session_class):
         assert result["glue_client"] == mock_glue_client
         # Verify stripped fields are not in table_input
         for field in ["DatabaseName", "CreateTime", "UpdateTime", "CreatedBy",
-                      "IsRegisteredWithLakeFormation", "CatalogId", "VersionId", "FederatedTable"]:
+                      "IsRegisteredWithLakeFormation", "CatalogId", "VersionId", "FederatedTable",
+                      "IsMultiDialectView", "IsMaterializedView"]:
             assert field not in result["table_input"]
         # Verify kept fields remain
         assert result["table_input"]["Name"] == "test_table"
