feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support - #5816

Merged
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf
May 13, 2026
Merged

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support#5816
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf

Conversation

@BassemHalim

@BassemHalimBassemHalim commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

This PR upgrades the Feature Processor module to support PySpark 3.5 and Python 3.12, adds Lake Formation credential vending for data ingestion, and improves Spark version handling across the board.

Description of changes:

  • Spark version upgrade: Bumps PySpark from 3.3.2 to 3.5.1 and sagemaker-feature-store-pyspark from 3.3 to 2.0.0 in
    pyproject.toml.
  • Python 3.12 support: Extends the allowed Python versions for Spark remote jobs from [3.9] to [3.9, 3.12] in
    sagemaker-core/job.py.
  • Auto-detect PySpark version: _get_default_spark_image now detects the installed PySpark version at runtime instead of using a
    hardcoded default.
  • Auto-inject Feature Store PySpark dependency: When spark_config is set, _JobSettings.init automatically appends pip
    install sagemaker-feature-store-pyspark and a JAR copy command to pre_execution_commands.
  • New _image_resolver.py module: Introduces _get_spark_image_uri() with a SPARK_IMAGE_SUPPORT_MATRIX that maps Spark versions
    to supported Python versions, replacing the hardcoded logic in feature_scheduler.py.
  • Dynamic Hadoop version resolution: New SPARK_TO_HADOOP_MAP and _get_hadoop_version() in _spark_factory.py resolve the correct
    Hadoop Maven coordinates based on the installed PySpark version.
  • Lazy imports for feature_store_pyspark: Moves feature_store_pyspark imports from module-level to inside methods, preventing
    import errors when the package isn't installed.
  • Feature Store JARs always on classpath: spark.jars config now includes version-matched Feature Store JARs for both training
    and non-training jobs. A new _install_feature_store_jars() method copies JARs to /usr/lib/spark/jars/.
  • Lake Formation credential vending: Adds use_lake_formation_credentials parameter to @feature_processor decorator, threaded
    through FeatureProcessorConfig -> _udf_output_receiver.ingest_udf_output() -> FeatureStoreManager.ingest_data.
  • ECDSA signing key generation: _config_uploader._prepare_and_upload_callable() now generates an ECDSA key pair, passes the
    private key to StoredFunction, and returns the public key PEM. The public key is set as REMOTE_FUNCTION_SECRET_KEY environment
    variable on the ModelTrainer.
  • Conditional image_uri in scheduler: _get_remote_decorator_config_from_input now only sets image_uri if one isn't already
    provided, allowing user-specified images.
  • Updated pre_execution_commands: Integration test helper uses python3 -m pip and python3 -m awscli patterns, installs awscli
    explicitly, and installs mlops_whl instead of sagemaker_whl with [feature-processor] extras.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Add configurable use_lake_formation_credentials parameter to the
@feature_processor decorator, defaulting to False. The value flows
through FeatureProcessorConfig to the Spark connector's ingest_data()
call, enabling Lake Formation credential vending when set to True.
---
X-AI-Prompt: make useLakeFormationCreds configurable, defaults to False, passed to feature_processor
X-AI-Tool: kiro-cli
Generate ECDSA signing key in ConfigUploader and pass it to
StoredFunction for function payload signature verification. The
public key PEM is returned to callers for remote-side verification.
---
X-AI-Prompt: fix StoredFunction missing signing_key error in feature_processor pipeline
X-AI-Tool: kiro-cli
Add _image_resolver module that resolves the SageMaker Spark
processing container image URI based on installed PySpark and Python
versions. Supports Spark 3.1/3.2/3.3/3.5 with appropriate Python
version mapping. Uses container_version=v1 as a floating tag.
---
X-AI-Prompt: add image resolver with container_version v1 for spark processing image
X-AI-Tool: kiro-cli
…cheduler
Update feature_scheduler to use _get_spark_image_uri for dynamic
image resolution instead of _JobSettings._get_default_spark_image.
Thread public_key_pem from ConfigUploader through to ModelTrainer
environment as REMOTE_FUNCTION_SECRET_KEY. Allow user-provided
image_uri to take precedence over auto-resolved URI.
---
X-AI-Prompt: integrate image resolver and signing key into feature scheduler pipeline
X-AI-Tool: kiro-cli
…Store JARs
Resolve Hadoop version dynamically based on installed PySpark version
instead of hardcoding 3.3.1. Move Feature Store JAR classpath setup
outside the non-training-job guard so spark.jars is always set,
fixing FeatureStoreManager class loading in training job mode.
---
X-AI-Prompt: fix spark factory hadoop version and jar classpath for spark 3.5
X-AI-Tool: kiro-cli
Update _get_default_spark_image to accept Python 3.12 in addition to
3.9. Auto-detect Spark version from installed pyspark instead of
hardcoding 3.3, falling back to the default if pyspark is not
installed. Also resolve correct Python binary in Spark bootstrap
script to avoid PATH conflicts with system python3.
---
X-AI-Prompt: fix job.py to select correct spark image for py312 and detect pyspark version
X-AI-Tool: kiro-cli
…on 3.12
Update expected error message in remote function tests to reflect that
SageMaker Spark images now support Python versions 3.9 and 3.12.
…or deps
Pin pyspark==3.5.1 in both feature-processor and test optional
dependencies to ensure consistent Spark version across environments.
…ersions
SageMaker Spark image only supports Python 3.9 and 3.12. Add skipif
markers to three feature processor integ tests that fail on Python 3.10.
Inject sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in _get_remote_decorator_config_from_input so it gets installed on the
remote container automatically.
Update integ tests: add skipif for Python 3.10 Spark tests, remove
manual feature-store-pyspark install, use python3 instead of python3.12.
… feature-store-pyspark
- Update test error messages to reflect Python 3.9 and 3.12 support
- Add pyspark 3.5.1 to test and feature-processor optional deps
- Skip Spark integ tests on unsupported Python versions (3.10)
- Auto-install sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in to_pipeline and copy version-matched JAR to Spark classpath
- Use standard SageMaker Spark image resolution via SparkConfig
- Use python3 instead of python3.12 in integ test pre_execution_commands
… remote jobs
When spark_config is set on a remote job, _JobSettings now automatically
injects pip install of sagemaker-feature-store-pyspark and copies the
Spark 3.5-matched JAR to /usr/lib/spark/jars/ via pre_execution_commands.
This makes the package work transparently when the SageMaker Spark image
does not pre-install sagemaker-feature-store-pyspark.
- Make feature_store_pyspark imports lazy in _spark_factory.py to avoid
deserialization failures when the module is not yet installed
- Add sagemaker-feature-store-pyspark to integ test requirements.txt
- Remove duplicate injection from feature_scheduler.py (to_pipeline path)
since _JobSettings now handles all Spark remote jobs
…e_execution_commands
_JobSettings now auto-injects feature-store-pyspark install and JAR copy
commands when spark_config is set, so update the test assertion to
expect these commands in the _prepare_and_upload_workspace call.
… tests
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration_on_training_job
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_with_iceberg_config
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_same_instance
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_configs_use_dynamic_hadoop_version
- Replace direct calls to feature_store_pyspark.classpath_jars() with mock_classpath_jars.return_value
- Update test_repack_model.py to use resolved path variable for consistency in _get_safe_members test
Add IcebergProperties to the feature_store __init__.py imports and
__all__ list so users can import it directly from the package instead
of reaching into the internal feature_group_manager module.
---
X-AI-Prompt: review staged change and commit if good
X-AI-Tool: kiro-cli
"pip install --root-user-action=ignore"
" 'sagemaker-feature-store-pyspark>=2,<3'"
)
copy_jar_cmd = (

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pyspark is not installed where this command runs so we read the $SPARK_HOME/usr/lib/spark/RELEASE file which has the currently installed spark version

@@ -92,7 +92,7 @@ def test_is_bad_link_unsafe():

def test_get_safe_members_all_safe():

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to this PR but It was failing in CI so I fixed it


import attr
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization as crypto_serialization

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intro of a library needed? If so, I see that sagemaker-mlops/pyproject.toml is not changed to add cryptography as a dependency.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are needed yes.
Cryptography is a dependency of sagemaker-core "cryptography>=46.0.0",
which sagemaker-mlops depends on but I think I will still add it to mlops in case it is removed from core in the future

BassemHalimand others added 2 commits May 12, 2026 11:42
… explicit cryptography dep
Add comment explaining REMOTE_FUNCTION_SECRET_KEY is a legacy misnomer —
the value is an ECDSA public key for signature verification, not a secret.
Add cryptography>=46.0.0 as explicit dependency in sagemaker-mlops.
---
X-AI-Prompt: resolve CR comment about misleading REMOTE_FUNCTION_SECRET_KEY naming and missing cryptography dependency
X-AI-Tool: kiro
@mollyheamazon
mollyheamazon merged commit 58ac9dc into aws:masterMay 13, 2026
38 of 53 checks passed
lucasjia-aws added a commit that referenced this pull request Jul 23, 2026
…sts (#6095)
The feature processor to_pipeline integ tests hardcoded fixed pipeline
names (pipeline-name-01, pipeline-name-lf-01) and thus shared fixed S3
paths (s3://.../<pipeline_name>/function/payload.pkl). Combined with the
asymmetric-signing scheme introduced in PR #5816 (each to_pipeline call
generates a fresh ECDSA key pair, overwrites the signed payload, and
pins the matching public key into the pipeline env), concurrent CI
builds on the same account overwrite each other's payloads. A running
execution then verifies a payload signed by a different build's key,
producing DeserializationError: "Integrity check for the serialized
function or data failed" and pipeline execution status Failed.
Generate unique pipeline names via unique_name_from_base so each test
run and build uses an isolated S3 prefix, and restore cleanup_pipeline
in the finally blocks to avoid resource leakage.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@BassemHalim@mollyheamazon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support - #5816

Merged
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf
May 13, 2026
Merged

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support#5816
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf

Conversation

@BassemHalim

@BassemHalimBassemHalim commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

This PR upgrades the Feature Processor module to support PySpark 3.5 and Python 3.12, adds Lake Formation credential vending for data ingestion, and improves Spark version handling across the board.

Description of changes:

  • Spark version upgrade: Bumps PySpark from 3.3.2 to 3.5.1 and sagemaker-feature-store-pyspark from 3.3 to 2.0.0 in
    pyproject.toml.
  • Python 3.12 support: Extends the allowed Python versions for Spark remote jobs from [3.9] to [3.9, 3.12] in
    sagemaker-core/job.py.
  • Auto-detect PySpark version: _get_default_spark_image now detects the installed PySpark version at runtime instead of using a
    hardcoded default.
  • Auto-inject Feature Store PySpark dependency: When spark_config is set, _JobSettings.init automatically appends pip
    install sagemaker-feature-store-pyspark and a JAR copy command to pre_execution_commands.
  • New _image_resolver.py module: Introduces _get_spark_image_uri() with a SPARK_IMAGE_SUPPORT_MATRIX that maps Spark versions
    to supported Python versions, replacing the hardcoded logic in feature_scheduler.py.
  • Dynamic Hadoop version resolution: New SPARK_TO_HADOOP_MAP and _get_hadoop_version() in _spark_factory.py resolve the correct
    Hadoop Maven coordinates based on the installed PySpark version.
  • Lazy imports for feature_store_pyspark: Moves feature_store_pyspark imports from module-level to inside methods, preventing
    import errors when the package isn't installed.
  • Feature Store JARs always on classpath: spark.jars config now includes version-matched Feature Store JARs for both training
    and non-training jobs. A new _install_feature_store_jars() method copies JARs to /usr/lib/spark/jars/.
  • Lake Formation credential vending: Adds use_lake_formation_credentials parameter to @feature_processor decorator, threaded
    through FeatureProcessorConfig -> _udf_output_receiver.ingest_udf_output() -> FeatureStoreManager.ingest_data.
  • ECDSA signing key generation: _config_uploader._prepare_and_upload_callable() now generates an ECDSA key pair, passes the
    private key to StoredFunction, and returns the public key PEM. The public key is set as REMOTE_FUNCTION_SECRET_KEY environment
    variable on the ModelTrainer.
  • Conditional image_uri in scheduler: _get_remote_decorator_config_from_input now only sets image_uri if one isn't already
    provided, allowing user-specified images.
  • Updated pre_execution_commands: Integration test helper uses python3 -m pip and python3 -m awscli patterns, installs awscli
    explicitly, and installs mlops_whl instead of sagemaker_whl with [feature-processor] extras.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Add configurable use_lake_formation_credentials parameter to the
@feature_processor decorator, defaulting to False. The value flows
through FeatureProcessorConfig to the Spark connector's ingest_data()
call, enabling Lake Formation credential vending when set to True.
---
X-AI-Prompt: make useLakeFormationCreds configurable, defaults to False, passed to feature_processor
X-AI-Tool: kiro-cli
Generate ECDSA signing key in ConfigUploader and pass it to
StoredFunction for function payload signature verification. The
public key PEM is returned to callers for remote-side verification.
---
X-AI-Prompt: fix StoredFunction missing signing_key error in feature_processor pipeline
X-AI-Tool: kiro-cli
Add _image_resolver module that resolves the SageMaker Spark
processing container image URI based on installed PySpark and Python
versions. Supports Spark 3.1/3.2/3.3/3.5 with appropriate Python
version mapping. Uses container_version=v1 as a floating tag.
---
X-AI-Prompt: add image resolver with container_version v1 for spark processing image
X-AI-Tool: kiro-cli
…cheduler
Update feature_scheduler to use _get_spark_image_uri for dynamic
image resolution instead of _JobSettings._get_default_spark_image.
Thread public_key_pem from ConfigUploader through to ModelTrainer
environment as REMOTE_FUNCTION_SECRET_KEY. Allow user-provided
image_uri to take precedence over auto-resolved URI.
---
X-AI-Prompt: integrate image resolver and signing key into feature scheduler pipeline
X-AI-Tool: kiro-cli
…Store JARs
Resolve Hadoop version dynamically based on installed PySpark version
instead of hardcoding 3.3.1. Move Feature Store JAR classpath setup
outside the non-training-job guard so spark.jars is always set,
fixing FeatureStoreManager class loading in training job mode.
---
X-AI-Prompt: fix spark factory hadoop version and jar classpath for spark 3.5
X-AI-Tool: kiro-cli
Update _get_default_spark_image to accept Python 3.12 in addition to
3.9. Auto-detect Spark version from installed pyspark instead of
hardcoding 3.3, falling back to the default if pyspark is not
installed. Also resolve correct Python binary in Spark bootstrap
script to avoid PATH conflicts with system python3.
---
X-AI-Prompt: fix job.py to select correct spark image for py312 and detect pyspark version
X-AI-Tool: kiro-cli
…on 3.12
Update expected error message in remote function tests to reflect that
SageMaker Spark images now support Python versions 3.9 and 3.12.
…or deps
Pin pyspark==3.5.1 in both feature-processor and test optional
dependencies to ensure consistent Spark version across environments.
…ersions
SageMaker Spark image only supports Python 3.9 and 3.12. Add skipif
markers to three feature processor integ tests that fail on Python 3.10.
Inject sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in _get_remote_decorator_config_from_input so it gets installed on the
remote container automatically.
Update integ tests: add skipif for Python 3.10 Spark tests, remove
manual feature-store-pyspark install, use python3 instead of python3.12.
… feature-store-pyspark
- Update test error messages to reflect Python 3.9 and 3.12 support
- Add pyspark 3.5.1 to test and feature-processor optional deps
- Skip Spark integ tests on unsupported Python versions (3.10)
- Auto-install sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in to_pipeline and copy version-matched JAR to Spark classpath
- Use standard SageMaker Spark image resolution via SparkConfig
- Use python3 instead of python3.12 in integ test pre_execution_commands
… remote jobs
When spark_config is set on a remote job, _JobSettings now automatically
injects pip install of sagemaker-feature-store-pyspark and copies the
Spark 3.5-matched JAR to /usr/lib/spark/jars/ via pre_execution_commands.
This makes the package work transparently when the SageMaker Spark image
does not pre-install sagemaker-feature-store-pyspark.
- Make feature_store_pyspark imports lazy in _spark_factory.py to avoid
deserialization failures when the module is not yet installed
- Add sagemaker-feature-store-pyspark to integ test requirements.txt
- Remove duplicate injection from feature_scheduler.py (to_pipeline path)
since _JobSettings now handles all Spark remote jobs
…e_execution_commands
_JobSettings now auto-injects feature-store-pyspark install and JAR copy
commands when spark_config is set, so update the test assertion to
expect these commands in the _prepare_and_upload_workspace call.
… tests
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration_on_training_job
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_with_iceberg_config
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_same_instance
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_configs_use_dynamic_hadoop_version
- Replace direct calls to feature_store_pyspark.classpath_jars() with mock_classpath_jars.return_value
- Update test_repack_model.py to use resolved path variable for consistency in _get_safe_members test
Add IcebergProperties to the feature_store __init__.py imports and
__all__ list so users can import it directly from the package instead
of reaching into the internal feature_group_manager module.
---
X-AI-Prompt: review staged change and commit if good
X-AI-Tool: kiro-cli
"pip install --root-user-action=ignore"
" 'sagemaker-feature-store-pyspark>=2,<3'"
)
copy_jar_cmd = (

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pyspark is not installed where this command runs so we read the $SPARK_HOME/usr/lib/spark/RELEASE file which has the currently installed spark version

@@ -92,7 +92,7 @@ def test_is_bad_link_unsafe():

def test_get_safe_members_all_safe():

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to this PR but It was failing in CI so I fixed it


import attr
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization as crypto_serialization

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intro of a library needed? If so, I see that sagemaker-mlops/pyproject.toml is not changed to add cryptography as a dependency.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are needed yes.
Cryptography is a dependency of sagemaker-core "cryptography>=46.0.0",
which sagemaker-mlops depends on but I think I will still add it to mlops in case it is removed from core in the future

BassemHalimand others added 2 commits May 12, 2026 11:42
… explicit cryptography dep
Add comment explaining REMOTE_FUNCTION_SECRET_KEY is a legacy misnomer —
the value is an ECDSA public key for signature verification, not a secret.
Add cryptography>=46.0.0 as explicit dependency in sagemaker-mlops.
---
X-AI-Prompt: resolve CR comment about misleading REMOTE_FUNCTION_SECRET_KEY naming and missing cryptography dependency
X-AI-Tool: kiro
@mollyheamazon
mollyheamazon merged commit 58ac9dc into aws:masterMay 13, 2026
38 of 53 checks passed
lucasjia-aws added a commit that referenced this pull request Jul 23, 2026
…sts (#6095)
The feature processor to_pipeline integ tests hardcoded fixed pipeline
names (pipeline-name-01, pipeline-name-lf-01) and thus shared fixed S3
paths (s3://.../<pipeline_name>/function/payload.pkl). Combined with the
asymmetric-signing scheme introduced in PR #5816 (each to_pipeline call
generates a fresh ECDSA key pair, overwrites the signed payload, and
pins the matching public key into the pipeline env), concurrent CI
builds on the same account overwrite each other's payloads. A running
execution then verifies a payload signed by a different build's key,
producing DeserializationError: "Integrity check for the serialized
function or data failed" and pipeline execution status Failed.
Generate unique pipeline names via unique_name_from_base so each test
run and build uses an isolated S3 prefix, and restore cleanup_pipeline
in the finally blocks to avoid resource leakage.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@BassemHalim@mollyheamazon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support - #5816

Merged
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf
May 13, 2026
Merged

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support#5816
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf

Conversation

@BassemHalim

@BassemHalimBassemHalim commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

This PR upgrades the Feature Processor module to support PySpark 3.5 and Python 3.12, adds Lake Formation credential vending for data ingestion, and improves Spark version handling across the board.

Description of changes:

  • Spark version upgrade: Bumps PySpark from 3.3.2 to 3.5.1 and sagemaker-feature-store-pyspark from 3.3 to 2.0.0 in
    pyproject.toml.
  • Python 3.12 support: Extends the allowed Python versions for Spark remote jobs from [3.9] to [3.9, 3.12] in
    sagemaker-core/job.py.
  • Auto-detect PySpark version: _get_default_spark_image now detects the installed PySpark version at runtime instead of using a
    hardcoded default.
  • Auto-inject Feature Store PySpark dependency: When spark_config is set, _JobSettings.init automatically appends pip
    install sagemaker-feature-store-pyspark and a JAR copy command to pre_execution_commands.
  • New _image_resolver.py module: Introduces _get_spark_image_uri() with a SPARK_IMAGE_SUPPORT_MATRIX that maps Spark versions
    to supported Python versions, replacing the hardcoded logic in feature_scheduler.py.
  • Dynamic Hadoop version resolution: New SPARK_TO_HADOOP_MAP and _get_hadoop_version() in _spark_factory.py resolve the correct
    Hadoop Maven coordinates based on the installed PySpark version.
  • Lazy imports for feature_store_pyspark: Moves feature_store_pyspark imports from module-level to inside methods, preventing
    import errors when the package isn't installed.
  • Feature Store JARs always on classpath: spark.jars config now includes version-matched Feature Store JARs for both training
    and non-training jobs. A new _install_feature_store_jars() method copies JARs to /usr/lib/spark/jars/.
  • Lake Formation credential vending: Adds use_lake_formation_credentials parameter to @feature_processor decorator, threaded
    through FeatureProcessorConfig -> _udf_output_receiver.ingest_udf_output() -> FeatureStoreManager.ingest_data.
  • ECDSA signing key generation: _config_uploader._prepare_and_upload_callable() now generates an ECDSA key pair, passes the
    private key to StoredFunction, and returns the public key PEM. The public key is set as REMOTE_FUNCTION_SECRET_KEY environment
    variable on the ModelTrainer.
  • Conditional image_uri in scheduler: _get_remote_decorator_config_from_input now only sets image_uri if one isn't already
    provided, allowing user-specified images.
  • Updated pre_execution_commands: Integration test helper uses python3 -m pip and python3 -m awscli patterns, installs awscli
    explicitly, and installs mlops_whl instead of sagemaker_whl with [feature-processor] extras.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Add configurable use_lake_formation_credentials parameter to the
@feature_processor decorator, defaulting to False. The value flows
through FeatureProcessorConfig to the Spark connector's ingest_data()
call, enabling Lake Formation credential vending when set to True.
---
X-AI-Prompt: make useLakeFormationCreds configurable, defaults to False, passed to feature_processor
X-AI-Tool: kiro-cli
Generate ECDSA signing key in ConfigUploader and pass it to
StoredFunction for function payload signature verification. The
public key PEM is returned to callers for remote-side verification.
---
X-AI-Prompt: fix StoredFunction missing signing_key error in feature_processor pipeline
X-AI-Tool: kiro-cli
Add _image_resolver module that resolves the SageMaker Spark
processing container image URI based on installed PySpark and Python
versions. Supports Spark 3.1/3.2/3.3/3.5 with appropriate Python
version mapping. Uses container_version=v1 as a floating tag.
---
X-AI-Prompt: add image resolver with container_version v1 for spark processing image
X-AI-Tool: kiro-cli
…cheduler
Update feature_scheduler to use _get_spark_image_uri for dynamic
image resolution instead of _JobSettings._get_default_spark_image.
Thread public_key_pem from ConfigUploader through to ModelTrainer
environment as REMOTE_FUNCTION_SECRET_KEY. Allow user-provided
image_uri to take precedence over auto-resolved URI.
---
X-AI-Prompt: integrate image resolver and signing key into feature scheduler pipeline
X-AI-Tool: kiro-cli
…Store JARs
Resolve Hadoop version dynamically based on installed PySpark version
instead of hardcoding 3.3.1. Move Feature Store JAR classpath setup
outside the non-training-job guard so spark.jars is always set,
fixing FeatureStoreManager class loading in training job mode.
---
X-AI-Prompt: fix spark factory hadoop version and jar classpath for spark 3.5
X-AI-Tool: kiro-cli
Update _get_default_spark_image to accept Python 3.12 in addition to
3.9. Auto-detect Spark version from installed pyspark instead of
hardcoding 3.3, falling back to the default if pyspark is not
installed. Also resolve correct Python binary in Spark bootstrap
script to avoid PATH conflicts with system python3.
---
X-AI-Prompt: fix job.py to select correct spark image for py312 and detect pyspark version
X-AI-Tool: kiro-cli
…on 3.12
Update expected error message in remote function tests to reflect that
SageMaker Spark images now support Python versions 3.9 and 3.12.
…or deps
Pin pyspark==3.5.1 in both feature-processor and test optional
dependencies to ensure consistent Spark version across environments.
…ersions
SageMaker Spark image only supports Python 3.9 and 3.12. Add skipif
markers to three feature processor integ tests that fail on Python 3.10.
Inject sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in _get_remote_decorator_config_from_input so it gets installed on the
remote container automatically.
Update integ tests: add skipif for Python 3.10 Spark tests, remove
manual feature-store-pyspark install, use python3 instead of python3.12.
… feature-store-pyspark
- Update test error messages to reflect Python 3.9 and 3.12 support
- Add pyspark 3.5.1 to test and feature-processor optional deps
- Skip Spark integ tests on unsupported Python versions (3.10)
- Auto-install sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in to_pipeline and copy version-matched JAR to Spark classpath
- Use standard SageMaker Spark image resolution via SparkConfig
- Use python3 instead of python3.12 in integ test pre_execution_commands
… remote jobs
When spark_config is set on a remote job, _JobSettings now automatically
injects pip install of sagemaker-feature-store-pyspark and copies the
Spark 3.5-matched JAR to /usr/lib/spark/jars/ via pre_execution_commands.
This makes the package work transparently when the SageMaker Spark image
does not pre-install sagemaker-feature-store-pyspark.
- Make feature_store_pyspark imports lazy in _spark_factory.py to avoid
deserialization failures when the module is not yet installed
- Add sagemaker-feature-store-pyspark to integ test requirements.txt
- Remove duplicate injection from feature_scheduler.py (to_pipeline path)
since _JobSettings now handles all Spark remote jobs
…e_execution_commands
_JobSettings now auto-injects feature-store-pyspark install and JAR copy
commands when spark_config is set, so update the test assertion to
expect these commands in the _prepare_and_upload_workspace call.
… tests
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration_on_training_job
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_with_iceberg_config
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_same_instance
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_configs_use_dynamic_hadoop_version
- Replace direct calls to feature_store_pyspark.classpath_jars() with mock_classpath_jars.return_value
- Update test_repack_model.py to use resolved path variable for consistency in _get_safe_members test
Add IcebergProperties to the feature_store __init__.py imports and
__all__ list so users can import it directly from the package instead
of reaching into the internal feature_group_manager module.
---
X-AI-Prompt: review staged change and commit if good
X-AI-Tool: kiro-cli
"pip install --root-user-action=ignore"
" 'sagemaker-feature-store-pyspark>=2,<3'"
)
copy_jar_cmd = (

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pyspark is not installed where this command runs so we read the $SPARK_HOME/usr/lib/spark/RELEASE file which has the currently installed spark version

@@ -92,7 +92,7 @@ def test_is_bad_link_unsafe():

def test_get_safe_members_all_safe():

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to this PR but It was failing in CI so I fixed it


import attr
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization as crypto_serialization

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intro of a library needed? If so, I see that sagemaker-mlops/pyproject.toml is not changed to add cryptography as a dependency.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are needed yes.
Cryptography is a dependency of sagemaker-core "cryptography>=46.0.0",
which sagemaker-mlops depends on but I think I will still add it to mlops in case it is removed from core in the future

BassemHalimand others added 2 commits May 12, 2026 11:42
… explicit cryptography dep
Add comment explaining REMOTE_FUNCTION_SECRET_KEY is a legacy misnomer —
the value is an ECDSA public key for signature verification, not a secret.
Add cryptography>=46.0.0 as explicit dependency in sagemaker-mlops.
---
X-AI-Prompt: resolve CR comment about misleading REMOTE_FUNCTION_SECRET_KEY naming and missing cryptography dependency
X-AI-Tool: kiro
@mollyheamazon
mollyheamazon merged commit 58ac9dc into aws:masterMay 13, 2026
38 of 53 checks passed
lucasjia-aws added a commit that referenced this pull request Jul 23, 2026
…sts (#6095)
The feature processor to_pipeline integ tests hardcoded fixed pipeline
names (pipeline-name-01, pipeline-name-lf-01) and thus shared fixed S3
paths (s3://.../<pipeline_name>/function/payload.pkl). Combined with the
asymmetric-signing scheme introduced in PR #5816 (each to_pipeline call
generates a fresh ECDSA key pair, overwrites the signed payload, and
pins the matching public key into the pipeline env), concurrent CI
builds on the same account overwrite each other's payloads. A running
execution then verifies a payload signed by a different build's key,
producing DeserializationError: "Integrity check for the serialized
function or data failed" and pipeline execution status Failed.
Generate unique pipeline names via unique_name_from_base so each test
run and build uses an isolated S3 prefix, and restore cleanup_pipeline
in the finally blocks to avoid resource leakage.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@BassemHalim@mollyheamazon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support - #5816

Merged
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf
May 13, 2026
Merged

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support#5816
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf

Conversation

@BassemHalim

@BassemHalimBassemHalim commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

This PR upgrades the Feature Processor module to support PySpark 3.5 and Python 3.12, adds Lake Formation credential vending for data ingestion, and improves Spark version handling across the board.

Description of changes:

  • Spark version upgrade: Bumps PySpark from 3.3.2 to 3.5.1 and sagemaker-feature-store-pyspark from 3.3 to 2.0.0 in
    pyproject.toml.
  • Python 3.12 support: Extends the allowed Python versions for Spark remote jobs from [3.9] to [3.9, 3.12] in
    sagemaker-core/job.py.
  • Auto-detect PySpark version: _get_default_spark_image now detects the installed PySpark version at runtime instead of using a
    hardcoded default.
  • Auto-inject Feature Store PySpark dependency: When spark_config is set, _JobSettings.init automatically appends pip
    install sagemaker-feature-store-pyspark and a JAR copy command to pre_execution_commands.
  • New _image_resolver.py module: Introduces _get_spark_image_uri() with a SPARK_IMAGE_SUPPORT_MATRIX that maps Spark versions
    to supported Python versions, replacing the hardcoded logic in feature_scheduler.py.
  • Dynamic Hadoop version resolution: New SPARK_TO_HADOOP_MAP and _get_hadoop_version() in _spark_factory.py resolve the correct
    Hadoop Maven coordinates based on the installed PySpark version.
  • Lazy imports for feature_store_pyspark: Moves feature_store_pyspark imports from module-level to inside methods, preventing
    import errors when the package isn't installed.
  • Feature Store JARs always on classpath: spark.jars config now includes version-matched Feature Store JARs for both training
    and non-training jobs. A new _install_feature_store_jars() method copies JARs to /usr/lib/spark/jars/.
  • Lake Formation credential vending: Adds use_lake_formation_credentials parameter to @feature_processor decorator, threaded
    through FeatureProcessorConfig -> _udf_output_receiver.ingest_udf_output() -> FeatureStoreManager.ingest_data.
  • ECDSA signing key generation: _config_uploader._prepare_and_upload_callable() now generates an ECDSA key pair, passes the
    private key to StoredFunction, and returns the public key PEM. The public key is set as REMOTE_FUNCTION_SECRET_KEY environment
    variable on the ModelTrainer.
  • Conditional image_uri in scheduler: _get_remote_decorator_config_from_input now only sets image_uri if one isn't already
    provided, allowing user-specified images.
  • Updated pre_execution_commands: Integration test helper uses python3 -m pip and python3 -m awscli patterns, installs awscli
    explicitly, and installs mlops_whl instead of sagemaker_whl with [feature-processor] extras.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Add configurable use_lake_formation_credentials parameter to the
@feature_processor decorator, defaulting to False. The value flows
through FeatureProcessorConfig to the Spark connector's ingest_data()
call, enabling Lake Formation credential vending when set to True.
---
X-AI-Prompt: make useLakeFormationCreds configurable, defaults to False, passed to feature_processor
X-AI-Tool: kiro-cli
Generate ECDSA signing key in ConfigUploader and pass it to
StoredFunction for function payload signature verification. The
public key PEM is returned to callers for remote-side verification.
---
X-AI-Prompt: fix StoredFunction missing signing_key error in feature_processor pipeline
X-AI-Tool: kiro-cli
Add _image_resolver module that resolves the SageMaker Spark
processing container image URI based on installed PySpark and Python
versions. Supports Spark 3.1/3.2/3.3/3.5 with appropriate Python
version mapping. Uses container_version=v1 as a floating tag.
---
X-AI-Prompt: add image resolver with container_version v1 for spark processing image
X-AI-Tool: kiro-cli
…cheduler
Update feature_scheduler to use _get_spark_image_uri for dynamic
image resolution instead of _JobSettings._get_default_spark_image.
Thread public_key_pem from ConfigUploader through to ModelTrainer
environment as REMOTE_FUNCTION_SECRET_KEY. Allow user-provided
image_uri to take precedence over auto-resolved URI.
---
X-AI-Prompt: integrate image resolver and signing key into feature scheduler pipeline
X-AI-Tool: kiro-cli
…Store JARs
Resolve Hadoop version dynamically based on installed PySpark version
instead of hardcoding 3.3.1. Move Feature Store JAR classpath setup
outside the non-training-job guard so spark.jars is always set,
fixing FeatureStoreManager class loading in training job mode.
---
X-AI-Prompt: fix spark factory hadoop version and jar classpath for spark 3.5
X-AI-Tool: kiro-cli
Update _get_default_spark_image to accept Python 3.12 in addition to
3.9. Auto-detect Spark version from installed pyspark instead of
hardcoding 3.3, falling back to the default if pyspark is not
installed. Also resolve correct Python binary in Spark bootstrap
script to avoid PATH conflicts with system python3.
---
X-AI-Prompt: fix job.py to select correct spark image for py312 and detect pyspark version
X-AI-Tool: kiro-cli
…on 3.12
Update expected error message in remote function tests to reflect that
SageMaker Spark images now support Python versions 3.9 and 3.12.
…or deps
Pin pyspark==3.5.1 in both feature-processor and test optional
dependencies to ensure consistent Spark version across environments.
…ersions
SageMaker Spark image only supports Python 3.9 and 3.12. Add skipif
markers to three feature processor integ tests that fail on Python 3.10.
Inject sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in _get_remote_decorator_config_from_input so it gets installed on the
remote container automatically.
Update integ tests: add skipif for Python 3.10 Spark tests, remove
manual feature-store-pyspark install, use python3 instead of python3.12.
… feature-store-pyspark
- Update test error messages to reflect Python 3.9 and 3.12 support
- Add pyspark 3.5.1 to test and feature-processor optional deps
- Skip Spark integ tests on unsupported Python versions (3.10)
- Auto-install sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in to_pipeline and copy version-matched JAR to Spark classpath
- Use standard SageMaker Spark image resolution via SparkConfig
- Use python3 instead of python3.12 in integ test pre_execution_commands
… remote jobs
When spark_config is set on a remote job, _JobSettings now automatically
injects pip install of sagemaker-feature-store-pyspark and copies the
Spark 3.5-matched JAR to /usr/lib/spark/jars/ via pre_execution_commands.
This makes the package work transparently when the SageMaker Spark image
does not pre-install sagemaker-feature-store-pyspark.
- Make feature_store_pyspark imports lazy in _spark_factory.py to avoid
deserialization failures when the module is not yet installed
- Add sagemaker-feature-store-pyspark to integ test requirements.txt
- Remove duplicate injection from feature_scheduler.py (to_pipeline path)
since _JobSettings now handles all Spark remote jobs
…e_execution_commands
_JobSettings now auto-injects feature-store-pyspark install and JAR copy
commands when spark_config is set, so update the test assertion to
expect these commands in the _prepare_and_upload_workspace call.
… tests
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration_on_training_job
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_with_iceberg_config
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_same_instance
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_configs_use_dynamic_hadoop_version
- Replace direct calls to feature_store_pyspark.classpath_jars() with mock_classpath_jars.return_value
- Update test_repack_model.py to use resolved path variable for consistency in _get_safe_members test
Add IcebergProperties to the feature_store __init__.py imports and
__all__ list so users can import it directly from the package instead
of reaching into the internal feature_group_manager module.
---
X-AI-Prompt: review staged change and commit if good
X-AI-Tool: kiro-cli
"pip install --root-user-action=ignore"
" 'sagemaker-feature-store-pyspark>=2,<3'"
)
copy_jar_cmd = (

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pyspark is not installed where this command runs so we read the $SPARK_HOME/usr/lib/spark/RELEASE file which has the currently installed spark version

@@ -92,7 +92,7 @@ def test_is_bad_link_unsafe():

def test_get_safe_members_all_safe():

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to this PR but It was failing in CI so I fixed it


import attr
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization as crypto_serialization

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intro of a library needed? If so, I see that sagemaker-mlops/pyproject.toml is not changed to add cryptography as a dependency.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are needed yes.
Cryptography is a dependency of sagemaker-core "cryptography>=46.0.0",
which sagemaker-mlops depends on but I think I will still add it to mlops in case it is removed from core in the future

BassemHalimand others added 2 commits May 12, 2026 11:42
… explicit cryptography dep
Add comment explaining REMOTE_FUNCTION_SECRET_KEY is a legacy misnomer —
the value is an ECDSA public key for signature verification, not a secret.
Add cryptography>=46.0.0 as explicit dependency in sagemaker-mlops.
---
X-AI-Prompt: resolve CR comment about misleading REMOTE_FUNCTION_SECRET_KEY naming and missing cryptography dependency
X-AI-Tool: kiro
@mollyheamazon
mollyheamazon merged commit 58ac9dc into aws:masterMay 13, 2026
38 of 53 checks passed
lucasjia-aws added a commit that referenced this pull request Jul 23, 2026
…sts (#6095)
The feature processor to_pipeline integ tests hardcoded fixed pipeline
names (pipeline-name-01, pipeline-name-lf-01) and thus shared fixed S3
paths (s3://.../<pipeline_name>/function/payload.pkl). Combined with the
asymmetric-signing scheme introduced in PR #5816 (each to_pipeline call
generates a fresh ECDSA key pair, overwrites the signed payload, and
pins the matching public key into the pipeline env), concurrent CI
builds on the same account overwrite each other's payloads. A running
execution then verifies a payload signed by a different build's key,
producing DeserializationError: "Integrity check for the serialized
function or data failed" and pipeline execution status Failed.
Generate unique pipeline names via unique_name_from_base so each test
run and build uses an isolated S3 prefix, and restore cleanup_pipeline
in the finally blocks to avoid resource leakage.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@BassemHalim@mollyheamazon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support - #5816

Merged
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf
May 13, 2026
Merged

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support#5816
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf

Conversation

@BassemHalim

@BassemHalimBassemHalim commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

This PR upgrades the Feature Processor module to support PySpark 3.5 and Python 3.12, adds Lake Formation credential vending for data ingestion, and improves Spark version handling across the board.

Description of changes:

  • Spark version upgrade: Bumps PySpark from 3.3.2 to 3.5.1 and sagemaker-feature-store-pyspark from 3.3 to 2.0.0 in
    pyproject.toml.
  • Python 3.12 support: Extends the allowed Python versions for Spark remote jobs from [3.9] to [3.9, 3.12] in
    sagemaker-core/job.py.
  • Auto-detect PySpark version: _get_default_spark_image now detects the installed PySpark version at runtime instead of using a
    hardcoded default.
  • Auto-inject Feature Store PySpark dependency: When spark_config is set, _JobSettings.init automatically appends pip
    install sagemaker-feature-store-pyspark and a JAR copy command to pre_execution_commands.
  • New _image_resolver.py module: Introduces _get_spark_image_uri() with a SPARK_IMAGE_SUPPORT_MATRIX that maps Spark versions
    to supported Python versions, replacing the hardcoded logic in feature_scheduler.py.
  • Dynamic Hadoop version resolution: New SPARK_TO_HADOOP_MAP and _get_hadoop_version() in _spark_factory.py resolve the correct
    Hadoop Maven coordinates based on the installed PySpark version.
  • Lazy imports for feature_store_pyspark: Moves feature_store_pyspark imports from module-level to inside methods, preventing
    import errors when the package isn't installed.
  • Feature Store JARs always on classpath: spark.jars config now includes version-matched Feature Store JARs for both training
    and non-training jobs. A new _install_feature_store_jars() method copies JARs to /usr/lib/spark/jars/.
  • Lake Formation credential vending: Adds use_lake_formation_credentials parameter to @feature_processor decorator, threaded
    through FeatureProcessorConfig -> _udf_output_receiver.ingest_udf_output() -> FeatureStoreManager.ingest_data.
  • ECDSA signing key generation: _config_uploader._prepare_and_upload_callable() now generates an ECDSA key pair, passes the
    private key to StoredFunction, and returns the public key PEM. The public key is set as REMOTE_FUNCTION_SECRET_KEY environment
    variable on the ModelTrainer.
  • Conditional image_uri in scheduler: _get_remote_decorator_config_from_input now only sets image_uri if one isn't already
    provided, allowing user-specified images.
  • Updated pre_execution_commands: Integration test helper uses python3 -m pip and python3 -m awscli patterns, installs awscli
    explicitly, and installs mlops_whl instead of sagemaker_whl with [feature-processor] extras.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Add configurable use_lake_formation_credentials parameter to the
@feature_processor decorator, defaulting to False. The value flows
through FeatureProcessorConfig to the Spark connector's ingest_data()
call, enabling Lake Formation credential vending when set to True.
---
X-AI-Prompt: make useLakeFormationCreds configurable, defaults to False, passed to feature_processor
X-AI-Tool: kiro-cli
Generate ECDSA signing key in ConfigUploader and pass it to
StoredFunction for function payload signature verification. The
public key PEM is returned to callers for remote-side verification.
---
X-AI-Prompt: fix StoredFunction missing signing_key error in feature_processor pipeline
X-AI-Tool: kiro-cli
Add _image_resolver module that resolves the SageMaker Spark
processing container image URI based on installed PySpark and Python
versions. Supports Spark 3.1/3.2/3.3/3.5 with appropriate Python
version mapping. Uses container_version=v1 as a floating tag.
---
X-AI-Prompt: add image resolver with container_version v1 for spark processing image
X-AI-Tool: kiro-cli
…cheduler
Update feature_scheduler to use _get_spark_image_uri for dynamic
image resolution instead of _JobSettings._get_default_spark_image.
Thread public_key_pem from ConfigUploader through to ModelTrainer
environment as REMOTE_FUNCTION_SECRET_KEY. Allow user-provided
image_uri to take precedence over auto-resolved URI.
---
X-AI-Prompt: integrate image resolver and signing key into feature scheduler pipeline
X-AI-Tool: kiro-cli
…Store JARs
Resolve Hadoop version dynamically based on installed PySpark version
instead of hardcoding 3.3.1. Move Feature Store JAR classpath setup
outside the non-training-job guard so spark.jars is always set,
fixing FeatureStoreManager class loading in training job mode.
---
X-AI-Prompt: fix spark factory hadoop version and jar classpath for spark 3.5
X-AI-Tool: kiro-cli
Update _get_default_spark_image to accept Python 3.12 in addition to
3.9. Auto-detect Spark version from installed pyspark instead of
hardcoding 3.3, falling back to the default if pyspark is not
installed. Also resolve correct Python binary in Spark bootstrap
script to avoid PATH conflicts with system python3.
---
X-AI-Prompt: fix job.py to select correct spark image for py312 and detect pyspark version
X-AI-Tool: kiro-cli
…on 3.12
Update expected error message in remote function tests to reflect that
SageMaker Spark images now support Python versions 3.9 and 3.12.
…or deps
Pin pyspark==3.5.1 in both feature-processor and test optional
dependencies to ensure consistent Spark version across environments.
…ersions
SageMaker Spark image only supports Python 3.9 and 3.12. Add skipif
markers to three feature processor integ tests that fail on Python 3.10.
Inject sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in _get_remote_decorator_config_from_input so it gets installed on the
remote container automatically.
Update integ tests: add skipif for Python 3.10 Spark tests, remove
manual feature-store-pyspark install, use python3 instead of python3.12.
… feature-store-pyspark
- Update test error messages to reflect Python 3.9 and 3.12 support
- Add pyspark 3.5.1 to test and feature-processor optional deps
- Skip Spark integ tests on unsupported Python versions (3.10)
- Auto-install sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in to_pipeline and copy version-matched JAR to Spark classpath
- Use standard SageMaker Spark image resolution via SparkConfig
- Use python3 instead of python3.12 in integ test pre_execution_commands
… remote jobs
When spark_config is set on a remote job, _JobSettings now automatically
injects pip install of sagemaker-feature-store-pyspark and copies the
Spark 3.5-matched JAR to /usr/lib/spark/jars/ via pre_execution_commands.
This makes the package work transparently when the SageMaker Spark image
does not pre-install sagemaker-feature-store-pyspark.
- Make feature_store_pyspark imports lazy in _spark_factory.py to avoid
deserialization failures when the module is not yet installed
- Add sagemaker-feature-store-pyspark to integ test requirements.txt
- Remove duplicate injection from feature_scheduler.py (to_pipeline path)
since _JobSettings now handles all Spark remote jobs
…e_execution_commands
_JobSettings now auto-injects feature-store-pyspark install and JAR copy
commands when spark_config is set, so update the test assertion to
expect these commands in the _prepare_and_upload_workspace call.
… tests
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration_on_training_job
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_with_iceberg_config
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_same_instance
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_configs_use_dynamic_hadoop_version
- Replace direct calls to feature_store_pyspark.classpath_jars() with mock_classpath_jars.return_value
- Update test_repack_model.py to use resolved path variable for consistency in _get_safe_members test
Add IcebergProperties to the feature_store __init__.py imports and
__all__ list so users can import it directly from the package instead
of reaching into the internal feature_group_manager module.
---
X-AI-Prompt: review staged change and commit if good
X-AI-Tool: kiro-cli
"pip install --root-user-action=ignore"
" 'sagemaker-feature-store-pyspark>=2,<3'"
)
copy_jar_cmd = (

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pyspark is not installed where this command runs so we read the $SPARK_HOME/usr/lib/spark/RELEASE file which has the currently installed spark version

@@ -92,7 +92,7 @@ def test_is_bad_link_unsafe():

def test_get_safe_members_all_safe():

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to this PR but It was failing in CI so I fixed it


import attr
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization as crypto_serialization

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intro of a library needed? If so, I see that sagemaker-mlops/pyproject.toml is not changed to add cryptography as a dependency.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are needed yes.
Cryptography is a dependency of sagemaker-core "cryptography>=46.0.0",
which sagemaker-mlops depends on but I think I will still add it to mlops in case it is removed from core in the future

BassemHalimand others added 2 commits May 12, 2026 11:42
… explicit cryptography dep
Add comment explaining REMOTE_FUNCTION_SECRET_KEY is a legacy misnomer —
the value is an ECDSA public key for signature verification, not a secret.
Add cryptography>=46.0.0 as explicit dependency in sagemaker-mlops.
---
X-AI-Prompt: resolve CR comment about misleading REMOTE_FUNCTION_SECRET_KEY naming and missing cryptography dependency
X-AI-Tool: kiro
@mollyheamazon
mollyheamazon merged commit 58ac9dc into aws:masterMay 13, 2026
38 of 53 checks passed
lucasjia-aws added a commit that referenced this pull request Jul 23, 2026
…sts (#6095)
The feature processor to_pipeline integ tests hardcoded fixed pipeline
names (pipeline-name-01, pipeline-name-lf-01) and thus shared fixed S3
paths (s3://.../<pipeline_name>/function/payload.pkl). Combined with the
asymmetric-signing scheme introduced in PR #5816 (each to_pipeline call
generates a fresh ECDSA key pair, overwrites the signed payload, and
pins the matching public key into the pipeline env), concurrent CI
builds on the same account overwrite each other's payloads. A running
execution then verifies a payload signed by a different build's key,
producing DeserializationError: "Integrity check for the serialized
function or data failed" and pipeline execution status Failed.
Generate unique pipeline names via unique_name_from_base so each test
run and build uses an isolated S3 prefix, and restore cleanup_pipeline
in the finally blocks to avoid resource leakage.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@BassemHalim@mollyheamazon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support - #5816

Merged
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf
May 13, 2026
Merged

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support#5816
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf

Conversation

@BassemHalim

@BassemHalimBassemHalim commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

This PR upgrades the Feature Processor module to support PySpark 3.5 and Python 3.12, adds Lake Formation credential vending for data ingestion, and improves Spark version handling across the board.

Description of changes:

  • Spark version upgrade: Bumps PySpark from 3.3.2 to 3.5.1 and sagemaker-feature-store-pyspark from 3.3 to 2.0.0 in
    pyproject.toml.
  • Python 3.12 support: Extends the allowed Python versions for Spark remote jobs from [3.9] to [3.9, 3.12] in
    sagemaker-core/job.py.
  • Auto-detect PySpark version: _get_default_spark_image now detects the installed PySpark version at runtime instead of using a
    hardcoded default.
  • Auto-inject Feature Store PySpark dependency: When spark_config is set, _JobSettings.init automatically appends pip
    install sagemaker-feature-store-pyspark and a JAR copy command to pre_execution_commands.
  • New _image_resolver.py module: Introduces _get_spark_image_uri() with a SPARK_IMAGE_SUPPORT_MATRIX that maps Spark versions
    to supported Python versions, replacing the hardcoded logic in feature_scheduler.py.
  • Dynamic Hadoop version resolution: New SPARK_TO_HADOOP_MAP and _get_hadoop_version() in _spark_factory.py resolve the correct
    Hadoop Maven coordinates based on the installed PySpark version.
  • Lazy imports for feature_store_pyspark: Moves feature_store_pyspark imports from module-level to inside methods, preventing
    import errors when the package isn't installed.
  • Feature Store JARs always on classpath: spark.jars config now includes version-matched Feature Store JARs for both training
    and non-training jobs. A new _install_feature_store_jars() method copies JARs to /usr/lib/spark/jars/.
  • Lake Formation credential vending: Adds use_lake_formation_credentials parameter to @feature_processor decorator, threaded
    through FeatureProcessorConfig -> _udf_output_receiver.ingest_udf_output() -> FeatureStoreManager.ingest_data.
  • ECDSA signing key generation: _config_uploader._prepare_and_upload_callable() now generates an ECDSA key pair, passes the
    private key to StoredFunction, and returns the public key PEM. The public key is set as REMOTE_FUNCTION_SECRET_KEY environment
    variable on the ModelTrainer.
  • Conditional image_uri in scheduler: _get_remote_decorator_config_from_input now only sets image_uri if one isn't already
    provided, allowing user-specified images.
  • Updated pre_execution_commands: Integration test helper uses python3 -m pip and python3 -m awscli patterns, installs awscli
    explicitly, and installs mlops_whl instead of sagemaker_whl with [feature-processor] extras.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Add configurable use_lake_formation_credentials parameter to the
@feature_processor decorator, defaulting to False. The value flows
through FeatureProcessorConfig to the Spark connector's ingest_data()
call, enabling Lake Formation credential vending when set to True.
---
X-AI-Prompt: make useLakeFormationCreds configurable, defaults to False, passed to feature_processor
X-AI-Tool: kiro-cli
Generate ECDSA signing key in ConfigUploader and pass it to
StoredFunction for function payload signature verification. The
public key PEM is returned to callers for remote-side verification.
---
X-AI-Prompt: fix StoredFunction missing signing_key error in feature_processor pipeline
X-AI-Tool: kiro-cli
Add _image_resolver module that resolves the SageMaker Spark
processing container image URI based on installed PySpark and Python
versions. Supports Spark 3.1/3.2/3.3/3.5 with appropriate Python
version mapping. Uses container_version=v1 as a floating tag.
---
X-AI-Prompt: add image resolver with container_version v1 for spark processing image
X-AI-Tool: kiro-cli
…cheduler
Update feature_scheduler to use _get_spark_image_uri for dynamic
image resolution instead of _JobSettings._get_default_spark_image.
Thread public_key_pem from ConfigUploader through to ModelTrainer
environment as REMOTE_FUNCTION_SECRET_KEY. Allow user-provided
image_uri to take precedence over auto-resolved URI.
---
X-AI-Prompt: integrate image resolver and signing key into feature scheduler pipeline
X-AI-Tool: kiro-cli
…Store JARs
Resolve Hadoop version dynamically based on installed PySpark version
instead of hardcoding 3.3.1. Move Feature Store JAR classpath setup
outside the non-training-job guard so spark.jars is always set,
fixing FeatureStoreManager class loading in training job mode.
---
X-AI-Prompt: fix spark factory hadoop version and jar classpath for spark 3.5
X-AI-Tool: kiro-cli
Update _get_default_spark_image to accept Python 3.12 in addition to
3.9. Auto-detect Spark version from installed pyspark instead of
hardcoding 3.3, falling back to the default if pyspark is not
installed. Also resolve correct Python binary in Spark bootstrap
script to avoid PATH conflicts with system python3.
---
X-AI-Prompt: fix job.py to select correct spark image for py312 and detect pyspark version
X-AI-Tool: kiro-cli
…on 3.12
Update expected error message in remote function tests to reflect that
SageMaker Spark images now support Python versions 3.9 and 3.12.
…or deps
Pin pyspark==3.5.1 in both feature-processor and test optional
dependencies to ensure consistent Spark version across environments.
…ersions
SageMaker Spark image only supports Python 3.9 and 3.12. Add skipif
markers to three feature processor integ tests that fail on Python 3.10.
Inject sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in _get_remote_decorator_config_from_input so it gets installed on the
remote container automatically.
Update integ tests: add skipif for Python 3.10 Spark tests, remove
manual feature-store-pyspark install, use python3 instead of python3.12.
… feature-store-pyspark
- Update test error messages to reflect Python 3.9 and 3.12 support
- Add pyspark 3.5.1 to test and feature-processor optional deps
- Skip Spark integ tests on unsupported Python versions (3.10)
- Auto-install sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in to_pipeline and copy version-matched JAR to Spark classpath
- Use standard SageMaker Spark image resolution via SparkConfig
- Use python3 instead of python3.12 in integ test pre_execution_commands
… remote jobs
When spark_config is set on a remote job, _JobSettings now automatically
injects pip install of sagemaker-feature-store-pyspark and copies the
Spark 3.5-matched JAR to /usr/lib/spark/jars/ via pre_execution_commands.
This makes the package work transparently when the SageMaker Spark image
does not pre-install sagemaker-feature-store-pyspark.
- Make feature_store_pyspark imports lazy in _spark_factory.py to avoid
deserialization failures when the module is not yet installed
- Add sagemaker-feature-store-pyspark to integ test requirements.txt
- Remove duplicate injection from feature_scheduler.py (to_pipeline path)
since _JobSettings now handles all Spark remote jobs
…e_execution_commands
_JobSettings now auto-injects feature-store-pyspark install and JAR copy
commands when spark_config is set, so update the test assertion to
expect these commands in the _prepare_and_upload_workspace call.
… tests
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration_on_training_job
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_with_iceberg_config
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_same_instance
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_configs_use_dynamic_hadoop_version
- Replace direct calls to feature_store_pyspark.classpath_jars() with mock_classpath_jars.return_value
- Update test_repack_model.py to use resolved path variable for consistency in _get_safe_members test
Add IcebergProperties to the feature_store __init__.py imports and
__all__ list so users can import it directly from the package instead
of reaching into the internal feature_group_manager module.
---
X-AI-Prompt: review staged change and commit if good
X-AI-Tool: kiro-cli
"pip install --root-user-action=ignore"
" 'sagemaker-feature-store-pyspark>=2,<3'"
)
copy_jar_cmd = (

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pyspark is not installed where this command runs so we read the $SPARK_HOME/usr/lib/spark/RELEASE file which has the currently installed spark version

@@ -92,7 +92,7 @@ def test_is_bad_link_unsafe():

def test_get_safe_members_all_safe():

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to this PR but It was failing in CI so I fixed it


import attr
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization as crypto_serialization

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intro of a library needed? If so, I see that sagemaker-mlops/pyproject.toml is not changed to add cryptography as a dependency.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are needed yes.
Cryptography is a dependency of sagemaker-core "cryptography>=46.0.0",
which sagemaker-mlops depends on but I think I will still add it to mlops in case it is removed from core in the future

BassemHalimand others added 2 commits May 12, 2026 11:42
… explicit cryptography dep
Add comment explaining REMOTE_FUNCTION_SECRET_KEY is a legacy misnomer —
the value is an ECDSA public key for signature verification, not a secret.
Add cryptography>=46.0.0 as explicit dependency in sagemaker-mlops.
---
X-AI-Prompt: resolve CR comment about misleading REMOTE_FUNCTION_SECRET_KEY naming and missing cryptography dependency
X-AI-Tool: kiro
@mollyheamazon
mollyheamazon merged commit 58ac9dc into aws:masterMay 13, 2026
38 of 53 checks passed
lucasjia-aws added a commit that referenced this pull request Jul 23, 2026
…sts (#6095)
The feature processor to_pipeline integ tests hardcoded fixed pipeline
names (pipeline-name-01, pipeline-name-lf-01) and thus shared fixed S3
paths (s3://.../<pipeline_name>/function/payload.pkl). Combined with the
asymmetric-signing scheme introduced in PR #5816 (each to_pipeline call
generates a fresh ECDSA key pair, overwrites the signed payload, and
pins the matching public key into the pipeline env), concurrent CI
builds on the same account overwrite each other's payloads. A running
execution then verifies a payload signed by a different build's key,
producing DeserializationError: "Integrity check for the serialized
function or data failed" and pipeline execution status Failed.
Generate unique pipeline names via unique_name_from_base so each test
run and build uses an isolated S3 prefix, and restore cleanup_pipeline
in the finally blocks to avoid resource leakage.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@BassemHalim@mollyheamazon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support - #5816

Merged
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf
May 13, 2026
Merged

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support#5816
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf

Conversation

@BassemHalim

@BassemHalimBassemHalim commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

This PR upgrades the Feature Processor module to support PySpark 3.5 and Python 3.12, adds Lake Formation credential vending for data ingestion, and improves Spark version handling across the board.

Description of changes:

  • Spark version upgrade: Bumps PySpark from 3.3.2 to 3.5.1 and sagemaker-feature-store-pyspark from 3.3 to 2.0.0 in
    pyproject.toml.
  • Python 3.12 support: Extends the allowed Python versions for Spark remote jobs from [3.9] to [3.9, 3.12] in
    sagemaker-core/job.py.
  • Auto-detect PySpark version: _get_default_spark_image now detects the installed PySpark version at runtime instead of using a
    hardcoded default.
  • Auto-inject Feature Store PySpark dependency: When spark_config is set, _JobSettings.init automatically appends pip
    install sagemaker-feature-store-pyspark and a JAR copy command to pre_execution_commands.
  • New _image_resolver.py module: Introduces _get_spark_image_uri() with a SPARK_IMAGE_SUPPORT_MATRIX that maps Spark versions
    to supported Python versions, replacing the hardcoded logic in feature_scheduler.py.
  • Dynamic Hadoop version resolution: New SPARK_TO_HADOOP_MAP and _get_hadoop_version() in _spark_factory.py resolve the correct
    Hadoop Maven coordinates based on the installed PySpark version.
  • Lazy imports for feature_store_pyspark: Moves feature_store_pyspark imports from module-level to inside methods, preventing
    import errors when the package isn't installed.
  • Feature Store JARs always on classpath: spark.jars config now includes version-matched Feature Store JARs for both training
    and non-training jobs. A new _install_feature_store_jars() method copies JARs to /usr/lib/spark/jars/.
  • Lake Formation credential vending: Adds use_lake_formation_credentials parameter to @feature_processor decorator, threaded
    through FeatureProcessorConfig -> _udf_output_receiver.ingest_udf_output() -> FeatureStoreManager.ingest_data.
  • ECDSA signing key generation: _config_uploader._prepare_and_upload_callable() now generates an ECDSA key pair, passes the
    private key to StoredFunction, and returns the public key PEM. The public key is set as REMOTE_FUNCTION_SECRET_KEY environment
    variable on the ModelTrainer.
  • Conditional image_uri in scheduler: _get_remote_decorator_config_from_input now only sets image_uri if one isn't already
    provided, allowing user-specified images.
  • Updated pre_execution_commands: Integration test helper uses python3 -m pip and python3 -m awscli patterns, installs awscli
    explicitly, and installs mlops_whl instead of sagemaker_whl with [feature-processor] extras.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Add configurable use_lake_formation_credentials parameter to the
@feature_processor decorator, defaulting to False. The value flows
through FeatureProcessorConfig to the Spark connector's ingest_data()
call, enabling Lake Formation credential vending when set to True.
---
X-AI-Prompt: make useLakeFormationCreds configurable, defaults to False, passed to feature_processor
X-AI-Tool: kiro-cli
Generate ECDSA signing key in ConfigUploader and pass it to
StoredFunction for function payload signature verification. The
public key PEM is returned to callers for remote-side verification.
---
X-AI-Prompt: fix StoredFunction missing signing_key error in feature_processor pipeline
X-AI-Tool: kiro-cli
Add _image_resolver module that resolves the SageMaker Spark
processing container image URI based on installed PySpark and Python
versions. Supports Spark 3.1/3.2/3.3/3.5 with appropriate Python
version mapping. Uses container_version=v1 as a floating tag.
---
X-AI-Prompt: add image resolver with container_version v1 for spark processing image
X-AI-Tool: kiro-cli
…cheduler
Update feature_scheduler to use _get_spark_image_uri for dynamic
image resolution instead of _JobSettings._get_default_spark_image.
Thread public_key_pem from ConfigUploader through to ModelTrainer
environment as REMOTE_FUNCTION_SECRET_KEY. Allow user-provided
image_uri to take precedence over auto-resolved URI.
---
X-AI-Prompt: integrate image resolver and signing key into feature scheduler pipeline
X-AI-Tool: kiro-cli
…Store JARs
Resolve Hadoop version dynamically based on installed PySpark version
instead of hardcoding 3.3.1. Move Feature Store JAR classpath setup
outside the non-training-job guard so spark.jars is always set,
fixing FeatureStoreManager class loading in training job mode.
---
X-AI-Prompt: fix spark factory hadoop version and jar classpath for spark 3.5
X-AI-Tool: kiro-cli
Update _get_default_spark_image to accept Python 3.12 in addition to
3.9. Auto-detect Spark version from installed pyspark instead of
hardcoding 3.3, falling back to the default if pyspark is not
installed. Also resolve correct Python binary in Spark bootstrap
script to avoid PATH conflicts with system python3.
---
X-AI-Prompt: fix job.py to select correct spark image for py312 and detect pyspark version
X-AI-Tool: kiro-cli
…on 3.12
Update expected error message in remote function tests to reflect that
SageMaker Spark images now support Python versions 3.9 and 3.12.
…or deps
Pin pyspark==3.5.1 in both feature-processor and test optional
dependencies to ensure consistent Spark version across environments.
…ersions
SageMaker Spark image only supports Python 3.9 and 3.12. Add skipif
markers to three feature processor integ tests that fail on Python 3.10.
Inject sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in _get_remote_decorator_config_from_input so it gets installed on the
remote container automatically.
Update integ tests: add skipif for Python 3.10 Spark tests, remove
manual feature-store-pyspark install, use python3 instead of python3.12.
… feature-store-pyspark
- Update test error messages to reflect Python 3.9 and 3.12 support
- Add pyspark 3.5.1 to test and feature-processor optional deps
- Skip Spark integ tests on unsupported Python versions (3.10)
- Auto-install sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in to_pipeline and copy version-matched JAR to Spark classpath
- Use standard SageMaker Spark image resolution via SparkConfig
- Use python3 instead of python3.12 in integ test pre_execution_commands
… remote jobs
When spark_config is set on a remote job, _JobSettings now automatically
injects pip install of sagemaker-feature-store-pyspark and copies the
Spark 3.5-matched JAR to /usr/lib/spark/jars/ via pre_execution_commands.
This makes the package work transparently when the SageMaker Spark image
does not pre-install sagemaker-feature-store-pyspark.
- Make feature_store_pyspark imports lazy in _spark_factory.py to avoid
deserialization failures when the module is not yet installed
- Add sagemaker-feature-store-pyspark to integ test requirements.txt
- Remove duplicate injection from feature_scheduler.py (to_pipeline path)
since _JobSettings now handles all Spark remote jobs
…e_execution_commands
_JobSettings now auto-injects feature-store-pyspark install and JAR copy
commands when spark_config is set, so update the test assertion to
expect these commands in the _prepare_and_upload_workspace call.
… tests
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration_on_training_job
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_with_iceberg_config
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_same_instance
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_configs_use_dynamic_hadoop_version
- Replace direct calls to feature_store_pyspark.classpath_jars() with mock_classpath_jars.return_value
- Update test_repack_model.py to use resolved path variable for consistency in _get_safe_members test
Add IcebergProperties to the feature_store __init__.py imports and
__all__ list so users can import it directly from the package instead
of reaching into the internal feature_group_manager module.
---
X-AI-Prompt: review staged change and commit if good
X-AI-Tool: kiro-cli
"pip install --root-user-action=ignore"
" 'sagemaker-feature-store-pyspark>=2,<3'"
)
copy_jar_cmd = (

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pyspark is not installed where this command runs so we read the $SPARK_HOME/usr/lib/spark/RELEASE file which has the currently installed spark version

@@ -92,7 +92,7 @@ def test_is_bad_link_unsafe():

def test_get_safe_members_all_safe():

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to this PR but It was failing in CI so I fixed it


import attr
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization as crypto_serialization

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intro of a library needed? If so, I see that sagemaker-mlops/pyproject.toml is not changed to add cryptography as a dependency.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are needed yes.
Cryptography is a dependency of sagemaker-core "cryptography>=46.0.0",
which sagemaker-mlops depends on but I think I will still add it to mlops in case it is removed from core in the future

BassemHalimand others added 2 commits May 12, 2026 11:42
… explicit cryptography dep
Add comment explaining REMOTE_FUNCTION_SECRET_KEY is a legacy misnomer —
the value is an ECDSA public key for signature verification, not a secret.
Add cryptography>=46.0.0 as explicit dependency in sagemaker-mlops.
---
X-AI-Prompt: resolve CR comment about misleading REMOTE_FUNCTION_SECRET_KEY naming and missing cryptography dependency
X-AI-Tool: kiro
@mollyheamazon
mollyheamazon merged commit 58ac9dc into aws:masterMay 13, 2026
38 of 53 checks passed
lucasjia-aws added a commit that referenced this pull request Jul 23, 2026
…sts (#6095)
The feature processor to_pipeline integ tests hardcoded fixed pipeline
names (pipeline-name-01, pipeline-name-lf-01) and thus shared fixed S3
paths (s3://.../<pipeline_name>/function/payload.pkl). Combined with the
asymmetric-signing scheme introduced in PR #5816 (each to_pipeline call
generates a fresh ECDSA key pair, overwrites the signed payload, and
pins the matching public key into the pipeline env), concurrent CI
builds on the same account overwrite each other's payloads. A running
execution then verifies a payload signed by a different build's key,
producing DeserializationError: "Integrity check for the serialized
function or data failed" and pipeline execution status Failed.
Generate unique pipeline names via unique_name_from_base so each test
run and build uses an isolated S3 prefix, and restore cleanup_pipeline
in the finally blocks to avoid resource leakage.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@BassemHalim@mollyheamazon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support - #5816

Merged
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf
May 13, 2026
Merged

feat(feature-processor): Add Lake Formation credential vending and Spark 3.5/Python 3.12 support#5816
mollyheamazon merged 34 commits into
aws:masterfrom
BassemHalim:feat/feature-store-fp-lf

Conversation

@BassemHalim

@BassemHalimBassemHalim commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

This PR upgrades the Feature Processor module to support PySpark 3.5 and Python 3.12, adds Lake Formation credential vending for data ingestion, and improves Spark version handling across the board.

Description of changes:

  • Spark version upgrade: Bumps PySpark from 3.3.2 to 3.5.1 and sagemaker-feature-store-pyspark from 3.3 to 2.0.0 in
    pyproject.toml.
  • Python 3.12 support: Extends the allowed Python versions for Spark remote jobs from [3.9] to [3.9, 3.12] in
    sagemaker-core/job.py.
  • Auto-detect PySpark version: _get_default_spark_image now detects the installed PySpark version at runtime instead of using a
    hardcoded default.
  • Auto-inject Feature Store PySpark dependency: When spark_config is set, _JobSettings.init automatically appends pip
    install sagemaker-feature-store-pyspark and a JAR copy command to pre_execution_commands.
  • New _image_resolver.py module: Introduces _get_spark_image_uri() with a SPARK_IMAGE_SUPPORT_MATRIX that maps Spark versions
    to supported Python versions, replacing the hardcoded logic in feature_scheduler.py.
  • Dynamic Hadoop version resolution: New SPARK_TO_HADOOP_MAP and _get_hadoop_version() in _spark_factory.py resolve the correct
    Hadoop Maven coordinates based on the installed PySpark version.
  • Lazy imports for feature_store_pyspark: Moves feature_store_pyspark imports from module-level to inside methods, preventing
    import errors when the package isn't installed.
  • Feature Store JARs always on classpath: spark.jars config now includes version-matched Feature Store JARs for both training
    and non-training jobs. A new _install_feature_store_jars() method copies JARs to /usr/lib/spark/jars/.
  • Lake Formation credential vending: Adds use_lake_formation_credentials parameter to @feature_processor decorator, threaded
    through FeatureProcessorConfig -> _udf_output_receiver.ingest_udf_output() -> FeatureStoreManager.ingest_data.
  • ECDSA signing key generation: _config_uploader._prepare_and_upload_callable() now generates an ECDSA key pair, passes the
    private key to StoredFunction, and returns the public key PEM. The public key is set as REMOTE_FUNCTION_SECRET_KEY environment
    variable on the ModelTrainer.
  • Conditional image_uri in scheduler: _get_remote_decorator_config_from_input now only sets image_uri if one isn't already
    provided, allowing user-specified images.
  • Updated pre_execution_commands: Integration test helper uses python3 -m pip and python3 -m awscli patterns, installs awscli
    explicitly, and installs mlops_whl instead of sagemaker_whl with [feature-processor] extras.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Add configurable use_lake_formation_credentials parameter to the
@feature_processor decorator, defaulting to False. The value flows
through FeatureProcessorConfig to the Spark connector's ingest_data()
call, enabling Lake Formation credential vending when set to True.
---
X-AI-Prompt: make useLakeFormationCreds configurable, defaults to False, passed to feature_processor
X-AI-Tool: kiro-cli
Generate ECDSA signing key in ConfigUploader and pass it to
StoredFunction for function payload signature verification. The
public key PEM is returned to callers for remote-side verification.
---
X-AI-Prompt: fix StoredFunction missing signing_key error in feature_processor pipeline
X-AI-Tool: kiro-cli
Add _image_resolver module that resolves the SageMaker Spark
processing container image URI based on installed PySpark and Python
versions. Supports Spark 3.1/3.2/3.3/3.5 with appropriate Python
version mapping. Uses container_version=v1 as a floating tag.
---
X-AI-Prompt: add image resolver with container_version v1 for spark processing image
X-AI-Tool: kiro-cli
…cheduler
Update feature_scheduler to use _get_spark_image_uri for dynamic
image resolution instead of _JobSettings._get_default_spark_image.
Thread public_key_pem from ConfigUploader through to ModelTrainer
environment as REMOTE_FUNCTION_SECRET_KEY. Allow user-provided
image_uri to take precedence over auto-resolved URI.
---
X-AI-Prompt: integrate image resolver and signing key into feature scheduler pipeline
X-AI-Tool: kiro-cli
…Store JARs
Resolve Hadoop version dynamically based on installed PySpark version
instead of hardcoding 3.3.1. Move Feature Store JAR classpath setup
outside the non-training-job guard so spark.jars is always set,
fixing FeatureStoreManager class loading in training job mode.
---
X-AI-Prompt: fix spark factory hadoop version and jar classpath for spark 3.5
X-AI-Tool: kiro-cli
Update _get_default_spark_image to accept Python 3.12 in addition to
3.9. Auto-detect Spark version from installed pyspark instead of
hardcoding 3.3, falling back to the default if pyspark is not
installed. Also resolve correct Python binary in Spark bootstrap
script to avoid PATH conflicts with system python3.
---
X-AI-Prompt: fix job.py to select correct spark image for py312 and detect pyspark version
X-AI-Tool: kiro-cli
…on 3.12
Update expected error message in remote function tests to reflect that
SageMaker Spark images now support Python versions 3.9 and 3.12.
…or deps
Pin pyspark==3.5.1 in both feature-processor and test optional
dependencies to ensure consistent Spark version across environments.
…ersions
SageMaker Spark image only supports Python 3.9 and 3.12. Add skipif
markers to three feature processor integ tests that fail on Python 3.10.
Inject sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in _get_remote_decorator_config_from_input so it gets installed on the
remote container automatically.
Update integ tests: add skipif for Python 3.10 Spark tests, remove
manual feature-store-pyspark install, use python3 instead of python3.12.
… feature-store-pyspark
- Update test error messages to reflect Python 3.9 and 3.12 support
- Add pyspark 3.5.1 to test and feature-processor optional deps
- Skip Spark integ tests on unsupported Python versions (3.10)
- Auto-install sagemaker-feature-store-pyspark>=2,<3 via pre_execution_commands
in to_pipeline and copy version-matched JAR to Spark classpath
- Use standard SageMaker Spark image resolution via SparkConfig
- Use python3 instead of python3.12 in integ test pre_execution_commands
… remote jobs
When spark_config is set on a remote job, _JobSettings now automatically
injects pip install of sagemaker-feature-store-pyspark and copies the
Spark 3.5-matched JAR to /usr/lib/spark/jars/ via pre_execution_commands.
This makes the package work transparently when the SageMaker Spark image
does not pre-install sagemaker-feature-store-pyspark.
- Make feature_store_pyspark imports lazy in _spark_factory.py to avoid
deserialization failures when the module is not yet installed
- Add sagemaker-feature-store-pyspark to integ test requirements.txt
- Remove duplicate injection from feature_scheduler.py (to_pipeline path)
since _JobSettings now handles all Spark remote jobs
…e_execution_commands
_JobSettings now auto-injects feature-store-pyspark install and JAR copy
commands when spark_config is set, so update the test assertion to
expect these commands in the _prepare_and_upload_workspace call.
… tests
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_configuration_on_training_job
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_with_iceberg_config
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_session_factory_same_instance
- Add @patch decorator to mock feature_store_pyspark.classpath_jars in test_spark_configs_use_dynamic_hadoop_version
- Replace direct calls to feature_store_pyspark.classpath_jars() with mock_classpath_jars.return_value
- Update test_repack_model.py to use resolved path variable for consistency in _get_safe_members test
Add IcebergProperties to the feature_store __init__.py imports and
__all__ list so users can import it directly from the package instead
of reaching into the internal feature_group_manager module.
---
X-AI-Prompt: review staged change and commit if good
X-AI-Tool: kiro-cli
"pip install --root-user-action=ignore"
" 'sagemaker-feature-store-pyspark>=2,<3'"
)
copy_jar_cmd = (

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pyspark is not installed where this command runs so we read the $SPARK_HOME/usr/lib/spark/RELEASE file which has the currently installed spark version

@@ -92,7 +92,7 @@ def test_is_bad_link_unsafe():

def test_get_safe_members_all_safe():

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to this PR but It was failing in CI so I fixed it


import attr
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization as crypto_serialization

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intro of a library needed? If so, I see that sagemaker-mlops/pyproject.toml is not changed to add cryptography as a dependency.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are needed yes.
Cryptography is a dependency of sagemaker-core "cryptography>=46.0.0",
which sagemaker-mlops depends on but I think I will still add it to mlops in case it is removed from core in the future

BassemHalimand others added 2 commits May 12, 2026 11:42
… explicit cryptography dep
Add comment explaining REMOTE_FUNCTION_SECRET_KEY is a legacy misnomer —
the value is an ECDSA public key for signature verification, not a secret.
Add cryptography>=46.0.0 as explicit dependency in sagemaker-mlops.
---
X-AI-Prompt: resolve CR comment about misleading REMOTE_FUNCTION_SECRET_KEY naming and missing cryptography dependency
X-AI-Tool: kiro
@mollyheamazon
mollyheamazon merged commit 58ac9dc into aws:masterMay 13, 2026
38 of 53 checks passed
lucasjia-aws added a commit that referenced this pull request Jul 23, 2026
…sts (#6095)
The feature processor to_pipeline integ tests hardcoded fixed pipeline
names (pipeline-name-01, pipeline-name-lf-01) and thus shared fixed S3
paths (s3://.../<pipeline_name>/function/payload.pkl). Combined with the
asymmetric-signing scheme introduced in PR #5816 (each to_pipeline call
generates a fresh ECDSA key pair, overwrites the signed payload, and
pins the matching public key into the pipeline env), concurrent CI
builds on the same account overwrite each other's payloads. A running
execution then verifies a payload signed by a different build's key,
producing DeserializationError: "Integrity check for the serialized
function or data failed" and pipeline execution status Failed.
Generate unique pipeline names via unique_name_from_base so each test
run and build uses an isolated S3 prefix, and restore cleanup_pipeline
in the finally blocks to avoid resource leakage.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@BassemHalim@mollyheamazon