Skip to content

migrate AutoML forecasting model loading to skops - #5250

Open
HarshaVardhanBabu (babu-namburi) wants to merge 12 commits into
mainfrom
fix/cwe-502-skops-model-loading
Open

migrate AutoML forecasting model loading to skops#5250
HarshaVardhanBabu (babu-namburi) wants to merge 12 commits into
mainfrom
fix/cwe-502-skops-model-loading

Conversation

@babu-namburi

@babu-namburi HarshaVardhanBabu (babu-namburi) commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Status

Ready for team review.

The producer-side integration is available in AzureMlCli PR 2234915. It directly serializes fitted forecasting models to outputs/mlflow-model/model.skops while retaining existing pickle/PyTorch artifacts for older consumers.

Summary

  • replace pickle-based forecasting model loading with fail-closed .skops loading
  • reject malformed archives, disguised pickle payloads, symlinked artifacts, unsupported extensions, and ambiguous multiple-model inputs
  • allow one safe .skops artifact to coexist with legacy artifacts for cross-version compatibility
  • install and validate skops==0.14.0 against the existing NumPy 1.23.5 AutoML stack
  • enable feature-gated safe forecasting export in the AutoML GPU environment
  • retain the latest environment vulnerability-remediation updates from main

Backward compatibility

  • existing AutoML runtime behavior is unchanged unless AUTOML_ENABLE_SAFE_FORECASTING_MODEL_EXPORT=true
  • opted-in training environments publish both .skops and unchanged legacy artifacts
  • older component versions continue consuming legacy artifacts
  • this hardened component consumes .skops and intentionally rejects legacy-only pickle/PyTorch models

Existing models must be retrained or re-exported before using this component version.

Security improvements

  • pickle files are not discovered or deserialized
  • renamed pickle payloads are rejected without executing payload code
  • artifact-provided trusted-type lists are never accepted
  • unsupported PyTorch/TCN full-object deserialization is rejected
  • malformed paths, symlinks, unsafe-only artifacts, and multiple .skops artifacts fail closed

Dependency resolution

The current AutoML runtime requires NumPy <=1.23.5, while skops 0.14 declares NumPy >=1.25. The environment installs skops==0.14.0 with --no-deps and runs a build-time compatibility test without changing the supported AutoML NumPy stack. This override remains outside skops' declared support matrix and should be removed when AzureML supports NumPy 1.25 or later.

Validation

  • 10 focused model-loader tests
  • realistic sklearn regression pipeline round-trip
  • malicious disguised-pickle rejection
  • invalid archive, path, symlink, ambiguous artifact, and unsupported extension coverage
  • build-time skops/NumPy compatibility test
  • repository documentation-style and diff checks
  • conflict resolution against current main

Remaining merge requirements

  • derive and security-review the exact trusted-type allowlist required by a genuine ForecastingPipelineWrapper
  • validate producer-to-consumer round-trip and forecast equivalence in the internal AutoML environment
  • keep TCN unsupported until a fixed architecture can be reconstructed from a weights-only state dictionary

Broad azureml.* trust and artifact-supplied trust lists are explicitly out of scope because they would weaken the deserialization boundary.

Add a validated skops 0.14 compatibility override for the AutoML NumPy stack and replace pickle loading with trusted skops and weights-only PyTorch loading.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fail closed on unsafe or ambiguous artifacts, retain legacy coexistence for older consumers, and validate the pinned skops environment path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Resolve the automl-gpu Dockerfile conflict by retaining the latest image vulnerability updates and the safe skops compatibility installation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@babu-namburi HarshaVardhanBabu (babu-namburi) changed the title draft: migrate AutoML forecasting model loading to skops migrate AutoML forecasting model loading to skops Aug 10, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 485f9b8c-40a7-4b88-8c20-e79042f96e16
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 485f9b8c-40a7-4b88-8c20-e79042f96e16
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 485f9b8c-40a7-4b88-8c20-e79042f96e16
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6ea2cc5d-cff6-46d5-80cb-7da059c76a2b

Copilot AI left a comment

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.

Pull request overview

Hardens AutoML forecasting inference by replacing pickle/PyTorch deserialization with fail-closed skops loading and updating the supporting GPU environment.

Changes:

  • Adds secure .skops discovery and loading.
  • Installs and validates skops against the existing NumPy stack.
  • Updates component metadata and loader tests.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
environments/automl-gpu/environment.yaml Includes the compatibility test in the build context.
environments/automl-gpu/context/skops_compatibility_test.py Smoke-tests skops serialization compatibility.
environments/automl-gpu/context/Dockerfile Installs skops and enables safe forecasting export.
environments/automl-gpu/context/conda_dependencies.yaml Adds the PrettyTable dependency.
automl-single-model-inference/tests/test_model_loader.py Tests safe model discovery and loading.
automl-single-model-inference/src/model_loader.py Implements fail-closed skops loading.
automl-single-model-inference/src/inference.py Delegates model handling to the secure loader.
automl-single-model-inference/components/inference/spec.yaml Versions and documents the hardened component.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +63 to +64
untrusted_types = skops_io.get_untrusted_types(file=model_full_path)
if untrusted_types:
Comment on lines +125 to +131
def test_find_model_rejects_non_directory_path(tmp_path):
"""Reject a file passed where a model directory is required."""
model_path = tmp_path / "model.skops"
model_path.write_bytes(b"skops")

with pytest.raises(ValueError, match="regular directory"):
model_loader.find_model(str(model_path))
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6ea2cc5d-cff6-46d5-80cb-7da059c76a2b
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

This pull request has been marked as stale because it has been inactive for 14 days.

@github-actions github-actions Bot added the Stale label Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants