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,372 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Datetime validation and normalization utilities.
|
|
4
|
+
|
|
5
|
+
This module provides utilities for ensuring datetime values are timezone-aware
|
|
6
|
+
before persisting to databases. Naive datetimes (without timezone info) can cause
|
|
7
|
+
subtle bugs when stored in PostgreSQL's TIMESTAMPTZ columns or when compared
|
|
8
|
+
across different timezones.
|
|
9
|
+
|
|
10
|
+
ONEX Datetime Guidelines:
|
|
11
|
+
- All datetimes should be timezone-aware (preferably UTC)
|
|
12
|
+
- Naive datetimes trigger warnings and are auto-converted to UTC
|
|
13
|
+
- Use datetime.now(UTC) instead of datetime.utcnow() (deprecated in Python 3.12+)
|
|
14
|
+
|
|
15
|
+
See Also:
|
|
16
|
+
- PostgreSQL TIMESTAMPTZ documentation
|
|
17
|
+
- Python datetime best practices (PEP 495)
|
|
18
|
+
- ONEX infrastructure datetime conventions
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
>>> from datetime import datetime, UTC
|
|
22
|
+
>>> from omnibase_infra.utils import ensure_timezone_aware
|
|
23
|
+
>>>
|
|
24
|
+
>>> # Aware datetime passes through unchanged
|
|
25
|
+
>>> aware_dt = datetime.now(UTC)
|
|
26
|
+
>>> result = ensure_timezone_aware(aware_dt)
|
|
27
|
+
>>> result == aware_dt
|
|
28
|
+
True
|
|
29
|
+
>>>
|
|
30
|
+
>>> # Naive datetime is converted to UTC with warning
|
|
31
|
+
>>> naive_dt = datetime(2025, 1, 15, 12, 0, 0)
|
|
32
|
+
>>> result = ensure_timezone_aware(naive_dt) # Logs warning
|
|
33
|
+
>>> result.tzinfo is not None
|
|
34
|
+
True
|
|
35
|
+
|
|
36
|
+
.. versionadded:: 0.8.0
|
|
37
|
+
Created as part of PR #146 datetime validation improvements.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
from __future__ import annotations
|
|
41
|
+
|
|
42
|
+
import logging
|
|
43
|
+
from datetime import UTC, datetime
|
|
44
|
+
from typing import TYPE_CHECKING
|
|
45
|
+
from uuid import UUID, uuid4
|
|
46
|
+
|
|
47
|
+
if TYPE_CHECKING:
|
|
48
|
+
from omnibase_infra.errors import ModelInfraErrorContext
|
|
49
|
+
|
|
50
|
+
logger = logging.getLogger(__name__)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def ensure_timezone_aware(
|
|
54
|
+
dt: datetime,
|
|
55
|
+
*,
|
|
56
|
+
assume_utc: bool = True,
|
|
57
|
+
warn_on_naive: bool = True,
|
|
58
|
+
context: str | None = None,
|
|
59
|
+
) -> datetime:
|
|
60
|
+
"""Ensure a datetime is timezone-aware, converting naive datetimes to UTC.
|
|
61
|
+
|
|
62
|
+
This function validates that datetime values have timezone information before
|
|
63
|
+
they are persisted to the database. Naive datetimes (those without tzinfo)
|
|
64
|
+
are ambiguous and can cause subtle bugs when stored in TIMESTAMPTZ columns
|
|
65
|
+
or compared across timezones.
|
|
66
|
+
|
|
67
|
+
Behavior:
|
|
68
|
+
- Timezone-aware datetimes: Passed through unchanged
|
|
69
|
+
- Naive datetimes with assume_utc=True: Converted to UTC with warning
|
|
70
|
+
- Naive datetimes with assume_utc=False: Raises ProtocolConfigurationError
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
dt: The datetime to validate/normalize.
|
|
74
|
+
assume_utc: If True (default), naive datetimes are assumed to be UTC
|
|
75
|
+
and converted. If False, naive datetimes raise ValueError.
|
|
76
|
+
warn_on_naive: If True (default), logs a warning when a naive datetime
|
|
77
|
+
is converted. Set to False to suppress warnings (e.g., in migration
|
|
78
|
+
scripts where naive datetimes are expected).
|
|
79
|
+
context: Optional context string for the warning message (e.g., column
|
|
80
|
+
name, operation type). Helps identify the source of naive datetimes.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
A timezone-aware datetime. If the input was already aware, returns
|
|
84
|
+
the same datetime. If naive and assume_utc=True, returns a new
|
|
85
|
+
datetime with UTC timezone.
|
|
86
|
+
|
|
87
|
+
Raises:
|
|
88
|
+
ProtocolConfigurationError: If dt is naive and assume_utc=False.
|
|
89
|
+
|
|
90
|
+
Example:
|
|
91
|
+
>>> from datetime import datetime, UTC, timezone
|
|
92
|
+
>>> from omnibase_infra.utils.util_datetime import ensure_timezone_aware
|
|
93
|
+
>>>
|
|
94
|
+
>>> # Already aware - passes through unchanged
|
|
95
|
+
>>> aware = datetime(2025, 1, 15, 12, 0, 0, tzinfo=UTC)
|
|
96
|
+
>>> ensure_timezone_aware(aware) == aware
|
|
97
|
+
True
|
|
98
|
+
>>>
|
|
99
|
+
>>> # Naive datetime - converted to UTC with warning
|
|
100
|
+
>>> naive = datetime(2025, 1, 15, 12, 0, 0)
|
|
101
|
+
>>> result = ensure_timezone_aware(naive, context="updated_at")
|
|
102
|
+
>>> result.tzinfo == UTC
|
|
103
|
+
True
|
|
104
|
+
>>>
|
|
105
|
+
>>> # Strict mode - raises ProtocolConfigurationError for naive datetimes
|
|
106
|
+
>>> ensure_timezone_aware(naive, assume_utc=False) # doctest: +ELLIPSIS
|
|
107
|
+
Traceback (most recent call last):
|
|
108
|
+
...
|
|
109
|
+
omnibase_infra.errors...ProtocolConfigurationError: Naive datetime not allowed...
|
|
110
|
+
|
|
111
|
+
Warning:
|
|
112
|
+
Using assume_utc=True can silently mask timezone bugs in your code.
|
|
113
|
+
It's better to fix the source of naive datetimes than to rely on
|
|
114
|
+
automatic conversion. The warning log helps identify these issues.
|
|
115
|
+
|
|
116
|
+
Related:
|
|
117
|
+
- OMN-1170: Converting ProjectorRegistration to declarative contracts
|
|
118
|
+
- PR #146: Datetime validation improvements
|
|
119
|
+
"""
|
|
120
|
+
# Check if datetime is already timezone-aware
|
|
121
|
+
if is_timezone_aware(dt):
|
|
122
|
+
return dt
|
|
123
|
+
|
|
124
|
+
# Handle naive datetime
|
|
125
|
+
if not assume_utc:
|
|
126
|
+
# Lazy imports to avoid circular dependency (utils -> errors -> models -> utils)
|
|
127
|
+
from omnibase_infra.enums import EnumInfraTransportType
|
|
128
|
+
from omnibase_infra.errors import (
|
|
129
|
+
ModelInfraErrorContext,
|
|
130
|
+
ProtocolConfigurationError,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
error_context = ModelInfraErrorContext(
|
|
134
|
+
transport_type=EnumInfraTransportType.RUNTIME,
|
|
135
|
+
operation="ensure_timezone_aware",
|
|
136
|
+
target_name=context,
|
|
137
|
+
correlation_id=uuid4(),
|
|
138
|
+
)
|
|
139
|
+
raise ProtocolConfigurationError(
|
|
140
|
+
"Naive datetime not allowed. "
|
|
141
|
+
"Use timezone-aware datetime (e.g., datetime.now(UTC)).",
|
|
142
|
+
context=error_context,
|
|
143
|
+
parameter="dt",
|
|
144
|
+
value=dt.isoformat(),
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Log warning if enabled
|
|
148
|
+
if warn_on_naive:
|
|
149
|
+
context_msg = f" for '{context}'" if context else ""
|
|
150
|
+
logger.warning(
|
|
151
|
+
"Converting naive datetime to UTC%s. "
|
|
152
|
+
"Consider using datetime.now(UTC) instead of datetime.utcnow() or naive datetime().",
|
|
153
|
+
context_msg,
|
|
154
|
+
extra={
|
|
155
|
+
"naive_datetime": dt.isoformat(),
|
|
156
|
+
"context": context,
|
|
157
|
+
"action": "converted_to_utc",
|
|
158
|
+
},
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# Convert naive datetime to UTC by replacing tzinfo
|
|
162
|
+
# Using replace() instead of astimezone() because astimezone() interprets
|
|
163
|
+
# naive datetimes as local time, which we don't want
|
|
164
|
+
return dt.replace(tzinfo=UTC)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def is_timezone_aware(dt: datetime) -> bool:
|
|
168
|
+
"""Check if a datetime is timezone-aware.
|
|
169
|
+
|
|
170
|
+
A datetime is timezone-aware if it has a tzinfo attribute that is not None
|
|
171
|
+
AND returns a valid utcoffset(). Some tzinfo objects may be set but not
|
|
172
|
+
properly configured, so we check both conditions.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
dt: The datetime to check.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
True if datetime is timezone-aware, False if naive.
|
|
179
|
+
|
|
180
|
+
Example:
|
|
181
|
+
>>> from datetime import datetime, UTC
|
|
182
|
+
>>> from omnibase_infra.utils.util_datetime import is_timezone_aware
|
|
183
|
+
>>>
|
|
184
|
+
>>> is_timezone_aware(datetime.now(UTC))
|
|
185
|
+
True
|
|
186
|
+
>>> is_timezone_aware(datetime.now()) # Naive
|
|
187
|
+
False
|
|
188
|
+
"""
|
|
189
|
+
return dt.tzinfo is not None and dt.utcoffset() is not None
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def validate_timezone_aware_with_context(
|
|
193
|
+
dt: datetime,
|
|
194
|
+
context: ModelInfraErrorContext,
|
|
195
|
+
*,
|
|
196
|
+
field_name: str = "envelope_timestamp",
|
|
197
|
+
) -> datetime:
|
|
198
|
+
"""Validate that a datetime is timezone-aware, raising ProtocolConfigurationError if not.
|
|
199
|
+
|
|
200
|
+
This is the SINGLE SOURCE OF TRUTH for handler-level timezone validation.
|
|
201
|
+
Use this function when you need to validate datetime values in handlers
|
|
202
|
+
and raise structured errors with context information.
|
|
203
|
+
|
|
204
|
+
For Pydantic field validators, use :func:`validate_timezone_aware_datetime`
|
|
205
|
+
from ``util_pydantic_validators.py`` instead.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
dt: The datetime to validate.
|
|
209
|
+
context: A ModelInfraErrorContext instance for error reporting.
|
|
210
|
+
The context provides transport_type, operation, target_name,
|
|
211
|
+
and correlation_id for the error.
|
|
212
|
+
field_name: Name of the field being validated, used in error message.
|
|
213
|
+
Defaults to "envelope_timestamp".
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
The validated datetime (unchanged if valid).
|
|
217
|
+
|
|
218
|
+
Raises:
|
|
219
|
+
ProtocolConfigurationError: If datetime is naive (no timezone info).
|
|
220
|
+
|
|
221
|
+
Example:
|
|
222
|
+
>>> from datetime import datetime, UTC
|
|
223
|
+
>>> from uuid import uuid4
|
|
224
|
+
>>> from omnibase_infra.enums import EnumInfraTransportType
|
|
225
|
+
>>> from omnibase_infra.errors import ModelInfraErrorContext
|
|
226
|
+
>>> from omnibase_infra.utils import validate_timezone_aware_with_context
|
|
227
|
+
>>>
|
|
228
|
+
>>> ctx = ModelInfraErrorContext(
|
|
229
|
+
... transport_type=EnumInfraTransportType.RUNTIME,
|
|
230
|
+
... operation="handle_event",
|
|
231
|
+
... target_name="my_handler",
|
|
232
|
+
... correlation_id=uuid4(),
|
|
233
|
+
... )
|
|
234
|
+
>>>
|
|
235
|
+
>>> # Valid: timezone-aware datetime passes through
|
|
236
|
+
>>> aware = datetime.now(UTC)
|
|
237
|
+
>>> validate_timezone_aware_with_context(aware, ctx) == aware
|
|
238
|
+
True
|
|
239
|
+
>>>
|
|
240
|
+
>>> # Invalid: naive datetime raises ProtocolConfigurationError
|
|
241
|
+
>>> naive = datetime.now()
|
|
242
|
+
>>> validate_timezone_aware_with_context(naive, ctx) # doctest: +ELLIPSIS
|
|
243
|
+
Traceback (most recent call last):
|
|
244
|
+
...
|
|
245
|
+
omnibase_infra.errors...ProtocolConfigurationError: envelope_timestamp must be timezone-aware...
|
|
246
|
+
|
|
247
|
+
Related:
|
|
248
|
+
- OMN-1181: Replace RuntimeError with structured errors
|
|
249
|
+
- PR #158: Consolidate duplicate validation functions
|
|
250
|
+
|
|
251
|
+
.. versionadded:: 0.9.1
|
|
252
|
+
Created to consolidate duplicate timezone validation in handlers.
|
|
253
|
+
"""
|
|
254
|
+
if is_timezone_aware(dt):
|
|
255
|
+
return dt
|
|
256
|
+
|
|
257
|
+
# Lazy imports to avoid circular dependency (utils -> errors -> models -> utils)
|
|
258
|
+
from omnibase_infra.errors import ProtocolConfigurationError
|
|
259
|
+
|
|
260
|
+
raise ProtocolConfigurationError(
|
|
261
|
+
f"{field_name} must be timezone-aware. Use datetime.now(UTC) or "
|
|
262
|
+
"datetime(..., tzinfo=timezone.utc) instead of naive datetime.",
|
|
263
|
+
context=context,
|
|
264
|
+
parameter=field_name,
|
|
265
|
+
value=dt.isoformat(),
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def warn_if_naive_datetime(
|
|
270
|
+
dt: datetime,
|
|
271
|
+
*,
|
|
272
|
+
field_name: str | None = None,
|
|
273
|
+
context: str | None = None,
|
|
274
|
+
correlation_id: UUID | None = None,
|
|
275
|
+
logger: logging.Logger | None = None,
|
|
276
|
+
) -> None:
|
|
277
|
+
"""Log a warning if the datetime is naive (lacks timezone info).
|
|
278
|
+
|
|
279
|
+
This is a WARNING-ONLY function that does not modify or convert the datetime.
|
|
280
|
+
Use this when you want to detect and log naive datetimes without changing
|
|
281
|
+
them, such as for auditing or gradual migration scenarios.
|
|
282
|
+
|
|
283
|
+
For automatic conversion of naive datetimes to UTC, use :func:`ensure_timezone_aware`
|
|
284
|
+
instead.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
dt: The datetime to check for timezone awareness.
|
|
288
|
+
field_name: Optional name of the field/column containing the datetime.
|
|
289
|
+
Used in the warning message to identify the source.
|
|
290
|
+
context: Optional context string for the warning message (e.g., operation
|
|
291
|
+
name, handler name). Provides additional context for debugging.
|
|
292
|
+
correlation_id: Optional correlation ID for distributed tracing. Included
|
|
293
|
+
in the log extra dict when provided.
|
|
294
|
+
logger: Optional logger instance to use. If not provided, uses the
|
|
295
|
+
module-level logger (omnibase_infra.utils.util_datetime).
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
None. This function only logs a warning and does not return a value.
|
|
299
|
+
|
|
300
|
+
Example:
|
|
301
|
+
>>> from datetime import datetime, UTC
|
|
302
|
+
>>> from uuid import uuid4
|
|
303
|
+
>>> from omnibase_infra.utils import warn_if_naive_datetime
|
|
304
|
+
>>>
|
|
305
|
+
>>> # Naive datetime triggers warning
|
|
306
|
+
>>> naive_dt = datetime(2025, 1, 15, 12, 0, 0)
|
|
307
|
+
>>> warn_if_naive_datetime(
|
|
308
|
+
... naive_dt,
|
|
309
|
+
... field_name="created_at",
|
|
310
|
+
... context="manifest_persistence",
|
|
311
|
+
... correlation_id=uuid4(),
|
|
312
|
+
... ) # Logs warning
|
|
313
|
+
>>>
|
|
314
|
+
>>> # Aware datetime - no warning logged
|
|
315
|
+
>>> aware_dt = datetime.now(UTC)
|
|
316
|
+
>>> warn_if_naive_datetime(aware_dt, field_name="updated_at") # Silent
|
|
317
|
+
|
|
318
|
+
Warning:
|
|
319
|
+
This function is intentionally warning-only. If you need to convert naive
|
|
320
|
+
datetimes to UTC, use :func:`ensure_timezone_aware` with ``assume_utc=True``.
|
|
321
|
+
The separation allows callers to choose between:
|
|
322
|
+
|
|
323
|
+
- **warn_if_naive_datetime**: Audit/detect without modification
|
|
324
|
+
- **ensure_timezone_aware**: Convert with optional warning
|
|
325
|
+
|
|
326
|
+
Related:
|
|
327
|
+
- OMN-1340: Extract datetime warning utility
|
|
328
|
+
- OMN-1163: Handler manifest persistence datetime handling
|
|
329
|
+
|
|
330
|
+
.. versionadded:: 0.9.0
|
|
331
|
+
Extracted from handler_manifest_persistence.py for reuse across codebase.
|
|
332
|
+
"""
|
|
333
|
+
# Use module logger if none provided
|
|
334
|
+
log = logger if logger is not None else globals()["logger"]
|
|
335
|
+
|
|
336
|
+
# Check if datetime is timezone-aware - if so, nothing to warn about
|
|
337
|
+
if is_timezone_aware(dt):
|
|
338
|
+
return
|
|
339
|
+
|
|
340
|
+
# Build context-aware message parts
|
|
341
|
+
location_parts: list[str] = []
|
|
342
|
+
if field_name:
|
|
343
|
+
location_parts.append(f"field '{field_name}'")
|
|
344
|
+
if context:
|
|
345
|
+
location_parts.append(f"context '{context}'")
|
|
346
|
+
|
|
347
|
+
location_str = " in ".join(location_parts) if location_parts else "datetime value"
|
|
348
|
+
|
|
349
|
+
# Build extra dict for structured logging
|
|
350
|
+
extra: dict[str, str | None] = {
|
|
351
|
+
"field_name": field_name,
|
|
352
|
+
"context": context,
|
|
353
|
+
"datetime_value": dt.isoformat(),
|
|
354
|
+
}
|
|
355
|
+
if correlation_id is not None:
|
|
356
|
+
extra["correlation_id"] = str(correlation_id)
|
|
357
|
+
|
|
358
|
+
log.warning(
|
|
359
|
+
"Naive datetime detected for %s. For accurate comparisons, use "
|
|
360
|
+
"timezone-aware datetimes (e.g., datetime.now(UTC)). "
|
|
361
|
+
"See util_datetime module docstring for timezone handling details.",
|
|
362
|
+
location_str,
|
|
363
|
+
extra=extra,
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
__all__: list[str] = [
|
|
368
|
+
"ensure_timezone_aware",
|
|
369
|
+
"is_timezone_aware",
|
|
370
|
+
"validate_timezone_aware_with_context",
|
|
371
|
+
"warn_if_naive_datetime",
|
|
372
|
+
]
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""PostgreSQL DSN validation utility.
|
|
4
|
+
|
|
5
|
+
This module provides robust DSN validation using urllib.parse instead of regex.
|
|
6
|
+
It handles edge cases like IPv6 addresses, URL-encoded passwords, query parameters,
|
|
7
|
+
and validates DSN structure comprehensively.
|
|
8
|
+
|
|
9
|
+
Security:
|
|
10
|
+
- Never logs credentials in error messages
|
|
11
|
+
- Returns [REDACTED] in error messages for sensitive values
|
|
12
|
+
- Validates structure without exposing DSN contents
|
|
13
|
+
|
|
14
|
+
Edge Cases Handled:
|
|
15
|
+
- IPv6 addresses: postgresql://user:pass@[::1]:5432/db
|
|
16
|
+
- URL-encoded passwords: user:p%40ssword@host (p@ssword)
|
|
17
|
+
- Missing components: postgresql://localhost/db (no user/pass/port)
|
|
18
|
+
- Query parameters: postgresql://host/db?sslmode=require
|
|
19
|
+
- Unix sockets: postgresql:///db?host=/var/run/postgresql
|
|
20
|
+
- Empty password: user:@host (different from no password)
|
|
21
|
+
|
|
22
|
+
Limitations:
|
|
23
|
+
- Multiple hosts (host1:5432,host2:5433) are not validated
|
|
24
|
+
(urllib.parse treats them as a single hostname)
|
|
25
|
+
- If multi-host support is needed, use a PostgreSQL-specific parser
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
from typing import Literal, cast
|
|
31
|
+
from urllib.parse import parse_qs, unquote, urlparse
|
|
32
|
+
from uuid import uuid4
|
|
33
|
+
|
|
34
|
+
from omnibase_infra.types import ModelParsedDSN
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _assert_postgres_scheme(scheme: str) -> Literal["postgresql", "postgres"]:
|
|
38
|
+
"""Type-safe scheme assertion for PostgreSQL DSN schemes.
|
|
39
|
+
|
|
40
|
+
This helper enables proper type narrowing for the Literal type
|
|
41
|
+
using typing.cast for explicit type assertion.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
scheme: The scheme string to validate
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
The scheme cast to the appropriate Literal type
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
ProtocolConfigurationError: If scheme is not 'postgresql' or 'postgres'.
|
|
51
|
+
|
|
52
|
+
Note:
|
|
53
|
+
This function should only be called AFTER validating
|
|
54
|
+
that scheme is one of the valid values.
|
|
55
|
+
"""
|
|
56
|
+
if scheme not in ("postgresql", "postgres"):
|
|
57
|
+
# Lazy imports to avoid circular dependency (utils -> errors -> models -> utils)
|
|
58
|
+
from omnibase_infra.enums import EnumInfraTransportType
|
|
59
|
+
from omnibase_infra.errors import (
|
|
60
|
+
ModelInfraErrorContext,
|
|
61
|
+
ProtocolConfigurationError,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
context = ModelInfraErrorContext(
|
|
65
|
+
transport_type=EnumInfraTransportType.DATABASE,
|
|
66
|
+
operation="validate_dsn_scheme",
|
|
67
|
+
target_name="dsn_validator",
|
|
68
|
+
correlation_id=uuid4(),
|
|
69
|
+
)
|
|
70
|
+
raise ProtocolConfigurationError(
|
|
71
|
+
f"Invalid scheme: expected 'postgresql' or 'postgres', got '{scheme}'",
|
|
72
|
+
context=context,
|
|
73
|
+
parameter="scheme",
|
|
74
|
+
value=scheme,
|
|
75
|
+
)
|
|
76
|
+
return cast(Literal["postgresql", "postgres"], scheme)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def parse_and_validate_dsn(dsn: object) -> ModelParsedDSN:
|
|
80
|
+
"""Parse and validate PostgreSQL DSN format using urllib.parse.
|
|
81
|
+
|
|
82
|
+
This function provides comprehensive DSN validation that handles edge cases
|
|
83
|
+
like IPv6 addresses, URL-encoded passwords, and query parameters. It uses
|
|
84
|
+
urllib.parse for robust parsing instead of fragile regex patterns.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
dsn: PostgreSQL connection string (any type - validated)
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
ModelParsedDSN with parsed components:
|
|
91
|
+
- scheme: "postgresql" or "postgres" (Literal type)
|
|
92
|
+
- username: Username or None
|
|
93
|
+
- password: Password (URL-decoded) or None
|
|
94
|
+
- hostname: Hostname or IP address or None
|
|
95
|
+
- port: Port number or None
|
|
96
|
+
- database: Database name
|
|
97
|
+
- query: Dict of query parameters (str keys, str | list[str] values)
|
|
98
|
+
|
|
99
|
+
Raises:
|
|
100
|
+
ProtocolConfigurationError: If DSN format is invalid
|
|
101
|
+
|
|
102
|
+
Example:
|
|
103
|
+
>>> result = parse_and_validate_dsn("postgresql://user:pass@localhost:5432/mydb")
|
|
104
|
+
>>> assert result.hostname == "localhost"
|
|
105
|
+
>>> assert result.database == "mydb"
|
|
106
|
+
|
|
107
|
+
Security Note:
|
|
108
|
+
Error messages never contain the actual DSN value. Sensitive information
|
|
109
|
+
is replaced with [REDACTED] to prevent credential leakage in logs.
|
|
110
|
+
"""
|
|
111
|
+
# Lazy imports to avoid circular dependency (utils → errors → models → utils)
|
|
112
|
+
from omnibase_infra.enums import EnumInfraTransportType
|
|
113
|
+
from omnibase_infra.errors import ModelInfraErrorContext, ProtocolConfigurationError
|
|
114
|
+
|
|
115
|
+
context = ModelInfraErrorContext(
|
|
116
|
+
transport_type=EnumInfraTransportType.DATABASE,
|
|
117
|
+
operation="validate_dsn",
|
|
118
|
+
target_name="dsn_validator",
|
|
119
|
+
correlation_id=uuid4(),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Type validation
|
|
123
|
+
if dsn is None:
|
|
124
|
+
raise ProtocolConfigurationError(
|
|
125
|
+
"Invalid dsn: expected a string, got None",
|
|
126
|
+
context=context,
|
|
127
|
+
parameter="dsn",
|
|
128
|
+
value=None,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
if not isinstance(dsn, str):
|
|
132
|
+
raise ProtocolConfigurationError(
|
|
133
|
+
f"Invalid dsn type: expected str, got {type(dsn).__name__}",
|
|
134
|
+
context=context,
|
|
135
|
+
parameter="dsn",
|
|
136
|
+
value=type(dsn).__name__,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Empty string validation
|
|
140
|
+
if not dsn.strip():
|
|
141
|
+
raise ProtocolConfigurationError(
|
|
142
|
+
"Invalid dsn: expected a non-empty string, got empty string",
|
|
143
|
+
context=context,
|
|
144
|
+
parameter="dsn",
|
|
145
|
+
value="",
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
dsn_str = dsn.strip()
|
|
149
|
+
|
|
150
|
+
# Scheme validation (before parsing to provide clear error)
|
|
151
|
+
valid_prefixes = ("postgresql://", "postgres://")
|
|
152
|
+
if not dsn_str.startswith(valid_prefixes):
|
|
153
|
+
raise ProtocolConfigurationError(
|
|
154
|
+
f"dsn must start with one of {valid_prefixes}",
|
|
155
|
+
context=context,
|
|
156
|
+
parameter="dsn",
|
|
157
|
+
value="[REDACTED]", # Never log DSN contents
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# Check for multi-host DSN format (not supported)
|
|
161
|
+
# Multi-host format: postgresql://host1:port1,host2:port2/db
|
|
162
|
+
# We check for comma after :// and before / (in the host portion)
|
|
163
|
+
scheme_end = dsn_str.index("://") + 3
|
|
164
|
+
path_start = dsn_str.find("/", scheme_end)
|
|
165
|
+
host_portion = (
|
|
166
|
+
dsn_str[scheme_end:path_start] if path_start != -1 else dsn_str[scheme_end:]
|
|
167
|
+
)
|
|
168
|
+
if "," in host_portion:
|
|
169
|
+
raise ProtocolConfigurationError(
|
|
170
|
+
"Multi-host DSNs are not supported. Use a single host or consider "
|
|
171
|
+
"psycopg2.conninfo_to_dict for multi-host parsing.",
|
|
172
|
+
context=context,
|
|
173
|
+
parameter="dsn",
|
|
174
|
+
value="[REDACTED]",
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Parse DSN using urllib.parse
|
|
178
|
+
try:
|
|
179
|
+
parsed = urlparse(dsn_str)
|
|
180
|
+
except ValueError as e:
|
|
181
|
+
# urlparse can raise ValueError for invalid ports, etc.
|
|
182
|
+
raise ProtocolConfigurationError(
|
|
183
|
+
f"Invalid DSN format: {e}",
|
|
184
|
+
context=context,
|
|
185
|
+
parameter="dsn",
|
|
186
|
+
value="[REDACTED]",
|
|
187
|
+
) from e
|
|
188
|
+
|
|
189
|
+
# Validate scheme (redundant but explicit)
|
|
190
|
+
if parsed.scheme not in ("postgresql", "postgres"):
|
|
191
|
+
raise ProtocolConfigurationError(
|
|
192
|
+
f"Invalid scheme: expected 'postgresql' or 'postgres', got '{parsed.scheme}'",
|
|
193
|
+
context=context,
|
|
194
|
+
parameter="dsn",
|
|
195
|
+
value="[REDACTED]",
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Validate port if present
|
|
199
|
+
# Note: Accessing parsed.port can raise ValueError if port is invalid
|
|
200
|
+
try:
|
|
201
|
+
port = parsed.port
|
|
202
|
+
if port is not None:
|
|
203
|
+
if port < 1 or port > 65535:
|
|
204
|
+
raise ProtocolConfigurationError(
|
|
205
|
+
f"Port must be between 1 and 65535, got {port}",
|
|
206
|
+
context=context,
|
|
207
|
+
parameter="dsn.port",
|
|
208
|
+
value=port,
|
|
209
|
+
)
|
|
210
|
+
except ValueError as e:
|
|
211
|
+
# urlparse raises ValueError for invalid ports (non-numeric, out of range)
|
|
212
|
+
raise ProtocolConfigurationError(
|
|
213
|
+
f"Invalid port in DSN: {e}",
|
|
214
|
+
context=context,
|
|
215
|
+
parameter="dsn.port",
|
|
216
|
+
value="[REDACTED]",
|
|
217
|
+
) from e
|
|
218
|
+
|
|
219
|
+
# Validate database name
|
|
220
|
+
# Path is "/dbname" or "///dbname" for Unix socket
|
|
221
|
+
# Strip leading slashes to get database name
|
|
222
|
+
database = parsed.path.lstrip("/") if parsed.path else ""
|
|
223
|
+
|
|
224
|
+
# Database name is required (unless using Unix socket with query param)
|
|
225
|
+
# For Unix sockets: postgresql:///dbname?host=/var/run/postgresql
|
|
226
|
+
# For network: postgresql://host/dbname
|
|
227
|
+
if not database:
|
|
228
|
+
# Check if Unix socket is specified in query params
|
|
229
|
+
query_params = parse_qs(parsed.query)
|
|
230
|
+
if "host" not in query_params:
|
|
231
|
+
raise ProtocolConfigurationError(
|
|
232
|
+
"Database name is required in DSN path (e.g., postgresql://host:5432/dbname)",
|
|
233
|
+
context=context,
|
|
234
|
+
parameter="dsn.path",
|
|
235
|
+
value="[REDACTED]",
|
|
236
|
+
)
|
|
237
|
+
# Unix socket case - database might be in query params or path
|
|
238
|
+
# Allow empty database for now (will be validated at connection time)
|
|
239
|
+
|
|
240
|
+
# Parse query parameters
|
|
241
|
+
query_dict = {}
|
|
242
|
+
if parsed.query:
|
|
243
|
+
# parse_qs returns lists, flatten to single values
|
|
244
|
+
parsed_qs = parse_qs(parsed.query)
|
|
245
|
+
query_dict = {k: v[0] if len(v) == 1 else v for k, v in parsed_qs.items()}
|
|
246
|
+
|
|
247
|
+
# Return parsed components
|
|
248
|
+
# Note: urlparse does NOT decode URL-encoded passwords, so we use unquote()
|
|
249
|
+
# Important: Check 'is not None' instead of truthiness to preserve empty strings
|
|
250
|
+
return ModelParsedDSN(
|
|
251
|
+
scheme=_assert_postgres_scheme(parsed.scheme),
|
|
252
|
+
username=unquote(parsed.username) if parsed.username is not None else None,
|
|
253
|
+
password=unquote(parsed.password) if parsed.password is not None else None,
|
|
254
|
+
hostname=parsed.hostname,
|
|
255
|
+
port=port,
|
|
256
|
+
database=database,
|
|
257
|
+
query=query_dict,
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def sanitize_dsn(dsn: str) -> str:
|
|
262
|
+
"""Sanitize DSN by removing password for safe logging.
|
|
263
|
+
|
|
264
|
+
SECURITY: This function should ONLY be used for development/debugging.
|
|
265
|
+
Production code should NEVER log DSN values, even sanitized ones.
|
|
266
|
+
|
|
267
|
+
Replaces the password portion of the DSN with asterisks using URL parsing
|
|
268
|
+
instead of regex for robustness.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
dsn: Raw PostgreSQL connection string containing credentials
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
Sanitized DSN with password replaced by '***'
|
|
275
|
+
|
|
276
|
+
Example:
|
|
277
|
+
>>> sanitize_dsn("postgresql://user:secret@host:5432/db")
|
|
278
|
+
'postgresql://user:***@host:5432/db'
|
|
279
|
+
|
|
280
|
+
>>> sanitize_dsn("postgresql://user:p%40ss@host/db")
|
|
281
|
+
'postgresql://user:***@host/db'
|
|
282
|
+
|
|
283
|
+
Note:
|
|
284
|
+
This function is intentionally NOT used in production error paths.
|
|
285
|
+
It exists as a utility for development/debugging only.
|
|
286
|
+
"""
|
|
287
|
+
try:
|
|
288
|
+
parsed = urlparse(dsn)
|
|
289
|
+
|
|
290
|
+
# Rebuild DSN with password masked
|
|
291
|
+
# Format: scheme://[user[:password]@]host[:port]/path[?query][#fragment]
|
|
292
|
+
netloc = parsed.hostname or ""
|
|
293
|
+
|
|
294
|
+
# Add port if present (handle ValueError from invalid ports)
|
|
295
|
+
try:
|
|
296
|
+
port = parsed.port
|
|
297
|
+
if port:
|
|
298
|
+
netloc = f"{netloc}:{port}"
|
|
299
|
+
except ValueError:
|
|
300
|
+
# Invalid port - include raw port string from netloc
|
|
301
|
+
# Extract port from raw netloc if present
|
|
302
|
+
if ":" in (parsed.netloc or ""):
|
|
303
|
+
# Keep original port notation even if invalid
|
|
304
|
+
parts = parsed.netloc.split("@")[-1] # Get host:port part
|
|
305
|
+
if ":" in parts:
|
|
306
|
+
netloc = parts
|
|
307
|
+
|
|
308
|
+
# Add username with masked password
|
|
309
|
+
if parsed.username:
|
|
310
|
+
if parsed.password:
|
|
311
|
+
netloc = f"{parsed.username}:***@{netloc}"
|
|
312
|
+
else:
|
|
313
|
+
netloc = f"{parsed.username}@{netloc}"
|
|
314
|
+
|
|
315
|
+
# Reconstruct URL
|
|
316
|
+
sanitized = f"{parsed.scheme}://{netloc}{parsed.path}"
|
|
317
|
+
|
|
318
|
+
# Add query string if present
|
|
319
|
+
if parsed.query:
|
|
320
|
+
sanitized = f"{sanitized}?{parsed.query}"
|
|
321
|
+
|
|
322
|
+
# Add fragment if present
|
|
323
|
+
if parsed.fragment:
|
|
324
|
+
sanitized = f"{sanitized}#{parsed.fragment}"
|
|
325
|
+
|
|
326
|
+
return sanitized
|
|
327
|
+
|
|
328
|
+
except Exception:
|
|
329
|
+
# If parsing fails, return a safe placeholder
|
|
330
|
+
return "[INVALID_DSN]"
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
__all__: list[str] = ["ModelParsedDSN", "parse_and_validate_dsn", "sanitize_dsn"]
|