genesis-flow 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- genesis_flow-1.0.0.dist-info/METADATA +822 -0
- genesis_flow-1.0.0.dist-info/RECORD +645 -0
- genesis_flow-1.0.0.dist-info/WHEEL +5 -0
- genesis_flow-1.0.0.dist-info/entry_points.txt +19 -0
- genesis_flow-1.0.0.dist-info/licenses/LICENSE.txt +202 -0
- genesis_flow-1.0.0.dist-info/top_level.txt +1 -0
- mlflow/__init__.py +367 -0
- mlflow/__main__.py +3 -0
- mlflow/ag2/__init__.py +56 -0
- mlflow/ag2/ag2_logger.py +294 -0
- mlflow/anthropic/__init__.py +40 -0
- mlflow/anthropic/autolog.py +129 -0
- mlflow/anthropic/chat.py +144 -0
- mlflow/artifacts/__init__.py +268 -0
- mlflow/autogen/__init__.py +144 -0
- mlflow/autogen/chat.py +142 -0
- mlflow/azure/__init__.py +26 -0
- mlflow/azure/auth_handler.py +257 -0
- mlflow/azure/client.py +319 -0
- mlflow/azure/config.py +120 -0
- mlflow/azure/connection_factory.py +340 -0
- mlflow/azure/exceptions.py +27 -0
- mlflow/azure/stores.py +327 -0
- mlflow/azure/utils.py +183 -0
- mlflow/bedrock/__init__.py +45 -0
- mlflow/bedrock/_autolog.py +202 -0
- mlflow/bedrock/chat.py +122 -0
- mlflow/bedrock/stream.py +160 -0
- mlflow/bedrock/utils.py +43 -0
- mlflow/cli.py +707 -0
- mlflow/client.py +12 -0
- mlflow/config/__init__.py +56 -0
- mlflow/crewai/__init__.py +79 -0
- mlflow/crewai/autolog.py +253 -0
- mlflow/crewai/chat.py +29 -0
- mlflow/data/__init__.py +75 -0
- mlflow/data/artifact_dataset_sources.py +170 -0
- mlflow/data/code_dataset_source.py +40 -0
- mlflow/data/dataset.py +123 -0
- mlflow/data/dataset_registry.py +168 -0
- mlflow/data/dataset_source.py +110 -0
- mlflow/data/dataset_source_registry.py +219 -0
- mlflow/data/delta_dataset_source.py +167 -0
- mlflow/data/digest_utils.py +108 -0
- mlflow/data/evaluation_dataset.py +562 -0
- mlflow/data/filesystem_dataset_source.py +81 -0
- mlflow/data/http_dataset_source.py +145 -0
- mlflow/data/huggingface_dataset.py +258 -0
- mlflow/data/huggingface_dataset_source.py +118 -0
- mlflow/data/meta_dataset.py +104 -0
- mlflow/data/numpy_dataset.py +223 -0
- mlflow/data/pandas_dataset.py +231 -0
- mlflow/data/polars_dataset.py +352 -0
- mlflow/data/pyfunc_dataset_mixin.py +31 -0
- mlflow/data/schema.py +76 -0
- mlflow/data/sources.py +1 -0
- mlflow/data/spark_dataset.py +406 -0
- mlflow/data/spark_dataset_source.py +74 -0
- mlflow/data/spark_delta_utils.py +118 -0
- mlflow/data/tensorflow_dataset.py +350 -0
- mlflow/data/uc_volume_dataset_source.py +81 -0
- mlflow/db.py +27 -0
- mlflow/dspy/__init__.py +17 -0
- mlflow/dspy/autolog.py +197 -0
- mlflow/dspy/callback.py +398 -0
- mlflow/dspy/constant.py +1 -0
- mlflow/dspy/load.py +93 -0
- mlflow/dspy/save.py +393 -0
- mlflow/dspy/util.py +109 -0
- mlflow/dspy/wrapper.py +226 -0
- mlflow/entities/__init__.py +104 -0
- mlflow/entities/_mlflow_object.py +52 -0
- mlflow/entities/assessment.py +545 -0
- mlflow/entities/assessment_error.py +80 -0
- mlflow/entities/assessment_source.py +141 -0
- mlflow/entities/dataset.py +92 -0
- mlflow/entities/dataset_input.py +51 -0
- mlflow/entities/dataset_summary.py +62 -0
- mlflow/entities/document.py +48 -0
- mlflow/entities/experiment.py +109 -0
- mlflow/entities/experiment_tag.py +35 -0
- mlflow/entities/file_info.py +45 -0
- mlflow/entities/input_tag.py +35 -0
- mlflow/entities/lifecycle_stage.py +35 -0
- mlflow/entities/logged_model.py +228 -0
- mlflow/entities/logged_model_input.py +26 -0
- mlflow/entities/logged_model_output.py +32 -0
- mlflow/entities/logged_model_parameter.py +46 -0
- mlflow/entities/logged_model_status.py +74 -0
- mlflow/entities/logged_model_tag.py +33 -0
- mlflow/entities/metric.py +200 -0
- mlflow/entities/model_registry/__init__.py +29 -0
- mlflow/entities/model_registry/_model_registry_entity.py +13 -0
- mlflow/entities/model_registry/model_version.py +243 -0
- mlflow/entities/model_registry/model_version_deployment_job_run_state.py +44 -0
- mlflow/entities/model_registry/model_version_deployment_job_state.py +70 -0
- mlflow/entities/model_registry/model_version_search.py +25 -0
- mlflow/entities/model_registry/model_version_stages.py +25 -0
- mlflow/entities/model_registry/model_version_status.py +35 -0
- mlflow/entities/model_registry/model_version_tag.py +35 -0
- mlflow/entities/model_registry/prompt.py +73 -0
- mlflow/entities/model_registry/prompt_version.py +244 -0
- mlflow/entities/model_registry/registered_model.py +175 -0
- mlflow/entities/model_registry/registered_model_alias.py +35 -0
- mlflow/entities/model_registry/registered_model_deployment_job_state.py +39 -0
- mlflow/entities/model_registry/registered_model_search.py +25 -0
- mlflow/entities/model_registry/registered_model_tag.py +35 -0
- mlflow/entities/multipart_upload.py +74 -0
- mlflow/entities/param.py +49 -0
- mlflow/entities/run.py +97 -0
- mlflow/entities/run_data.py +84 -0
- mlflow/entities/run_info.py +188 -0
- mlflow/entities/run_inputs.py +59 -0
- mlflow/entities/run_outputs.py +43 -0
- mlflow/entities/run_status.py +41 -0
- mlflow/entities/run_tag.py +36 -0
- mlflow/entities/source_type.py +31 -0
- mlflow/entities/span.py +774 -0
- mlflow/entities/span_event.py +96 -0
- mlflow/entities/span_status.py +102 -0
- mlflow/entities/trace.py +317 -0
- mlflow/entities/trace_data.py +71 -0
- mlflow/entities/trace_info.py +220 -0
- mlflow/entities/trace_info_v2.py +162 -0
- mlflow/entities/trace_location.py +173 -0
- mlflow/entities/trace_state.py +39 -0
- mlflow/entities/trace_status.py +68 -0
- mlflow/entities/view_type.py +51 -0
- mlflow/environment_variables.py +866 -0
- mlflow/evaluation/__init__.py +16 -0
- mlflow/evaluation/assessment.py +369 -0
- mlflow/evaluation/evaluation.py +411 -0
- mlflow/evaluation/evaluation_tag.py +61 -0
- mlflow/evaluation/fluent.py +48 -0
- mlflow/evaluation/utils.py +201 -0
- mlflow/exceptions.py +213 -0
- mlflow/experiments.py +140 -0
- mlflow/gemini/__init__.py +81 -0
- mlflow/gemini/autolog.py +186 -0
- mlflow/gemini/chat.py +261 -0
- mlflow/genai/__init__.py +71 -0
- mlflow/genai/datasets/__init__.py +67 -0
- mlflow/genai/datasets/evaluation_dataset.py +131 -0
- mlflow/genai/evaluation/__init__.py +3 -0
- mlflow/genai/evaluation/base.py +411 -0
- mlflow/genai/evaluation/constant.py +23 -0
- mlflow/genai/evaluation/utils.py +244 -0
- mlflow/genai/judges/__init__.py +21 -0
- mlflow/genai/judges/databricks.py +404 -0
- mlflow/genai/label_schemas/__init__.py +153 -0
- mlflow/genai/label_schemas/label_schemas.py +209 -0
- mlflow/genai/labeling/__init__.py +159 -0
- mlflow/genai/labeling/labeling.py +250 -0
- mlflow/genai/optimize/__init__.py +13 -0
- mlflow/genai/optimize/base.py +198 -0
- mlflow/genai/optimize/optimizers/__init__.py +4 -0
- mlflow/genai/optimize/optimizers/base_optimizer.py +38 -0
- mlflow/genai/optimize/optimizers/dspy_mipro_optimizer.py +221 -0
- mlflow/genai/optimize/optimizers/dspy_optimizer.py +91 -0
- mlflow/genai/optimize/optimizers/utils/dspy_mipro_callback.py +76 -0
- mlflow/genai/optimize/optimizers/utils/dspy_mipro_utils.py +18 -0
- mlflow/genai/optimize/types.py +75 -0
- mlflow/genai/optimize/util.py +30 -0
- mlflow/genai/prompts/__init__.py +206 -0
- mlflow/genai/scheduled_scorers.py +431 -0
- mlflow/genai/scorers/__init__.py +26 -0
- mlflow/genai/scorers/base.py +492 -0
- mlflow/genai/scorers/builtin_scorers.py +765 -0
- mlflow/genai/scorers/scorer_utils.py +138 -0
- mlflow/genai/scorers/validation.py +165 -0
- mlflow/genai/utils/data_validation.py +146 -0
- mlflow/genai/utils/enum_utils.py +23 -0
- mlflow/genai/utils/trace_utils.py +211 -0
- mlflow/groq/__init__.py +42 -0
- mlflow/groq/_groq_autolog.py +74 -0
- mlflow/johnsnowlabs/__init__.py +888 -0
- mlflow/langchain/__init__.py +24 -0
- mlflow/langchain/api_request_parallel_processor.py +330 -0
- mlflow/langchain/autolog.py +147 -0
- mlflow/langchain/chat_agent_langgraph.py +340 -0
- mlflow/langchain/constant.py +1 -0
- mlflow/langchain/constants.py +1 -0
- mlflow/langchain/databricks_dependencies.py +444 -0
- mlflow/langchain/langchain_tracer.py +597 -0
- mlflow/langchain/model.py +919 -0
- mlflow/langchain/output_parsers.py +142 -0
- mlflow/langchain/retriever_chain.py +153 -0
- mlflow/langchain/runnables.py +527 -0
- mlflow/langchain/utils/chat.py +402 -0
- mlflow/langchain/utils/logging.py +671 -0
- mlflow/langchain/utils/serialization.py +36 -0
- mlflow/legacy_databricks_cli/__init__.py +0 -0
- mlflow/legacy_databricks_cli/configure/__init__.py +0 -0
- mlflow/legacy_databricks_cli/configure/provider.py +482 -0
- mlflow/litellm/__init__.py +175 -0
- mlflow/llama_index/__init__.py +22 -0
- mlflow/llama_index/autolog.py +55 -0
- mlflow/llama_index/chat.py +43 -0
- mlflow/llama_index/constant.py +1 -0
- mlflow/llama_index/model.py +577 -0
- mlflow/llama_index/pyfunc_wrapper.py +332 -0
- mlflow/llama_index/serialize_objects.py +188 -0
- mlflow/llama_index/tracer.py +561 -0
- mlflow/metrics/__init__.py +479 -0
- mlflow/metrics/base.py +39 -0
- mlflow/metrics/genai/__init__.py +25 -0
- mlflow/metrics/genai/base.py +101 -0
- mlflow/metrics/genai/genai_metric.py +771 -0
- mlflow/metrics/genai/metric_definitions.py +450 -0
- mlflow/metrics/genai/model_utils.py +371 -0
- mlflow/metrics/genai/prompt_template.py +68 -0
- mlflow/metrics/genai/prompts/__init__.py +0 -0
- mlflow/metrics/genai/prompts/v1.py +422 -0
- mlflow/metrics/genai/utils.py +6 -0
- mlflow/metrics/metric_definitions.py +619 -0
- mlflow/mismatch.py +34 -0
- mlflow/mistral/__init__.py +34 -0
- mlflow/mistral/autolog.py +71 -0
- mlflow/mistral/chat.py +135 -0
- mlflow/ml_package_versions.py +452 -0
- mlflow/models/__init__.py +97 -0
- mlflow/models/auth_policy.py +83 -0
- mlflow/models/cli.py +354 -0
- mlflow/models/container/__init__.py +294 -0
- mlflow/models/container/scoring_server/__init__.py +0 -0
- mlflow/models/container/scoring_server/nginx.conf +39 -0
- mlflow/models/dependencies_schemas.py +287 -0
- mlflow/models/display_utils.py +158 -0
- mlflow/models/docker_utils.py +211 -0
- mlflow/models/evaluation/__init__.py +23 -0
- mlflow/models/evaluation/_shap_patch.py +64 -0
- mlflow/models/evaluation/artifacts.py +194 -0
- mlflow/models/evaluation/base.py +1811 -0
- mlflow/models/evaluation/calibration_curve.py +109 -0
- mlflow/models/evaluation/default_evaluator.py +996 -0
- mlflow/models/evaluation/deprecated.py +23 -0
- mlflow/models/evaluation/evaluator_registry.py +80 -0
- mlflow/models/evaluation/evaluators/classifier.py +704 -0
- mlflow/models/evaluation/evaluators/default.py +233 -0
- mlflow/models/evaluation/evaluators/regressor.py +96 -0
- mlflow/models/evaluation/evaluators/shap.py +296 -0
- mlflow/models/evaluation/lift_curve.py +178 -0
- mlflow/models/evaluation/utils/metric.py +123 -0
- mlflow/models/evaluation/utils/trace.py +179 -0
- mlflow/models/evaluation/validation.py +434 -0
- mlflow/models/flavor_backend.py +93 -0
- mlflow/models/flavor_backend_registry.py +53 -0
- mlflow/models/model.py +1639 -0
- mlflow/models/model_config.py +150 -0
- mlflow/models/notebook_resources/agent_evaluation_template.html +235 -0
- mlflow/models/notebook_resources/eval_with_dataset_example.py +22 -0
- mlflow/models/notebook_resources/eval_with_synthetic_example.py +22 -0
- mlflow/models/python_api.py +369 -0
- mlflow/models/rag_signatures.py +128 -0
- mlflow/models/resources.py +321 -0
- mlflow/models/signature.py +662 -0
- mlflow/models/utils.py +2054 -0
- mlflow/models/wheeled_model.py +280 -0
- mlflow/openai/__init__.py +57 -0
- mlflow/openai/_agent_tracer.py +364 -0
- mlflow/openai/api_request_parallel_processor.py +131 -0
- mlflow/openai/autolog.py +509 -0
- mlflow/openai/constant.py +1 -0
- mlflow/openai/model.py +824 -0
- mlflow/openai/utils/chat_schema.py +367 -0
- mlflow/optuna/__init__.py +3 -0
- mlflow/optuna/storage.py +646 -0
- mlflow/plugins/__init__.py +72 -0
- mlflow/plugins/base.py +358 -0
- mlflow/plugins/builtin/__init__.py +24 -0
- mlflow/plugins/builtin/pytorch_plugin.py +150 -0
- mlflow/plugins/builtin/sklearn_plugin.py +158 -0
- mlflow/plugins/builtin/transformers_plugin.py +187 -0
- mlflow/plugins/cli.py +321 -0
- mlflow/plugins/discovery.py +340 -0
- mlflow/plugins/manager.py +465 -0
- mlflow/plugins/registry.py +316 -0
- mlflow/plugins/templates/framework_plugin_template.py +329 -0
- mlflow/prompt/constants.py +20 -0
- mlflow/prompt/promptlab_model.py +197 -0
- mlflow/prompt/registry_utils.py +248 -0
- mlflow/promptflow/__init__.py +495 -0
- mlflow/protos/__init__.py +0 -0
- mlflow/protos/assessments_pb2.py +174 -0
- mlflow/protos/databricks_artifacts_pb2.py +489 -0
- mlflow/protos/databricks_filesystem_service_pb2.py +196 -0
- mlflow/protos/databricks_managed_catalog_messages_pb2.py +95 -0
- mlflow/protos/databricks_managed_catalog_service_pb2.py +86 -0
- mlflow/protos/databricks_pb2.py +267 -0
- mlflow/protos/databricks_trace_server_pb2.py +374 -0
- mlflow/protos/databricks_uc_registry_messages_pb2.py +1249 -0
- mlflow/protos/databricks_uc_registry_service_pb2.py +170 -0
- mlflow/protos/facet_feature_statistics_pb2.py +296 -0
- mlflow/protos/internal_pb2.py +77 -0
- mlflow/protos/mlflow_artifacts_pb2.py +336 -0
- mlflow/protos/model_registry_pb2.py +1073 -0
- mlflow/protos/scalapb/__init__.py +0 -0
- mlflow/protos/scalapb/scalapb_pb2.py +104 -0
- mlflow/protos/service_pb2.py +2600 -0
- mlflow/protos/unity_catalog_oss_messages_pb2.py +457 -0
- mlflow/protos/unity_catalog_oss_service_pb2.py +130 -0
- mlflow/protos/unity_catalog_prompt_messages_pb2.py +447 -0
- mlflow/protos/unity_catalog_prompt_messages_pb2_grpc.py +24 -0
- mlflow/protos/unity_catalog_prompt_service_pb2.py +164 -0
- mlflow/protos/unity_catalog_prompt_service_pb2_grpc.py +785 -0
- mlflow/py.typed +0 -0
- mlflow/pydantic_ai/__init__.py +57 -0
- mlflow/pydantic_ai/autolog.py +173 -0
- mlflow/pyfunc/__init__.py +3844 -0
- mlflow/pyfunc/_mlflow_pyfunc_backend_predict.py +61 -0
- mlflow/pyfunc/backend.py +523 -0
- mlflow/pyfunc/context.py +78 -0
- mlflow/pyfunc/dbconnect_artifact_cache.py +144 -0
- mlflow/pyfunc/loaders/__init__.py +7 -0
- mlflow/pyfunc/loaders/chat_agent.py +117 -0
- mlflow/pyfunc/loaders/chat_model.py +125 -0
- mlflow/pyfunc/loaders/code_model.py +31 -0
- mlflow/pyfunc/loaders/responses_agent.py +112 -0
- mlflow/pyfunc/mlserver.py +46 -0
- mlflow/pyfunc/model.py +1473 -0
- mlflow/pyfunc/scoring_server/__init__.py +604 -0
- mlflow/pyfunc/scoring_server/app.py +7 -0
- mlflow/pyfunc/scoring_server/client.py +146 -0
- mlflow/pyfunc/spark_model_cache.py +48 -0
- mlflow/pyfunc/stdin_server.py +44 -0
- mlflow/pyfunc/utils/__init__.py +3 -0
- mlflow/pyfunc/utils/data_validation.py +224 -0
- mlflow/pyfunc/utils/environment.py +22 -0
- mlflow/pyfunc/utils/input_converter.py +47 -0
- mlflow/pyfunc/utils/serving_data_parser.py +11 -0
- mlflow/pytorch/__init__.py +1171 -0
- mlflow/pytorch/_lightning_autolog.py +580 -0
- mlflow/pytorch/_pytorch_autolog.py +50 -0
- mlflow/pytorch/pickle_module.py +35 -0
- mlflow/rfunc/__init__.py +42 -0
- mlflow/rfunc/backend.py +134 -0
- mlflow/runs.py +89 -0
- mlflow/server/__init__.py +302 -0
- mlflow/server/auth/__init__.py +1224 -0
- mlflow/server/auth/__main__.py +4 -0
- mlflow/server/auth/basic_auth.ini +6 -0
- mlflow/server/auth/cli.py +11 -0
- mlflow/server/auth/client.py +537 -0
- mlflow/server/auth/config.py +34 -0
- mlflow/server/auth/db/__init__.py +0 -0
- mlflow/server/auth/db/cli.py +18 -0
- mlflow/server/auth/db/migrations/__init__.py +0 -0
- mlflow/server/auth/db/migrations/alembic.ini +110 -0
- mlflow/server/auth/db/migrations/env.py +76 -0
- mlflow/server/auth/db/migrations/versions/8606fa83a998_initial_migration.py +51 -0
- mlflow/server/auth/db/migrations/versions/__init__.py +0 -0
- mlflow/server/auth/db/models.py +67 -0
- mlflow/server/auth/db/utils.py +37 -0
- mlflow/server/auth/entities.py +165 -0
- mlflow/server/auth/logo.py +14 -0
- mlflow/server/auth/permissions.py +65 -0
- mlflow/server/auth/routes.py +18 -0
- mlflow/server/auth/sqlalchemy_store.py +263 -0
- mlflow/server/graphql/__init__.py +0 -0
- mlflow/server/graphql/autogenerated_graphql_schema.py +353 -0
- mlflow/server/graphql/graphql_custom_scalars.py +24 -0
- mlflow/server/graphql/graphql_errors.py +15 -0
- mlflow/server/graphql/graphql_no_batching.py +89 -0
- mlflow/server/graphql/graphql_schema_extensions.py +74 -0
- mlflow/server/handlers.py +3217 -0
- mlflow/server/prometheus_exporter.py +17 -0
- mlflow/server/validation.py +30 -0
- mlflow/shap/__init__.py +691 -0
- mlflow/sklearn/__init__.py +1994 -0
- mlflow/sklearn/utils.py +1041 -0
- mlflow/smolagents/__init__.py +66 -0
- mlflow/smolagents/autolog.py +139 -0
- mlflow/smolagents/chat.py +29 -0
- mlflow/store/__init__.py +10 -0
- mlflow/store/_unity_catalog/__init__.py +1 -0
- mlflow/store/_unity_catalog/lineage/__init__.py +1 -0
- mlflow/store/_unity_catalog/lineage/constants.py +2 -0
- mlflow/store/_unity_catalog/registry/__init__.py +6 -0
- mlflow/store/_unity_catalog/registry/prompt_info.py +75 -0
- mlflow/store/_unity_catalog/registry/rest_store.py +1740 -0
- mlflow/store/_unity_catalog/registry/uc_oss_rest_store.py +507 -0
- mlflow/store/_unity_catalog/registry/utils.py +121 -0
- mlflow/store/artifact/__init__.py +0 -0
- mlflow/store/artifact/artifact_repo.py +472 -0
- mlflow/store/artifact/artifact_repository_registry.py +154 -0
- mlflow/store/artifact/azure_blob_artifact_repo.py +275 -0
- mlflow/store/artifact/azure_data_lake_artifact_repo.py +295 -0
- mlflow/store/artifact/cli.py +141 -0
- mlflow/store/artifact/cloud_artifact_repo.py +332 -0
- mlflow/store/artifact/databricks_artifact_repo.py +729 -0
- mlflow/store/artifact/databricks_artifact_repo_resources.py +301 -0
- mlflow/store/artifact/databricks_logged_model_artifact_repo.py +93 -0
- mlflow/store/artifact/databricks_models_artifact_repo.py +216 -0
- mlflow/store/artifact/databricks_sdk_artifact_repo.py +134 -0
- mlflow/store/artifact/databricks_sdk_models_artifact_repo.py +97 -0
- mlflow/store/artifact/dbfs_artifact_repo.py +240 -0
- mlflow/store/artifact/ftp_artifact_repo.py +132 -0
- mlflow/store/artifact/gcs_artifact_repo.py +296 -0
- mlflow/store/artifact/hdfs_artifact_repo.py +209 -0
- mlflow/store/artifact/http_artifact_repo.py +218 -0
- mlflow/store/artifact/local_artifact_repo.py +142 -0
- mlflow/store/artifact/mlflow_artifacts_repo.py +94 -0
- mlflow/store/artifact/models_artifact_repo.py +259 -0
- mlflow/store/artifact/optimized_s3_artifact_repo.py +356 -0
- mlflow/store/artifact/presigned_url_artifact_repo.py +173 -0
- mlflow/store/artifact/r2_artifact_repo.py +70 -0
- mlflow/store/artifact/runs_artifact_repo.py +265 -0
- mlflow/store/artifact/s3_artifact_repo.py +330 -0
- mlflow/store/artifact/sftp_artifact_repo.py +141 -0
- mlflow/store/artifact/uc_volume_artifact_repo.py +76 -0
- mlflow/store/artifact/unity_catalog_models_artifact_repo.py +168 -0
- mlflow/store/artifact/unity_catalog_oss_models_artifact_repo.py +168 -0
- mlflow/store/artifact/utils/__init__.py +0 -0
- mlflow/store/artifact/utils/models.py +148 -0
- mlflow/store/db/__init__.py +0 -0
- mlflow/store/db/base_sql_model.py +3 -0
- mlflow/store/db/db_types.py +10 -0
- mlflow/store/db/utils.py +314 -0
- mlflow/store/db_migrations/__init__.py +0 -0
- mlflow/store/db_migrations/alembic.ini +74 -0
- mlflow/store/db_migrations/env.py +84 -0
- mlflow/store/db_migrations/versions/0584bdc529eb_add_cascading_deletion_to_datasets_from_experiments.py +88 -0
- mlflow/store/db_migrations/versions/0a8213491aaa_drop_duplicate_killed_constraint.py +49 -0
- mlflow/store/db_migrations/versions/0c779009ac13_add_deleted_time_field_to_runs_table.py +24 -0
- mlflow/store/db_migrations/versions/181f10493468_allow_nulls_for_metric_values.py +35 -0
- mlflow/store/db_migrations/versions/27a6a02d2cf1_add_model_version_tags_table.py +38 -0
- mlflow/store/db_migrations/versions/2b4d017a5e9b_add_model_registry_tables_to_db.py +77 -0
- mlflow/store/db_migrations/versions/2d6e25af4d3e_increase_max_param_val_length.py +33 -0
- mlflow/store/db_migrations/versions/3500859a5d39_add_model_aliases_table.py +50 -0
- mlflow/store/db_migrations/versions/39d1c3be5f05_add_is_nan_constraint_for_metrics_tables_if_necessary.py +41 -0
- mlflow/store/db_migrations/versions/400f98739977_add_logged_model_tables.py +123 -0
- mlflow/store/db_migrations/versions/4465047574b1_increase_max_dataset_schema_size.py +38 -0
- mlflow/store/db_migrations/versions/451aebb31d03_add_metric_step.py +35 -0
- mlflow/store/db_migrations/versions/5b0e9adcef9c_add_cascade_deletion_to_trace_tables_fk.py +40 -0
- mlflow/store/db_migrations/versions/6953534de441_add_step_to_inputs_table.py +25 -0
- mlflow/store/db_migrations/versions/728d730b5ebd_add_registered_model_tags_table.py +38 -0
- mlflow/store/db_migrations/versions/7ac759974ad8_update_run_tags_with_larger_limit.py +36 -0
- mlflow/store/db_migrations/versions/7f2a7d5fae7d_add_datasets_inputs_input_tags_tables.py +82 -0
- mlflow/store/db_migrations/versions/84291f40a231_add_run_link_to_model_version.py +26 -0
- mlflow/store/db_migrations/versions/867495a8f9d4_add_trace_tables.py +90 -0
- mlflow/store/db_migrations/versions/89d4b8295536_create_latest_metrics_table.py +169 -0
- mlflow/store/db_migrations/versions/90e64c465722_migrate_user_column_to_tags.py +64 -0
- mlflow/store/db_migrations/versions/97727af70f4d_creation_time_last_update_time_experiments.py +25 -0
- mlflow/store/db_migrations/versions/__init__.py +0 -0
- mlflow/store/db_migrations/versions/a8c4a736bde6_allow_nulls_for_run_id.py +27 -0
- mlflow/store/db_migrations/versions/acf3f17fdcc7_add_storage_location_field_to_model_.py +29 -0
- mlflow/store/db_migrations/versions/bd07f7e963c5_create_index_on_run_uuid.py +26 -0
- mlflow/store/db_migrations/versions/bda7b8c39065_increase_model_version_tag_value_limit.py +38 -0
- mlflow/store/db_migrations/versions/c48cb773bb87_reset_default_value_for_is_nan_in_metrics_table_for_mysql.py +41 -0
- mlflow/store/db_migrations/versions/cbc13b556ace_add_v3_trace_schema_columns.py +31 -0
- mlflow/store/db_migrations/versions/cc1f77228345_change_param_value_length_to_500.py +34 -0
- mlflow/store/db_migrations/versions/cfd24bdc0731_update_run_status_constraint_with_killed.py +78 -0
- mlflow/store/db_migrations/versions/df50e92ffc5e_add_experiment_tags_table.py +38 -0
- mlflow/store/db_migrations/versions/f5a4f2784254_increase_run_tag_value_limit.py +36 -0
- mlflow/store/entities/__init__.py +3 -0
- mlflow/store/entities/paged_list.py +18 -0
- mlflow/store/model_registry/__init__.py +10 -0
- mlflow/store/model_registry/abstract_store.py +1081 -0
- mlflow/store/model_registry/base_rest_store.py +44 -0
- mlflow/store/model_registry/databricks_workspace_model_registry_rest_store.py +37 -0
- mlflow/store/model_registry/dbmodels/__init__.py +0 -0
- mlflow/store/model_registry/dbmodels/models.py +206 -0
- mlflow/store/model_registry/file_store.py +1091 -0
- mlflow/store/model_registry/rest_store.py +481 -0
- mlflow/store/model_registry/sqlalchemy_store.py +1286 -0
- mlflow/store/tracking/__init__.py +23 -0
- mlflow/store/tracking/abstract_store.py +816 -0
- mlflow/store/tracking/dbmodels/__init__.py +0 -0
- mlflow/store/tracking/dbmodels/initial_models.py +243 -0
- mlflow/store/tracking/dbmodels/models.py +1073 -0
- mlflow/store/tracking/file_store.py +2438 -0
- mlflow/store/tracking/postgres_managed_identity.py +146 -0
- mlflow/store/tracking/rest_store.py +1131 -0
- mlflow/store/tracking/sqlalchemy_store.py +2785 -0
- mlflow/system_metrics/__init__.py +61 -0
- mlflow/system_metrics/metrics/__init__.py +0 -0
- mlflow/system_metrics/metrics/base_metrics_monitor.py +32 -0
- mlflow/system_metrics/metrics/cpu_monitor.py +23 -0
- mlflow/system_metrics/metrics/disk_monitor.py +21 -0
- mlflow/system_metrics/metrics/gpu_monitor.py +71 -0
- mlflow/system_metrics/metrics/network_monitor.py +34 -0
- mlflow/system_metrics/metrics/rocm_monitor.py +123 -0
- mlflow/system_metrics/system_metrics_monitor.py +198 -0
- mlflow/tracing/__init__.py +16 -0
- mlflow/tracing/assessment.py +356 -0
- mlflow/tracing/client.py +531 -0
- mlflow/tracing/config.py +125 -0
- mlflow/tracing/constant.py +105 -0
- mlflow/tracing/destination.py +81 -0
- mlflow/tracing/display/__init__.py +40 -0
- mlflow/tracing/display/display_handler.py +196 -0
- mlflow/tracing/export/async_export_queue.py +186 -0
- mlflow/tracing/export/inference_table.py +138 -0
- mlflow/tracing/export/mlflow_v3.py +137 -0
- mlflow/tracing/export/utils.py +70 -0
- mlflow/tracing/fluent.py +1417 -0
- mlflow/tracing/processor/base_mlflow.py +199 -0
- mlflow/tracing/processor/inference_table.py +175 -0
- mlflow/tracing/processor/mlflow_v3.py +47 -0
- mlflow/tracing/processor/otel.py +73 -0
- mlflow/tracing/provider.py +487 -0
- mlflow/tracing/trace_manager.py +200 -0
- mlflow/tracing/utils/__init__.py +616 -0
- mlflow/tracing/utils/artifact_utils.py +28 -0
- mlflow/tracing/utils/copy.py +55 -0
- mlflow/tracing/utils/environment.py +55 -0
- mlflow/tracing/utils/exception.py +21 -0
- mlflow/tracing/utils/once.py +35 -0
- mlflow/tracing/utils/otlp.py +63 -0
- mlflow/tracing/utils/processor.py +54 -0
- mlflow/tracing/utils/search.py +292 -0
- mlflow/tracing/utils/timeout.py +250 -0
- mlflow/tracing/utils/token.py +19 -0
- mlflow/tracing/utils/truncation.py +124 -0
- mlflow/tracing/utils/warning.py +76 -0
- mlflow/tracking/__init__.py +39 -0
- mlflow/tracking/_model_registry/__init__.py +1 -0
- mlflow/tracking/_model_registry/client.py +764 -0
- mlflow/tracking/_model_registry/fluent.py +853 -0
- mlflow/tracking/_model_registry/registry.py +67 -0
- mlflow/tracking/_model_registry/utils.py +251 -0
- mlflow/tracking/_tracking_service/__init__.py +0 -0
- mlflow/tracking/_tracking_service/client.py +883 -0
- mlflow/tracking/_tracking_service/registry.py +56 -0
- mlflow/tracking/_tracking_service/utils.py +275 -0
- mlflow/tracking/artifact_utils.py +179 -0
- mlflow/tracking/client.py +5900 -0
- mlflow/tracking/context/__init__.py +0 -0
- mlflow/tracking/context/abstract_context.py +35 -0
- mlflow/tracking/context/databricks_cluster_context.py +15 -0
- mlflow/tracking/context/databricks_command_context.py +15 -0
- mlflow/tracking/context/databricks_job_context.py +49 -0
- mlflow/tracking/context/databricks_notebook_context.py +41 -0
- mlflow/tracking/context/databricks_repo_context.py +43 -0
- mlflow/tracking/context/default_context.py +51 -0
- mlflow/tracking/context/git_context.py +32 -0
- mlflow/tracking/context/registry.py +98 -0
- mlflow/tracking/context/system_environment_context.py +15 -0
- mlflow/tracking/default_experiment/__init__.py +1 -0
- mlflow/tracking/default_experiment/abstract_context.py +43 -0
- mlflow/tracking/default_experiment/databricks_notebook_experiment_provider.py +44 -0
- mlflow/tracking/default_experiment/registry.py +75 -0
- mlflow/tracking/fluent.py +3595 -0
- mlflow/tracking/metric_value_conversion_utils.py +93 -0
- mlflow/tracking/multimedia.py +206 -0
- mlflow/tracking/registry.py +86 -0
- mlflow/tracking/request_auth/__init__.py +0 -0
- mlflow/tracking/request_auth/abstract_request_auth_provider.py +34 -0
- mlflow/tracking/request_auth/registry.py +60 -0
- mlflow/tracking/request_header/__init__.py +0 -0
- mlflow/tracking/request_header/abstract_request_header_provider.py +36 -0
- mlflow/tracking/request_header/databricks_request_header_provider.py +38 -0
- mlflow/tracking/request_header/default_request_header_provider.py +17 -0
- mlflow/tracking/request_header/registry.py +79 -0
- mlflow/transformers/__init__.py +2982 -0
- mlflow/transformers/flavor_config.py +258 -0
- mlflow/transformers/hub_utils.py +83 -0
- mlflow/transformers/llm_inference_utils.py +468 -0
- mlflow/transformers/model_io.py +301 -0
- mlflow/transformers/peft.py +51 -0
- mlflow/transformers/signature.py +183 -0
- mlflow/transformers/torch_utils.py +55 -0
- mlflow/types/__init__.py +21 -0
- mlflow/types/agent.py +270 -0
- mlflow/types/chat.py +240 -0
- mlflow/types/llm.py +935 -0
- mlflow/types/responses.py +139 -0
- mlflow/types/responses_helpers.py +416 -0
- mlflow/types/schema.py +1505 -0
- mlflow/types/type_hints.py +647 -0
- mlflow/types/utils.py +753 -0
- mlflow/utils/__init__.py +283 -0
- mlflow/utils/_capture_modules.py +256 -0
- mlflow/utils/_capture_transformers_modules.py +75 -0
- mlflow/utils/_spark_utils.py +201 -0
- mlflow/utils/_unity_catalog_oss_utils.py +97 -0
- mlflow/utils/_unity_catalog_utils.py +479 -0
- mlflow/utils/annotations.py +218 -0
- mlflow/utils/arguments_utils.py +16 -0
- mlflow/utils/async_logging/__init__.py +1 -0
- mlflow/utils/async_logging/async_artifacts_logging_queue.py +258 -0
- mlflow/utils/async_logging/async_logging_queue.py +366 -0
- mlflow/utils/async_logging/run_artifact.py +38 -0
- mlflow/utils/async_logging/run_batch.py +58 -0
- mlflow/utils/async_logging/run_operations.py +49 -0
- mlflow/utils/autologging_utils/__init__.py +737 -0
- mlflow/utils/autologging_utils/client.py +432 -0
- mlflow/utils/autologging_utils/config.py +33 -0
- mlflow/utils/autologging_utils/events.py +294 -0
- mlflow/utils/autologging_utils/logging_and_warnings.py +328 -0
- mlflow/utils/autologging_utils/metrics_queue.py +71 -0
- mlflow/utils/autologging_utils/safety.py +1104 -0
- mlflow/utils/autologging_utils/versioning.py +95 -0
- mlflow/utils/checkpoint_utils.py +206 -0
- mlflow/utils/class_utils.py +6 -0
- mlflow/utils/cli_args.py +257 -0
- mlflow/utils/conda.py +354 -0
- mlflow/utils/credentials.py +231 -0
- mlflow/utils/data_utils.py +17 -0
- mlflow/utils/databricks_utils.py +1436 -0
- mlflow/utils/docstring_utils.py +477 -0
- mlflow/utils/doctor.py +133 -0
- mlflow/utils/download_cloud_file_chunk.py +43 -0
- mlflow/utils/env_manager.py +16 -0
- mlflow/utils/env_pack.py +131 -0
- mlflow/utils/environment.py +1009 -0
- mlflow/utils/exception_utils.py +14 -0
- mlflow/utils/file_utils.py +978 -0
- mlflow/utils/git_utils.py +77 -0
- mlflow/utils/gorilla.py +797 -0
- mlflow/utils/import_hooks/__init__.py +363 -0
- mlflow/utils/lazy_load.py +51 -0
- mlflow/utils/logging_utils.py +168 -0
- mlflow/utils/mime_type_utils.py +58 -0
- mlflow/utils/mlflow_tags.py +103 -0
- mlflow/utils/model_utils.py +486 -0
- mlflow/utils/name_utils.py +346 -0
- mlflow/utils/nfs_on_spark.py +62 -0
- mlflow/utils/openai_utils.py +164 -0
- mlflow/utils/os.py +12 -0
- mlflow/utils/oss_registry_utils.py +29 -0
- mlflow/utils/plugins.py +17 -0
- mlflow/utils/process.py +182 -0
- mlflow/utils/promptlab_utils.py +146 -0
- mlflow/utils/proto_json_utils.py +743 -0
- mlflow/utils/pydantic_utils.py +54 -0
- mlflow/utils/request_utils.py +279 -0
- mlflow/utils/requirements_utils.py +704 -0
- mlflow/utils/rest_utils.py +673 -0
- mlflow/utils/search_logged_model_utils.py +127 -0
- mlflow/utils/search_utils.py +2111 -0
- mlflow/utils/secure_loading.py +221 -0
- mlflow/utils/security_validation.py +384 -0
- mlflow/utils/server_cli_utils.py +61 -0
- mlflow/utils/spark_utils.py +15 -0
- mlflow/utils/string_utils.py +138 -0
- mlflow/utils/thread_utils.py +63 -0
- mlflow/utils/time.py +54 -0
- mlflow/utils/timeout.py +42 -0
- mlflow/utils/uri.py +572 -0
- mlflow/utils/validation.py +662 -0
- mlflow/utils/virtualenv.py +458 -0
- mlflow/utils/warnings_utils.py +25 -0
- mlflow/utils/yaml_utils.py +179 -0
- mlflow/version.py +24 -0
@@ -0,0 +1,221 @@
|
|
1
|
+
"""
|
2
|
+
Genesis-Flow Secure Model Loading
|
3
|
+
|
4
|
+
This module provides secure alternatives to pickle-based model loading,
|
5
|
+
addressing security vulnerabilities in model deserialization.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import io
|
9
|
+
import pickle
|
10
|
+
import cloudpickle
|
11
|
+
import logging
|
12
|
+
import hashlib
|
13
|
+
from typing import Any, Set, Optional, Union, Type
|
14
|
+
from pathlib import Path
|
15
|
+
|
16
|
+
logger = logging.getLogger(__name__)
|
17
|
+
|
18
|
+
# Allowlist of safe classes that can be unpickled
|
19
|
+
SAFE_PICKLE_CLASSES = {
|
20
|
+
# NumPy types
|
21
|
+
'numpy.ndarray',
|
22
|
+
'numpy.dtype',
|
23
|
+
'numpy.int32', 'numpy.int64', 'numpy.float32', 'numpy.float64',
|
24
|
+
'numpy.bool_', 'numpy.str_',
|
25
|
+
|
26
|
+
# Pandas types
|
27
|
+
'pandas.core.frame.DataFrame',
|
28
|
+
'pandas.core.series.Series',
|
29
|
+
'pandas.core.index.Index',
|
30
|
+
'pandas.core.dtypes.dtypes.CategoricalDtype',
|
31
|
+
|
32
|
+
# Scikit-learn estimators (core models only)
|
33
|
+
'sklearn.linear_model._base.LinearRegression',
|
34
|
+
'sklearn.linear_model._logistic.LogisticRegression',
|
35
|
+
'sklearn.ensemble._forest.RandomForestClassifier',
|
36
|
+
'sklearn.ensemble._forest.RandomForestRegressor',
|
37
|
+
'sklearn.tree._classes.DecisionTreeClassifier',
|
38
|
+
'sklearn.tree._classes.DecisionTreeRegressor',
|
39
|
+
'sklearn.svm._classes.SVC',
|
40
|
+
'sklearn.svm._classes.SVR',
|
41
|
+
|
42
|
+
# Standard Python types
|
43
|
+
'builtins.dict', 'builtins.list', 'builtins.tuple', 'builtins.set',
|
44
|
+
'builtins.str', 'builtins.int', 'builtins.float', 'builtins.bool',
|
45
|
+
|
46
|
+
# Collections
|
47
|
+
'collections.OrderedDict',
|
48
|
+
'collections.defaultdict',
|
49
|
+
|
50
|
+
# Genesis-Flow internal types
|
51
|
+
'mlflow.models.signature.ModelSignature',
|
52
|
+
'mlflow.types.schema.Schema',
|
53
|
+
}
|
54
|
+
|
55
|
+
class RestrictedUnpickler(pickle.Unpickler):
|
56
|
+
"""
|
57
|
+
Secure unpickler that only allows safe, whitelisted classes.
|
58
|
+
|
59
|
+
This prevents arbitrary code execution during model deserialization
|
60
|
+
by restricting which classes can be instantiated.
|
61
|
+
"""
|
62
|
+
|
63
|
+
def __init__(self, file, *, safe_classes: Optional[Set[str]] = None):
|
64
|
+
super().__init__(file)
|
65
|
+
self.safe_classes = safe_classes or SAFE_PICKLE_CLASSES
|
66
|
+
|
67
|
+
def find_class(self, module: str, name: str) -> Type:
|
68
|
+
"""
|
69
|
+
Override to restrict class loading to safe classes only.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
module: Module name
|
73
|
+
name: Class name
|
74
|
+
|
75
|
+
Returns:
|
76
|
+
Class object if safe
|
77
|
+
|
78
|
+
Raises:
|
79
|
+
SecurityError: If class is not in allowlist
|
80
|
+
"""
|
81
|
+
full_name = f"{module}.{name}"
|
82
|
+
|
83
|
+
# Check if the class is in our safe list
|
84
|
+
if full_name in self.safe_classes:
|
85
|
+
logger.debug(f"Loading safe class: {full_name}")
|
86
|
+
return super().find_class(module, name)
|
87
|
+
|
88
|
+
# Additional check for known safe modules
|
89
|
+
safe_modules = {
|
90
|
+
'numpy': ['ndarray', 'dtype', 'int32', 'int64', 'float32', 'float64', 'bool_'],
|
91
|
+
'pandas': ['DataFrame', 'Series', 'Index'],
|
92
|
+
'builtins': ['dict', 'list', 'tuple', 'set', 'str', 'int', 'float', 'bool'],
|
93
|
+
}
|
94
|
+
|
95
|
+
if module in safe_modules and name in safe_modules[module]:
|
96
|
+
logger.debug(f"Loading safe module class: {full_name}")
|
97
|
+
return super().find_class(module, name)
|
98
|
+
|
99
|
+
# Log and block unsafe class
|
100
|
+
logger.warning(f"Blocked potentially unsafe class: {full_name}")
|
101
|
+
raise pickle.UnpicklingError(
|
102
|
+
f"Security: Class '{full_name}' is not in the allowlist. "
|
103
|
+
f"If this is a legitimate model class, add it to SAFE_PICKLE_CLASSES."
|
104
|
+
)
|
105
|
+
|
106
|
+
class SecureModelLoader:
|
107
|
+
"""
|
108
|
+
Secure model loading with multiple safety mechanisms.
|
109
|
+
"""
|
110
|
+
|
111
|
+
@staticmethod
|
112
|
+
def calculate_file_hash(file_path: Union[str, Path]) -> str:
|
113
|
+
"""Calculate SHA256 hash of a file for integrity checking."""
|
114
|
+
hasher = hashlib.sha256()
|
115
|
+
with open(file_path, 'rb') as f:
|
116
|
+
for chunk in iter(lambda: f.read(4096), b""):
|
117
|
+
hasher.update(chunk)
|
118
|
+
return hasher.hexdigest()
|
119
|
+
|
120
|
+
@staticmethod
|
121
|
+
def safe_pickle_load(file_path: Union[str, Path], *, safe_classes: Optional[Set[str]] = None) -> Any:
|
122
|
+
"""
|
123
|
+
Safely load a pickle file using restricted unpickler.
|
124
|
+
|
125
|
+
Args:
|
126
|
+
file_path: Path to pickle file
|
127
|
+
safe_classes: Optional custom set of safe classes
|
128
|
+
|
129
|
+
Returns:
|
130
|
+
Unpickled object
|
131
|
+
|
132
|
+
Raises:
|
133
|
+
SecurityError: If file contains unsafe classes
|
134
|
+
FileNotFoundError: If file doesn't exist
|
135
|
+
"""
|
136
|
+
file_path = Path(file_path)
|
137
|
+
|
138
|
+
if not file_path.exists():
|
139
|
+
raise FileNotFoundError(f"Model file not found: {file_path}")
|
140
|
+
|
141
|
+
# Log file hash for audit trail
|
142
|
+
file_hash = SecureModelLoader.calculate_file_hash(file_path)
|
143
|
+
logger.info(f"Loading model file {file_path.name} (SHA256: {file_hash[:16]}...)")
|
144
|
+
|
145
|
+
try:
|
146
|
+
with open(file_path, 'rb') as f:
|
147
|
+
unpickler = RestrictedUnpickler(f, safe_classes=safe_classes)
|
148
|
+
model = unpickler.load()
|
149
|
+
logger.info(f"Successfully loaded model of type: {type(model).__name__}")
|
150
|
+
return model
|
151
|
+
except pickle.UnpicklingError as e:
|
152
|
+
logger.error(f"Security: Unsafe model file rejected: {e}")
|
153
|
+
raise SecurityError(f"Model file contains unsafe content: {e}") from e
|
154
|
+
except Exception as e:
|
155
|
+
logger.error(f"Error loading model: {e}")
|
156
|
+
raise
|
157
|
+
|
158
|
+
@staticmethod
|
159
|
+
def safe_cloudpickle_load(file_path: Union[str, Path], *, safe_classes: Optional[Set[str]] = None) -> Any:
|
160
|
+
"""
|
161
|
+
Safely load a cloudpickle file using restricted unpickler.
|
162
|
+
|
163
|
+
Args:
|
164
|
+
file_path: Path to cloudpickle file
|
165
|
+
safe_classes: Optional custom set of safe classes
|
166
|
+
|
167
|
+
Returns:
|
168
|
+
Unpickled object
|
169
|
+
"""
|
170
|
+
file_path = Path(file_path)
|
171
|
+
|
172
|
+
if not file_path.exists():
|
173
|
+
raise FileNotFoundError(f"Model file not found: {file_path}")
|
174
|
+
|
175
|
+
# Calculate file hash for audit trail
|
176
|
+
file_hash = SecureModelLoader.calculate_file_hash(file_path)
|
177
|
+
logger.info(f"Loading cloudpickle file {file_path.name} (SHA256: {file_hash[:16]}...)")
|
178
|
+
|
179
|
+
try:
|
180
|
+
with open(file_path, 'rb') as f:
|
181
|
+
# Use cloudpickle's load with our custom unpickler
|
182
|
+
# Note: This is a simplified approach - in practice, cloudpickle's
|
183
|
+
# load function would need to be modified to accept a custom unpickler
|
184
|
+
unpickler = RestrictedUnpickler(f, safe_classes=safe_classes)
|
185
|
+
model = unpickler.load()
|
186
|
+
logger.info(f"Successfully loaded cloudpickle model of type: {type(model).__name__}")
|
187
|
+
return model
|
188
|
+
except pickle.UnpicklingError as e:
|
189
|
+
logger.error(f"Security: Unsafe cloudpickle file rejected: {e}")
|
190
|
+
raise SecurityError(f"CloudPickle file contains unsafe content: {e}") from e
|
191
|
+
except Exception as e:
|
192
|
+
logger.error(f"Error loading cloudpickle model: {e}")
|
193
|
+
raise
|
194
|
+
|
195
|
+
class SecurityError(Exception):
|
196
|
+
"""Exception raised for security-related model loading issues."""
|
197
|
+
pass
|
198
|
+
|
199
|
+
def add_safe_class(class_name: str) -> None:
|
200
|
+
"""
|
201
|
+
Add a class to the safe loading allowlist.
|
202
|
+
|
203
|
+
Args:
|
204
|
+
class_name: Full class name (e.g., 'mymodule.MyClass')
|
205
|
+
"""
|
206
|
+
SAFE_PICKLE_CLASSES.add(class_name)
|
207
|
+
logger.info(f"Added {class_name} to safe loading allowlist")
|
208
|
+
|
209
|
+
def remove_safe_class(class_name: str) -> None:
|
210
|
+
"""
|
211
|
+
Remove a class from the safe loading allowlist.
|
212
|
+
|
213
|
+
Args:
|
214
|
+
class_name: Full class name to remove
|
215
|
+
"""
|
216
|
+
SAFE_PICKLE_CLASSES.discard(class_name)
|
217
|
+
logger.info(f"Removed {class_name} from safe loading allowlist")
|
218
|
+
|
219
|
+
def get_safe_classes() -> Set[str]:
|
220
|
+
"""Return a copy of the current safe classes set."""
|
221
|
+
return SAFE_PICKLE_CLASSES.copy()
|
@@ -0,0 +1,384 @@
|
|
1
|
+
"""
|
2
|
+
Genesis-Flow Security Validation
|
3
|
+
|
4
|
+
This module provides comprehensive input validation to prevent
|
5
|
+
injection attacks, path traversal, and other security vulnerabilities.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import os
|
9
|
+
import re
|
10
|
+
import logging
|
11
|
+
from pathlib import Path
|
12
|
+
from typing import Union, Optional
|
13
|
+
from urllib.parse import urlparse
|
14
|
+
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
class SecurityValidationError(Exception):
|
18
|
+
"""Exception raised for security validation failures."""
|
19
|
+
pass
|
20
|
+
|
21
|
+
class InputValidator:
|
22
|
+
"""
|
23
|
+
Comprehensive input validation for Genesis-Flow.
|
24
|
+
"""
|
25
|
+
|
26
|
+
# Safe characters for different input types
|
27
|
+
SAFE_NAME_PATTERN = re.compile(r'^[a-zA-Z0-9_\-\.]+$')
|
28
|
+
SAFE_TAG_KEY_PATTERN = re.compile(r'^[a-zA-Z0-9_\-\.\/]+$')
|
29
|
+
SAFE_TAG_VALUE_PATTERN = re.compile(r'^[a-zA-Z0-9_\-\.\s\/\:\@]+$')
|
30
|
+
|
31
|
+
# Maximum lengths to prevent DoS
|
32
|
+
MAX_NAME_LENGTH = 256
|
33
|
+
MAX_TAG_KEY_LENGTH = 250
|
34
|
+
MAX_TAG_VALUE_LENGTH = 5000
|
35
|
+
MAX_DESCRIPTION_LENGTH = 10000
|
36
|
+
MAX_ARTIFACT_PATH_LENGTH = 1000
|
37
|
+
|
38
|
+
@staticmethod
|
39
|
+
def validate_experiment_name(name: str) -> str:
|
40
|
+
"""
|
41
|
+
Validate experiment name against injection attacks.
|
42
|
+
|
43
|
+
Args:
|
44
|
+
name: Experiment name to validate
|
45
|
+
|
46
|
+
Returns:
|
47
|
+
Validated name
|
48
|
+
|
49
|
+
Raises:
|
50
|
+
SecurityValidationError: If name is invalid
|
51
|
+
"""
|
52
|
+
if not name or not isinstance(name, str):
|
53
|
+
raise SecurityValidationError("Experiment name must be a non-empty string")
|
54
|
+
|
55
|
+
if len(name) > InputValidator.MAX_NAME_LENGTH:
|
56
|
+
raise SecurityValidationError(
|
57
|
+
f"Experiment name too long (max {InputValidator.MAX_NAME_LENGTH} chars)"
|
58
|
+
)
|
59
|
+
|
60
|
+
# Check for dangerous characters
|
61
|
+
if not InputValidator.SAFE_NAME_PATTERN.match(name):
|
62
|
+
raise SecurityValidationError(
|
63
|
+
"Experiment name contains invalid characters. "
|
64
|
+
"Only alphanumeric, dash, underscore, and dot allowed."
|
65
|
+
)
|
66
|
+
|
67
|
+
# Prevent directory traversal
|
68
|
+
if '..' in name or '/' in name or '\\' in name:
|
69
|
+
raise SecurityValidationError("Experiment name cannot contain path traversal sequences")
|
70
|
+
|
71
|
+
logger.debug(f"Validated experiment name: {name}")
|
72
|
+
return name
|
73
|
+
|
74
|
+
@staticmethod
|
75
|
+
def validate_run_name(name: Optional[str]) -> Optional[str]:
|
76
|
+
"""
|
77
|
+
Validate run name.
|
78
|
+
|
79
|
+
Args:
|
80
|
+
name: Run name to validate (can be None)
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
Validated name or None
|
84
|
+
"""
|
85
|
+
if name is None:
|
86
|
+
return None
|
87
|
+
|
88
|
+
if not isinstance(name, str):
|
89
|
+
raise SecurityValidationError("Run name must be a string")
|
90
|
+
|
91
|
+
if len(name) > InputValidator.MAX_NAME_LENGTH:
|
92
|
+
raise SecurityValidationError(
|
93
|
+
f"Run name too long (max {InputValidator.MAX_NAME_LENGTH} chars)"
|
94
|
+
)
|
95
|
+
|
96
|
+
# Allow more flexible run names but still prevent injection
|
97
|
+
if '..' in name or '\x00' in name:
|
98
|
+
raise SecurityValidationError("Run name contains invalid sequences")
|
99
|
+
|
100
|
+
return name
|
101
|
+
|
102
|
+
@staticmethod
|
103
|
+
def validate_tag_key(key: str) -> str:
|
104
|
+
"""
|
105
|
+
Validate tag key.
|
106
|
+
|
107
|
+
Args:
|
108
|
+
key: Tag key to validate
|
109
|
+
|
110
|
+
Returns:
|
111
|
+
Validated key
|
112
|
+
"""
|
113
|
+
if not key or not isinstance(key, str):
|
114
|
+
raise SecurityValidationError("Tag key must be a non-empty string")
|
115
|
+
|
116
|
+
if len(key) > InputValidator.MAX_TAG_KEY_LENGTH:
|
117
|
+
raise SecurityValidationError(
|
118
|
+
f"Tag key too long (max {InputValidator.MAX_TAG_KEY_LENGTH} chars)"
|
119
|
+
)
|
120
|
+
|
121
|
+
if not InputValidator.SAFE_TAG_KEY_PATTERN.match(key):
|
122
|
+
raise SecurityValidationError(
|
123
|
+
"Tag key contains invalid characters"
|
124
|
+
)
|
125
|
+
|
126
|
+
return key
|
127
|
+
|
128
|
+
@staticmethod
|
129
|
+
def validate_tag_value(value: str) -> str:
|
130
|
+
"""
|
131
|
+
Validate tag value.
|
132
|
+
|
133
|
+
Args:
|
134
|
+
value: Tag value to validate
|
135
|
+
|
136
|
+
Returns:
|
137
|
+
Validated value
|
138
|
+
"""
|
139
|
+
if not isinstance(value, str):
|
140
|
+
raise SecurityValidationError("Tag value must be a string")
|
141
|
+
|
142
|
+
if len(value) > InputValidator.MAX_TAG_VALUE_LENGTH:
|
143
|
+
raise SecurityValidationError(
|
144
|
+
f"Tag value too long (max {InputValidator.MAX_TAG_VALUE_LENGTH} chars)"
|
145
|
+
)
|
146
|
+
|
147
|
+
# Check for control characters and potential injection
|
148
|
+
if '\x00' in value or '\r' in value:
|
149
|
+
raise SecurityValidationError("Tag value contains invalid control characters")
|
150
|
+
|
151
|
+
return value
|
152
|
+
|
153
|
+
@staticmethod
|
154
|
+
def validate_artifact_path(path: str, base_path: Optional[str] = None) -> str:
|
155
|
+
"""
|
156
|
+
Validate artifact path to prevent path traversal attacks.
|
157
|
+
|
158
|
+
Args:
|
159
|
+
path: Artifact path to validate
|
160
|
+
base_path: Optional base path for additional validation
|
161
|
+
|
162
|
+
Returns:
|
163
|
+
Validated path
|
164
|
+
|
165
|
+
Raises:
|
166
|
+
SecurityValidationError: If path is unsafe
|
167
|
+
"""
|
168
|
+
if not path or not isinstance(path, str):
|
169
|
+
raise SecurityValidationError("Artifact path must be a non-empty string")
|
170
|
+
|
171
|
+
if len(path) > InputValidator.MAX_ARTIFACT_PATH_LENGTH:
|
172
|
+
raise SecurityValidationError(
|
173
|
+
f"Artifact path too long (max {InputValidator.MAX_ARTIFACT_PATH_LENGTH} chars)"
|
174
|
+
)
|
175
|
+
|
176
|
+
# Normalize the path to resolve any relative components
|
177
|
+
normalized_path = os.path.normpath(path)
|
178
|
+
|
179
|
+
# Check for path traversal attempts
|
180
|
+
if '..' in normalized_path or normalized_path.startswith('/'):
|
181
|
+
raise SecurityValidationError("Artifact path contains path traversal sequences")
|
182
|
+
|
183
|
+
# Additional check if base path provided
|
184
|
+
if base_path:
|
185
|
+
base = Path(base_path).resolve()
|
186
|
+
try:
|
187
|
+
target = (base / normalized_path).resolve()
|
188
|
+
# Ensure target is within base directory
|
189
|
+
target.relative_to(base)
|
190
|
+
except ValueError:
|
191
|
+
raise SecurityValidationError("Artifact path escapes base directory")
|
192
|
+
|
193
|
+
logger.debug(f"Validated artifact path: {normalized_path}")
|
194
|
+
return normalized_path
|
195
|
+
|
196
|
+
@staticmethod
|
197
|
+
def validate_metric_key(key: str) -> str:
|
198
|
+
"""
|
199
|
+
Validate metric key.
|
200
|
+
|
201
|
+
Args:
|
202
|
+
key: Metric key to validate
|
203
|
+
|
204
|
+
Returns:
|
205
|
+
Validated key
|
206
|
+
"""
|
207
|
+
if not key or not isinstance(key, str):
|
208
|
+
raise SecurityValidationError("Metric key must be a non-empty string")
|
209
|
+
|
210
|
+
if len(key) > InputValidator.MAX_TAG_KEY_LENGTH:
|
211
|
+
raise SecurityValidationError(
|
212
|
+
f"Metric key too long (max {InputValidator.MAX_TAG_KEY_LENGTH} chars)"
|
213
|
+
)
|
214
|
+
|
215
|
+
# Metric keys should be more restrictive
|
216
|
+
if not re.match(r'^[a-zA-Z0-9_\-\.]+$', key):
|
217
|
+
raise SecurityValidationError(
|
218
|
+
"Metric key contains invalid characters. "
|
219
|
+
"Only alphanumeric, dash, underscore, and dot allowed."
|
220
|
+
)
|
221
|
+
|
222
|
+
return key
|
223
|
+
|
224
|
+
@staticmethod
|
225
|
+
def validate_param_key(key: str) -> str:
|
226
|
+
"""
|
227
|
+
Validate parameter key.
|
228
|
+
|
229
|
+
Args:
|
230
|
+
key: Parameter key to validate
|
231
|
+
|
232
|
+
Returns:
|
233
|
+
Validated key
|
234
|
+
"""
|
235
|
+
if not key or not isinstance(key, str):
|
236
|
+
raise SecurityValidationError("Parameter key must be a non-empty string")
|
237
|
+
|
238
|
+
if len(key) > InputValidator.MAX_TAG_KEY_LENGTH:
|
239
|
+
raise SecurityValidationError(
|
240
|
+
f"Parameter key too long (max {InputValidator.MAX_TAG_KEY_LENGTH} chars)"
|
241
|
+
)
|
242
|
+
|
243
|
+
# Parameter keys should be restrictive
|
244
|
+
if not re.match(r'^[a-zA-Z0-9_\-\.]+$', key):
|
245
|
+
raise SecurityValidationError(
|
246
|
+
"Parameter key contains invalid characters. "
|
247
|
+
"Only alphanumeric, dash, underscore, and dot allowed."
|
248
|
+
)
|
249
|
+
|
250
|
+
return key
|
251
|
+
|
252
|
+
@staticmethod
|
253
|
+
def validate_param_value(value: Union[str, int, float]) -> str:
|
254
|
+
"""
|
255
|
+
Validate parameter value.
|
256
|
+
|
257
|
+
Args:
|
258
|
+
value: Parameter value to validate
|
259
|
+
|
260
|
+
Returns:
|
261
|
+
Validated value as string
|
262
|
+
"""
|
263
|
+
if value is None:
|
264
|
+
raise SecurityValidationError("Parameter value cannot be None")
|
265
|
+
|
266
|
+
# Convert to string if needed
|
267
|
+
str_value = str(value)
|
268
|
+
|
269
|
+
if len(str_value) > InputValidator.MAX_TAG_VALUE_LENGTH:
|
270
|
+
raise SecurityValidationError(
|
271
|
+
f"Parameter value too long (max {InputValidator.MAX_TAG_VALUE_LENGTH} chars)"
|
272
|
+
)
|
273
|
+
|
274
|
+
# Check for control characters
|
275
|
+
if '\x00' in str_value or '\r' in str_value:
|
276
|
+
raise SecurityValidationError("Parameter value contains invalid control characters")
|
277
|
+
|
278
|
+
return str_value
|
279
|
+
|
280
|
+
@staticmethod
|
281
|
+
def validate_model_name(name: str) -> str:
|
282
|
+
"""
|
283
|
+
Validate registered model name.
|
284
|
+
|
285
|
+
Args:
|
286
|
+
name: Model name to validate
|
287
|
+
|
288
|
+
Returns:
|
289
|
+
Validated name
|
290
|
+
"""
|
291
|
+
if not name or not isinstance(name, str):
|
292
|
+
raise SecurityValidationError("Model name must be a non-empty string")
|
293
|
+
|
294
|
+
if len(name) > InputValidator.MAX_NAME_LENGTH:
|
295
|
+
raise SecurityValidationError(
|
296
|
+
f"Model name too long (max {InputValidator.MAX_NAME_LENGTH} chars)"
|
297
|
+
)
|
298
|
+
|
299
|
+
# Model names should be safe for file systems and URLs
|
300
|
+
if not re.match(r'^[a-zA-Z0-9_\-\.]+$', name):
|
301
|
+
raise SecurityValidationError(
|
302
|
+
"Model name contains invalid characters. "
|
303
|
+
"Only alphanumeric, dash, underscore, and dot allowed."
|
304
|
+
)
|
305
|
+
|
306
|
+
# Prevent directory traversal
|
307
|
+
if '..' in name:
|
308
|
+
raise SecurityValidationError("Model name cannot contain '..'")
|
309
|
+
|
310
|
+
return name
|
311
|
+
|
312
|
+
@staticmethod
|
313
|
+
def validate_uri(uri: str, allowed_schemes: Optional[set] = None) -> str:
|
314
|
+
"""
|
315
|
+
Validate URI for safety.
|
316
|
+
|
317
|
+
Args:
|
318
|
+
uri: URI to validate
|
319
|
+
allowed_schemes: Set of allowed URI schemes
|
320
|
+
|
321
|
+
Returns:
|
322
|
+
Validated URI
|
323
|
+
"""
|
324
|
+
if not uri or not isinstance(uri, str):
|
325
|
+
raise SecurityValidationError("URI must be a non-empty string")
|
326
|
+
|
327
|
+
if allowed_schemes is None:
|
328
|
+
allowed_schemes = {'http', 'https', 'file', 's3', 'gs', 'azure'}
|
329
|
+
|
330
|
+
try:
|
331
|
+
parsed = urlparse(uri)
|
332
|
+
except Exception as e:
|
333
|
+
raise SecurityValidationError(f"Invalid URI format: {e}")
|
334
|
+
|
335
|
+
if parsed.scheme and parsed.scheme not in allowed_schemes:
|
336
|
+
raise SecurityValidationError(
|
337
|
+
f"URI scheme '{parsed.scheme}' not allowed. "
|
338
|
+
f"Allowed schemes: {sorted(allowed_schemes)}"
|
339
|
+
)
|
340
|
+
|
341
|
+
# Check for potential SSRF attacks
|
342
|
+
if parsed.hostname:
|
343
|
+
# Block private/local addresses for HTTP schemes
|
344
|
+
if parsed.scheme in ('http', 'https'):
|
345
|
+
if parsed.hostname.lower() in ('localhost', '127.0.0.1', '0.0.0.0'):
|
346
|
+
raise SecurityValidationError("URI points to localhost/loopback address")
|
347
|
+
|
348
|
+
# Block private IP ranges (basic check)
|
349
|
+
if (parsed.hostname.startswith('192.168.') or
|
350
|
+
parsed.hostname.startswith('10.') or
|
351
|
+
parsed.hostname.startswith('172.')):
|
352
|
+
raise SecurityValidationError("URI points to private IP address")
|
353
|
+
|
354
|
+
return uri
|
355
|
+
|
356
|
+
def secure_filename(filename: str) -> str:
|
357
|
+
"""
|
358
|
+
Secure a filename by removing/replacing dangerous characters.
|
359
|
+
|
360
|
+
Args:
|
361
|
+
filename: Original filename
|
362
|
+
|
363
|
+
Returns:
|
364
|
+
Secured filename
|
365
|
+
"""
|
366
|
+
if not filename:
|
367
|
+
raise SecurityValidationError("Filename cannot be empty")
|
368
|
+
|
369
|
+
# Remove path components
|
370
|
+
filename = os.path.basename(filename)
|
371
|
+
|
372
|
+
# Replace dangerous characters
|
373
|
+
filename = re.sub(r'[^\w\-_\.]', '_', filename)
|
374
|
+
|
375
|
+
# Ensure it doesn't start with dot (hidden file)
|
376
|
+
if filename.startswith('.'):
|
377
|
+
filename = '_' + filename[1:]
|
378
|
+
|
379
|
+
# Ensure reasonable length
|
380
|
+
if len(filename) > 255:
|
381
|
+
name, ext = os.path.splitext(filename)
|
382
|
+
filename = name[:251-len(ext)] + ext
|
383
|
+
|
384
|
+
return filename
|
@@ -0,0 +1,61 @@
|
|
1
|
+
"""
|
2
|
+
Utilities for MLflow cli server config validation and resolving.
|
3
|
+
NOTE: these functions are intended to be used as utilities for the cli click-based interface.
|
4
|
+
Do not use for any other purpose as the potential Exceptions being raised will be misleading
|
5
|
+
for users.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import click
|
9
|
+
|
10
|
+
from mlflow.store.tracking import DEFAULT_ARTIFACTS_URI, DEFAULT_LOCAL_FILE_AND_ARTIFACT_PATH
|
11
|
+
from mlflow.utils.logging_utils import eprint
|
12
|
+
from mlflow.utils.uri import is_local_uri
|
13
|
+
|
14
|
+
|
15
|
+
def resolve_default_artifact_root(
|
16
|
+
serve_artifacts: bool,
|
17
|
+
default_artifact_root: str,
|
18
|
+
backend_store_uri: str,
|
19
|
+
resolve_to_local: bool = False,
|
20
|
+
) -> str:
|
21
|
+
if serve_artifacts and not default_artifact_root:
|
22
|
+
default_artifact_root = DEFAULT_ARTIFACTS_URI
|
23
|
+
elif not serve_artifacts and not default_artifact_root:
|
24
|
+
if is_local_uri(backend_store_uri):
|
25
|
+
default_artifact_root = backend_store_uri
|
26
|
+
elif resolve_to_local:
|
27
|
+
default_artifact_root = DEFAULT_LOCAL_FILE_AND_ARTIFACT_PATH
|
28
|
+
else:
|
29
|
+
msg = (
|
30
|
+
"Option 'default-artifact-root' is required when backend store is not "
|
31
|
+
"local file based and artifact serving is disabled."
|
32
|
+
)
|
33
|
+
eprint(msg)
|
34
|
+
raise click.UsageError(message=msg)
|
35
|
+
return default_artifact_root
|
36
|
+
|
37
|
+
|
38
|
+
def _is_default_backend_store_uri(backend_store_uri: str) -> bool:
|
39
|
+
"""Utility function to validate if the configured backend store uri location is set as the
|
40
|
+
default value for MLflow server.
|
41
|
+
|
42
|
+
Args:
|
43
|
+
backend_store_uri: The value set for the backend store uri for MLflow server artifact
|
44
|
+
handling.
|
45
|
+
|
46
|
+
Returns:
|
47
|
+
bool True if the default value is set.
|
48
|
+
|
49
|
+
"""
|
50
|
+
return backend_store_uri == DEFAULT_LOCAL_FILE_AND_ARTIFACT_PATH
|
51
|
+
|
52
|
+
|
53
|
+
def artifacts_only_config_validation(artifacts_only: bool, backend_store_uri: str) -> None:
|
54
|
+
if artifacts_only and not _is_default_backend_store_uri(backend_store_uri):
|
55
|
+
msg = (
|
56
|
+
"You are starting a tracking server in `--artifacts-only` mode and have provided a "
|
57
|
+
f"value for `--backend_store_uri`: '{backend_store_uri}'. A tracking server in "
|
58
|
+
"`--artifacts-only` mode cannot have a value set for `--backend_store_uri` to "
|
59
|
+
"properly proxy access to the artifact storage location."
|
60
|
+
)
|
61
|
+
raise click.UsageError(message=msg)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
def is_spark_connect_mode():
|
2
|
+
try:
|
3
|
+
from pyspark.sql.utils import is_remote
|
4
|
+
except ImportError:
|
5
|
+
return False
|
6
|
+
return is_remote()
|
7
|
+
|
8
|
+
|
9
|
+
def get_spark_dataframe_type():
|
10
|
+
if is_spark_connect_mode():
|
11
|
+
from pyspark.sql.connect.dataframe import DataFrame as SparkDataFrame
|
12
|
+
else:
|
13
|
+
from pyspark.sql import DataFrame as SparkDataFrame
|
14
|
+
|
15
|
+
return SparkDataFrame
|