mcp-proxy-adapter 4.1.1__py3-none-any.whl → 6.0.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.
Files changed (200) hide show
  1. mcp_proxy_adapter/__main__.py +32 -0
  2. mcp_proxy_adapter/api/app.py +290 -33
  3. mcp_proxy_adapter/api/handlers.py +32 -6
  4. mcp_proxy_adapter/api/middleware/__init__.py +38 -32
  5. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
  6. mcp_proxy_adapter/api/middleware/error_handling.py +9 -0
  7. mcp_proxy_adapter/api/middleware/factory.py +243 -0
  8. mcp_proxy_adapter/api/middleware/logging.py +32 -6
  9. mcp_proxy_adapter/api/middleware/protocol_middleware.py +201 -0
  10. mcp_proxy_adapter/api/middleware/transport_middleware.py +122 -0
  11. mcp_proxy_adapter/api/middleware/unified_security.py +197 -0
  12. mcp_proxy_adapter/api/middleware/user_info_middleware.py +158 -0
  13. mcp_proxy_adapter/commands/__init__.py +19 -4
  14. mcp_proxy_adapter/commands/auth_validation_command.py +408 -0
  15. mcp_proxy_adapter/commands/base.py +66 -32
  16. mcp_proxy_adapter/commands/builtin_commands.py +95 -0
  17. mcp_proxy_adapter/commands/catalog_manager.py +838 -0
  18. mcp_proxy_adapter/commands/cert_monitor_command.py +620 -0
  19. mcp_proxy_adapter/commands/certificate_management_command.py +608 -0
  20. mcp_proxy_adapter/commands/command_registry.py +711 -354
  21. mcp_proxy_adapter/commands/dependency_manager.py +245 -0
  22. mcp_proxy_adapter/commands/echo_command.py +81 -0
  23. mcp_proxy_adapter/commands/health_command.py +8 -1
  24. mcp_proxy_adapter/commands/help_command.py +21 -14
  25. mcp_proxy_adapter/commands/hooks.py +200 -167
  26. mcp_proxy_adapter/commands/key_management_command.py +506 -0
  27. mcp_proxy_adapter/commands/load_command.py +176 -0
  28. mcp_proxy_adapter/commands/plugins_command.py +235 -0
  29. mcp_proxy_adapter/commands/protocol_management_command.py +232 -0
  30. mcp_proxy_adapter/commands/proxy_registration_command.py +409 -0
  31. mcp_proxy_adapter/commands/reload_command.py +48 -50
  32. mcp_proxy_adapter/commands/result.py +1 -0
  33. mcp_proxy_adapter/commands/role_test_command.py +141 -0
  34. mcp_proxy_adapter/commands/roles_management_command.py +697 -0
  35. mcp_proxy_adapter/commands/security_command.py +488 -0
  36. mcp_proxy_adapter/commands/ssl_setup_command.py +366 -0
  37. mcp_proxy_adapter/commands/token_management_command.py +529 -0
  38. mcp_proxy_adapter/commands/transport_management_command.py +144 -0
  39. mcp_proxy_adapter/commands/unload_command.py +158 -0
  40. mcp_proxy_adapter/config.py +394 -14
  41. mcp_proxy_adapter/core/app_factory.py +410 -0
  42. mcp_proxy_adapter/core/app_runner.py +272 -0
  43. mcp_proxy_adapter/core/auth_validator.py +606 -0
  44. mcp_proxy_adapter/core/certificate_utils.py +1045 -0
  45. mcp_proxy_adapter/core/client.py +574 -0
  46. mcp_proxy_adapter/core/client_manager.py +284 -0
  47. mcp_proxy_adapter/core/client_security.py +384 -0
  48. mcp_proxy_adapter/core/config_converter.py +405 -0
  49. mcp_proxy_adapter/core/config_validator.py +218 -0
  50. mcp_proxy_adapter/core/logging.py +19 -3
  51. mcp_proxy_adapter/core/mtls_asgi.py +156 -0
  52. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  53. mcp_proxy_adapter/core/protocol_manager.py +385 -0
  54. mcp_proxy_adapter/core/proxy_client.py +602 -0
  55. mcp_proxy_adapter/core/proxy_registration.py +522 -0
  56. mcp_proxy_adapter/core/role_utils.py +426 -0
  57. mcp_proxy_adapter/core/security_adapter.py +370 -0
  58. mcp_proxy_adapter/core/security_factory.py +239 -0
  59. mcp_proxy_adapter/core/security_integration.py +286 -0
  60. mcp_proxy_adapter/core/server_adapter.py +282 -0
  61. mcp_proxy_adapter/core/server_engine.py +270 -0
  62. mcp_proxy_adapter/core/settings.py +1 -0
  63. mcp_proxy_adapter/core/ssl_utils.py +234 -0
  64. mcp_proxy_adapter/core/transport_manager.py +292 -0
  65. mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
  66. mcp_proxy_adapter/custom_openapi.py +22 -11
  67. mcp_proxy_adapter/examples/__init__.py +13 -4
  68. mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
  69. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  70. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  71. mcp_proxy_adapter/examples/basic_framework/main.py +44 -0
  72. mcp_proxy_adapter/examples/commands/__init__.py +5 -0
  73. mcp_proxy_adapter/examples/create_certificates_simple.py +550 -0
  74. mcp_proxy_adapter/examples/debug_request_state.py +112 -0
  75. mcp_proxy_adapter/examples/debug_role_chain.py +158 -0
  76. mcp_proxy_adapter/examples/demo_client.py +275 -0
  77. mcp_proxy_adapter/examples/examples/basic_framework/__init__.py +9 -0
  78. mcp_proxy_adapter/examples/examples/basic_framework/commands/__init__.py +4 -0
  79. mcp_proxy_adapter/examples/examples/basic_framework/hooks/__init__.py +4 -0
  80. mcp_proxy_adapter/examples/examples/basic_framework/main.py +44 -0
  81. mcp_proxy_adapter/examples/examples/full_application/__init__.py +12 -0
  82. mcp_proxy_adapter/examples/examples/full_application/commands/__init__.py +7 -0
  83. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +80 -0
  84. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +90 -0
  85. mcp_proxy_adapter/examples/examples/full_application/hooks/__init__.py +7 -0
  86. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +75 -0
  87. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +71 -0
  88. mcp_proxy_adapter/examples/examples/full_application/main.py +173 -0
  89. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +154 -0
  90. mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
  91. mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
  92. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +80 -0
  93. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +90 -0
  94. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
  95. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +75 -0
  96. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +71 -0
  97. mcp_proxy_adapter/examples/full_application/main.py +173 -0
  98. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
  99. mcp_proxy_adapter/examples/generate_all_certificates.py +362 -0
  100. mcp_proxy_adapter/examples/generate_certificates.py +177 -0
  101. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
  102. mcp_proxy_adapter/examples/generate_test_configs.py +331 -0
  103. mcp_proxy_adapter/examples/proxy_registration_example.py +334 -0
  104. mcp_proxy_adapter/examples/run_example.py +59 -0
  105. mcp_proxy_adapter/examples/run_full_test_suite.py +318 -0
  106. mcp_proxy_adapter/examples/run_proxy_server.py +146 -0
  107. mcp_proxy_adapter/examples/run_security_tests.py +544 -0
  108. mcp_proxy_adapter/examples/run_security_tests_fixed.py +247 -0
  109. mcp_proxy_adapter/examples/scripts/config_generator.py +740 -0
  110. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +560 -0
  111. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +369 -0
  112. mcp_proxy_adapter/examples/security_test_client.py +782 -0
  113. mcp_proxy_adapter/examples/setup_test_environment.py +328 -0
  114. mcp_proxy_adapter/examples/test_config.py +148 -0
  115. mcp_proxy_adapter/examples/test_config_generator.py +86 -0
  116. mcp_proxy_adapter/examples/test_examples.py +281 -0
  117. mcp_proxy_adapter/examples/universal_client.py +620 -0
  118. mcp_proxy_adapter/main.py +93 -0
  119. mcp_proxy_adapter/utils/config_generator.py +1008 -0
  120. mcp_proxy_adapter/version.py +5 -2
  121. mcp_proxy_adapter-6.0.1.dist-info/METADATA +679 -0
  122. mcp_proxy_adapter-6.0.1.dist-info/RECORD +140 -0
  123. mcp_proxy_adapter-6.0.1.dist-info/entry_points.txt +2 -0
  124. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/licenses/LICENSE +2 -2
  125. mcp_proxy_adapter/api/middleware/auth.py +0 -146
  126. mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
  127. mcp_proxy_adapter/commands/reload_settings_command.py +0 -125
  128. mcp_proxy_adapter/examples/README.md +0 -124
  129. mcp_proxy_adapter/examples/basic_server/README.md +0 -60
  130. mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
  131. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
  132. mcp_proxy_adapter/examples/basic_server/config.json +0 -35
  133. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
  134. mcp_proxy_adapter/examples/basic_server/server.py +0 -103
  135. mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
  136. mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
  137. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -250
  138. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
  139. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
  140. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
  141. mcp_proxy_adapter/examples/custom_commands/config.json +0 -35
  142. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
  143. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
  144. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
  145. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
  146. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
  147. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
  148. mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
  149. mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
  150. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
  151. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
  152. mcp_proxy_adapter/examples/custom_commands/server.py +0 -228
  153. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
  154. mcp_proxy_adapter/examples/deployment/README.md +0 -49
  155. mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
  156. mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
  157. mcp_proxy_adapter/examples/deployment/config.json +0 -29
  158. mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
  159. mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
  160. mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
  161. mcp_proxy_adapter/examples/deployment/run.sh +0 -43
  162. mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
  163. mcp_proxy_adapter/schemas/base_schema.json +0 -114
  164. mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
  165. mcp_proxy_adapter/tests/__init__.py +0 -0
  166. mcp_proxy_adapter/tests/api/__init__.py +0 -3
  167. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
  168. mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
  169. mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
  170. mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
  171. mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
  172. mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
  173. mcp_proxy_adapter/tests/commands/__init__.py +0 -3
  174. mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
  175. mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
  176. mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
  177. mcp_proxy_adapter/tests/conftest.py +0 -131
  178. mcp_proxy_adapter/tests/functional/__init__.py +0 -3
  179. mcp_proxy_adapter/tests/functional/test_api.py +0 -253
  180. mcp_proxy_adapter/tests/integration/__init__.py +0 -3
  181. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
  182. mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
  183. mcp_proxy_adapter/tests/performance/__init__.py +0 -3
  184. mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
  185. mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
  186. mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
  187. mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
  188. mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
  189. mcp_proxy_adapter/tests/test_base_command.py +0 -123
  190. mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
  191. mcp_proxy_adapter/tests/test_command_registry.py +0 -281
  192. mcp_proxy_adapter/tests/test_config.py +0 -127
  193. mcp_proxy_adapter/tests/test_utils.py +0 -65
  194. mcp_proxy_adapter/tests/unit/__init__.py +0 -3
  195. mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
  196. mcp_proxy_adapter/tests/unit/test_config.py +0 -217
  197. mcp_proxy_adapter-4.1.1.dist-info/METADATA +0 -200
  198. mcp_proxy_adapter-4.1.1.dist-info/RECORD +0 -110
  199. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/WHEEL +0 -0
  200. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Security Testing Script - Fixed Version
4
+ This script runs comprehensive security tests without fallback mode
5
+ and with proper port management.
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+ import asyncio
10
+ import json
11
+ import os
12
+ import signal
13
+ import subprocess
14
+ import sys
15
+ import time
16
+ from pathlib import Path
17
+ from typing import Dict, List, Optional, Tuple
18
+ # Add project root to path
19
+ project_root = Path(__file__).parent.parent.parent
20
+ sys.path.insert(0, str(project_root))
21
+ from security_test_client import SecurityTestClient, TestResult
22
+ class SecurityTestRunner:
23
+ """Security test runner with proper port management."""
24
+ def __init__(self):
25
+ self.project_root = Path(__file__).parent.parent.parent
26
+ self.configs_dir = self.project_root / "mcp_proxy_adapter" / "examples" / "server_configs"
27
+ self.server_processes = {}
28
+ self.test_results = []
29
+ def kill_process_on_port(self, port: int) -> bool:
30
+ """Kill process using specific port."""
31
+ try:
32
+ # Find process using the port
33
+ result = subprocess.run(
34
+ ["lsof", "-ti", f":{port}"],
35
+ capture_output=True,
36
+ text=True,
37
+ timeout=5
38
+ )
39
+ if result.returncode == 0 and result.stdout.strip():
40
+ pid = result.stdout.strip()
41
+ # Kill the process
42
+ subprocess.run(["kill", "-9", pid], check=True)
43
+ print(f"✅ Killed process {pid} on port {port}")
44
+ time.sleep(1) # Wait for port to be released
45
+ return True
46
+ else:
47
+ print(f"ℹ️ No process found on port {port}")
48
+ return True
49
+ except subprocess.TimeoutExpired:
50
+ print(f"⚠️ Timeout checking port {port}")
51
+ return False
52
+ except Exception as e:
53
+ print(f"❌ Error killing process on port {port}: {e}")
54
+ return False
55
+ def start_server(self, config_name: str, config_path: Path) -> Optional[subprocess.Popen]:
56
+ """Start server with proper error handling."""
57
+ try:
58
+ # Get port from config
59
+ with open(config_path) as f:
60
+ config = json.load(f)
61
+ port = config.get("server", {}).get("port", 8000)
62
+ # Kill any existing process on this port
63
+ self.kill_process_on_port(port)
64
+ # Start server
65
+ cmd = [
66
+ sys.executable, "-m", "mcp_proxy_adapter.main",
67
+ "--config", str(config_path)
68
+ ]
69
+ # For mTLS, start from examples directory
70
+ if config_name == "mtls":
71
+ cwd = self.project_root / "mcp_proxy_adapter" / "examples"
72
+ else:
73
+ cwd = self.project_root
74
+ print(f"🚀 Starting {config_name} on port {port}...")
75
+ process = subprocess.Popen(
76
+ cmd,
77
+ cwd=cwd,
78
+ stdout=subprocess.PIPE,
79
+ stderr=subprocess.PIPE,
80
+ text=True
81
+ )
82
+ # Wait a bit for server to start
83
+ time.sleep(3)
84
+ # Check if process is still running
85
+ if process.poll() is None:
86
+ print(f"✅ {config_name} started successfully on port {port}")
87
+ return process
88
+ else:
89
+ stdout, stderr = process.communicate()
90
+ print(f"❌ {config_name} failed to start:")
91
+ print(f"STDOUT: {stdout}")
92
+ print(f"STDERR: {stderr}")
93
+ return None
94
+ except Exception as e:
95
+ print(f"❌ Error starting {config_name}: {e}")
96
+ return None
97
+ def stop_server(self, config_name: str, process: subprocess.Popen):
98
+ """Stop server gracefully."""
99
+ try:
100
+ print(f"🛑 Stopping {config_name}...")
101
+ process.terminate()
102
+ process.wait(timeout=5)
103
+ print(f"✅ {config_name} stopped")
104
+ except subprocess.TimeoutExpired:
105
+ print(f"⚠️ Force killing {config_name}...")
106
+ process.kill()
107
+ process.wait()
108
+ except Exception as e:
109
+ print(f"❌ Error stopping {config_name}: {e}")
110
+ async def test_server(self, config_name: str, config_path: Path) -> List[TestResult]:
111
+ """Test a single server configuration."""
112
+ results = []
113
+ # Start server
114
+ process = self.start_server(config_name, config_path)
115
+ if not process:
116
+ return [TestResult(
117
+ test_name=f"{config_name}_startup",
118
+ server_url=f"http://localhost:{port}",
119
+ auth_type="none",
120
+ success=False,
121
+ error_message="Server failed to start"
122
+ )]
123
+ try:
124
+ # Get config for client setup
125
+ with open(config_path) as f:
126
+ config = json.load(f)
127
+ port = config.get("server", {}).get("port", 8000)
128
+ auth_enabled = config.get("security", {}).get("auth", {}).get("enabled", False)
129
+ auth_methods = config.get("security", {}).get("auth", {}).get("methods", [])
130
+ # Create test client with correct protocol
131
+ protocol = "https" if config.get("ssl", {}).get("enabled", False) else "http"
132
+ client = SecurityTestClient(base_url=f"{protocol}://localhost:{port}")
133
+ client.auth_enabled = auth_enabled
134
+ client.auth_methods = auth_methods
135
+ client.api_keys = config.get("security", {}).get("auth", {}).get("api_keys", {})
136
+ # For mTLS, override SSL context creation and change working directory
137
+ if config_name == "mtls":
138
+ client.create_ssl_context = client.create_ssl_context_for_mtls
139
+ # Ensure mTLS uses certificate auth
140
+ client.auth_methods = ["certificate"]
141
+ # Change to examples directory for mTLS tests
142
+ import os
143
+ os.chdir(self.project_root / "mcp_proxy_adapter" / "examples")
144
+ # Run tests
145
+ async with client:
146
+ # Test 1: Health check
147
+ result = await client.test_health()
148
+ results.append(result)
149
+ # Test 2: Command execution
150
+ result = await client.test_command_execution()
151
+ results.append(result)
152
+ # Test 3: Authentication (if enabled)
153
+ if auth_enabled:
154
+ result = await client.test_authentication()
155
+ results.append(result)
156
+ # Test 4: Negative authentication
157
+ result = await client.test_negative_authentication()
158
+ results.append(result)
159
+ # Test 5: Role-based access
160
+ result = await client.test_role_based_access(client.base_url, "api_key")
161
+ results.append(result)
162
+ # Test 6: Role permissions
163
+ result = await client.test_role_permissions(client.base_url, "api_key")
164
+ results.append(result)
165
+ # Test 7: Multiple roles test
166
+ result = await client.test_multiple_roles(client.base_url, "api_key")
167
+ results.append(result)
168
+ else:
169
+ # Test 3: No authentication required
170
+ result = await client.test_no_auth_required()
171
+ results.append(result)
172
+ # Test 4: Negative auth (should fail)
173
+ result = await client.test_negative_authentication()
174
+ results.append(result)
175
+ except Exception as e:
176
+ results.append(TestResult(
177
+ test_name=f"{config_name}_client_error",
178
+ server_url=f"http://localhost:{port}",
179
+ auth_type="none",
180
+ success=False,
181
+ error_message=str(e)
182
+ ))
183
+ finally:
184
+ # Stop server
185
+ self.stop_server(config_name, process)
186
+ return results
187
+ async def run_all_tests(self):
188
+ """Run all security tests."""
189
+ print("🔒 Starting Security Testing Suite")
190
+ print("=" * 50)
191
+ # Test configurations
192
+ configs = [
193
+ ("basic_http", "config_basic_http.json"),
194
+ ("http_token", "config_http_token.json"),
195
+ ("https", "config_https.json"),
196
+ ("https_token", "config_https_token.json"),
197
+ ("mtls", "config_mtls.json")
198
+ ]
199
+ total_tests = 0
200
+ passed_tests = 0
201
+ for config_name, config_file in configs:
202
+ config_path = self.configs_dir / config_file
203
+ if not config_path.exists():
204
+ print(f"❌ Configuration not found: {config_path}")
205
+ continue
206
+ print(f"\n📋 Testing {config_name.upper()} configuration")
207
+ print("-" * 30)
208
+ results = await self.test_server(config_name, config_path)
209
+ for result in results:
210
+ total_tests += 1
211
+ if result.success:
212
+ passed_tests += 1
213
+ print(f"✅ {result.test_name}: PASS")
214
+ else:
215
+ print(f"❌ {result.test_name}: FAIL - {result.error_message}")
216
+ self.test_results.extend(results)
217
+ # Print summary
218
+ print("\n" + "=" * 50)
219
+ print("📊 TEST SUMMARY")
220
+ print("=" * 50)
221
+ print(f"Total tests: {total_tests}")
222
+ print(f"Passed: {passed_tests}")
223
+ print(f"Failed: {total_tests - passed_tests}")
224
+ print(f"Success rate: {(passed_tests/total_tests*100):.1f}%" if total_tests > 0 else "N/A")
225
+ # Detailed results
226
+ print("\n📋 DETAILED RESULTS")
227
+ print("-" * 30)
228
+ for result in self.test_results:
229
+ status = "✅ PASS" if result.success else "❌ FAIL"
230
+ print(f"{status} {result.test_name}")
231
+ if not result.success and result.error_message:
232
+ print(f" Error: {result.error_message}")
233
+ return passed_tests == total_tests
234
+ async def main():
235
+ """Main function."""
236
+ runner = SecurityTestRunner()
237
+ try:
238
+ success = await runner.run_all_tests()
239
+ sys.exit(0 if success else 1)
240
+ except KeyboardInterrupt:
241
+ print("\n⚠️ Testing interrupted by user")
242
+ sys.exit(1)
243
+ except Exception as e:
244
+ print(f"\n❌ Testing failed: {e}")
245
+ sys.exit(1)
246
+ if __name__ == "__main__":
247
+ asyncio.run(main())