prefect-client 3.6.28.dev1__tar.gz → 3.6.28.dev3__tar.gz
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.
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/PKG-INFO +1 -1
- prefect_client-3.6.28.dev3/src/prefect/_build_info.py +5 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/bundles/__init__.py +44 -31
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/bundles/execute.py +1 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/blocks/notifications.py +19 -7
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/blocks/webhook.py +16 -4
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/_version_checking.py +1 -1
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/AGENTS.md +5 -1
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/task_runners.py +11 -3
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/urls.py +230 -8
- prefect_client-3.6.28.dev1/src/prefect/_build_info.py +0 -5
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/.gitignore +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/LICENSE +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/README.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/pyproject.toml +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/.prefectignore +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/__main__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/_launchers.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/bundles/_file_collector.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/bundles/_ignore_filter.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/bundles/_path_resolver.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/bundles/_zip_builder.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/bundles/_zip_extractor.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/plugins/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/plugins/apply.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/plugins/diagnostics.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/plugins/manager.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/plugins/spec.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/sla/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/sla/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/sla/objects.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/_logging.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/ci_detection.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/device_id.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/emit.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/enabled.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/events.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/milestones.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/notice.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/service.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/compatibility/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/compatibility/async_dispatch.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/compatibility/backports.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/compatibility/blocks.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/compatibility/deprecated.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/compatibility/migration.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/compatibility/starlette.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/concurrency/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/concurrency/api.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/concurrency/calls.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/concurrency/cancellation.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/concurrency/event_loop.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/concurrency/inspection.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/concurrency/primitives.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/concurrency/services.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/concurrency/threads.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/concurrency/waiters.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/control_listener.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/installation.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/integrations.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/lazy.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/observability.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/pydantic/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/pydantic/schemas.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/pydantic/v1_schema.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/pydantic/v2_schema.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/pydantic/validated_func.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/pytz.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/retries.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/schemas/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/schemas/bases.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/schemas/fields.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/schemas/serializers.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/schemas/validators.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/send_entrypoint_logs.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/testing.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/urls.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/uuid7.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/websockets.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_observers.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_result_records.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_sdk/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_sdk/fetcher.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_sdk/generator.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_sdk/models.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_sdk/naming.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_sdk/renderer.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_sdk/schema_converter.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_sdk/templates/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_sdk/templates/sdk.py.jinja +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_sdk/types.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_sdk/unions.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_states.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_vendor/croniter/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_vendor/croniter/croniter.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_versioning.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_waiters.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/agent.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/analytics/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/artifacts.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/assets/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/assets/core.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/assets/materialize.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/automations.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/blocks/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/blocks/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/blocks/abstract.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/blocks/core.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/blocks/fields.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/blocks/redis.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/blocks/system.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/cache_policies.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/attribution.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/base.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/cloud.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/collections.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/constants.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_artifacts/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_artifacts/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_automations/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_automations/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_blocks_documents/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_blocks_documents/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_blocks_schemas/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_blocks_schemas/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_blocks_types/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_blocks_types/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_concurrency_limits/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_concurrency_limits/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_deployments/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_deployments/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_events/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_events/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_flow_runs/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_flow_runs/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_flows/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_flows/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_logs/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_logs/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_variables/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_variables/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_work_pools/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/_work_pools/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/base.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/orchestration/routes.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/schemas/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/schemas/actions.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/schemas/events.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/schemas/filters.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/schemas/objects.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/schemas/responses.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/schemas/schedules.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/schemas/sorting.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/subscriptions.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/types/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/types/flexible_schedule_list.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/utilities.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/_asyncio.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/_events.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/_leases.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/_sync.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/asyncio.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/context.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/services.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/sync.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/v1/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/v1/_asyncio.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/v1/_events.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/v1/asyncio.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/v1/context.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/v1/services.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/concurrency/v1/sync.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/context.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/deployments/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/deployments/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/deployments/base.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/deployments/deployments.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/deployments/flow_runs.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/deployments/runner.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/deployments/schedules.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/deployments/steps/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/deployments/steps/core.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/deployments/steps/pull.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/deployments/steps/utility.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/docker/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/docker/_buildx.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/docker/docker_image.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/engine.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/actions.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/clients.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/filters.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/related.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/schemas/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/schemas/automations.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/schemas/deployment_triggers.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/schemas/events.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/schemas/labelling.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/subscribers.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/utilities.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/events/worker.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/exceptions.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/filesystems.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/flow_engine.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/flow_runs.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/flows.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/futures.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/infrastructure/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/infrastructure/base.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/infrastructure/provisioners/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/infrastructure/provisioners/cloud_run.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/infrastructure/provisioners/coiled.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/infrastructure/provisioners/container_instance.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/infrastructure/provisioners/ecs.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/infrastructure/provisioners/modal.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/input/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/input/actions.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/input/run_input.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/locking/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/locking/filesystem.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/locking/memory.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/locking/protocol.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/logging/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/logging/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/logging/clients.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/logging/configuration.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/logging/filters.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/logging/formatters.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/logging/handlers.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/logging/highlighters.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/logging/loggers.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/logging/logging.yml +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/main.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/plugins.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/py.typed +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/results.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_cancel_finalizer.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_cancellation_manager.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_control_channel.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_deployment_registry.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_event_emitter.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_flow_resolver.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_flow_run_executor.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_hook_runner.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_limit_manager.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_process_manager.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_scheduled_run_poller.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_starter_bundle.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_starter_direct.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_starter_engine.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/_state_proposer.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/runner.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/server.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runner/storage.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runtime/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runtime/deployment.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runtime/flow_run.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/runtime/task_run.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/schedules.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/serializers.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/admin.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/artifacts.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/automations.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/background_workers.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/block_capabilities.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/block_documents.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/block_schemas.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/block_types.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/clients.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/collections.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/collections_data/views/aggregate-worker-metadata.json +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/concurrency_limits.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/concurrency_limits_v2.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/csrf_token.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/dependencies.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/deployments.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/events.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/flow_run_states.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/flow_runs.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/flows.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/logs.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/middleware.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/root.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/run_history.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/saved_searches.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/server.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/static/prefect-logo-mark-gradient.png +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/task_run_states.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/task_runs.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/task_workers.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/templates.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/ui/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/ui/flow_runs.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/ui/flows.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/ui/schemas.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/ui/task_runs.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/validation.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/variables.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/work_queues.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/server/api/workers.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/base.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/constants.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/context.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/legacy.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/_defaults.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/api.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/cli.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/client.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/cloud.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/deployments.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/events.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/experiments.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/flows.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/internal.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/logging.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/results.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/root.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/runner.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/api.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/concurrency.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/database.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/deployments.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/docket.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/ephemeral.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/events.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/flow_run_graph.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/logs.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/root.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/services.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/tasks.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/server/ui.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/tasks.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/telemetry.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/testing.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/models/worker.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/profiles.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/profiles.toml +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/settings/sources.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/states.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/task_engine.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/task_runs.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/task_worker.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/tasks.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/telemetry/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/telemetry/_metrics.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/telemetry/run_telemetry.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/transactions.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/types/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/types/_concurrency.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/types/_datetime.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/types/_schema.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/types/entrypoint.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/types/names.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/_ast.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/_deprecated.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/_engine.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/_git.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/_infrastructure_exit_codes.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/annotations.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/asyncutils/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/asyncutils/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/callables/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/callables/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/collections.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/compat.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/context.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/dispatch.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/dockerutils.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/engine/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/engine/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/filesystem/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/filesystem/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/generics.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/hashing.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/importtools.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/math.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/names.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/processutils/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/processutils/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/pydantic.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/render_swagger.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/schema_tools/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/schema_tools/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/schema_tools/hydration.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/schema_tools/validation.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/services.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/slugify.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/templating/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/templating/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/text.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/timeout.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/utilities/visualization.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/variables.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/workers/AGENTS.md +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/workers/__init__.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/workers/base.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/workers/block.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/workers/cloud.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/workers/process.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/workers/server.py +0 -0
- {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/workers/utilities.py +0 -0
|
@@ -36,7 +36,10 @@ from prefect.settings.models.root import Settings
|
|
|
36
36
|
from prefect.utilities.processutils import sanitize_subprocess_env
|
|
37
37
|
from prefect.utilities.slugify import slugify
|
|
38
38
|
|
|
39
|
-
from prefect._experimental._launchers import
|
|
39
|
+
from prefect._experimental._launchers import (
|
|
40
|
+
get_launcher_for_side,
|
|
41
|
+
validate_bundle_step_launcher,
|
|
42
|
+
)
|
|
40
43
|
|
|
41
44
|
from .execute import execute_bundle_from_file
|
|
42
45
|
from ._file_collector import FileCollector
|
|
@@ -411,38 +414,48 @@ def create_bundle_for_flow_run(
|
|
|
411
414
|
"""
|
|
412
415
|
context = context or serialize_context()
|
|
413
416
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
417
|
+
# Skip `uv pip freeze` when the execution side of the flow's launcher
|
|
418
|
+
# opts out of uv-based launchers. The `dependencies` field is only
|
|
419
|
+
# consumed by `execute_bundle_in_subprocess` (which uses `uv pip install`);
|
|
420
|
+
# custom execution launchers are responsible for their own environment.
|
|
421
|
+
# Upload-only launcher overrides still use `uv run` at execution time and
|
|
422
|
+
# therefore still need the dependency snapshot.
|
|
423
|
+
flow_launcher = getattr(flow, "launcher", None)
|
|
424
|
+
if get_launcher_for_side(flow_launcher, "execution") is None:
|
|
425
|
+
dependencies = (
|
|
426
|
+
subprocess.check_output(
|
|
427
|
+
[
|
|
428
|
+
_get_uv_path(),
|
|
429
|
+
"pip",
|
|
430
|
+
"freeze",
|
|
431
|
+
# Exclude editable installs because we won't be able to install them in the execution environment
|
|
432
|
+
"--exclude-editable",
|
|
433
|
+
]
|
|
434
|
+
)
|
|
435
|
+
.decode()
|
|
436
|
+
.strip()
|
|
423
437
|
)
|
|
424
|
-
.decode()
|
|
425
|
-
.strip()
|
|
426
|
-
)
|
|
427
438
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
439
|
+
# Remove dependencies installed from a local file path because we won't be able
|
|
440
|
+
# to install them in the execution environment. The user will be responsible for
|
|
441
|
+
# making sure they are available in the execution environment
|
|
442
|
+
filtered_dependencies: list[str] = []
|
|
443
|
+
file_dependencies: list[str] = []
|
|
444
|
+
for line in dependencies.split("\n"):
|
|
445
|
+
if "file://" in line:
|
|
446
|
+
file_dependencies.append(line)
|
|
447
|
+
else:
|
|
448
|
+
filtered_dependencies.append(line)
|
|
449
|
+
dependencies = "\n".join(filtered_dependencies)
|
|
450
|
+
if file_dependencies:
|
|
451
|
+
logger.warning(
|
|
452
|
+
"The following dependencies were installed from a local file path and will not be "
|
|
453
|
+
"automatically installed in the execution environment: %s. If these dependencies "
|
|
454
|
+
"are not available in the execution environment, your flow run may fail.",
|
|
455
|
+
"\n".join(file_dependencies),
|
|
456
|
+
)
|
|
457
|
+
else:
|
|
458
|
+
dependencies = ""
|
|
446
459
|
|
|
447
460
|
# Collect and package included files if specified
|
|
448
461
|
files_key: str | None = None
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/blocks/notifications.py
RENAMED
|
@@ -13,7 +13,11 @@ from prefect.blocks.abstract import NotificationBlock, NotificationError
|
|
|
13
13
|
from prefect.logging import LogEavesdropper
|
|
14
14
|
from prefect.types import SecretDict
|
|
15
15
|
from prefect.utilities.templating import apply_values, find_placeholders
|
|
16
|
-
from prefect.utilities.urls import
|
|
16
|
+
from prefect.utilities.urls import (
|
|
17
|
+
SSRFProtectedAsyncHTTPTransport,
|
|
18
|
+
SSRFProtectedHTTPTransport,
|
|
19
|
+
validate_restricted_url,
|
|
20
|
+
)
|
|
17
21
|
|
|
18
22
|
PREFECT_NOTIFY_TYPE_DEFAULT = "info" # Use a valid apprise type as default
|
|
19
23
|
|
|
@@ -987,13 +991,18 @@ class CustomWebhookNotificationBlock(NotificationBlock):
|
|
|
987
991
|
import httpx
|
|
988
992
|
|
|
989
993
|
request_args = self._build_request_args(body, subject)
|
|
994
|
+
client_kwargs: dict[str, Any] = {
|
|
995
|
+
"headers": {"user-agent": "Prefect Notifications"},
|
|
996
|
+
}
|
|
990
997
|
if not self.allow_private_urls:
|
|
991
998
|
validate_restricted_url(request_args["url"])
|
|
999
|
+
# Re-validate at connection time and pin the resolved IP to close
|
|
1000
|
+
# the DNS-rebinding TOCTOU window.
|
|
1001
|
+
client_kwargs["transport"] = SSRFProtectedAsyncHTTPTransport()
|
|
992
1002
|
cookies = request_args.pop("cookies", dict())
|
|
1003
|
+
client_kwargs["cookies"] = cookies
|
|
993
1004
|
# make request with httpx
|
|
994
|
-
async with httpx.AsyncClient(
|
|
995
|
-
headers={"user-agent": "Prefect Notifications"}, cookies=cookies
|
|
996
|
-
) as client:
|
|
1005
|
+
async with httpx.AsyncClient(**client_kwargs) as client:
|
|
997
1006
|
resp = await client.request(**request_args)
|
|
998
1007
|
resp.raise_for_status()
|
|
999
1008
|
|
|
@@ -1002,13 +1011,16 @@ class CustomWebhookNotificationBlock(NotificationBlock):
|
|
|
1002
1011
|
import httpx
|
|
1003
1012
|
|
|
1004
1013
|
request_args = self._build_request_args(body, subject)
|
|
1014
|
+
client_kwargs: dict[str, Any] = {
|
|
1015
|
+
"headers": {"user-agent": "Prefect Notifications"},
|
|
1016
|
+
}
|
|
1005
1017
|
if not self.allow_private_urls:
|
|
1006
1018
|
validate_restricted_url(request_args["url"])
|
|
1019
|
+
client_kwargs["transport"] = SSRFProtectedHTTPTransport()
|
|
1007
1020
|
cookies = request_args.pop("cookies", dict())
|
|
1021
|
+
client_kwargs["cookies"] = cookies
|
|
1008
1022
|
# make request with httpx
|
|
1009
|
-
with httpx.Client(
|
|
1010
|
-
headers={"user-agent": "Prefect Notifications"}, cookies=cookies
|
|
1011
|
-
) as client:
|
|
1023
|
+
with httpx.Client(**client_kwargs) as client:
|
|
1012
1024
|
resp = client.request(**request_args)
|
|
1013
1025
|
resp.raise_for_status()
|
|
1014
1026
|
|
|
@@ -8,12 +8,21 @@ from typing_extensions import Literal
|
|
|
8
8
|
|
|
9
9
|
from prefect.blocks.core import Block
|
|
10
10
|
from prefect.types import SecretDict
|
|
11
|
-
from prefect.utilities.urls import
|
|
11
|
+
from prefect.utilities.urls import (
|
|
12
|
+
SSRFProtectedAsyncHTTPTransport,
|
|
13
|
+
validate_restricted_url,
|
|
14
|
+
)
|
|
12
15
|
|
|
13
16
|
# Use a global HTTP transport to maintain a process-wide connection pool for
|
|
14
17
|
# interservice requests
|
|
15
18
|
_http_transport = AsyncHTTPTransport()
|
|
16
19
|
_insecure_http_transport = AsyncHTTPTransport(verify=False)
|
|
20
|
+
# Separate pools for calls that must be protected from DNS-rebinding SSRF. The
|
|
21
|
+
# protected transport validates the resolved IP at connection time and connects
|
|
22
|
+
# to the pre-resolved address, closing the TOCTOU window exploited by DNS
|
|
23
|
+
# rebinding attacks.
|
|
24
|
+
_safe_http_transport = SSRFProtectedAsyncHTTPTransport()
|
|
25
|
+
_safe_insecure_http_transport = SSRFProtectedAsyncHTTPTransport(verify=False)
|
|
17
26
|
|
|
18
27
|
|
|
19
28
|
class Webhook(Block):
|
|
@@ -53,10 +62,13 @@ class Webhook(Block):
|
|
|
53
62
|
)
|
|
54
63
|
|
|
55
64
|
def block_initialization(self) -> None:
|
|
56
|
-
if self.
|
|
57
|
-
self.
|
|
65
|
+
if self.allow_private_urls:
|
|
66
|
+
transport = _http_transport if self.verify else _insecure_http_transport
|
|
58
67
|
else:
|
|
59
|
-
|
|
68
|
+
transport = (
|
|
69
|
+
_safe_http_transport if self.verify else _safe_insecure_http_transport
|
|
70
|
+
)
|
|
71
|
+
self._client = AsyncClient(transport=transport)
|
|
60
72
|
|
|
61
73
|
async def call(self, payload: dict[str, Any] | str | None = None) -> Response:
|
|
62
74
|
"""
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/client/_version_checking.py
RENAMED
|
@@ -142,7 +142,7 @@ async def check_server_version(
|
|
|
142
142
|
if auth_string:
|
|
143
143
|
token = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8")
|
|
144
144
|
headers["Authorization"] = f"Basic {token}"
|
|
145
|
-
elif api_key:
|
|
145
|
+
elif api_key and "Authorization" not in headers:
|
|
146
146
|
headers["Authorization"] = f"Bearer {api_key}"
|
|
147
147
|
if headers:
|
|
148
148
|
httpx_kwargs["headers"] = headers
|
|
@@ -96,7 +96,11 @@ Each execution mode has a ProcessStarter implementation. To add a new execution
|
|
|
96
96
|
|
|
97
97
|
`ScheduledRunPoller` now calls `propose_pending` (Scheduled → Pending) before handing off to `FlowRunExecutor`. `FlowRunExecutor` then calls `propose_submitting` (Pending → Submitting sub-state) as step 1 of its lifecycle **when `propose_submitting=True` (the default)**. These are two separate transitions — do not collapse them. The split exists so automations listening for the Pending state fire correctly before the executor begins.
|
|
98
98
|
|
|
99
|
-
**
|
|
99
|
+
**Two callers set `propose_submitting=False`** via `FlowRunExecutorContext.create_executor(propose_submitting=False)` — both have already advanced the flow run past the Pending state, so proposing Submitting again would be wrong:
|
|
100
|
+
- `prefect flow-run execute` CLI path (invoked by a worker)
|
|
101
|
+
- `execute_bundle()` in `prefect._experimental.bundles.execute` (invoked by bundle dispatch)
|
|
102
|
+
|
|
103
|
+
The cancelling precheck (step 1a) still runs unconditionally even when `propose_submitting=False`.
|
|
100
104
|
|
|
101
105
|
## ProcessWorker Migration (Known Gap)
|
|
102
106
|
|
|
@@ -616,14 +616,19 @@ class _UnpicklingFuture(concurrent.futures.Future[R]):
|
|
|
616
616
|
|
|
617
617
|
def __init__(self, wrapped_future: concurrent.futures.Future[bytes]):
|
|
618
618
|
self.wrapped_future = wrapped_future
|
|
619
|
+
self._deserialization_error: BaseException | None = None
|
|
619
620
|
|
|
620
621
|
def result(self, timeout: float | None = None) -> R:
|
|
622
|
+
if self._deserialization_error is not None:
|
|
623
|
+
raise self._deserialization_error
|
|
621
624
|
pickled_result = self.wrapped_future.result(timeout)
|
|
622
625
|
import cloudpickle
|
|
623
626
|
|
|
624
627
|
return cloudpickle.loads(pickled_result)
|
|
625
628
|
|
|
626
629
|
def exception(self, timeout: float | None = None) -> BaseException | None:
|
|
630
|
+
if self._deserialization_error is not None:
|
|
631
|
+
return self._deserialization_error
|
|
627
632
|
return self.wrapped_future.exception(timeout)
|
|
628
633
|
|
|
629
634
|
def done(self) -> bool:
|
|
@@ -639,10 +644,13 @@ class _UnpicklingFuture(concurrent.futures.Future[R]):
|
|
|
639
644
|
self, fn: Callable[[concurrent.futures.Future[R]], object]
|
|
640
645
|
) -> None:
|
|
641
646
|
def _fn(wrapped_future: concurrent.futures.Future[bytes]) -> None:
|
|
642
|
-
|
|
647
|
+
try:
|
|
648
|
+
import cloudpickle
|
|
643
649
|
|
|
644
|
-
|
|
645
|
-
|
|
650
|
+
cloudpickle.loads(wrapped_future.result())
|
|
651
|
+
except Exception as e:
|
|
652
|
+
self._deserialization_error = e
|
|
653
|
+
fn(self)
|
|
646
654
|
|
|
647
655
|
return self.wrapped_future.add_done_callback(_fn)
|
|
648
656
|
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
import ipaddress
|
|
3
3
|
import socket
|
|
4
|
+
import time
|
|
4
5
|
import urllib.parse
|
|
6
|
+
from collections.abc import Iterable
|
|
5
7
|
from logging import Logger
|
|
6
8
|
from string import Formatter
|
|
7
9
|
from typing import TYPE_CHECKING, Any, Literal, Optional, Union, cast
|
|
8
10
|
from urllib.parse import urlparse
|
|
9
11
|
from uuid import UUID
|
|
10
12
|
|
|
13
|
+
import anyio.to_thread
|
|
14
|
+
import httpcore
|
|
15
|
+
import httpx
|
|
11
16
|
from pydantic import BaseModel
|
|
12
17
|
|
|
13
18
|
from prefect import settings
|
|
@@ -71,7 +76,14 @@ def validate_restricted_url(url: str) -> None:
|
|
|
71
76
|
Validate that the provided URL is safe for outbound requests. This prevents
|
|
72
77
|
attacks like SSRF (Server Side Request Forgery), where an attacker can make
|
|
73
78
|
requests to internal services (like the GCP metadata service, localhost addresses,
|
|
74
|
-
or in-cluster Kubernetes services)
|
|
79
|
+
or in-cluster Kubernetes services).
|
|
80
|
+
|
|
81
|
+
This is a pre-flight check that validates every address the hostname resolves
|
|
82
|
+
to via `getaddrinfo`. Because DNS can change between this check and the
|
|
83
|
+
actual HTTP connection, callers that need hardened SSRF protection should
|
|
84
|
+
also use `SSRFProtectedAsyncHTTPTransport` / `SSRFProtectedHTTPTransport`,
|
|
85
|
+
which re-validate at connection time and connect to the pre-resolved IP to
|
|
86
|
+
close the TOCTOU window exploited by DNS rebinding attacks.
|
|
75
87
|
|
|
76
88
|
Args:
|
|
77
89
|
url: The URL to validate.
|
|
@@ -100,17 +112,227 @@ def validate_restricted_url(url: str) -> None:
|
|
|
100
112
|
raise ValueError(f"{url!r} is not a valid URL.")
|
|
101
113
|
|
|
102
114
|
try:
|
|
103
|
-
|
|
104
|
-
|
|
115
|
+
_validate_resolved_hostname(hostname)
|
|
116
|
+
except _RestrictedHostError as exc:
|
|
117
|
+
raise ValueError(f"{url!r} is not a valid URL. {exc}")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class _RestrictedHostError(Exception):
|
|
121
|
+
"""Internal exception raised when a hostname resolves to a restricted address."""
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _validate_resolved_hostname(hostname: str) -> list[str]:
|
|
125
|
+
"""Resolve `hostname` and validate every returned address.
|
|
126
|
+
|
|
127
|
+
Returns the list of resolved IPs (as strings) in resolution order. Raises
|
|
128
|
+
`_RestrictedHostError` if any resolved address is private, or if the
|
|
129
|
+
hostname cannot be resolved.
|
|
130
|
+
|
|
131
|
+
Using `getaddrinfo` (rather than `gethostbyname`, which returns only the
|
|
132
|
+
first A record) closes an SSRF bypass where a hostname publishes both a
|
|
133
|
+
public and a private A/AAAA record: every resolved address is checked.
|
|
134
|
+
"""
|
|
135
|
+
# IP literal: validate directly.
|
|
136
|
+
try:
|
|
137
|
+
ip = ipaddress.ip_address(hostname)
|
|
138
|
+
except ValueError:
|
|
139
|
+
pass
|
|
140
|
+
else:
|
|
141
|
+
if ip.is_private:
|
|
142
|
+
raise _RestrictedHostError(f"It resolves to the private address {ip}.")
|
|
143
|
+
return [str(ip)]
|
|
144
|
+
|
|
145
|
+
try:
|
|
146
|
+
addrinfos = socket.getaddrinfo(hostname, None, type=socket.SOCK_STREAM)
|
|
105
147
|
except socket.gaierror:
|
|
148
|
+
raise _RestrictedHostError("It could not be resolved.")
|
|
149
|
+
|
|
150
|
+
resolved: list[str] = []
|
|
151
|
+
for addrinfo in addrinfos:
|
|
152
|
+
sockaddr = addrinfo[4]
|
|
153
|
+
ip_str = sockaddr[0]
|
|
154
|
+
# Strip IPv6 zone identifier if present (e.g. "fe80::1%eth0")
|
|
155
|
+
ip_str = ip_str.split("%", 1)[0]
|
|
106
156
|
try:
|
|
107
|
-
ip = ipaddress.ip_address(
|
|
157
|
+
ip = ipaddress.ip_address(ip_str)
|
|
108
158
|
except ValueError:
|
|
109
|
-
|
|
159
|
+
continue
|
|
160
|
+
if ip.is_private:
|
|
161
|
+
raise _RestrictedHostError(f"It resolves to the private address {ip}.")
|
|
162
|
+
if ip_str not in resolved:
|
|
163
|
+
resolved.append(ip_str)
|
|
110
164
|
|
|
111
|
-
if
|
|
112
|
-
raise
|
|
113
|
-
|
|
165
|
+
if not resolved:
|
|
166
|
+
raise _RestrictedHostError("It could not be resolved.")
|
|
167
|
+
|
|
168
|
+
return resolved
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class _SSRFProtectedAsyncBackend(httpcore.AsyncNetworkBackend):
|
|
172
|
+
"""An `httpcore.AsyncNetworkBackend` that validates resolved addresses.
|
|
173
|
+
|
|
174
|
+
Wraps an existing backend and, on each `connect_tcp` call, resolves the
|
|
175
|
+
hostname itself, rejects any resolved address that is private, and then
|
|
176
|
+
connects to the validated IP directly (rather than the hostname) so that
|
|
177
|
+
the underlying backend cannot re-resolve to a different address.
|
|
178
|
+
|
|
179
|
+
TLS SNI / certificate validation is unaffected because httpcore passes the
|
|
180
|
+
original hostname to `start_tls` via `server_hostname`, independently of
|
|
181
|
+
the host used for the TCP connection.
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
def __init__(self, wrapped: httpcore.AsyncNetworkBackend) -> None:
|
|
185
|
+
self._wrapped = wrapped
|
|
186
|
+
|
|
187
|
+
async def connect_tcp(
|
|
188
|
+
self,
|
|
189
|
+
host: str,
|
|
190
|
+
port: int,
|
|
191
|
+
timeout: Optional[float] = None,
|
|
192
|
+
local_address: Optional[str] = None,
|
|
193
|
+
socket_options: Optional[Iterable[Any]] = None,
|
|
194
|
+
) -> httpcore.AsyncNetworkStream:
|
|
195
|
+
# Resolve in a worker thread so the event loop is not blocked during
|
|
196
|
+
# DNS lookups (which can be slow or intermittently failing).
|
|
197
|
+
validated_ips = await anyio.to_thread.run_sync(
|
|
198
|
+
_resolve_and_validate_for_connect, host
|
|
199
|
+
)
|
|
200
|
+
last_exc: Optional[BaseException] = None
|
|
201
|
+
deadline = time.monotonic() + timeout if timeout is not None else None
|
|
202
|
+
for ip in validated_ips:
|
|
203
|
+
remaining = _remaining_timeout(deadline)
|
|
204
|
+
if remaining == 0.0:
|
|
205
|
+
break
|
|
206
|
+
try:
|
|
207
|
+
return await self._wrapped.connect_tcp(
|
|
208
|
+
ip,
|
|
209
|
+
port,
|
|
210
|
+
timeout=remaining,
|
|
211
|
+
local_address=local_address,
|
|
212
|
+
socket_options=socket_options,
|
|
213
|
+
)
|
|
214
|
+
except (httpcore.ConnectError, httpcore.ConnectTimeout, OSError) as exc:
|
|
215
|
+
last_exc = exc
|
|
216
|
+
assert last_exc is not None
|
|
217
|
+
raise last_exc
|
|
218
|
+
|
|
219
|
+
async def connect_unix_socket(
|
|
220
|
+
self,
|
|
221
|
+
path: str,
|
|
222
|
+
timeout: Optional[float] = None,
|
|
223
|
+
socket_options: Optional[Iterable[Any]] = None,
|
|
224
|
+
) -> httpcore.AsyncNetworkStream:
|
|
225
|
+
return await self._wrapped.connect_unix_socket(
|
|
226
|
+
path, timeout=timeout, socket_options=socket_options
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
async def sleep(self, seconds: float) -> None:
|
|
230
|
+
await self._wrapped.sleep(seconds)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class _SSRFProtectedSyncBackend(httpcore.NetworkBackend):
|
|
234
|
+
"""Synchronous counterpart of `_SSRFProtectedAsyncBackend`."""
|
|
235
|
+
|
|
236
|
+
def __init__(self, wrapped: httpcore.NetworkBackend) -> None:
|
|
237
|
+
self._wrapped = wrapped
|
|
238
|
+
|
|
239
|
+
def connect_tcp(
|
|
240
|
+
self,
|
|
241
|
+
host: str,
|
|
242
|
+
port: int,
|
|
243
|
+
timeout: Optional[float] = None,
|
|
244
|
+
local_address: Optional[str] = None,
|
|
245
|
+
socket_options: Optional[Iterable[Any]] = None,
|
|
246
|
+
) -> httpcore.NetworkStream:
|
|
247
|
+
validated_ips = _resolve_and_validate_for_connect(host)
|
|
248
|
+
last_exc: Optional[BaseException] = None
|
|
249
|
+
deadline = time.monotonic() + timeout if timeout is not None else None
|
|
250
|
+
for ip in validated_ips:
|
|
251
|
+
remaining = _remaining_timeout(deadline)
|
|
252
|
+
if remaining == 0.0:
|
|
253
|
+
break
|
|
254
|
+
try:
|
|
255
|
+
return self._wrapped.connect_tcp(
|
|
256
|
+
ip,
|
|
257
|
+
port,
|
|
258
|
+
timeout=remaining,
|
|
259
|
+
local_address=local_address,
|
|
260
|
+
socket_options=socket_options,
|
|
261
|
+
)
|
|
262
|
+
except (httpcore.ConnectError, httpcore.ConnectTimeout, OSError) as exc:
|
|
263
|
+
last_exc = exc
|
|
264
|
+
assert last_exc is not None
|
|
265
|
+
raise last_exc
|
|
266
|
+
|
|
267
|
+
def connect_unix_socket(
|
|
268
|
+
self,
|
|
269
|
+
path: str,
|
|
270
|
+
timeout: Optional[float] = None,
|
|
271
|
+
socket_options: Optional[Iterable[Any]] = None,
|
|
272
|
+
) -> httpcore.NetworkStream:
|
|
273
|
+
return self._wrapped.connect_unix_socket(
|
|
274
|
+
path, timeout=timeout, socket_options=socket_options
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
def sleep(self, seconds: float) -> None:
|
|
278
|
+
self._wrapped.sleep(seconds)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _remaining_timeout(deadline: Optional[float]) -> Optional[float]:
|
|
282
|
+
"""Return the time left until `deadline`, or `None` if no deadline is set.
|
|
283
|
+
|
|
284
|
+
Clamps to `0.0` when the deadline has already passed. Callers use this to
|
|
285
|
+
share a single connect-timeout budget across multiple per-IP retries so
|
|
286
|
+
that connect time stays bounded (roughly) by the caller's timeout rather
|
|
287
|
+
than scaling with the number of resolved addresses.
|
|
288
|
+
"""
|
|
289
|
+
if deadline is None:
|
|
290
|
+
return None
|
|
291
|
+
return max(0.0, deadline - time.monotonic())
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _resolve_and_validate_for_connect(host: str) -> list[str]:
|
|
295
|
+
"""Resolve `host` and return all safe IPs to connect to.
|
|
296
|
+
|
|
297
|
+
Every returned IP has been validated against the private-address blocklist;
|
|
298
|
+
callers iterate them in order and retry on connect failures so that dual-
|
|
299
|
+
stack hostnames still work in single-stack environments.
|
|
300
|
+
|
|
301
|
+
Raises `httpcore.ConnectError` if any resolved address is private or if the
|
|
302
|
+
hostname cannot be resolved. The returned IPs are passed to the underlying
|
|
303
|
+
network backend as IP literals, so it will not perform further DNS
|
|
304
|
+
resolution — eliminating the DNS rebinding TOCTOU window.
|
|
305
|
+
"""
|
|
306
|
+
try:
|
|
307
|
+
return _validate_resolved_hostname(host)
|
|
308
|
+
except _RestrictedHostError as exc:
|
|
309
|
+
raise httpcore.ConnectError(f"Refusing to connect to {host!r}: {exc}") from None
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
class SSRFProtectedAsyncHTTPTransport(httpx.AsyncHTTPTransport):
|
|
313
|
+
"""An `httpx.AsyncHTTPTransport` that guards against DNS rebinding SSRF.
|
|
314
|
+
|
|
315
|
+
Behaves identically to `httpx.AsyncHTTPTransport` except that, for every
|
|
316
|
+
request, the hostname is resolved, every resolved address is checked
|
|
317
|
+
against the private-address blocklist, and the connection is made to the
|
|
318
|
+
specific validated IP. This closes the TOCTOU window between a pre-flight
|
|
319
|
+
`validate_restricted_url` check and the actual HTTP connection.
|
|
320
|
+
"""
|
|
321
|
+
|
|
322
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
323
|
+
super().__init__(*args, **kwargs)
|
|
324
|
+
self._pool._network_backend = _SSRFProtectedAsyncBackend(
|
|
325
|
+
self._pool._network_backend
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class SSRFProtectedHTTPTransport(httpx.HTTPTransport):
|
|
330
|
+
"""Synchronous counterpart of `SSRFProtectedAsyncHTTPTransport`."""
|
|
331
|
+
|
|
332
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
333
|
+
super().__init__(*args, **kwargs)
|
|
334
|
+
self._pool._network_backend = _SSRFProtectedSyncBackend(
|
|
335
|
+
self._pool._network_backend
|
|
114
336
|
)
|
|
115
337
|
|
|
116
338
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/__init__.py
RENAMED
|
File without changes
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/_launchers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/plugins/apply.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/plugins/spec.py
RENAMED
|
File without changes
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/sla/__init__.py
RENAMED
|
File without changes
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/sla/client.py
RENAMED
|
File without changes
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_experimental/sla/objects.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/client.py
RENAMED
|
File without changes
|
|
File without changes
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/emit.py
RENAMED
|
File without changes
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/enabled.py
RENAMED
|
File without changes
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/events.py
RENAMED
|
File without changes
|
|
File without changes
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/notice.py
RENAMED
|
File without changes
|
{prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev3}/src/prefect/_internal/analytics/service.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|