omnibase_infra 0.2.1__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.
- omnibase_infra/__init__.py +101 -0
- omnibase_infra/cli/__init__.py +1 -0
- omnibase_infra/cli/commands.py +216 -0
- omnibase_infra/clients/__init__.py +0 -0
- omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +261 -0
- omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +138 -0
- omnibase_infra/decorators/__init__.py +29 -0
- omnibase_infra/decorators/allow_any.py +109 -0
- omnibase_infra/dlq/__init__.py +90 -0
- omnibase_infra/dlq/constants_dlq.py +57 -0
- omnibase_infra/dlq/models/__init__.py +26 -0
- omnibase_infra/dlq/models/enum_replay_status.py +37 -0
- omnibase_infra/dlq/models/model_dlq_replay_record.py +135 -0
- omnibase_infra/dlq/models/model_dlq_tracking_config.py +184 -0
- omnibase_infra/dlq/service_dlq_tracking.py +611 -0
- omnibase_infra/enums/__init__.py +123 -0
- omnibase_infra/enums/enum_any_type_violation.py +104 -0
- omnibase_infra/enums/enum_backend_type.py +27 -0
- omnibase_infra/enums/enum_capture_outcome.py +42 -0
- omnibase_infra/enums/enum_capture_state.py +88 -0
- omnibase_infra/enums/enum_chain_violation_type.py +119 -0
- omnibase_infra/enums/enum_circuit_state.py +51 -0
- omnibase_infra/enums/enum_confirmation_event_type.py +27 -0
- omnibase_infra/enums/enum_contract_type.py +84 -0
- omnibase_infra/enums/enum_dedupe_strategy.py +46 -0
- omnibase_infra/enums/enum_dispatch_status.py +191 -0
- omnibase_infra/enums/enum_environment.py +46 -0
- omnibase_infra/enums/enum_execution_shape_violation.py +103 -0
- omnibase_infra/enums/enum_handler_error_type.py +101 -0
- omnibase_infra/enums/enum_handler_loader_error.py +178 -0
- omnibase_infra/enums/enum_handler_source_type.py +87 -0
- omnibase_infra/enums/enum_handler_type.py +77 -0
- omnibase_infra/enums/enum_handler_type_category.py +61 -0
- omnibase_infra/enums/enum_infra_transport_type.py +73 -0
- omnibase_infra/enums/enum_introspection_reason.py +154 -0
- omnibase_infra/enums/enum_message_category.py +213 -0
- omnibase_infra/enums/enum_node_archetype.py +74 -0
- omnibase_infra/enums/enum_node_output_type.py +185 -0
- omnibase_infra/enums/enum_non_retryable_error_category.py +224 -0
- omnibase_infra/enums/enum_policy_type.py +32 -0
- omnibase_infra/enums/enum_registration_state.py +261 -0
- omnibase_infra/enums/enum_registration_status.py +33 -0
- omnibase_infra/enums/enum_registry_response_status.py +28 -0
- omnibase_infra/enums/enum_response_status.py +26 -0
- omnibase_infra/enums/enum_retry_error_category.py +98 -0
- omnibase_infra/enums/enum_security_rule_id.py +103 -0
- omnibase_infra/enums/enum_selection_strategy.py +91 -0
- omnibase_infra/enums/enum_topic_standard.py +42 -0
- omnibase_infra/enums/enum_validation_severity.py +78 -0
- omnibase_infra/errors/__init__.py +156 -0
- omnibase_infra/errors/error_architecture_violation.py +152 -0
- omnibase_infra/errors/error_chain_propagation.py +188 -0
- omnibase_infra/errors/error_compute_registry.py +92 -0
- omnibase_infra/errors/error_consul.py +132 -0
- omnibase_infra/errors/error_container_wiring.py +243 -0
- omnibase_infra/errors/error_event_bus_registry.py +102 -0
- omnibase_infra/errors/error_infra.py +608 -0
- omnibase_infra/errors/error_message_type_registry.py +101 -0
- omnibase_infra/errors/error_policy_registry.py +112 -0
- omnibase_infra/errors/error_vault.py +123 -0
- omnibase_infra/event_bus/__init__.py +72 -0
- omnibase_infra/event_bus/configs/kafka_event_bus_config.yaml +86 -0
- omnibase_infra/event_bus/event_bus_inmemory.py +743 -0
- omnibase_infra/event_bus/event_bus_kafka.py +1658 -0
- omnibase_infra/event_bus/mixin_kafka_broadcast.py +184 -0
- omnibase_infra/event_bus/mixin_kafka_dlq.py +765 -0
- omnibase_infra/event_bus/models/__init__.py +29 -0
- omnibase_infra/event_bus/models/config/__init__.py +20 -0
- omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +725 -0
- omnibase_infra/event_bus/models/model_dlq_event.py +206 -0
- omnibase_infra/event_bus/models/model_dlq_metrics.py +304 -0
- omnibase_infra/event_bus/models/model_event_headers.py +115 -0
- omnibase_infra/event_bus/models/model_event_message.py +60 -0
- omnibase_infra/event_bus/topic_constants.py +376 -0
- omnibase_infra/handlers/__init__.py +75 -0
- omnibase_infra/handlers/filesystem/__init__.py +48 -0
- omnibase_infra/handlers/filesystem/enum_file_system_operation.py +35 -0
- omnibase_infra/handlers/filesystem/model_file_system_request.py +298 -0
- omnibase_infra/handlers/filesystem/model_file_system_result.py +166 -0
- omnibase_infra/handlers/handler_consul.py +787 -0
- omnibase_infra/handlers/handler_db.py +1039 -0
- omnibase_infra/handlers/handler_filesystem.py +1478 -0
- omnibase_infra/handlers/handler_graph.py +1154 -0
- omnibase_infra/handlers/handler_http.py +920 -0
- omnibase_infra/handlers/handler_manifest_persistence.contract.yaml +184 -0
- omnibase_infra/handlers/handler_manifest_persistence.py +1539 -0
- omnibase_infra/handlers/handler_mcp.py +748 -0
- omnibase_infra/handlers/handler_qdrant.py +1076 -0
- omnibase_infra/handlers/handler_vault.py +422 -0
- omnibase_infra/handlers/mcp/__init__.py +19 -0
- omnibase_infra/handlers/mcp/adapter_onex_to_mcp.py +446 -0
- omnibase_infra/handlers/mcp/protocols.py +178 -0
- omnibase_infra/handlers/mcp/transport_streamable_http.py +352 -0
- omnibase_infra/handlers/mixins/__init__.py +42 -0
- omnibase_infra/handlers/mixins/mixin_consul_initialization.py +349 -0
- omnibase_infra/handlers/mixins/mixin_consul_kv.py +337 -0
- omnibase_infra/handlers/mixins/mixin_consul_service.py +277 -0
- omnibase_infra/handlers/mixins/mixin_vault_initialization.py +338 -0
- omnibase_infra/handlers/mixins/mixin_vault_retry.py +412 -0
- omnibase_infra/handlers/mixins/mixin_vault_secrets.py +450 -0
- omnibase_infra/handlers/mixins/mixin_vault_token.py +365 -0
- omnibase_infra/handlers/models/__init__.py +286 -0
- omnibase_infra/handlers/models/consul/__init__.py +81 -0
- omnibase_infra/handlers/models/consul/enum_consul_operation_type.py +57 -0
- omnibase_infra/handlers/models/consul/model_consul_deregister_payload.py +51 -0
- omnibase_infra/handlers/models/consul/model_consul_handler_config.py +153 -0
- omnibase_infra/handlers/models/consul/model_consul_handler_payload.py +89 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_get_found_payload.py +55 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_get_not_found_payload.py +49 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_get_recurse_payload.py +50 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_item.py +33 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_put_payload.py +41 -0
- omnibase_infra/handlers/models/consul/model_consul_register_payload.py +53 -0
- omnibase_infra/handlers/models/consul/model_consul_retry_config.py +66 -0
- omnibase_infra/handlers/models/consul/model_payload_consul.py +66 -0
- omnibase_infra/handlers/models/consul/registry_payload_consul.py +214 -0
- omnibase_infra/handlers/models/graph/__init__.py +35 -0
- omnibase_infra/handlers/models/graph/enum_graph_operation_type.py +20 -0
- omnibase_infra/handlers/models/graph/model_graph_execute_payload.py +38 -0
- omnibase_infra/handlers/models/graph/model_graph_handler_config.py +54 -0
- omnibase_infra/handlers/models/graph/model_graph_handler_payload.py +44 -0
- omnibase_infra/handlers/models/graph/model_graph_query_payload.py +40 -0
- omnibase_infra/handlers/models/graph/model_graph_record.py +22 -0
- omnibase_infra/handlers/models/http/__init__.py +50 -0
- omnibase_infra/handlers/models/http/enum_http_operation_type.py +29 -0
- omnibase_infra/handlers/models/http/model_http_body_content.py +45 -0
- omnibase_infra/handlers/models/http/model_http_get_payload.py +88 -0
- omnibase_infra/handlers/models/http/model_http_handler_payload.py +90 -0
- omnibase_infra/handlers/models/http/model_http_post_payload.py +88 -0
- omnibase_infra/handlers/models/http/model_payload_http.py +66 -0
- omnibase_infra/handlers/models/http/registry_payload_http.py +212 -0
- omnibase_infra/handlers/models/mcp/__init__.py +23 -0
- omnibase_infra/handlers/models/mcp/enum_mcp_operation_type.py +24 -0
- omnibase_infra/handlers/models/mcp/model_mcp_handler_config.py +40 -0
- omnibase_infra/handlers/models/mcp/model_mcp_tool_call.py +32 -0
- omnibase_infra/handlers/models/mcp/model_mcp_tool_result.py +45 -0
- omnibase_infra/handlers/models/model_consul_handler_response.py +96 -0
- omnibase_infra/handlers/models/model_db_describe_response.py +83 -0
- omnibase_infra/handlers/models/model_db_query_payload.py +95 -0
- omnibase_infra/handlers/models/model_db_query_response.py +60 -0
- omnibase_infra/handlers/models/model_filesystem_config.py +98 -0
- omnibase_infra/handlers/models/model_filesystem_delete_payload.py +54 -0
- omnibase_infra/handlers/models/model_filesystem_delete_result.py +77 -0
- omnibase_infra/handlers/models/model_filesystem_directory_entry.py +75 -0
- omnibase_infra/handlers/models/model_filesystem_ensure_directory_payload.py +54 -0
- omnibase_infra/handlers/models/model_filesystem_ensure_directory_result.py +60 -0
- omnibase_infra/handlers/models/model_filesystem_list_directory_payload.py +60 -0
- omnibase_infra/handlers/models/model_filesystem_list_directory_result.py +68 -0
- omnibase_infra/handlers/models/model_filesystem_read_payload.py +62 -0
- omnibase_infra/handlers/models/model_filesystem_read_result.py +61 -0
- omnibase_infra/handlers/models/model_filesystem_write_payload.py +70 -0
- omnibase_infra/handlers/models/model_filesystem_write_result.py +55 -0
- omnibase_infra/handlers/models/model_graph_handler_response.py +98 -0
- omnibase_infra/handlers/models/model_handler_response.py +103 -0
- omnibase_infra/handlers/models/model_http_handler_response.py +101 -0
- omnibase_infra/handlers/models/model_manifest_metadata.py +75 -0
- omnibase_infra/handlers/models/model_manifest_persistence_config.py +62 -0
- omnibase_infra/handlers/models/model_manifest_query_payload.py +90 -0
- omnibase_infra/handlers/models/model_manifest_query_result.py +97 -0
- omnibase_infra/handlers/models/model_manifest_retrieve_payload.py +44 -0
- omnibase_infra/handlers/models/model_manifest_retrieve_result.py +98 -0
- omnibase_infra/handlers/models/model_manifest_store_payload.py +47 -0
- omnibase_infra/handlers/models/model_manifest_store_result.py +67 -0
- omnibase_infra/handlers/models/model_operation_context.py +187 -0
- omnibase_infra/handlers/models/model_qdrant_handler_response.py +98 -0
- omnibase_infra/handlers/models/model_retry_state.py +162 -0
- omnibase_infra/handlers/models/model_vault_handler_response.py +98 -0
- omnibase_infra/handlers/models/qdrant/__init__.py +44 -0
- omnibase_infra/handlers/models/qdrant/enum_qdrant_operation_type.py +26 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_collection_payload.py +42 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_delete_payload.py +36 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_handler_config.py +42 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_handler_payload.py +54 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_search_payload.py +42 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_search_result.py +30 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_upsert_payload.py +36 -0
- omnibase_infra/handlers/models/vault/__init__.py +69 -0
- omnibase_infra/handlers/models/vault/enum_vault_operation_type.py +35 -0
- omnibase_infra/handlers/models/vault/model_payload_vault.py +66 -0
- omnibase_infra/handlers/models/vault/model_vault_delete_payload.py +57 -0
- omnibase_infra/handlers/models/vault/model_vault_handler_config.py +148 -0
- omnibase_infra/handlers/models/vault/model_vault_handler_payload.py +101 -0
- omnibase_infra/handlers/models/vault/model_vault_list_payload.py +58 -0
- omnibase_infra/handlers/models/vault/model_vault_renew_token_payload.py +67 -0
- omnibase_infra/handlers/models/vault/model_vault_retry_config.py +66 -0
- omnibase_infra/handlers/models/vault/model_vault_secret_payload.py +106 -0
- omnibase_infra/handlers/models/vault/model_vault_write_payload.py +66 -0
- omnibase_infra/handlers/models/vault/registry_payload_vault.py +213 -0
- omnibase_infra/handlers/registration_storage/__init__.py +43 -0
- omnibase_infra/handlers/registration_storage/handler_registration_storage_mock.py +392 -0
- omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +915 -0
- omnibase_infra/handlers/registration_storage/models/__init__.py +23 -0
- omnibase_infra/handlers/registration_storage/models/model_delete_registration_request.py +58 -0
- omnibase_infra/handlers/registration_storage/models/model_update_registration_request.py +73 -0
- omnibase_infra/handlers/registration_storage/protocol_registration_persistence.py +191 -0
- omnibase_infra/handlers/service_discovery/__init__.py +43 -0
- omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +747 -0
- omnibase_infra/handlers/service_discovery/handler_service_discovery_mock.py +258 -0
- omnibase_infra/handlers/service_discovery/models/__init__.py +22 -0
- omnibase_infra/handlers/service_discovery/models/model_discovery_result.py +64 -0
- omnibase_infra/handlers/service_discovery/models/model_registration_result.py +138 -0
- omnibase_infra/handlers/service_discovery/models/model_service_info.py +99 -0
- omnibase_infra/handlers/service_discovery/protocol_discovery_operations.py +170 -0
- omnibase_infra/idempotency/__init__.py +94 -0
- omnibase_infra/idempotency/models/__init__.py +43 -0
- omnibase_infra/idempotency/models/model_idempotency_check_result.py +85 -0
- omnibase_infra/idempotency/models/model_idempotency_guard_config.py +130 -0
- omnibase_infra/idempotency/models/model_idempotency_record.py +86 -0
- omnibase_infra/idempotency/models/model_idempotency_store_health_check_result.py +81 -0
- omnibase_infra/idempotency/models/model_idempotency_store_metrics.py +140 -0
- omnibase_infra/idempotency/models/model_postgres_idempotency_store_config.py +299 -0
- omnibase_infra/idempotency/protocol_idempotency_store.py +184 -0
- omnibase_infra/idempotency/store_inmemory.py +265 -0
- omnibase_infra/idempotency/store_postgres.py +923 -0
- omnibase_infra/infrastructure/__init__.py +0 -0
- omnibase_infra/mixins/__init__.py +71 -0
- omnibase_infra/mixins/mixin_async_circuit_breaker.py +655 -0
- omnibase_infra/mixins/mixin_dict_like_accessors.py +146 -0
- omnibase_infra/mixins/mixin_envelope_extraction.py +119 -0
- omnibase_infra/mixins/mixin_node_introspection.py +2465 -0
- omnibase_infra/mixins/mixin_retry_execution.py +386 -0
- omnibase_infra/mixins/protocol_circuit_breaker_aware.py +133 -0
- omnibase_infra/models/__init__.py +136 -0
- omnibase_infra/models/corpus/__init__.py +17 -0
- omnibase_infra/models/corpus/model_capture_config.py +133 -0
- omnibase_infra/models/corpus/model_capture_result.py +86 -0
- omnibase_infra/models/discovery/__init__.py +42 -0
- omnibase_infra/models/discovery/model_dependency_spec.py +319 -0
- omnibase_infra/models/discovery/model_discovered_capabilities.py +50 -0
- omnibase_infra/models/discovery/model_introspection_config.py +311 -0
- omnibase_infra/models/discovery/model_introspection_performance_metrics.py +169 -0
- omnibase_infra/models/discovery/model_introspection_task_config.py +116 -0
- omnibase_infra/models/dispatch/__init__.py +147 -0
- omnibase_infra/models/dispatch/model_dispatch_context.py +439 -0
- omnibase_infra/models/dispatch/model_dispatch_error.py +336 -0
- omnibase_infra/models/dispatch/model_dispatch_log_context.py +400 -0
- omnibase_infra/models/dispatch/model_dispatch_metadata.py +228 -0
- omnibase_infra/models/dispatch/model_dispatch_metrics.py +496 -0
- omnibase_infra/models/dispatch/model_dispatch_outcome.py +317 -0
- omnibase_infra/models/dispatch/model_dispatch_outputs.py +231 -0
- omnibase_infra/models/dispatch/model_dispatch_result.py +436 -0
- omnibase_infra/models/dispatch/model_dispatch_route.py +279 -0
- omnibase_infra/models/dispatch/model_dispatcher_metrics.py +275 -0
- omnibase_infra/models/dispatch/model_dispatcher_registration.py +352 -0
- omnibase_infra/models/dispatch/model_parsed_topic.py +135 -0
- omnibase_infra/models/dispatch/model_topic_parser.py +725 -0
- omnibase_infra/models/dispatch/model_tracing_context.py +285 -0
- omnibase_infra/models/errors/__init__.py +45 -0
- omnibase_infra/models/errors/model_handler_validation_error.py +594 -0
- omnibase_infra/models/errors/model_infra_error_context.py +99 -0
- omnibase_infra/models/errors/model_message_type_registry_error_context.py +71 -0
- omnibase_infra/models/errors/model_timeout_error_context.py +110 -0
- omnibase_infra/models/handlers/__init__.py +37 -0
- omnibase_infra/models/handlers/model_contract_discovery_result.py +80 -0
- omnibase_infra/models/handlers/model_handler_descriptor.py +185 -0
- omnibase_infra/models/handlers/model_handler_identifier.py +215 -0
- omnibase_infra/models/health/__init__.py +9 -0
- omnibase_infra/models/health/model_health_check_result.py +40 -0
- omnibase_infra/models/lifecycle/__init__.py +39 -0
- omnibase_infra/models/logging/__init__.py +51 -0
- omnibase_infra/models/logging/model_log_context.py +756 -0
- omnibase_infra/models/model_retry_error_classification.py +78 -0
- omnibase_infra/models/projection/__init__.py +43 -0
- omnibase_infra/models/projection/model_capability_fields.py +112 -0
- omnibase_infra/models/projection/model_registration_projection.py +434 -0
- omnibase_infra/models/projection/model_registration_snapshot.py +322 -0
- omnibase_infra/models/projection/model_sequence_info.py +182 -0
- omnibase_infra/models/projection/model_snapshot_topic_config.py +590 -0
- omnibase_infra/models/projectors/__init__.py +41 -0
- omnibase_infra/models/projectors/model_projector_column.py +289 -0
- omnibase_infra/models/projectors/model_projector_discovery_result.py +65 -0
- omnibase_infra/models/projectors/model_projector_index.py +270 -0
- omnibase_infra/models/projectors/model_projector_schema.py +415 -0
- omnibase_infra/models/projectors/model_projector_validation_error.py +63 -0
- omnibase_infra/models/projectors/util_sql_identifiers.py +115 -0
- omnibase_infra/models/registration/__init__.py +59 -0
- omnibase_infra/models/registration/commands/__init__.py +15 -0
- omnibase_infra/models/registration/commands/model_node_registration_acked.py +108 -0
- omnibase_infra/models/registration/events/__init__.py +56 -0
- omnibase_infra/models/registration/events/model_node_became_active.py +103 -0
- omnibase_infra/models/registration/events/model_node_liveness_expired.py +103 -0
- omnibase_infra/models/registration/events/model_node_registration_accepted.py +98 -0
- omnibase_infra/models/registration/events/model_node_registration_ack_received.py +98 -0
- omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py +112 -0
- omnibase_infra/models/registration/events/model_node_registration_initiated.py +107 -0
- omnibase_infra/models/registration/events/model_node_registration_rejected.py +104 -0
- omnibase_infra/models/registration/model_introspection_metrics.py +253 -0
- omnibase_infra/models/registration/model_node_capabilities.py +179 -0
- omnibase_infra/models/registration/model_node_heartbeat_event.py +126 -0
- omnibase_infra/models/registration/model_node_introspection_event.py +175 -0
- omnibase_infra/models/registration/model_node_metadata.py +79 -0
- omnibase_infra/models/registration/model_node_registration.py +162 -0
- omnibase_infra/models/registration/model_node_registration_record.py +162 -0
- omnibase_infra/models/registry/__init__.py +29 -0
- omnibase_infra/models/registry/model_domain_constraint.py +202 -0
- omnibase_infra/models/registry/model_message_type_entry.py +271 -0
- omnibase_infra/models/resilience/__init__.py +9 -0
- omnibase_infra/models/resilience/model_circuit_breaker_config.py +227 -0
- omnibase_infra/models/routing/__init__.py +25 -0
- omnibase_infra/models/routing/model_routing_entry.py +52 -0
- omnibase_infra/models/routing/model_routing_subcontract.py +70 -0
- omnibase_infra/models/runtime/__init__.py +40 -0
- omnibase_infra/models/runtime/model_contract_security_config.py +41 -0
- omnibase_infra/models/runtime/model_discovery_error.py +81 -0
- omnibase_infra/models/runtime/model_discovery_result.py +162 -0
- omnibase_infra/models/runtime/model_discovery_warning.py +74 -0
- omnibase_infra/models/runtime/model_failed_plugin_load.py +63 -0
- omnibase_infra/models/runtime/model_handler_contract.py +280 -0
- omnibase_infra/models/runtime/model_loaded_handler.py +120 -0
- omnibase_infra/models/runtime/model_plugin_load_context.py +93 -0
- omnibase_infra/models/runtime/model_plugin_load_summary.py +124 -0
- omnibase_infra/models/security/__init__.py +50 -0
- omnibase_infra/models/security/classification_levels.py +99 -0
- omnibase_infra/models/security/model_environment_policy.py +145 -0
- omnibase_infra/models/security/model_handler_security_policy.py +107 -0
- omnibase_infra/models/security/model_security_error.py +81 -0
- omnibase_infra/models/security/model_security_validation_result.py +328 -0
- omnibase_infra/models/security/model_security_warning.py +67 -0
- omnibase_infra/models/snapshot/__init__.py +27 -0
- omnibase_infra/models/snapshot/model_field_change.py +65 -0
- omnibase_infra/models/snapshot/model_snapshot.py +270 -0
- omnibase_infra/models/snapshot/model_snapshot_diff.py +203 -0
- omnibase_infra/models/snapshot/model_subject_ref.py +81 -0
- omnibase_infra/models/types/__init__.py +71 -0
- omnibase_infra/models/validation/__init__.py +89 -0
- omnibase_infra/models/validation/model_any_type_validation_result.py +118 -0
- omnibase_infra/models/validation/model_any_type_violation.py +141 -0
- omnibase_infra/models/validation/model_category_match_result.py +345 -0
- omnibase_infra/models/validation/model_chain_violation.py +166 -0
- omnibase_infra/models/validation/model_coverage_metrics.py +316 -0
- omnibase_infra/models/validation/model_execution_shape_rule.py +159 -0
- omnibase_infra/models/validation/model_execution_shape_validation.py +208 -0
- omnibase_infra/models/validation/model_execution_shape_validation_result.py +294 -0
- omnibase_infra/models/validation/model_execution_shape_violation.py +122 -0
- omnibase_infra/models/validation/model_localhandler_validation_result.py +139 -0
- omnibase_infra/models/validation/model_localhandler_violation.py +100 -0
- omnibase_infra/models/validation/model_output_validation_params.py +74 -0
- omnibase_infra/models/validation/model_validate_and_raise_params.py +84 -0
- omnibase_infra/models/validation/model_validation_error_params.py +84 -0
- omnibase_infra/models/validation/model_validation_outcome.py +287 -0
- omnibase_infra/nodes/__init__.py +48 -0
- omnibase_infra/nodes/architecture_validator/__init__.py +79 -0
- omnibase_infra/nodes/architecture_validator/contract.yaml +252 -0
- omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +208 -0
- omnibase_infra/nodes/architecture_validator/mixins/__init__.py +16 -0
- omnibase_infra/nodes/architecture_validator/mixins/mixin_file_path_rule.py +92 -0
- omnibase_infra/nodes/architecture_validator/models/__init__.py +36 -0
- omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_request.py +56 -0
- omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_result.py +311 -0
- omnibase_infra/nodes/architecture_validator/models/model_architecture_violation.py +163 -0
- omnibase_infra/nodes/architecture_validator/models/model_rule_check_result.py +265 -0
- omnibase_infra/nodes/architecture_validator/models/model_validation_request.py +105 -0
- omnibase_infra/nodes/architecture_validator/models/model_validation_result.py +314 -0
- omnibase_infra/nodes/architecture_validator/node.py +262 -0
- omnibase_infra/nodes/architecture_validator/node_architecture_validator.py +383 -0
- omnibase_infra/nodes/architecture_validator/protocols/__init__.py +9 -0
- omnibase_infra/nodes/architecture_validator/protocols/protocol_architecture_rule.py +225 -0
- omnibase_infra/nodes/architecture_validator/registry/__init__.py +28 -0
- omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +99 -0
- omnibase_infra/nodes/architecture_validator/validators/__init__.py +104 -0
- omnibase_infra/nodes/architecture_validator/validators/validator_no_direct_dispatch.py +422 -0
- omnibase_infra/nodes/architecture_validator/validators/validator_no_handler_publishing.py +481 -0
- omnibase_infra/nodes/architecture_validator/validators/validator_no_orchestrator_fsm.py +491 -0
- omnibase_infra/nodes/effects/README.md +358 -0
- omnibase_infra/nodes/effects/__init__.py +26 -0
- omnibase_infra/nodes/effects/contract.yaml +172 -0
- omnibase_infra/nodes/effects/models/__init__.py +32 -0
- omnibase_infra/nodes/effects/models/model_backend_result.py +190 -0
- omnibase_infra/nodes/effects/models/model_effect_idempotency_config.py +92 -0
- omnibase_infra/nodes/effects/models/model_registry_request.py +132 -0
- omnibase_infra/nodes/effects/models/model_registry_response.py +263 -0
- omnibase_infra/nodes/effects/protocol_consul_client.py +89 -0
- omnibase_infra/nodes/effects/protocol_effect_idempotency_store.py +143 -0
- omnibase_infra/nodes/effects/protocol_postgres_adapter.py +96 -0
- omnibase_infra/nodes/effects/registry_effect.py +525 -0
- omnibase_infra/nodes/effects/store_effect_idempotency_inmemory.py +425 -0
- omnibase_infra/nodes/node_registration_orchestrator/README.md +542 -0
- omnibase_infra/nodes/node_registration_orchestrator/__init__.py +120 -0
- omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +475 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/__init__.py +53 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_introspected.py +376 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_registration_acked.py +376 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_runtime_tick.py +373 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.py +62 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_heartbeat.py +376 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +609 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py +458 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py +364 -0
- omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +544 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/__init__.py +75 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_intent_payload.py +194 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_registration_intent.py +67 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_intent_execution_result.py +50 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_node_liveness_expired.py +107 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_config.py +67 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_input.py +41 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_output.py +166 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_intent_payload.py +235 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_upsert_intent.py +68 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_execution_result.py +384 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_state.py +60 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_registration_intent.py +177 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_registry_intent.py +247 -0
- omnibase_infra/nodes/node_registration_orchestrator/node.py +195 -0
- omnibase_infra/nodes/node_registration_orchestrator/plugin.py +909 -0
- omnibase_infra/nodes/node_registration_orchestrator/protocols.py +439 -0
- omnibase_infra/nodes/node_registration_orchestrator/registry/__init__.py +41 -0
- omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +525 -0
- omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +392 -0
- omnibase_infra/nodes/node_registration_orchestrator/wiring.py +742 -0
- omnibase_infra/nodes/node_registration_reducer/__init__.py +15 -0
- omnibase_infra/nodes/node_registration_reducer/contract.yaml +301 -0
- omnibase_infra/nodes/node_registration_reducer/models/__init__.py +38 -0
- omnibase_infra/nodes/node_registration_reducer/models/model_validation_result.py +113 -0
- omnibase_infra/nodes/node_registration_reducer/node.py +139 -0
- omnibase_infra/nodes/node_registration_reducer/registry/__init__.py +9 -0
- omnibase_infra/nodes/node_registration_reducer/registry/registry_infra_node_registration_reducer.py +79 -0
- omnibase_infra/nodes/node_registration_storage_effect/__init__.py +41 -0
- omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +225 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/__init__.py +44 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_delete_result.py +132 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_record.py +199 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_update.py +155 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_details.py +123 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_result.py +117 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_query.py +100 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_result.py +136 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_upsert_result.py +127 -0
- omnibase_infra/nodes/node_registration_storage_effect/node.py +109 -0
- omnibase_infra/nodes/node_registration_storage_effect/protocols/__init__.py +22 -0
- omnibase_infra/nodes/node_registration_storage_effect/protocols/protocol_registration_persistence.py +333 -0
- omnibase_infra/nodes/node_registration_storage_effect/registry/__init__.py +23 -0
- omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +194 -0
- omnibase_infra/nodes/node_registry_effect/__init__.py +85 -0
- omnibase_infra/nodes/node_registry_effect/contract.yaml +682 -0
- omnibase_infra/nodes/node_registry_effect/handlers/__init__.py +70 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_deregister.py +211 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_register.py +212 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +416 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_deactivate.py +215 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_upsert.py +208 -0
- omnibase_infra/nodes/node_registry_effect/models/__init__.py +43 -0
- omnibase_infra/nodes/node_registry_effect/models/model_partial_retry_request.py +92 -0
- omnibase_infra/nodes/node_registry_effect/node.py +165 -0
- omnibase_infra/nodes/node_registry_effect/registry/__init__.py +27 -0
- omnibase_infra/nodes/node_registry_effect/registry/registry_infra_registry_effect.py +196 -0
- omnibase_infra/nodes/node_service_discovery_effect/__init__.py +111 -0
- omnibase_infra/nodes/node_service_discovery_effect/contract.yaml +246 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/__init__.py +67 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/enum_health_status.py +72 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/enum_service_discovery_operation.py +58 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_query.py +99 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_result.py +98 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_health_check_config.py +121 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_query_metadata.py +63 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_registration_result.py +130 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_details.py +111 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_result.py +119 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_info.py +106 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_registration.py +121 -0
- omnibase_infra/nodes/node_service_discovery_effect/node.py +111 -0
- omnibase_infra/nodes/node_service_discovery_effect/protocols/__init__.py +14 -0
- omnibase_infra/nodes/node_service_discovery_effect/protocols/protocol_discovery_operations.py +279 -0
- omnibase_infra/nodes/node_service_discovery_effect/registry/__init__.py +13 -0
- omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +214 -0
- omnibase_infra/nodes/reducers/__init__.py +30 -0
- omnibase_infra/nodes/reducers/models/__init__.py +32 -0
- omnibase_infra/nodes/reducers/models/model_payload_consul_register.py +76 -0
- omnibase_infra/nodes/reducers/models/model_payload_postgres_upsert_registration.py +60 -0
- omnibase_infra/nodes/reducers/models/model_registration_confirmation.py +166 -0
- omnibase_infra/nodes/reducers/models/model_registration_state.py +433 -0
- omnibase_infra/nodes/reducers/registration_reducer.py +1137 -0
- omnibase_infra/observability/__init__.py +143 -0
- omnibase_infra/observability/constants_metrics.py +91 -0
- omnibase_infra/observability/factory_observability_sink.py +525 -0
- omnibase_infra/observability/handlers/__init__.py +118 -0
- omnibase_infra/observability/handlers/handler_logging_structured.py +967 -0
- omnibase_infra/observability/handlers/handler_metrics_prometheus.py +1120 -0
- omnibase_infra/observability/handlers/model_logging_handler_config.py +71 -0
- omnibase_infra/observability/handlers/model_logging_handler_response.py +77 -0
- omnibase_infra/observability/handlers/model_metrics_handler_config.py +172 -0
- omnibase_infra/observability/handlers/model_metrics_handler_payload.py +135 -0
- omnibase_infra/observability/handlers/model_metrics_handler_response.py +101 -0
- omnibase_infra/observability/hooks/__init__.py +74 -0
- omnibase_infra/observability/hooks/hook_observability.py +1223 -0
- omnibase_infra/observability/models/__init__.py +30 -0
- omnibase_infra/observability/models/enum_required_log_context_key.py +77 -0
- omnibase_infra/observability/models/model_buffered_log_entry.py +117 -0
- omnibase_infra/observability/models/model_logging_sink_config.py +73 -0
- omnibase_infra/observability/models/model_metrics_sink_config.py +156 -0
- omnibase_infra/observability/sinks/__init__.py +69 -0
- omnibase_infra/observability/sinks/sink_logging_structured.py +809 -0
- omnibase_infra/observability/sinks/sink_metrics_prometheus.py +710 -0
- omnibase_infra/plugins/__init__.py +27 -0
- omnibase_infra/plugins/examples/__init__.py +28 -0
- omnibase_infra/plugins/examples/plugin_json_normalizer.py +271 -0
- omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +210 -0
- omnibase_infra/plugins/models/__init__.py +21 -0
- omnibase_infra/plugins/models/model_plugin_context.py +76 -0
- omnibase_infra/plugins/models/model_plugin_input_data.py +58 -0
- omnibase_infra/plugins/models/model_plugin_output_data.py +62 -0
- omnibase_infra/plugins/plugin_compute_base.py +435 -0
- omnibase_infra/projectors/__init__.py +30 -0
- omnibase_infra/projectors/contracts/__init__.py +63 -0
- omnibase_infra/projectors/contracts/registration_projector.yaml +370 -0
- omnibase_infra/projectors/projection_reader_registration.py +1559 -0
- omnibase_infra/projectors/snapshot_publisher_registration.py +1329 -0
- omnibase_infra/protocols/__init__.py +99 -0
- omnibase_infra/protocols/protocol_capability_projection.py +253 -0
- omnibase_infra/protocols/protocol_capability_query.py +251 -0
- omnibase_infra/protocols/protocol_event_bus_like.py +127 -0
- omnibase_infra/protocols/protocol_event_projector.py +96 -0
- omnibase_infra/protocols/protocol_idempotency_store.py +142 -0
- omnibase_infra/protocols/protocol_message_dispatcher.py +247 -0
- omnibase_infra/protocols/protocol_message_type_registry.py +306 -0
- omnibase_infra/protocols/protocol_plugin_compute.py +368 -0
- omnibase_infra/protocols/protocol_projector_schema_validator.py +82 -0
- omnibase_infra/protocols/protocol_registry_metrics.py +215 -0
- omnibase_infra/protocols/protocol_snapshot_publisher.py +396 -0
- omnibase_infra/protocols/protocol_snapshot_store.py +567 -0
- omnibase_infra/runtime/__init__.py +296 -0
- omnibase_infra/runtime/binding_config_resolver.py +2706 -0
- omnibase_infra/runtime/chain_aware_dispatch.py +467 -0
- omnibase_infra/runtime/contract_handler_discovery.py +582 -0
- omnibase_infra/runtime/contract_loaders/__init__.py +42 -0
- omnibase_infra/runtime/contract_loaders/handler_routing_loader.py +464 -0
- omnibase_infra/runtime/dispatch_context_enforcer.py +427 -0
- omnibase_infra/runtime/enums/__init__.py +18 -0
- omnibase_infra/runtime/enums/enum_config_ref_scheme.py +33 -0
- omnibase_infra/runtime/enums/enum_scheduler_status.py +170 -0
- omnibase_infra/runtime/envelope_validator.py +179 -0
- omnibase_infra/runtime/handler_contract_source.py +669 -0
- omnibase_infra/runtime/handler_plugin_loader.py +2029 -0
- omnibase_infra/runtime/handler_registry.py +321 -0
- omnibase_infra/runtime/invocation_security_enforcer.py +427 -0
- omnibase_infra/runtime/kernel.py +40 -0
- omnibase_infra/runtime/mixin_policy_validation.py +522 -0
- omnibase_infra/runtime/mixin_semver_cache.py +378 -0
- omnibase_infra/runtime/mixins/__init__.py +17 -0
- omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +757 -0
- omnibase_infra/runtime/models/__init__.py +192 -0
- omnibase_infra/runtime/models/model_batch_lifecycle_result.py +217 -0
- omnibase_infra/runtime/models/model_binding_config.py +168 -0
- omnibase_infra/runtime/models/model_binding_config_cache_stats.py +135 -0
- omnibase_infra/runtime/models/model_binding_config_resolver_config.py +329 -0
- omnibase_infra/runtime/models/model_cached_secret.py +138 -0
- omnibase_infra/runtime/models/model_compute_key.py +138 -0
- omnibase_infra/runtime/models/model_compute_registration.py +97 -0
- omnibase_infra/runtime/models/model_config_cache_entry.py +61 -0
- omnibase_infra/runtime/models/model_config_ref.py +331 -0
- omnibase_infra/runtime/models/model_config_ref_parse_result.py +125 -0
- omnibase_infra/runtime/models/model_domain_plugin_config.py +92 -0
- omnibase_infra/runtime/models/model_domain_plugin_result.py +270 -0
- omnibase_infra/runtime/models/model_duplicate_response.py +54 -0
- omnibase_infra/runtime/models/model_enabled_protocols_config.py +61 -0
- omnibase_infra/runtime/models/model_event_bus_config.py +54 -0
- omnibase_infra/runtime/models/model_failed_component.py +55 -0
- omnibase_infra/runtime/models/model_health_check_response.py +168 -0
- omnibase_infra/runtime/models/model_health_check_result.py +228 -0
- omnibase_infra/runtime/models/model_lifecycle_result.py +245 -0
- omnibase_infra/runtime/models/model_logging_config.py +42 -0
- omnibase_infra/runtime/models/model_optional_correlation_id.py +167 -0
- omnibase_infra/runtime/models/model_optional_string.py +94 -0
- omnibase_infra/runtime/models/model_optional_uuid.py +110 -0
- omnibase_infra/runtime/models/model_policy_context.py +100 -0
- omnibase_infra/runtime/models/model_policy_key.py +138 -0
- omnibase_infra/runtime/models/model_policy_registration.py +139 -0
- omnibase_infra/runtime/models/model_policy_result.py +103 -0
- omnibase_infra/runtime/models/model_policy_type_filter.py +157 -0
- omnibase_infra/runtime/models/model_projector_plugin_loader_config.py +47 -0
- omnibase_infra/runtime/models/model_protocol_registration_config.py +65 -0
- omnibase_infra/runtime/models/model_retry_policy.py +105 -0
- omnibase_infra/runtime/models/model_runtime_config.py +150 -0
- omnibase_infra/runtime/models/model_runtime_scheduler_config.py +624 -0
- omnibase_infra/runtime/models/model_runtime_scheduler_metrics.py +233 -0
- omnibase_infra/runtime/models/model_runtime_tick.py +193 -0
- omnibase_infra/runtime/models/model_secret_cache_stats.py +82 -0
- omnibase_infra/runtime/models/model_secret_mapping.py +63 -0
- omnibase_infra/runtime/models/model_secret_resolver_config.py +107 -0
- omnibase_infra/runtime/models/model_secret_resolver_metrics.py +111 -0
- omnibase_infra/runtime/models/model_secret_source_info.py +72 -0
- omnibase_infra/runtime/models/model_secret_source_spec.py +66 -0
- omnibase_infra/runtime/models/model_shutdown_batch_result.py +75 -0
- omnibase_infra/runtime/models/model_shutdown_config.py +94 -0
- omnibase_infra/runtime/projector_plugin_loader.py +1462 -0
- omnibase_infra/runtime/projector_schema_manager.py +565 -0
- omnibase_infra/runtime/projector_shell.py +1102 -0
- omnibase_infra/runtime/protocol_contract_descriptor.py +92 -0
- omnibase_infra/runtime/protocol_contract_source.py +92 -0
- omnibase_infra/runtime/protocol_domain_plugin.py +474 -0
- omnibase_infra/runtime/protocol_handler_discovery.py +221 -0
- omnibase_infra/runtime/protocol_handler_plugin_loader.py +327 -0
- omnibase_infra/runtime/protocol_lifecycle_executor.py +435 -0
- omnibase_infra/runtime/protocol_policy.py +366 -0
- omnibase_infra/runtime/protocols/__init__.py +27 -0
- omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py +468 -0
- omnibase_infra/runtime/registry/__init__.py +93 -0
- omnibase_infra/runtime/registry/mixin_message_type_query.py +326 -0
- omnibase_infra/runtime/registry/mixin_message_type_registration.py +354 -0
- omnibase_infra/runtime/registry/registry_event_bus_binding.py +268 -0
- omnibase_infra/runtime/registry/registry_message_type.py +542 -0
- omnibase_infra/runtime/registry/registry_protocol_binding.py +444 -0
- omnibase_infra/runtime/registry_compute.py +1143 -0
- omnibase_infra/runtime/registry_dispatcher.py +678 -0
- omnibase_infra/runtime/registry_policy.py +1502 -0
- omnibase_infra/runtime/runtime_scheduler.py +1070 -0
- omnibase_infra/runtime/secret_resolver.py +2110 -0
- omnibase_infra/runtime/security_metadata_validator.py +776 -0
- omnibase_infra/runtime/service_kernel.py +1573 -0
- omnibase_infra/runtime/service_message_dispatch_engine.py +1805 -0
- omnibase_infra/runtime/service_runtime_host_process.py +2260 -0
- omnibase_infra/runtime/util_container_wiring.py +1123 -0
- omnibase_infra/runtime/util_validation.py +314 -0
- omnibase_infra/runtime/util_version.py +98 -0
- omnibase_infra/runtime/util_wiring.py +566 -0
- omnibase_infra/schemas/schema_registration_projection.sql +320 -0
- omnibase_infra/services/__init__.py +68 -0
- omnibase_infra/services/corpus_capture.py +678 -0
- omnibase_infra/services/service_capability_query.py +945 -0
- omnibase_infra/services/service_health.py +897 -0
- omnibase_infra/services/service_node_selector.py +530 -0
- omnibase_infra/services/service_timeout_emitter.py +682 -0
- omnibase_infra/services/service_timeout_scanner.py +390 -0
- omnibase_infra/services/snapshot/__init__.py +31 -0
- omnibase_infra/services/snapshot/service_snapshot.py +647 -0
- omnibase_infra/services/snapshot/store_inmemory.py +637 -0
- omnibase_infra/services/snapshot/store_postgres.py +1279 -0
- omnibase_infra/shared/__init__.py +8 -0
- omnibase_infra/testing/__init__.py +10 -0
- omnibase_infra/testing/utils.py +23 -0
- omnibase_infra/types/__init__.py +48 -0
- omnibase_infra/types/type_cache_info.py +49 -0
- omnibase_infra/types/type_dsn.py +173 -0
- omnibase_infra/types/type_infra_aliases.py +60 -0
- omnibase_infra/types/typed_dict/__init__.py +21 -0
- omnibase_infra/types/typed_dict/typed_dict_introspection_cache.py +128 -0
- omnibase_infra/types/typed_dict/typed_dict_performance_metrics_cache.py +140 -0
- omnibase_infra/types/typed_dict_capabilities.py +64 -0
- omnibase_infra/utils/__init__.py +89 -0
- omnibase_infra/utils/correlation.py +208 -0
- omnibase_infra/utils/util_datetime.py +372 -0
- omnibase_infra/utils/util_dsn_validation.py +333 -0
- omnibase_infra/utils/util_env_parsing.py +264 -0
- omnibase_infra/utils/util_error_sanitization.py +457 -0
- omnibase_infra/utils/util_pydantic_validators.py +477 -0
- omnibase_infra/utils/util_semver.py +233 -0
- omnibase_infra/validation/__init__.py +307 -0
- omnibase_infra/validation/enums/__init__.py +11 -0
- omnibase_infra/validation/enums/enum_contract_violation_severity.py +13 -0
- omnibase_infra/validation/infra_validators.py +1486 -0
- omnibase_infra/validation/linter_contract.py +907 -0
- omnibase_infra/validation/mixin_any_type_classification.py +120 -0
- omnibase_infra/validation/mixin_any_type_exemption.py +580 -0
- omnibase_infra/validation/mixin_any_type_reporting.py +106 -0
- omnibase_infra/validation/mixin_execution_shape_violation_checks.py +596 -0
- omnibase_infra/validation/mixin_node_archetype_detection.py +254 -0
- omnibase_infra/validation/models/__init__.py +15 -0
- omnibase_infra/validation/models/model_contract_lint_result.py +101 -0
- omnibase_infra/validation/models/model_contract_violation.py +41 -0
- omnibase_infra/validation/service_validation_aggregator.py +395 -0
- omnibase_infra/validation/validation_exemptions.yaml +1710 -0
- omnibase_infra/validation/validator_any_type.py +715 -0
- omnibase_infra/validation/validator_chain_propagation.py +839 -0
- omnibase_infra/validation/validator_execution_shape.py +465 -0
- omnibase_infra/validation/validator_localhandler.py +261 -0
- omnibase_infra/validation/validator_registration_security.py +410 -0
- omnibase_infra/validation/validator_routing_coverage.py +1020 -0
- omnibase_infra/validation/validator_runtime_shape.py +915 -0
- omnibase_infra/validation/validator_security.py +410 -0
- omnibase_infra/validation/validator_topic_category.py +1152 -0
- omnibase_infra-0.2.1.dist-info/METADATA +197 -0
- omnibase_infra-0.2.1.dist-info/RECORD +675 -0
- omnibase_infra-0.2.1.dist-info/WHEEL +4 -0
- omnibase_infra-0.2.1.dist-info/entry_points.txt +4 -0
- omnibase_infra-0.2.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,920 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""HTTP REST Handler - MVP implementation using httpx async client.
|
|
4
|
+
|
|
5
|
+
Supports GET and POST operations with 30-second fixed timeout.
|
|
6
|
+
PUT, DELETE, PATCH deferred to Beta. Retry logic and rate limiting deferred to Beta.
|
|
7
|
+
|
|
8
|
+
Note:
|
|
9
|
+
Environment variable configuration (ONEX_HTTP_TIMEOUT, ONEX_HTTP_MAX_REQUEST_SIZE,
|
|
10
|
+
ONEX_HTTP_MAX_RESPONSE_SIZE) is parsed at module import time, not at handler
|
|
11
|
+
instantiation. This means:
|
|
12
|
+
|
|
13
|
+
- Changes to environment variables require application restart to take effect
|
|
14
|
+
- Tests should use ``unittest.mock.patch.dict(os.environ, ...)`` before importing,
|
|
15
|
+
or use ``importlib.reload()`` to re-import the module after patching
|
|
16
|
+
- This is an intentional design choice for startup-time validation
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import json
|
|
22
|
+
import logging
|
|
23
|
+
from uuid import UUID, uuid4
|
|
24
|
+
|
|
25
|
+
import httpx
|
|
26
|
+
|
|
27
|
+
from omnibase_core.models.dispatch import ModelHandlerOutput
|
|
28
|
+
from omnibase_infra.enums import (
|
|
29
|
+
EnumHandlerType,
|
|
30
|
+
EnumHandlerTypeCategory,
|
|
31
|
+
EnumInfraTransportType,
|
|
32
|
+
)
|
|
33
|
+
from omnibase_infra.errors import (
|
|
34
|
+
InfraConnectionError,
|
|
35
|
+
InfraTimeoutError,
|
|
36
|
+
InfraUnavailableError,
|
|
37
|
+
ModelInfraErrorContext,
|
|
38
|
+
ModelTimeoutErrorContext,
|
|
39
|
+
ProtocolConfigurationError,
|
|
40
|
+
RuntimeHostError,
|
|
41
|
+
)
|
|
42
|
+
from omnibase_infra.handlers.models.http import ModelHttpBodyContent
|
|
43
|
+
from omnibase_infra.mixins import MixinEnvelopeExtraction
|
|
44
|
+
from omnibase_infra.utils import parse_env_float, parse_env_int
|
|
45
|
+
|
|
46
|
+
logger = logging.getLogger(__name__)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
_DEFAULT_TIMEOUT_SECONDS: float = parse_env_float(
|
|
50
|
+
"ONEX_HTTP_TIMEOUT",
|
|
51
|
+
30.0,
|
|
52
|
+
min_value=1.0,
|
|
53
|
+
max_value=300.0,
|
|
54
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
55
|
+
service_name="http_handler",
|
|
56
|
+
)
|
|
57
|
+
_DEFAULT_MAX_REQUEST_SIZE: int = parse_env_int(
|
|
58
|
+
"ONEX_HTTP_MAX_REQUEST_SIZE",
|
|
59
|
+
10 * 1024 * 1024,
|
|
60
|
+
min_value=1024,
|
|
61
|
+
max_value=104857600,
|
|
62
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
63
|
+
service_name="http_handler",
|
|
64
|
+
) # 10 MB default, min 1 KB, max 100 MB
|
|
65
|
+
_DEFAULT_MAX_RESPONSE_SIZE: int = parse_env_int(
|
|
66
|
+
"ONEX_HTTP_MAX_RESPONSE_SIZE",
|
|
67
|
+
50 * 1024 * 1024,
|
|
68
|
+
min_value=1024,
|
|
69
|
+
max_value=104857600,
|
|
70
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
71
|
+
service_name="http_handler",
|
|
72
|
+
) # 50 MB default, min 1 KB, max 100 MB
|
|
73
|
+
_SUPPORTED_OPERATIONS: frozenset[str] = frozenset({"http.get", "http.post"})
|
|
74
|
+
# Streaming chunk size for responses without Content-Length header
|
|
75
|
+
_STREAMING_CHUNK_SIZE: int = 8192 # 8 KB chunks
|
|
76
|
+
|
|
77
|
+
# Handler ID for ModelHandlerOutput
|
|
78
|
+
HANDLER_ID_HTTP: str = "http-handler"
|
|
79
|
+
|
|
80
|
+
# Size category thresholds for sanitized logging
|
|
81
|
+
_SIZE_THRESHOLD_KB: int = 1024 # 1 KB
|
|
82
|
+
_SIZE_THRESHOLD_MB: int = 1024 * 1024 # 1 MB
|
|
83
|
+
_SIZE_THRESHOLD_10MB: int = 10 * 1024 * 1024 # 10 MB
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _categorize_size(size: int) -> str:
|
|
87
|
+
"""Categorize byte size into security-safe categories.
|
|
88
|
+
|
|
89
|
+
This prevents exact payload sizes from being exposed in error messages
|
|
90
|
+
and logs, which could help attackers probe size limits.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
size: Size in bytes
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Size category: "small", "medium", "large", or "very_large"
|
|
97
|
+
"""
|
|
98
|
+
if size < _SIZE_THRESHOLD_KB:
|
|
99
|
+
return "small"
|
|
100
|
+
elif size < _SIZE_THRESHOLD_MB:
|
|
101
|
+
return "medium"
|
|
102
|
+
elif size < _SIZE_THRESHOLD_10MB:
|
|
103
|
+
return "large"
|
|
104
|
+
else:
|
|
105
|
+
return "very_large"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class HandlerHttpRest(MixinEnvelopeExtraction):
|
|
109
|
+
"""HTTP REST protocol handler using httpx async client (MVP: GET, POST only).
|
|
110
|
+
|
|
111
|
+
Security Features:
|
|
112
|
+
- Configurable request/response size limits to prevent DoS attacks
|
|
113
|
+
- Pre-read Content-Length validation to prevent memory exhaustion
|
|
114
|
+
- Streaming body validation for chunked transfer encoding
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
def __init__(self) -> None:
|
|
118
|
+
"""Initialize HandlerHttpRest in uninitialized state."""
|
|
119
|
+
self._client: httpx.AsyncClient | None = None
|
|
120
|
+
self._timeout: float = _DEFAULT_TIMEOUT_SECONDS
|
|
121
|
+
self._max_request_size: int = _DEFAULT_MAX_REQUEST_SIZE
|
|
122
|
+
self._max_response_size: int = _DEFAULT_MAX_RESPONSE_SIZE
|
|
123
|
+
self._initialized: bool = False
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def handler_type(self) -> EnumHandlerType:
|
|
127
|
+
"""Return the architectural role of this handler.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
EnumHandlerType.INFRA_HANDLER - This handler is an infrastructure
|
|
131
|
+
protocol/transport handler (as opposed to NODE_HANDLER for event
|
|
132
|
+
processing, PROJECTION_HANDLER for read models, or COMPUTE_HANDLER
|
|
133
|
+
for pure computation).
|
|
134
|
+
|
|
135
|
+
Note:
|
|
136
|
+
handler_type determines lifecycle, protocol selection, and runtime
|
|
137
|
+
invocation patterns. It answers "what is this handler in the architecture?"
|
|
138
|
+
|
|
139
|
+
See Also:
|
|
140
|
+
- handler_category: Behavioral classification (EFFECT/COMPUTE)
|
|
141
|
+
- transport_type: Specific transport protocol (HTTP/DATABASE/etc.)
|
|
142
|
+
- docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
|
|
143
|
+
"""
|
|
144
|
+
return EnumHandlerType.INFRA_HANDLER
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def handler_category(self) -> EnumHandlerTypeCategory:
|
|
148
|
+
"""Return the behavioral classification of this handler.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
EnumHandlerTypeCategory.EFFECT - This handler performs side-effecting
|
|
152
|
+
I/O operations (external HTTP requests). EFFECT handlers are not
|
|
153
|
+
deterministic and interact with external systems.
|
|
154
|
+
|
|
155
|
+
Note:
|
|
156
|
+
handler_category determines security rules, determinism guarantees,
|
|
157
|
+
replay safety, and permissions. It answers "how does this handler
|
|
158
|
+
behave at runtime?"
|
|
159
|
+
|
|
160
|
+
Categories:
|
|
161
|
+
- COMPUTE: Pure, deterministic transformations (no side effects)
|
|
162
|
+
- EFFECT: Side-effecting I/O (database, HTTP, service calls)
|
|
163
|
+
- NONDETERMINISTIC_COMPUTE: Pure but not deterministic (UUID, random)
|
|
164
|
+
|
|
165
|
+
See Also:
|
|
166
|
+
- handler_type: Architectural role (INFRA_HANDLER/NODE_HANDLER/etc.)
|
|
167
|
+
- transport_type: Specific transport protocol (HTTP/DATABASE/etc.)
|
|
168
|
+
- docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
|
|
169
|
+
"""
|
|
170
|
+
return EnumHandlerTypeCategory.EFFECT
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def transport_type(self) -> EnumInfraTransportType:
|
|
174
|
+
"""Return the transport protocol identifier for this handler.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
EnumInfraTransportType.HTTP - This handler uses HTTP/REST protocol.
|
|
178
|
+
|
|
179
|
+
Note:
|
|
180
|
+
transport_type identifies the specific transport/protocol this handler
|
|
181
|
+
uses. It is the third dimension of the handler type system, alongside
|
|
182
|
+
handler_type (architectural role) and handler_category (behavioral
|
|
183
|
+
classification).
|
|
184
|
+
|
|
185
|
+
The three dimensions together form a complete handler classification:
|
|
186
|
+
- handler_type: INFRA_HANDLER (what it is architecturally)
|
|
187
|
+
- handler_category: EFFECT (how it behaves at runtime)
|
|
188
|
+
- transport_type: HTTP (what protocol it uses)
|
|
189
|
+
|
|
190
|
+
See Also:
|
|
191
|
+
- handler_type: Architectural role
|
|
192
|
+
- handler_category: Behavioral classification
|
|
193
|
+
- docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
|
|
194
|
+
"""
|
|
195
|
+
return EnumInfraTransportType.HTTP
|
|
196
|
+
|
|
197
|
+
async def initialize(self, config: dict[str, object]) -> None:
|
|
198
|
+
"""Initialize HTTP client with configurable timeout and size limits.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
config: Configuration dict containing:
|
|
202
|
+
- max_request_size: Optional max request body size in bytes (default: 10 MB)
|
|
203
|
+
- max_response_size: Optional max response body size in bytes (default: 50 MB)
|
|
204
|
+
- correlation_id: Optional UUID or string for error tracing
|
|
205
|
+
|
|
206
|
+
Raises:
|
|
207
|
+
ProtocolConfigurationError: If client initialization fails.
|
|
208
|
+
|
|
209
|
+
Security:
|
|
210
|
+
Size limits provide DoS (Denial of Service) protection by preventing:
|
|
211
|
+
- Memory exhaustion from oversized request bodies
|
|
212
|
+
- Memory exhaustion from malicious/misconfigured server responses
|
|
213
|
+
- Resource starvation attacks via large payload processing
|
|
214
|
+
|
|
215
|
+
Content-Length headers are validated BEFORE reading response bodies,
|
|
216
|
+
and streaming validation protects against chunked transfer encoding attacks.
|
|
217
|
+
|
|
218
|
+
Note:
|
|
219
|
+
Size limit violations raise InfraUnavailableError with sanitized size
|
|
220
|
+
categories (small/medium/large/very_large) - exact sizes are not exposed
|
|
221
|
+
in error messages to prevent attackers from probing limits.
|
|
222
|
+
"""
|
|
223
|
+
# Generate correlation_id for initialization tracing
|
|
224
|
+
init_correlation_id = uuid4()
|
|
225
|
+
|
|
226
|
+
logger.info(
|
|
227
|
+
"Initializing %s",
|
|
228
|
+
self.__class__.__name__,
|
|
229
|
+
extra={
|
|
230
|
+
"handler": self.__class__.__name__,
|
|
231
|
+
"correlation_id": str(init_correlation_id),
|
|
232
|
+
},
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
self._timeout = _DEFAULT_TIMEOUT_SECONDS
|
|
237
|
+
|
|
238
|
+
# Extract configurable size limits
|
|
239
|
+
max_request_raw = config.get("max_request_size")
|
|
240
|
+
if max_request_raw is not None:
|
|
241
|
+
if isinstance(max_request_raw, int) and max_request_raw > 0:
|
|
242
|
+
self._max_request_size = max_request_raw
|
|
243
|
+
else:
|
|
244
|
+
logger.warning(
|
|
245
|
+
"Invalid max_request_size config value ignored, using default",
|
|
246
|
+
extra={
|
|
247
|
+
"provided_value": max_request_raw,
|
|
248
|
+
"default_value": self._max_request_size,
|
|
249
|
+
},
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
max_response_raw = config.get("max_response_size")
|
|
253
|
+
if max_response_raw is not None:
|
|
254
|
+
if isinstance(max_response_raw, int) and max_response_raw > 0:
|
|
255
|
+
self._max_response_size = max_response_raw
|
|
256
|
+
else:
|
|
257
|
+
logger.warning(
|
|
258
|
+
"Invalid max_response_size config value ignored, using default",
|
|
259
|
+
extra={
|
|
260
|
+
"provided_value": max_response_raw,
|
|
261
|
+
"default_value": self._max_response_size,
|
|
262
|
+
},
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
self._client = httpx.AsyncClient(
|
|
266
|
+
timeout=httpx.Timeout(self._timeout),
|
|
267
|
+
follow_redirects=True,
|
|
268
|
+
)
|
|
269
|
+
self._initialized = True
|
|
270
|
+
logger.info(
|
|
271
|
+
"%s initialized successfully",
|
|
272
|
+
self.__class__.__name__,
|
|
273
|
+
extra={
|
|
274
|
+
"handler": self.__class__.__name__,
|
|
275
|
+
"timeout_seconds": self._timeout,
|
|
276
|
+
"max_request_size_bytes": self._max_request_size,
|
|
277
|
+
"max_response_size_bytes": self._max_response_size,
|
|
278
|
+
"correlation_id": str(init_correlation_id),
|
|
279
|
+
},
|
|
280
|
+
)
|
|
281
|
+
except Exception as e:
|
|
282
|
+
ctx = ModelInfraErrorContext(
|
|
283
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
284
|
+
operation="initialize",
|
|
285
|
+
target_name="http_handler",
|
|
286
|
+
correlation_id=init_correlation_id,
|
|
287
|
+
)
|
|
288
|
+
raise ProtocolConfigurationError(
|
|
289
|
+
"Failed to initialize HTTP handler", context=ctx
|
|
290
|
+
) from e
|
|
291
|
+
|
|
292
|
+
async def shutdown(self) -> None:
|
|
293
|
+
"""Close HTTP client and release resources."""
|
|
294
|
+
if self._client is not None:
|
|
295
|
+
await self._client.aclose()
|
|
296
|
+
self._client = None
|
|
297
|
+
self._initialized = False
|
|
298
|
+
logger.info("HandlerHttpRest shutdown complete")
|
|
299
|
+
|
|
300
|
+
async def execute(
|
|
301
|
+
self, envelope: dict[str, object]
|
|
302
|
+
) -> ModelHandlerOutput[dict[str, object]]:
|
|
303
|
+
"""Execute HTTP operation (http.get or http.post) from envelope.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
envelope: Request envelope containing:
|
|
307
|
+
- operation: "http.get" or "http.post"
|
|
308
|
+
- payload: dict with "url" (required), "headers" (optional), "body" (optional for POST)
|
|
309
|
+
- correlation_id: Optional correlation ID for tracing
|
|
310
|
+
- envelope_id: Optional envelope ID for causality tracking
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
ModelHandlerOutput[dict[str, object]] containing:
|
|
314
|
+
- result: dict with status, payload (status_code, headers, body), and correlation_id
|
|
315
|
+
- input_envelope_id: UUID for causality tracking
|
|
316
|
+
- correlation_id: UUID for request/response correlation
|
|
317
|
+
- handler_id: "http-handler"
|
|
318
|
+
"""
|
|
319
|
+
correlation_id = self._extract_correlation_id(envelope)
|
|
320
|
+
input_envelope_id = self._extract_envelope_id(envelope)
|
|
321
|
+
|
|
322
|
+
if not self._initialized or self._client is None:
|
|
323
|
+
ctx = ModelInfraErrorContext(
|
|
324
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
325
|
+
operation="execute",
|
|
326
|
+
target_name="http_handler",
|
|
327
|
+
correlation_id=correlation_id,
|
|
328
|
+
)
|
|
329
|
+
raise RuntimeHostError(
|
|
330
|
+
"HandlerHttpRest not initialized. Call initialize() first.", context=ctx
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
operation = envelope.get("operation")
|
|
334
|
+
if not isinstance(operation, str):
|
|
335
|
+
ctx = ModelInfraErrorContext(
|
|
336
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
337
|
+
operation="execute",
|
|
338
|
+
target_name="http_handler",
|
|
339
|
+
correlation_id=correlation_id,
|
|
340
|
+
)
|
|
341
|
+
raise ProtocolConfigurationError(
|
|
342
|
+
"Missing or invalid 'operation' in envelope", context=ctx
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
if operation not in _SUPPORTED_OPERATIONS:
|
|
346
|
+
ctx = ModelInfraErrorContext(
|
|
347
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
348
|
+
operation=operation,
|
|
349
|
+
target_name="http_handler",
|
|
350
|
+
correlation_id=correlation_id,
|
|
351
|
+
)
|
|
352
|
+
raise ProtocolConfigurationError(
|
|
353
|
+
f"Operation '{operation}' not supported in MVP. Available: {', '.join(sorted(_SUPPORTED_OPERATIONS))}",
|
|
354
|
+
context=ctx,
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
payload = envelope.get("payload")
|
|
358
|
+
if not isinstance(payload, dict):
|
|
359
|
+
ctx = ModelInfraErrorContext(
|
|
360
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
361
|
+
operation=operation,
|
|
362
|
+
target_name="http_handler",
|
|
363
|
+
correlation_id=correlation_id,
|
|
364
|
+
)
|
|
365
|
+
raise ProtocolConfigurationError(
|
|
366
|
+
"Missing or invalid 'payload' in envelope", context=ctx
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
url = payload.get("url")
|
|
370
|
+
if not isinstance(url, str) or not url:
|
|
371
|
+
ctx = ModelInfraErrorContext(
|
|
372
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
373
|
+
operation=operation,
|
|
374
|
+
target_name="http_handler",
|
|
375
|
+
correlation_id=correlation_id,
|
|
376
|
+
)
|
|
377
|
+
raise ProtocolConfigurationError(
|
|
378
|
+
"Missing or invalid 'url' in payload", context=ctx
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
headers = self._extract_headers(payload, operation, url, correlation_id)
|
|
382
|
+
|
|
383
|
+
if operation == "http.get":
|
|
384
|
+
return await self._execute_request(
|
|
385
|
+
"GET", url, headers, None, correlation_id, input_envelope_id, None
|
|
386
|
+
)
|
|
387
|
+
else: # http.post
|
|
388
|
+
body = payload.get("body")
|
|
389
|
+
# Validate request body size and get pre-serialized bytes for dict bodies.
|
|
390
|
+
# This avoids double serialization - dict bodies are serialized once here
|
|
391
|
+
# and the cached bytes are passed to _execute_request().
|
|
392
|
+
pre_serialized = self._validate_request_size(body, correlation_id)
|
|
393
|
+
return await self._execute_request(
|
|
394
|
+
"POST",
|
|
395
|
+
url,
|
|
396
|
+
headers,
|
|
397
|
+
body,
|
|
398
|
+
correlation_id,
|
|
399
|
+
input_envelope_id,
|
|
400
|
+
pre_serialized,
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
def _extract_headers(
|
|
404
|
+
self,
|
|
405
|
+
payload: dict[str, object],
|
|
406
|
+
operation: str,
|
|
407
|
+
url: str,
|
|
408
|
+
correlation_id: UUID,
|
|
409
|
+
) -> dict[str, str]:
|
|
410
|
+
"""Extract and validate headers from payload."""
|
|
411
|
+
headers_raw = payload.get("headers")
|
|
412
|
+
if headers_raw is None:
|
|
413
|
+
return {}
|
|
414
|
+
if isinstance(headers_raw, dict):
|
|
415
|
+
return {str(k): str(v) for k, v in headers_raw.items()}
|
|
416
|
+
ctx = ModelInfraErrorContext(
|
|
417
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
418
|
+
operation=operation,
|
|
419
|
+
target_name=url,
|
|
420
|
+
correlation_id=correlation_id,
|
|
421
|
+
)
|
|
422
|
+
raise ProtocolConfigurationError(
|
|
423
|
+
"Invalid 'headers' in payload - must be a dict", context=ctx
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
def _validate_request_size(
|
|
427
|
+
self, body: object, correlation_id: UUID
|
|
428
|
+
) -> bytes | None:
|
|
429
|
+
"""Validate request body size and cache serialized bytes for dict bodies.
|
|
430
|
+
|
|
431
|
+
For dict bodies, this method serializes the body once and returns the
|
|
432
|
+
serialized bytes. This avoids double serialization - the returned bytes
|
|
433
|
+
can be passed directly to _execute_request() instead of re-serializing.
|
|
434
|
+
|
|
435
|
+
Args:
|
|
436
|
+
body: Request body (str, dict, bytes, or None)
|
|
437
|
+
correlation_id: Correlation ID for error context
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
For dict bodies: The pre-serialized JSON bytes (cached for reuse)
|
|
441
|
+
For other body types: None (no caching needed)
|
|
442
|
+
|
|
443
|
+
Raises:
|
|
444
|
+
InfraUnavailableError: If body size exceeds max_request_size limit.
|
|
445
|
+
"""
|
|
446
|
+
if body is None:
|
|
447
|
+
return None
|
|
448
|
+
|
|
449
|
+
size: int = 0
|
|
450
|
+
serialized_bytes: bytes | None = None
|
|
451
|
+
|
|
452
|
+
if isinstance(body, str):
|
|
453
|
+
size = len(body.encode("utf-8"))
|
|
454
|
+
elif isinstance(body, dict):
|
|
455
|
+
# DESIGN TRADEOFF: Double-Serialization Avoidance
|
|
456
|
+
#
|
|
457
|
+
# We serialize dict bodies once here during validation and cache the bytes.
|
|
458
|
+
# The cached bytes are then passed to _execute_request() via the return value,
|
|
459
|
+
# avoiding re-serialization when building the HTTP request.
|
|
460
|
+
#
|
|
461
|
+
# Tradeoff considerations:
|
|
462
|
+
# - Memory: Serialized bytes are held in memory during validation and request
|
|
463
|
+
# execution. For large payloads near the size limit, this adds ~10MB overhead.
|
|
464
|
+
# - Performance: Single serialization is faster than serializing twice (once
|
|
465
|
+
# for size check, once for request body).
|
|
466
|
+
# - Alternative: We could serialize twice (once here for size, once in execute)
|
|
467
|
+
# which would use less peak memory but double the CPU cost for serialization.
|
|
468
|
+
#
|
|
469
|
+
# Current approach prioritizes CPU efficiency over peak memory usage, which is
|
|
470
|
+
# appropriate since we enforce max_request_size limits anyway.
|
|
471
|
+
try:
|
|
472
|
+
serialized_bytes = json.dumps(body).encode("utf-8")
|
|
473
|
+
size = len(serialized_bytes)
|
|
474
|
+
except (TypeError, ValueError):
|
|
475
|
+
# If we can't serialize, skip validation and let execute() handle it
|
|
476
|
+
return None
|
|
477
|
+
elif isinstance(body, bytes):
|
|
478
|
+
size = len(body)
|
|
479
|
+
else:
|
|
480
|
+
# Unknown type - skip validation, let execute() handle serialization
|
|
481
|
+
return None
|
|
482
|
+
|
|
483
|
+
if size > self._max_request_size:
|
|
484
|
+
ctx = ModelInfraErrorContext(
|
|
485
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
486
|
+
operation="validate_request_size",
|
|
487
|
+
target_name="http_handler",
|
|
488
|
+
correlation_id=correlation_id,
|
|
489
|
+
)
|
|
490
|
+
raise InfraUnavailableError(
|
|
491
|
+
f"Request body size ({_categorize_size(size)}) exceeds configured limit",
|
|
492
|
+
context=ctx,
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
logger.debug(
|
|
496
|
+
"Request size validated",
|
|
497
|
+
extra={
|
|
498
|
+
"request_size_category": _categorize_size(size),
|
|
499
|
+
"limit": self._max_request_size,
|
|
500
|
+
"correlation_id": str(correlation_id),
|
|
501
|
+
},
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
# Return cached serialized bytes for dict bodies, None for other types
|
|
505
|
+
return serialized_bytes
|
|
506
|
+
|
|
507
|
+
def _validate_content_length_header(
|
|
508
|
+
self, response: httpx.Response, url: str, correlation_id: UUID
|
|
509
|
+
) -> None:
|
|
510
|
+
"""Validate Content-Length header BEFORE reading response body.
|
|
511
|
+
|
|
512
|
+
This prevents memory exhaustion by rejecting large responses before
|
|
513
|
+
they are loaded into memory. This is critical for security as it
|
|
514
|
+
prevents denial-of-service attacks via large response payloads.
|
|
515
|
+
|
|
516
|
+
Args:
|
|
517
|
+
response: The httpx Response object (body not yet read)
|
|
518
|
+
url: Target URL for error context
|
|
519
|
+
correlation_id: Correlation ID for error context
|
|
520
|
+
|
|
521
|
+
Raises:
|
|
522
|
+
InfraUnavailableError: If Content-Length exceeds max_response_size limit.
|
|
523
|
+
"""
|
|
524
|
+
content_length_header = response.headers.get("content-length")
|
|
525
|
+
if content_length_header is None:
|
|
526
|
+
# No Content-Length header - will use streaming validation
|
|
527
|
+
return
|
|
528
|
+
|
|
529
|
+
try:
|
|
530
|
+
content_length = int(content_length_header)
|
|
531
|
+
except ValueError:
|
|
532
|
+
# Invalid Content-Length header - log warning and proceed with body-based validation
|
|
533
|
+
logger.warning(
|
|
534
|
+
"Invalid Content-Length header value",
|
|
535
|
+
extra={
|
|
536
|
+
"content_length_header": content_length_header,
|
|
537
|
+
"url": url,
|
|
538
|
+
"correlation_id": str(correlation_id),
|
|
539
|
+
},
|
|
540
|
+
)
|
|
541
|
+
return
|
|
542
|
+
|
|
543
|
+
if content_length < 0:
|
|
544
|
+
# Negative Content-Length is invalid per HTTP spec - log warning and proceed
|
|
545
|
+
# with body-based validation (streaming protection still applies)
|
|
546
|
+
logger.warning(
|
|
547
|
+
"Negative Content-Length header value ignored",
|
|
548
|
+
extra={
|
|
549
|
+
"content_length_header": content_length_header,
|
|
550
|
+
"url": url,
|
|
551
|
+
"correlation_id": str(correlation_id),
|
|
552
|
+
},
|
|
553
|
+
)
|
|
554
|
+
return
|
|
555
|
+
|
|
556
|
+
if content_length > self._max_response_size:
|
|
557
|
+
ctx = ModelInfraErrorContext(
|
|
558
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
559
|
+
operation="validate_content_length",
|
|
560
|
+
target_name=url,
|
|
561
|
+
correlation_id=correlation_id,
|
|
562
|
+
)
|
|
563
|
+
raise InfraUnavailableError(
|
|
564
|
+
f"Response Content-Length ({_categorize_size(content_length)}) exceeds configured limit",
|
|
565
|
+
context=ctx,
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
logger.debug(
|
|
569
|
+
"Content-Length header validated",
|
|
570
|
+
extra={
|
|
571
|
+
"content_length_category": _categorize_size(content_length),
|
|
572
|
+
"limit": self._max_response_size,
|
|
573
|
+
"url": url,
|
|
574
|
+
"correlation_id": str(correlation_id),
|
|
575
|
+
},
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
async def _read_response_body_with_limit(
|
|
579
|
+
self, response: httpx.Response, url: str, correlation_id: UUID
|
|
580
|
+
) -> bytes:
|
|
581
|
+
"""Read response body with streaming size limit enforcement.
|
|
582
|
+
|
|
583
|
+
For responses without Content-Length header (e.g., chunked transfer encoding),
|
|
584
|
+
this method reads the body in chunks and tracks the total size, stopping
|
|
585
|
+
and raising an error if the limit is exceeded.
|
|
586
|
+
|
|
587
|
+
Security Note: This method provides DoS protection for chunked transfer
|
|
588
|
+
encoding responses where Content-Length is not available for pre-read
|
|
589
|
+
validation. By enforcing limits during streaming, we prevent memory
|
|
590
|
+
exhaustion attacks from maliciously large chunked responses.
|
|
591
|
+
|
|
592
|
+
Args:
|
|
593
|
+
response: The httpx Response object
|
|
594
|
+
url: Target URL for error context
|
|
595
|
+
correlation_id: Correlation ID for error context
|
|
596
|
+
|
|
597
|
+
Returns:
|
|
598
|
+
The complete response body as bytes
|
|
599
|
+
|
|
600
|
+
Raises:
|
|
601
|
+
InfraUnavailableError: If body size exceeds max_response_size during streaming.
|
|
602
|
+
"""
|
|
603
|
+
chunks: list[bytes] = []
|
|
604
|
+
total_size: int = 0
|
|
605
|
+
|
|
606
|
+
async for chunk in response.aiter_bytes(chunk_size=_STREAMING_CHUNK_SIZE):
|
|
607
|
+
total_size += len(chunk)
|
|
608
|
+
if total_size > self._max_response_size:
|
|
609
|
+
logger.warning(
|
|
610
|
+
"Response body exceeded size limit during streaming read",
|
|
611
|
+
extra={
|
|
612
|
+
"size_category": _categorize_size(total_size),
|
|
613
|
+
"limit": self._max_response_size,
|
|
614
|
+
"url": url,
|
|
615
|
+
"correlation_id": str(correlation_id),
|
|
616
|
+
},
|
|
617
|
+
)
|
|
618
|
+
ctx = ModelInfraErrorContext(
|
|
619
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
620
|
+
operation="read_response_body",
|
|
621
|
+
target_name=url,
|
|
622
|
+
correlation_id=correlation_id,
|
|
623
|
+
)
|
|
624
|
+
raise InfraUnavailableError(
|
|
625
|
+
f"Response body size ({_categorize_size(total_size)}) exceeds configured limit during streaming read",
|
|
626
|
+
context=ctx,
|
|
627
|
+
)
|
|
628
|
+
chunks.append(chunk)
|
|
629
|
+
|
|
630
|
+
return b"".join(chunks)
|
|
631
|
+
|
|
632
|
+
def _prepare_request_content(
|
|
633
|
+
self,
|
|
634
|
+
method: str,
|
|
635
|
+
headers: dict[str, str],
|
|
636
|
+
body_content: ModelHttpBodyContent,
|
|
637
|
+
ctx: ModelInfraErrorContext,
|
|
638
|
+
) -> tuple[bytes | str | None, dict[str, object] | None, dict[str, str]]:
|
|
639
|
+
"""Prepare request content for HTTP request.
|
|
640
|
+
|
|
641
|
+
Handles body serialization for POST requests, managing pre-serialized bytes
|
|
642
|
+
from size validation and various body types (dict, str, other JSON-serializable).
|
|
643
|
+
|
|
644
|
+
Args:
|
|
645
|
+
method: HTTP method (GET, POST)
|
|
646
|
+
headers: Request headers (will be copied, not mutated)
|
|
647
|
+
body_content: Model containing body and optional pre-serialized bytes
|
|
648
|
+
ctx: Error context for exceptions
|
|
649
|
+
|
|
650
|
+
Returns:
|
|
651
|
+
Tuple of (request_content, request_json, request_headers):
|
|
652
|
+
- request_content: bytes or str content for the request
|
|
653
|
+
- request_json: dict for httpx json= parameter (mutually exclusive with content)
|
|
654
|
+
- request_headers: Headers dict (possibly with Content-Type added)
|
|
655
|
+
|
|
656
|
+
Raises:
|
|
657
|
+
ProtocolConfigurationError: If body is not JSON-serializable.
|
|
658
|
+
"""
|
|
659
|
+
request_content: bytes | str | None = None
|
|
660
|
+
request_json: dict[str, object] | None = None
|
|
661
|
+
request_headers = dict(headers) # Copy to avoid mutating caller's headers
|
|
662
|
+
|
|
663
|
+
body = body_content.body
|
|
664
|
+
pre_serialized = body_content.pre_serialized
|
|
665
|
+
|
|
666
|
+
if method != "POST" or body is None:
|
|
667
|
+
return request_content, request_json, request_headers
|
|
668
|
+
|
|
669
|
+
if pre_serialized is not None:
|
|
670
|
+
# Use pre-serialized bytes from _validate_request_size to avoid
|
|
671
|
+
# double serialization. Set Content-Type header since we're using
|
|
672
|
+
# content= instead of json= parameter.
|
|
673
|
+
request_content = pre_serialized
|
|
674
|
+
if "content-type" not in {k.lower() for k in request_headers}:
|
|
675
|
+
request_headers["Content-Type"] = "application/json"
|
|
676
|
+
elif isinstance(body, dict):
|
|
677
|
+
# Fallback for dict bodies without pre-serialized content
|
|
678
|
+
# (shouldn't happen in normal flow, but handles edge cases)
|
|
679
|
+
request_json = body
|
|
680
|
+
elif isinstance(body, str):
|
|
681
|
+
request_content = body
|
|
682
|
+
else:
|
|
683
|
+
try:
|
|
684
|
+
request_content = json.dumps(body)
|
|
685
|
+
except TypeError as e:
|
|
686
|
+
raise ProtocolConfigurationError(
|
|
687
|
+
f"Body is not JSON-serializable: {type(body).__name__}",
|
|
688
|
+
context=ctx,
|
|
689
|
+
) from e
|
|
690
|
+
|
|
691
|
+
return request_content, request_json, request_headers
|
|
692
|
+
|
|
693
|
+
async def _execute_request(
|
|
694
|
+
self,
|
|
695
|
+
method: str,
|
|
696
|
+
url: str,
|
|
697
|
+
headers: dict[str, str],
|
|
698
|
+
body: object,
|
|
699
|
+
correlation_id: UUID,
|
|
700
|
+
input_envelope_id: UUID,
|
|
701
|
+
pre_serialized: bytes | None = None,
|
|
702
|
+
) -> ModelHandlerOutput[dict[str, object]]:
|
|
703
|
+
"""Execute HTTP request with pre-read response size validation.
|
|
704
|
+
|
|
705
|
+
Uses httpx streaming to validate Content-Length header BEFORE reading
|
|
706
|
+
the response body into memory, preventing memory exhaustion attacks.
|
|
707
|
+
|
|
708
|
+
Args:
|
|
709
|
+
method: HTTP method (GET, POST)
|
|
710
|
+
url: Target URL
|
|
711
|
+
headers: Request headers
|
|
712
|
+
body: Request body (used only if pre_serialized is None)
|
|
713
|
+
correlation_id: Correlation ID for tracing
|
|
714
|
+
input_envelope_id: Envelope ID for causality tracking
|
|
715
|
+
pre_serialized: Pre-serialized JSON bytes for dict bodies (from
|
|
716
|
+
_validate_request_size). When provided, this is used directly
|
|
717
|
+
instead of re-serializing the body, avoiding double serialization.
|
|
718
|
+
|
|
719
|
+
Returns:
|
|
720
|
+
ModelHandlerOutput[dict[str, object]] with wrapped response data
|
|
721
|
+
"""
|
|
722
|
+
if self._client is None:
|
|
723
|
+
ctx = ModelInfraErrorContext(
|
|
724
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
725
|
+
operation=f"http.{method.lower()}",
|
|
726
|
+
target_name=url,
|
|
727
|
+
correlation_id=correlation_id,
|
|
728
|
+
)
|
|
729
|
+
raise RuntimeHostError(
|
|
730
|
+
"HandlerHttpRest not initialized - call initialize() first", context=ctx
|
|
731
|
+
)
|
|
732
|
+
|
|
733
|
+
ctx = ModelInfraErrorContext(
|
|
734
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
735
|
+
operation=f"http.{method.lower()}",
|
|
736
|
+
target_name=url,
|
|
737
|
+
correlation_id=correlation_id,
|
|
738
|
+
)
|
|
739
|
+
|
|
740
|
+
# Prepare request content for POST
|
|
741
|
+
body_content = ModelHttpBodyContent(body=body, pre_serialized=pre_serialized)
|
|
742
|
+
request_content, request_json, request_headers = self._prepare_request_content(
|
|
743
|
+
method, headers, body_content, ctx
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
try:
|
|
747
|
+
# Use streaming request to get response headers before reading body
|
|
748
|
+
# This allows us to check Content-Length before loading body into memory
|
|
749
|
+
async with self._client.stream(
|
|
750
|
+
method,
|
|
751
|
+
url,
|
|
752
|
+
headers=request_headers,
|
|
753
|
+
content=request_content,
|
|
754
|
+
json=request_json,
|
|
755
|
+
) as response:
|
|
756
|
+
# CRITICAL: Validate Content-Length header BEFORE reading body
|
|
757
|
+
# This prevents memory exhaustion from large responses
|
|
758
|
+
self._validate_content_length_header(response, url, correlation_id)
|
|
759
|
+
|
|
760
|
+
# Read body with streaming size limit enforcement
|
|
761
|
+
# For responses without Content-Length, this stops early if limit exceeded
|
|
762
|
+
response_body_bytes = await self._read_response_body_with_limit(
|
|
763
|
+
response, url, correlation_id
|
|
764
|
+
)
|
|
765
|
+
|
|
766
|
+
return self._build_response_from_bytes(
|
|
767
|
+
response, response_body_bytes, correlation_id, input_envelope_id
|
|
768
|
+
)
|
|
769
|
+
|
|
770
|
+
except httpx.TimeoutException as e:
|
|
771
|
+
timeout_ctx = ModelTimeoutErrorContext(
|
|
772
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
773
|
+
operation=f"http.{method.lower()}",
|
|
774
|
+
target_name=url,
|
|
775
|
+
correlation_id=correlation_id,
|
|
776
|
+
timeout_seconds=self._timeout,
|
|
777
|
+
)
|
|
778
|
+
raise InfraTimeoutError(
|
|
779
|
+
f"HTTP {method} request timed out after {self._timeout}s",
|
|
780
|
+
context=timeout_ctx,
|
|
781
|
+
) from e
|
|
782
|
+
except httpx.ConnectError as e:
|
|
783
|
+
raise InfraConnectionError(
|
|
784
|
+
f"Failed to connect to {url}", context=ctx
|
|
785
|
+
) from e
|
|
786
|
+
except httpx.HTTPError as e:
|
|
787
|
+
raise InfraConnectionError(
|
|
788
|
+
f"HTTP error during {method} request: {type(e).__name__}", context=ctx
|
|
789
|
+
) from e
|
|
790
|
+
|
|
791
|
+
def _build_response_from_bytes(
|
|
792
|
+
self,
|
|
793
|
+
response: httpx.Response,
|
|
794
|
+
body_bytes: bytes,
|
|
795
|
+
correlation_id: UUID,
|
|
796
|
+
input_envelope_id: UUID,
|
|
797
|
+
) -> ModelHandlerOutput[dict[str, object]]:
|
|
798
|
+
"""Build response envelope from httpx Response and pre-read body bytes.
|
|
799
|
+
|
|
800
|
+
This method is used with streaming responses where the body has already
|
|
801
|
+
been read with size limit enforcement.
|
|
802
|
+
|
|
803
|
+
Args:
|
|
804
|
+
response: The httpx Response object (headers already available)
|
|
805
|
+
body_bytes: The pre-read response body bytes
|
|
806
|
+
correlation_id: Correlation ID for tracing
|
|
807
|
+
input_envelope_id: Envelope ID for causality tracking
|
|
808
|
+
|
|
809
|
+
Returns:
|
|
810
|
+
ModelHandlerOutput wrapping response dict with status, payload, and correlation_id
|
|
811
|
+
"""
|
|
812
|
+
content_type = response.headers.get("content-type", "")
|
|
813
|
+
body: object
|
|
814
|
+
|
|
815
|
+
# TODO(OMN-43): When rate limiting is implemented, extract and log rate limit
|
|
816
|
+
# response headers: x-ratelimit-remaining, x-ratelimit-limit, x-ratelimit-reset
|
|
817
|
+
# These headers will be added to the debug log metadata below for observability.
|
|
818
|
+
|
|
819
|
+
logger.debug(
|
|
820
|
+
"Response body received",
|
|
821
|
+
extra={
|
|
822
|
+
"body_size": len(body_bytes),
|
|
823
|
+
"size_utilization_pct": round(
|
|
824
|
+
(len(body_bytes) / self._max_response_size) * 100, 2
|
|
825
|
+
),
|
|
826
|
+
"content_type": content_type,
|
|
827
|
+
"status_code": response.status_code,
|
|
828
|
+
"correlation_id": str(correlation_id),
|
|
829
|
+
# TODO(OMN-43): Add rate limit metadata here when rate limiting is implemented:
|
|
830
|
+
# "ratelimit_remaining": response.headers.get("x-ratelimit-remaining"),
|
|
831
|
+
# "ratelimit_limit": response.headers.get("x-ratelimit-limit"),
|
|
832
|
+
# "ratelimit_reset": response.headers.get("x-ratelimit-reset"),
|
|
833
|
+
},
|
|
834
|
+
)
|
|
835
|
+
|
|
836
|
+
# Decode bytes to string first
|
|
837
|
+
try:
|
|
838
|
+
body_text = body_bytes.decode("utf-8")
|
|
839
|
+
except UnicodeDecodeError:
|
|
840
|
+
# If UTF-8 decoding fails, try latin-1 as fallback
|
|
841
|
+
body_text = body_bytes.decode("latin-1")
|
|
842
|
+
|
|
843
|
+
# Try to parse as JSON if content type indicates JSON
|
|
844
|
+
if "application/json" in content_type:
|
|
845
|
+
try:
|
|
846
|
+
body = json.loads(body_text)
|
|
847
|
+
except json.JSONDecodeError:
|
|
848
|
+
body = body_text
|
|
849
|
+
else:
|
|
850
|
+
body = body_text
|
|
851
|
+
|
|
852
|
+
return ModelHandlerOutput.for_compute(
|
|
853
|
+
input_envelope_id=input_envelope_id,
|
|
854
|
+
correlation_id=correlation_id,
|
|
855
|
+
handler_id=HANDLER_ID_HTTP,
|
|
856
|
+
result={
|
|
857
|
+
"status": "success",
|
|
858
|
+
"payload": {
|
|
859
|
+
"status_code": response.status_code,
|
|
860
|
+
"headers": dict(response.headers),
|
|
861
|
+
"body": body,
|
|
862
|
+
},
|
|
863
|
+
"correlation_id": str(correlation_id),
|
|
864
|
+
},
|
|
865
|
+
)
|
|
866
|
+
|
|
867
|
+
def describe(self) -> dict[str, object]:
|
|
868
|
+
"""Return handler metadata and capabilities for introspection.
|
|
869
|
+
|
|
870
|
+
This method exposes the handler's three-dimensional type classification
|
|
871
|
+
along with its operational configuration and capabilities.
|
|
872
|
+
|
|
873
|
+
Returns:
|
|
874
|
+
dict containing:
|
|
875
|
+
- handler_type: Architectural role from handler_type property
|
|
876
|
+
(e.g., "infra_handler"). See EnumHandlerType for valid values.
|
|
877
|
+
- handler_category: Behavioral classification from handler_category
|
|
878
|
+
property (e.g., "effect"). See EnumHandlerTypeCategory for valid values.
|
|
879
|
+
- transport_type: Protocol identifier from transport_type property
|
|
880
|
+
(e.g., "http"). See EnumInfraTransportType for valid values.
|
|
881
|
+
- supported_operations: List of supported operations
|
|
882
|
+
- timeout_seconds: Request timeout in seconds
|
|
883
|
+
- max_request_size: Maximum request body size in bytes
|
|
884
|
+
- max_response_size: Maximum response body size in bytes
|
|
885
|
+
- initialized: Whether the handler is initialized
|
|
886
|
+
- version: Handler version string
|
|
887
|
+
|
|
888
|
+
Note:
|
|
889
|
+
The handler_type, handler_category, and transport_type fields form the
|
|
890
|
+
three-dimensional handler classification system:
|
|
891
|
+
|
|
892
|
+
1. handler_type (architectural role): Determines lifecycle and invocation
|
|
893
|
+
patterns. This handler is INFRA_HANDLER (protocol/transport handler).
|
|
894
|
+
|
|
895
|
+
2. handler_category (behavioral classification): Determines security rules
|
|
896
|
+
and replay safety. This handler is EFFECT (side-effecting I/O).
|
|
897
|
+
|
|
898
|
+
3. transport_type (protocol identifier): Identifies the specific transport.
|
|
899
|
+
This handler uses HTTP protocol.
|
|
900
|
+
|
|
901
|
+
See Also:
|
|
902
|
+
- handler_type property: Full documentation of architectural role
|
|
903
|
+
- handler_category property: Full documentation of behavioral classification
|
|
904
|
+
- transport_type property: Full documentation of transport identifier
|
|
905
|
+
- docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
|
|
906
|
+
"""
|
|
907
|
+
return {
|
|
908
|
+
"handler_type": self.handler_type.value,
|
|
909
|
+
"handler_category": self.handler_category.value,
|
|
910
|
+
"transport_type": self.transport_type.value,
|
|
911
|
+
"supported_operations": sorted(_SUPPORTED_OPERATIONS),
|
|
912
|
+
"timeout_seconds": self._timeout,
|
|
913
|
+
"max_request_size": self._max_request_size,
|
|
914
|
+
"max_response_size": self._max_response_size,
|
|
915
|
+
"initialized": self._initialized,
|
|
916
|
+
"version": "0.1.0-mvp",
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
__all__: list[str] = ["HandlerHttpRest"]
|