mcp-proxy-adapter 2.0.1__py3-none-any.whl → 6.9.50__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.

Potentially problematic release.


This version of mcp-proxy-adapter might be problematic. Click here for more details.

Files changed (269) hide show
  1. mcp_proxy_adapter/__init__.py +47 -0
  2. mcp_proxy_adapter/__main__.py +13 -0
  3. mcp_proxy_adapter/api/__init__.py +0 -0
  4. mcp_proxy_adapter/api/app.py +66 -0
  5. mcp_proxy_adapter/api/core/__init__.py +18 -0
  6. mcp_proxy_adapter/api/core/app_factory.py +400 -0
  7. mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
  8. mcp_proxy_adapter/api/core/registration_context.py +356 -0
  9. mcp_proxy_adapter/api/core/registration_manager.py +307 -0
  10. mcp_proxy_adapter/api/core/registration_tasks.py +84 -0
  11. mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
  12. mcp_proxy_adapter/api/handlers.py +181 -0
  13. mcp_proxy_adapter/api/middleware/__init__.py +21 -0
  14. mcp_proxy_adapter/api/middleware/base.py +54 -0
  15. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +73 -0
  16. mcp_proxy_adapter/api/middleware/error_handling.py +76 -0
  17. mcp_proxy_adapter/api/middleware/factory.py +147 -0
  18. mcp_proxy_adapter/api/middleware/logging.py +31 -0
  19. mcp_proxy_adapter/api/middleware/performance.py +51 -0
  20. mcp_proxy_adapter/api/middleware/protocol_middleware.py +140 -0
  21. mcp_proxy_adapter/api/middleware/transport_middleware.py +87 -0
  22. mcp_proxy_adapter/api/middleware/unified_security.py +223 -0
  23. mcp_proxy_adapter/api/middleware/user_info_middleware.py +132 -0
  24. mcp_proxy_adapter/api/openapi/__init__.py +21 -0
  25. mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
  26. mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
  27. mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
  28. mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
  29. mcp_proxy_adapter/api/schemas.py +270 -0
  30. mcp_proxy_adapter/api/tool_integration.py +131 -0
  31. mcp_proxy_adapter/api/tools.py +163 -0
  32. mcp_proxy_adapter/cli/__init__.py +12 -0
  33. mcp_proxy_adapter/cli/commands/__init__.py +15 -0
  34. mcp_proxy_adapter/cli/commands/client.py +100 -0
  35. mcp_proxy_adapter/cli/commands/config_generate.py +105 -0
  36. mcp_proxy_adapter/cli/commands/config_validate.py +94 -0
  37. mcp_proxy_adapter/cli/commands/generate.py +259 -0
  38. mcp_proxy_adapter/cli/commands/server.py +174 -0
  39. mcp_proxy_adapter/cli/commands/sets.py +132 -0
  40. mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
  41. mcp_proxy_adapter/cli/examples/__init__.py +8 -0
  42. mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
  43. mcp_proxy_adapter/cli/examples/https_token.py +96 -0
  44. mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
  45. mcp_proxy_adapter/cli/main.py +63 -0
  46. mcp_proxy_adapter/cli/parser.py +338 -0
  47. mcp_proxy_adapter/cli/validators.py +231 -0
  48. mcp_proxy_adapter/client/jsonrpc_client/__init__.py +9 -0
  49. mcp_proxy_adapter/client/jsonrpc_client/client.py +42 -0
  50. mcp_proxy_adapter/client/jsonrpc_client/command_api.py +45 -0
  51. mcp_proxy_adapter/client/jsonrpc_client/proxy_api.py +224 -0
  52. mcp_proxy_adapter/client/jsonrpc_client/queue_api.py +60 -0
  53. mcp_proxy_adapter/client/jsonrpc_client/transport.py +108 -0
  54. mcp_proxy_adapter/client/proxy.py +123 -0
  55. mcp_proxy_adapter/commands/__init__.py +66 -0
  56. mcp_proxy_adapter/commands/auth_validation_command.py +69 -0
  57. mcp_proxy_adapter/commands/base.py +389 -0
  58. mcp_proxy_adapter/commands/builtin_commands.py +30 -0
  59. mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
  60. mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
  61. mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
  62. mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
  63. mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
  64. mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
  65. mcp_proxy_adapter/commands/catalog_manager.py +97 -0
  66. mcp_proxy_adapter/commands/cert_monitor_command.py +552 -0
  67. mcp_proxy_adapter/commands/certificate_management_command.py +562 -0
  68. mcp_proxy_adapter/commands/command_registry.py +298 -0
  69. mcp_proxy_adapter/commands/config_command.py +102 -0
  70. mcp_proxy_adapter/commands/dependency_container.py +40 -0
  71. mcp_proxy_adapter/commands/dependency_manager.py +143 -0
  72. mcp_proxy_adapter/commands/echo_command.py +48 -0
  73. mcp_proxy_adapter/commands/health_command.py +142 -0
  74. mcp_proxy_adapter/commands/help_command.py +175 -0
  75. mcp_proxy_adapter/commands/hooks.py +172 -0
  76. mcp_proxy_adapter/commands/key_management_command.py +484 -0
  77. mcp_proxy_adapter/commands/load_command.py +123 -0
  78. mcp_proxy_adapter/commands/plugins_command.py +246 -0
  79. mcp_proxy_adapter/commands/protocol_management_command.py +216 -0
  80. mcp_proxy_adapter/commands/proxy_registration_command.py +319 -0
  81. mcp_proxy_adapter/commands/queue_commands.py +750 -0
  82. mcp_proxy_adapter/commands/registration_status_command.py +76 -0
  83. mcp_proxy_adapter/commands/registry/__init__.py +18 -0
  84. mcp_proxy_adapter/commands/registry/command_info.py +103 -0
  85. mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
  86. mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
  87. mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
  88. mcp_proxy_adapter/commands/reload_command.py +136 -0
  89. mcp_proxy_adapter/commands/result.py +157 -0
  90. mcp_proxy_adapter/commands/role_test_command.py +99 -0
  91. mcp_proxy_adapter/commands/roles_management_command.py +502 -0
  92. mcp_proxy_adapter/commands/security_command.py +472 -0
  93. mcp_proxy_adapter/commands/settings_command.py +113 -0
  94. mcp_proxy_adapter/commands/ssl_setup_command.py +306 -0
  95. mcp_proxy_adapter/commands/token_management_command.py +500 -0
  96. mcp_proxy_adapter/commands/transport_management_command.py +129 -0
  97. mcp_proxy_adapter/commands/unload_command.py +92 -0
  98. mcp_proxy_adapter/config.py +32 -0
  99. mcp_proxy_adapter/core/__init__.py +8 -0
  100. mcp_proxy_adapter/core/app_factory.py +560 -0
  101. mcp_proxy_adapter/core/app_runner.py +318 -0
  102. mcp_proxy_adapter/core/auth_validator.py +508 -0
  103. mcp_proxy_adapter/core/certificate/__init__.py +20 -0
  104. mcp_proxy_adapter/core/certificate/certificate_creator.py +372 -0
  105. mcp_proxy_adapter/core/certificate/certificate_extractor.py +185 -0
  106. mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
  107. mcp_proxy_adapter/core/certificate/certificate_validator.py +481 -0
  108. mcp_proxy_adapter/core/certificate/ssl_context_manager.py +65 -0
  109. mcp_proxy_adapter/core/certificate_utils.py +249 -0
  110. mcp_proxy_adapter/core/client.py +608 -0
  111. mcp_proxy_adapter/core/client_manager.py +271 -0
  112. mcp_proxy_adapter/core/client_security.py +411 -0
  113. mcp_proxy_adapter/core/config/__init__.py +18 -0
  114. mcp_proxy_adapter/core/config/config.py +237 -0
  115. mcp_proxy_adapter/core/config/config_factory.py +22 -0
  116. mcp_proxy_adapter/core/config/config_loader.py +66 -0
  117. mcp_proxy_adapter/core/config/feature_manager.py +31 -0
  118. mcp_proxy_adapter/core/config/simple_config.py +204 -0
  119. mcp_proxy_adapter/core/config/simple_config_generator.py +131 -0
  120. mcp_proxy_adapter/core/config/simple_config_validator.py +476 -0
  121. mcp_proxy_adapter/core/config_converter.py +252 -0
  122. mcp_proxy_adapter/core/config_validator.py +211 -0
  123. mcp_proxy_adapter/core/crl_utils.py +362 -0
  124. mcp_proxy_adapter/core/errors.py +276 -0
  125. mcp_proxy_adapter/core/job_manager.py +54 -0
  126. mcp_proxy_adapter/core/logging.py +250 -0
  127. mcp_proxy_adapter/core/mtls_asgi.py +140 -0
  128. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  129. mcp_proxy_adapter/core/mtls_proxy.py +229 -0
  130. mcp_proxy_adapter/core/mtls_server.py +154 -0
  131. mcp_proxy_adapter/core/protocol_manager.py +232 -0
  132. mcp_proxy_adapter/core/proxy/__init__.py +19 -0
  133. mcp_proxy_adapter/core/proxy/auth_manager.py +26 -0
  134. mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +160 -0
  135. mcp_proxy_adapter/core/proxy/registration_client.py +186 -0
  136. mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
  137. mcp_proxy_adapter/core/proxy_client.py +184 -0
  138. mcp_proxy_adapter/core/proxy_registration.py +80 -0
  139. mcp_proxy_adapter/core/role_utils.py +103 -0
  140. mcp_proxy_adapter/core/security_adapter.py +343 -0
  141. mcp_proxy_adapter/core/security_factory.py +96 -0
  142. mcp_proxy_adapter/core/security_integration.py +342 -0
  143. mcp_proxy_adapter/core/server_adapter.py +251 -0
  144. mcp_proxy_adapter/core/server_engine.py +217 -0
  145. mcp_proxy_adapter/core/settings.py +260 -0
  146. mcp_proxy_adapter/core/signal_handler.py +107 -0
  147. mcp_proxy_adapter/core/ssl_utils.py +161 -0
  148. mcp_proxy_adapter/core/transport_manager.py +153 -0
  149. mcp_proxy_adapter/core/unified_config_adapter.py +471 -0
  150. mcp_proxy_adapter/core/utils.py +101 -0
  151. mcp_proxy_adapter/core/validation/__init__.py +21 -0
  152. mcp_proxy_adapter/core/validation/config_validator.py +219 -0
  153. mcp_proxy_adapter/core/validation/file_validator.py +131 -0
  154. mcp_proxy_adapter/core/validation/protocol_validator.py +205 -0
  155. mcp_proxy_adapter/core/validation/security_validator.py +140 -0
  156. mcp_proxy_adapter/core/validation/validation_result.py +27 -0
  157. mcp_proxy_adapter/custom_openapi.py +58 -0
  158. mcp_proxy_adapter/examples/__init__.py +16 -0
  159. mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
  160. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  161. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  162. mcp_proxy_adapter/examples/basic_framework/main.py +52 -0
  163. mcp_proxy_adapter/examples/bugfix_certificate_config.py +261 -0
  164. mcp_proxy_adapter/examples/cert_manager_bugfix.py +203 -0
  165. mcp_proxy_adapter/examples/check_config.py +413 -0
  166. mcp_proxy_adapter/examples/client_usage_example.py +164 -0
  167. mcp_proxy_adapter/examples/commands/__init__.py +5 -0
  168. mcp_proxy_adapter/examples/config_builder.py +234 -0
  169. mcp_proxy_adapter/examples/config_cli.py +282 -0
  170. mcp_proxy_adapter/examples/create_test_configs.py +174 -0
  171. mcp_proxy_adapter/examples/debug_request_state.py +130 -0
  172. mcp_proxy_adapter/examples/debug_role_chain.py +191 -0
  173. mcp_proxy_adapter/examples/demo_client.py +287 -0
  174. mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
  175. mcp_proxy_adapter/examples/full_application/commands/__init__.py +8 -0
  176. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +45 -0
  177. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +52 -0
  178. mcp_proxy_adapter/examples/full_application/commands/echo_command.py +32 -0
  179. mcp_proxy_adapter/examples/full_application/commands/help_command.py +54 -0
  180. mcp_proxy_adapter/examples/full_application/commands/list_command.py +57 -0
  181. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +5 -0
  182. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +29 -0
  183. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +27 -0
  184. mcp_proxy_adapter/examples/full_application/main.py +311 -0
  185. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +161 -0
  186. mcp_proxy_adapter/examples/full_application/run_mtls.py +252 -0
  187. mcp_proxy_adapter/examples/full_application/run_simple.py +152 -0
  188. mcp_proxy_adapter/examples/full_application/test_minimal_server.py +45 -0
  189. mcp_proxy_adapter/examples/full_application/test_server.py +163 -0
  190. mcp_proxy_adapter/examples/full_application/test_simple_server.py +62 -0
  191. mcp_proxy_adapter/examples/generate_config.py +502 -0
  192. mcp_proxy_adapter/examples/proxy_registration_example.py +335 -0
  193. mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
  194. mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
  195. mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
  196. mcp_proxy_adapter/examples/queue_server_example.py +85 -0
  197. mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
  198. mcp_proxy_adapter/examples/required_certificates.py +208 -0
  199. mcp_proxy_adapter/examples/run_example.py +77 -0
  200. mcp_proxy_adapter/examples/run_full_test_suite.py +619 -0
  201. mcp_proxy_adapter/examples/run_proxy_server.py +153 -0
  202. mcp_proxy_adapter/examples/run_security_tests_fixed.py +435 -0
  203. mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
  204. mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
  205. mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
  206. mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
  207. mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
  208. mcp_proxy_adapter/examples/security_test_client.py +72 -0
  209. mcp_proxy_adapter/examples/setup/__init__.py +24 -0
  210. mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
  211. mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
  212. mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
  213. mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
  214. mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
  215. mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
  216. mcp_proxy_adapter/examples/setup_test_environment.py +235 -0
  217. mcp_proxy_adapter/examples/simple_protocol_test.py +125 -0
  218. mcp_proxy_adapter/examples/test_chk_hostname_automated.py +211 -0
  219. mcp_proxy_adapter/examples/test_config.py +205 -0
  220. mcp_proxy_adapter/examples/test_config_builder.py +110 -0
  221. mcp_proxy_adapter/examples/test_examples.py +308 -0
  222. mcp_proxy_adapter/examples/test_framework_complete.py +267 -0
  223. mcp_proxy_adapter/examples/test_mcp_server.py +187 -0
  224. mcp_proxy_adapter/examples/test_protocol_examples.py +337 -0
  225. mcp_proxy_adapter/examples/universal_client.py +674 -0
  226. mcp_proxy_adapter/examples/update_config_certificates.py +135 -0
  227. mcp_proxy_adapter/examples/validate_generator_compatibility.py +385 -0
  228. mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +61 -0
  229. mcp_proxy_adapter/integrations/__init__.py +25 -0
  230. mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
  231. mcp_proxy_adapter/main.py +311 -0
  232. mcp_proxy_adapter/openapi.py +375 -0
  233. mcp_proxy_adapter/schemas/base_schema.json +114 -0
  234. mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
  235. mcp_proxy_adapter/schemas/roles.json +37 -0
  236. mcp_proxy_adapter/schemas/roles_schema.json +162 -0
  237. mcp_proxy_adapter/version.py +5 -0
  238. mcp_proxy_adapter-6.9.50.dist-info/METADATA +1088 -0
  239. mcp_proxy_adapter-6.9.50.dist-info/RECORD +242 -0
  240. {mcp_proxy_adapter-2.0.1.dist-info → mcp_proxy_adapter-6.9.50.dist-info}/WHEEL +1 -1
  241. mcp_proxy_adapter-6.9.50.dist-info/entry_points.txt +14 -0
  242. mcp_proxy_adapter-6.9.50.dist-info/top_level.txt +1 -0
  243. adapters/__init__.py +0 -16
  244. analyzers/__init__.py +0 -14
  245. analyzers/docstring_analyzer.py +0 -199
  246. analyzers/type_analyzer.py +0 -151
  247. cli/__init__.py +0 -12
  248. cli/__main__.py +0 -79
  249. cli/command_runner.py +0 -233
  250. dispatchers/__init__.py +0 -14
  251. dispatchers/base_dispatcher.py +0 -85
  252. dispatchers/json_rpc_dispatcher.py +0 -198
  253. generators/__init__.py +0 -14
  254. generators/endpoint_generator.py +0 -172
  255. generators/openapi_generator.py +0 -254
  256. generators/rest_api_generator.py +0 -207
  257. mcp_proxy_adapter-2.0.1.dist-info/METADATA +0 -272
  258. mcp_proxy_adapter-2.0.1.dist-info/RECORD +0 -28
  259. mcp_proxy_adapter-2.0.1.dist-info/licenses/LICENSE +0 -21
  260. mcp_proxy_adapter-2.0.1.dist-info/top_level.txt +0 -7
  261. openapi_schema/__init__.py +0 -38
  262. openapi_schema/command_registry.py +0 -312
  263. openapi_schema/rest_schema.py +0 -510
  264. openapi_schema/rpc_generator.py +0 -307
  265. openapi_schema/rpc_schema.py +0 -416
  266. validators/__init__.py +0 -14
  267. validators/base_validator.py +0 -23
  268. validators/docstring_validator.py +0 -75
  269. validators/metadata_validator.py +0 -76
@@ -0,0 +1,318 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Application Runner for MCP Proxy Adapter
6
+
7
+ This module provides the ApplicationRunner class for running applications
8
+ with full configuration validation and error handling.
9
+ """
10
+
11
+ import socket
12
+ import sys
13
+ from pathlib import Path
14
+ from typing import Any, Dict, List
15
+
16
+ from fastapi import FastAPI
17
+
18
+ from mcp_proxy_adapter.core.logging import get_logger
19
+ from mcp_proxy_adapter.core.signal_handler import (
20
+ setup_signal_handling,
21
+ is_shutdown_requested,
22
+ )
23
+
24
+ logger = get_logger("app_runner")
25
+
26
+
27
+ class ApplicationRunner:
28
+ """
29
+ Class for running applications with configuration validation.
30
+ """
31
+
32
+ def __init__(self, app: FastAPI, config: Dict[str, Any]):
33
+ """
34
+ Initialize ApplicationRunner.
35
+
36
+ Args:
37
+ app: FastAPI application instance
38
+ config: Application configuration dictionary
39
+ """
40
+ self.app = app
41
+ self.config = config
42
+ self.errors: List[str] = []
43
+
44
+ def validate_configuration(self) -> List[str]:
45
+ """
46
+ Validates configuration and returns list of errors.
47
+
48
+ Returns:
49
+ List of validation error messages
50
+ """
51
+ self.errors = []
52
+
53
+ # Validate server configuration
54
+ self._validate_server_config()
55
+
56
+ # Validate SSL configuration
57
+ self._validate_ssl_config()
58
+
59
+ # Validate security configuration
60
+ self._validate_security_config()
61
+
62
+ # Validate file paths
63
+ self._validate_file_paths()
64
+
65
+ # Validate port availability
66
+ self._validate_port_availability()
67
+
68
+ # Validate configuration compatibility
69
+ self._validate_compatibility()
70
+
71
+ return self.errors
72
+
73
+ def _validate_server_config(self) -> None:
74
+ """Validate server configuration."""
75
+ server_config = self.config.get("server", {})
76
+
77
+ if not server_config:
78
+ self.errors.append("Server configuration is missing")
79
+ return
80
+
81
+ host = server_config.get("host")
82
+ port = server_config.get("port")
83
+
84
+ if not host:
85
+ self.errors.append("Server host is not specified")
86
+
87
+ if not port:
88
+ self.errors.append("Server port is not specified")
89
+ elif not isinstance(port, int) or port < 1 or port > 65535:
90
+ self.errors.append(f"Invalid server port: {port}")
91
+
92
+ def _validate_ssl_config(self) -> None:
93
+ """Validate SSL configuration based on protocol."""
94
+ server_config = self.config.get("server", {})
95
+ protocol = server_config.get("protocol", "http")
96
+
97
+ # SSL is automatically enabled for https and mtls protocols
98
+ if protocol in ("https", "mtls"):
99
+ ssl_config = self.config.get("ssl", {})
100
+ cert_file = ssl_config.get("cert_file")
101
+ key_file = ssl_config.get("key_file")
102
+
103
+ # Only validate if certificates are specified
104
+ if cert_file and key_file:
105
+ if not Path(cert_file).exists():
106
+ self.errors.append(f"Certificate file not found: {cert_file}")
107
+
108
+ if not Path(key_file).exists():
109
+ self.errors.append(f"Private key file not found: {key_file}")
110
+
111
+ # Validate mTLS configuration
112
+ if protocol == "mtls" or ssl_config.get("verify_client", False):
113
+ ca_cert = ssl_config.get("ca_cert")
114
+ if not ca_cert:
115
+ self.errors.append(
116
+ f"{protocol.upper()} requires CA certificate to be specified"
117
+ )
118
+ elif not Path(ca_cert).exists():
119
+ self.errors.append(f"CA certificate file not found: {ca_cert}")
120
+
121
+ def _validate_security_config(self) -> None:
122
+ """Validate security configuration."""
123
+ security_config = self.config.get("security", {})
124
+
125
+ if security_config.get("enabled", False):
126
+ auth_config = security_config.get("auth", {})
127
+ permissions_config = security_config.get("permissions", {})
128
+
129
+ # Validate authentication configuration
130
+ if auth_config.get("enabled", False):
131
+ methods = auth_config.get("methods", [])
132
+ if not methods:
133
+ self.errors.append(
134
+ "Authentication enabled but no methods specified"
135
+ )
136
+
137
+ # Validate API key configuration
138
+ if "api_key" in methods:
139
+ # Check if roles file exists for API key auth
140
+ if permissions_config.get("enabled", False):
141
+ roles_file = permissions_config.get("roles_file")
142
+ if not roles_file:
143
+ self.errors.append(
144
+ "Permissions enabled but roles file not specified"
145
+ )
146
+ elif not Path(roles_file).exists():
147
+ self.errors.append(f"Roles file not found: {roles_file}")
148
+
149
+ # Validate certificate configuration
150
+ if "certificate" in methods:
151
+ server_config = self.config.get("server", {})
152
+ protocol = server_config.get("protocol", "http")
153
+ if protocol not in ("https", "mtls"):
154
+ self.errors.append(
155
+ "Certificate authentication requires https or mtls protocol"
156
+ )
157
+ ssl_config = self.config.get("ssl", {})
158
+ if not ssl_config.get("verify_client", False):
159
+ self.errors.append(
160
+ "Certificate authentication requires client verification to be enabled"
161
+ )
162
+
163
+ def _validate_file_paths(self) -> None:
164
+ """Validate all file paths in configuration."""
165
+ # Check SSL certificate files based on protocol
166
+ server_config = self.config.get("server", {})
167
+ protocol = server_config.get("protocol", "http")
168
+
169
+ if protocol in ("https", "mtls"):
170
+ ssl_config = self.config.get("ssl", {})
171
+ cert_file = ssl_config.get("cert_file")
172
+ key_file = ssl_config.get("key_file")
173
+ ca_cert = ssl_config.get("ca_cert")
174
+
175
+ # Only validate if certificates are specified
176
+ if cert_file and not Path(cert_file).is_file():
177
+ self.errors.append(
178
+ f"Certificate file is not a regular file: {cert_file}"
179
+ )
180
+
181
+ if key_file and not Path(key_file).is_file():
182
+ self.errors.append(
183
+ f"Private key file is not a regular file: {key_file}"
184
+ )
185
+
186
+ if ca_cert and not Path(ca_cert).is_file():
187
+ self.errors.append(
188
+ f"CA certificate file is not a regular file: {ca_cert}"
189
+ )
190
+
191
+ # Check roles file
192
+ security_config = self.config.get("security", {})
193
+ permissions_config = security_config.get("permissions", {})
194
+ if permissions_config.get("enabled", False):
195
+ roles_file = permissions_config.get("roles_file")
196
+ if roles_file and not Path(roles_file).is_file():
197
+ self.errors.append(f"Roles file is not a regular file: {roles_file}")
198
+
199
+ def _validate_port_availability(self) -> None:
200
+ """Validate that the configured port is available."""
201
+ server_config = self.config.get("server", {})
202
+ port = server_config.get("port")
203
+
204
+ if port:
205
+ try:
206
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
207
+ s.bind(("127.0.0.1", port))
208
+ except OSError:
209
+ self.errors.append(f"Port {port} is already in use")
210
+
211
+ def _validate_compatibility(self) -> None:
212
+ """Validate configuration compatibility."""
213
+ server_config = self.config.get("server", {})
214
+ protocol = server_config.get("protocol", "http")
215
+ security_config = self.config.get("security", {})
216
+ protocols_config = self.config.get("protocols", {})
217
+
218
+ # Check protocol compatibility
219
+ if protocol in ("https", "mtls"):
220
+ allowed_protocols = protocols_config.get("allowed_protocols", [])
221
+ if allowed_protocols and protocol not in allowed_protocols:
222
+ self.errors.append(
223
+ f"Protocol {protocol} is not in allowed protocols: {allowed_protocols}"
224
+ )
225
+
226
+ # Check security and protocol compatibility
227
+ if security_config.get("enabled", False):
228
+ auth_config = security_config.get("auth", {})
229
+ if auth_config.get("enabled", False):
230
+ methods = auth_config.get("methods", [])
231
+ if "certificate" in methods and protocol not in ("https", "mtls"):
232
+ self.errors.append(
233
+ "Certificate authentication requires https or mtls protocol"
234
+ )
235
+
236
+ def setup_hooks(self) -> None:
237
+ """
238
+ Setup application hooks.
239
+ """
240
+
241
+ # Add startup event
242
+ @self.app.on_event("startup")
243
+ def startup():
244
+ pass
245
+
246
+ # Add shutdown event
247
+ @self.app.on_event("shutdown")
248
+ def shutdown():
249
+ pass
250
+
251
+ def run(self) -> None:
252
+ """
253
+ Run application with full validation.
254
+ """
255
+ # Validate configuration
256
+ errors = self.validate_configuration()
257
+
258
+ if errors:
259
+ print("ERROR: Configuration validation failed:", file=sys.stderr)
260
+ for error in errors:
261
+ print(f" - {error}", file=sys.stderr)
262
+ sys.exit(1)
263
+
264
+ # Setup signal handling for graceful shutdown
265
+ def shutdown_callback():
266
+ """Callback for graceful shutdown."""
267
+ logger.info("Graceful shutdown requested")
268
+
269
+ setup_signal_handling(shutdown_callback)
270
+ print("šŸ”§ Signal handling configured for graceful shutdown")
271
+
272
+ # Setup hooks
273
+ self.setup_hooks()
274
+
275
+ # Get server configuration
276
+ server_config = self.config.get("server", {})
277
+ host = server_config.get("host", "127.0.0.1")
278
+ port = server_config.get("port", 8000)
279
+
280
+ # Prepare server configuration for hypercorn
281
+ server_kwargs = {"host": host, "port": port, "log_level": "info"}
282
+
283
+ # Add SSL configuration based on protocol
284
+ protocol = server_config.get("protocol", "http")
285
+ if protocol in ("https", "mtls"):
286
+ ssl_config = self.config.get("ssl", {})
287
+ cert_file = ssl_config.get("cert_file")
288
+ key_file = ssl_config.get("key_file")
289
+
290
+ # Only add SSL config if certificates are specified
291
+ if cert_file and key_file:
292
+ server_kwargs["certfile"] = cert_file
293
+ server_kwargs["keyfile"] = key_file
294
+
295
+ # Add mTLS configuration
296
+ if protocol == "mtls" or ssl_config.get("verify_client", False):
297
+ ca_cert = ssl_config.get("ca_cert")
298
+ if ca_cert:
299
+ server_kwargs["ca_certs"] = ca_cert
300
+
301
+ try:
302
+ import hypercorn.asyncio
303
+ import asyncio
304
+
305
+ print(f"šŸš€ Starting server on {host}:{port}")
306
+ print("šŸ›‘ Use Ctrl+C or send SIGTERM for graceful shutdown")
307
+ print("=" * 60)
308
+
309
+ # Run with hypercorn
310
+ asyncio.run(hypercorn.asyncio.serve(self.app, **server_kwargs))
311
+
312
+ except KeyboardInterrupt:
313
+ print("\nšŸ›‘ Server stopped by user (Ctrl+C)")
314
+ if is_shutdown_requested():
315
+ print("āœ… Graceful shutdown completed")
316
+ except Exception as e:
317
+ print(f"\nāŒ Failed to start server: {e}", file=sys.stderr)
318
+ sys.exit(1)