mcp-proxy-adapter 6.2.24__py3-none-any.whl → 6.2.26__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.
- mcp_proxy_adapter/api/app.py +0 -3
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +10 -10
- mcp_proxy_adapter/commands/health_command.py +1 -1
- mcp_proxy_adapter/config.py +234 -23
- mcp_proxy_adapter/core/protocol_manager.py +9 -9
- mcp_proxy_adapter/examples/create_certificates_simple.py +7 -17
- mcp_proxy_adapter/examples/examples/basic_framework/__init__.py +9 -0
- mcp_proxy_adapter/examples/examples/basic_framework/commands/__init__.py +4 -0
- mcp_proxy_adapter/examples/examples/basic_framework/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/examples/basic_framework/main.py +44 -0
- mcp_proxy_adapter/examples/examples/full_application/__init__.py +12 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/__init__.py +7 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +80 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +90 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/__init__.py +7 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +75 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +71 -0
- mcp_proxy_adapter/examples/examples/full_application/main.py +173 -0
- mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +154 -0
- mcp_proxy_adapter/examples/generate_test_configs.py +70 -33
- mcp_proxy_adapter/examples/run_full_test_suite.py +302 -109
- mcp_proxy_adapter/examples/run_security_tests.py +14 -5
- mcp_proxy_adapter/examples/scripts/config_generator.py +740 -0
- mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +560 -0
- mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +369 -0
- mcp_proxy_adapter/main.py +0 -2
- mcp_proxy_adapter/utils/config_generator.py +275 -7
- {mcp_proxy_adapter-6.2.24.dist-info → mcp_proxy_adapter-6.2.26.dist-info}/METADATA +1 -1
- {mcp_proxy_adapter-6.2.24.dist-info → mcp_proxy_adapter-6.2.26.dist-info}/RECORD +33 -17
- {mcp_proxy_adapter-6.2.24.dist-info → mcp_proxy_adapter-6.2.26.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.2.24.dist-info → mcp_proxy_adapter-6.2.26.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.2.24.dist-info → mcp_proxy_adapter-6.2.26.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-6.2.24.dist-info → mcp_proxy_adapter-6.2.26.dist-info}/top_level.txt +0 -0
@@ -9,7 +9,7 @@ import json
|
|
9
9
|
import os
|
10
10
|
import argparse
|
11
11
|
from typing import Dict, Any
|
12
|
-
def generate_http_simple_config(port: int = 20000, certs_dir: str = "
|
12
|
+
def generate_http_simple_config(port: int = 20000, certs_dir: str = "certs", keys_dir: str = "keys") -> Dict[str, Any]:
|
13
13
|
"""Generate HTTP configuration without authorization."""
|
14
14
|
return {
|
15
15
|
"server": {"host": "127.0.0.1", "port": port},
|
@@ -29,7 +29,7 @@ def generate_http_simple_config(port: int = 20000, certs_dir: str = "./certs", k
|
|
29
29
|
},
|
30
30
|
"protocols": {"enabled": True, "allowed_protocols": ["http"]}
|
31
31
|
}
|
32
|
-
def generate_http_token_config(port: int = 20001, certs_dir: str = "
|
32
|
+
def generate_http_token_config(port: int = 20001, certs_dir: str = "certs", keys_dir: str = "keys", roles_file: str = "configs/roles.json") -> Dict[str, Any]:
|
33
33
|
"""Generate HTTP configuration with token authorization."""
|
34
34
|
return {
|
35
35
|
"server": {"host": "127.0.0.1", "port": port},
|
@@ -48,7 +48,7 @@ def generate_http_token_config(port: int = 20001, certs_dir: str = "./certs", ke
|
|
48
48
|
"proxy-token-123": "proxy"
|
49
49
|
}
|
50
50
|
},
|
51
|
-
"permissions": {"enabled": True, "roles_file":
|
51
|
+
"permissions": {"enabled": True, "roles_file": roles_file}
|
52
52
|
},
|
53
53
|
"registration": {
|
54
54
|
"enabled": True,
|
@@ -61,14 +61,14 @@ def generate_http_token_config(port: int = 20001, certs_dir: str = "./certs", ke
|
|
61
61
|
},
|
62
62
|
"protocols": {"enabled": True, "allowed_protocols": ["http"]}
|
63
63
|
}
|
64
|
-
def generate_https_simple_config(port: int = 20002, certs_dir: str = "
|
64
|
+
def generate_https_simple_config(port: int = 20002, certs_dir: str = "certs", keys_dir: str = "keys") -> Dict[str, Any]:
|
65
65
|
"""Generate HTTPS configuration without client certificate verification and authorization."""
|
66
66
|
return {
|
67
67
|
"server": {"host": "127.0.0.1", "port": port},
|
68
68
|
"ssl": {
|
69
69
|
"enabled": True,
|
70
|
-
"cert_file": "
|
71
|
-
"key_file": "
|
70
|
+
"cert_file": f"{certs_dir}/localhost_server.crt",
|
71
|
+
"key_file": f"{keys_dir}/localhost_server.key"
|
72
72
|
},
|
73
73
|
"security": {"enabled": False},
|
74
74
|
"registration": {
|
@@ -82,14 +82,14 @@ def generate_https_simple_config(port: int = 20002, certs_dir: str = "./certs",
|
|
82
82
|
},
|
83
83
|
"protocols": {"enabled": True, "allowed_protocols": ["http", "https"]}
|
84
84
|
}
|
85
|
-
def generate_https_token_config(port: int = 20003, certs_dir: str = "
|
85
|
+
def generate_https_token_config(port: int = 20003, certs_dir: str = "certs", keys_dir: str = "keys") -> Dict[str, Any]:
|
86
86
|
"""Generate HTTPS configuration without client certificate verification with token authorization."""
|
87
87
|
return {
|
88
88
|
"server": {"host": "127.0.0.1", "port": port},
|
89
89
|
"ssl": {
|
90
90
|
"enabled": True,
|
91
|
-
"cert_file": "
|
92
|
-
"key_file": "
|
91
|
+
"cert_file": f"{certs_dir}/localhost_server.crt",
|
92
|
+
"key_file": f"{keys_dir}/localhost_server.key"
|
93
93
|
},
|
94
94
|
"security": {
|
95
95
|
"enabled": True,
|
@@ -104,7 +104,7 @@ def generate_https_token_config(port: int = 20003, certs_dir: str = "./certs", k
|
|
104
104
|
"proxy-token-123": "proxy"
|
105
105
|
}
|
106
106
|
},
|
107
|
-
"permissions": {"enabled": True, "roles_file": "./roles.json"}
|
107
|
+
"permissions": {"enabled": True, "roles_file": "./configs/roles.json"}
|
108
108
|
},
|
109
109
|
"registration": {
|
110
110
|
"enabled": True,
|
@@ -117,33 +117,33 @@ def generate_https_token_config(port: int = 20003, certs_dir: str = "./certs", k
|
|
117
117
|
},
|
118
118
|
"protocols": {"enabled": True, "allowed_protocols": ["http", "https"]}
|
119
119
|
}
|
120
|
-
def generate_mtls_no_roles_config(port: int = 20004, certs_dir: str = "
|
120
|
+
def generate_mtls_no_roles_config(port: int = 20004, certs_dir: str = "certs", keys_dir: str = "keys") -> Dict[str, Any]:
|
121
121
|
"""Generate mTLS configuration without roles."""
|
122
122
|
return {
|
123
123
|
"server": {"host": "127.0.0.1", "port": port},
|
124
124
|
"ssl": {
|
125
125
|
"enabled": True,
|
126
|
-
"cert_file": "
|
127
|
-
"key_file": "
|
128
|
-
"ca_cert": "
|
126
|
+
"cert_file": f"{certs_dir}/localhost_server.crt",
|
127
|
+
"key_file": f"{keys_dir}/localhost_server.key",
|
128
|
+
"ca_cert": f"{certs_dir}/mcp_proxy_adapter_ca_ca.crt",
|
129
129
|
"verify_client": True
|
130
130
|
},
|
131
131
|
"security": {
|
132
132
|
"enabled": True,
|
133
133
|
"auth": {"enabled": True, "methods": ["certificate"]},
|
134
|
-
"permissions": {"enabled":
|
134
|
+
"permissions": {"enabled": False}
|
135
135
|
},
|
136
136
|
"protocols": {"enabled": True, "allowed_protocols": ["https", "mtls"]}
|
137
137
|
}
|
138
|
-
def generate_mtls_with_roles_config(port: int = 20005, certs_dir: str = "
|
138
|
+
def generate_mtls_with_roles_config(port: int = 20005, certs_dir: str = "certs", keys_dir: str = "keys", roles_file: str = "configs/roles.json") -> Dict[str, Any]:
|
139
139
|
"""Generate mTLS configuration with roles."""
|
140
140
|
return {
|
141
141
|
"server": {"host": "127.0.0.1", "port": port},
|
142
142
|
"ssl": {
|
143
143
|
"enabled": True,
|
144
|
-
"cert_file": "
|
145
|
-
"key_file": "
|
146
|
-
"ca_cert": "
|
144
|
+
"cert_file": f"{certs_dir}/localhost_server.crt",
|
145
|
+
"key_file": f"{keys_dir}/localhost_server.key",
|
146
|
+
"ca_cert": f"{certs_dir}/mcp_proxy_adapter_ca_ca.crt",
|
147
147
|
"verify_client": True
|
148
148
|
},
|
149
149
|
"registration": {
|
@@ -161,7 +161,7 @@ def generate_mtls_with_roles_config(port: int = 20005, certs_dir: str = "./certs
|
|
161
161
|
"security": {
|
162
162
|
"enabled": True,
|
163
163
|
"auth": {"enabled": True, "methods": ["certificate"]},
|
164
|
-
"permissions": {"enabled": True, "roles_file":
|
164
|
+
"permissions": {"enabled": True, "roles_file": roles_file}
|
165
165
|
},
|
166
166
|
"protocols": {"enabled": True, "allowed_protocols": ["https", "mtls"]}
|
167
167
|
}
|
@@ -222,15 +222,18 @@ def generate_roles_config() -> Dict[str, Any]:
|
|
222
222
|
"tokens": ["proxy-token-123"]
|
223
223
|
}
|
224
224
|
}
|
225
|
-
def generate_all_configs(output_dir: str, certs_dir: str = "
|
225
|
+
def generate_all_configs(output_dir: str, certs_dir: str = "certs", keys_dir: str = "keys", roles_file: str = "configs/roles.json") -> None:
|
226
226
|
"""Generate all 6 configuration types and save them to files."""
|
227
|
+
# Ensure output directory exists first
|
228
|
+
os.makedirs(output_dir, exist_ok=True)
|
229
|
+
|
227
230
|
configs = {
|
228
231
|
"http_simple": generate_http_simple_config(20000, certs_dir, keys_dir),
|
229
|
-
"http_token": generate_http_token_config(20001, certs_dir, keys_dir),
|
232
|
+
"http_token": generate_http_token_config(20001, certs_dir, keys_dir, roles_file),
|
230
233
|
"https_simple": generate_https_simple_config(20002, certs_dir, keys_dir),
|
231
234
|
"https_token": generate_https_token_config(20003, certs_dir, keys_dir),
|
232
235
|
"mtls_no_roles": generate_mtls_no_roles_config(20004, certs_dir, keys_dir),
|
233
|
-
"mtls_with_roles": generate_mtls_with_roles_config(20005, certs_dir, keys_dir)
|
236
|
+
"mtls_with_roles": generate_mtls_with_roles_config(20005, certs_dir, keys_dir, roles_file)
|
234
237
|
}
|
235
238
|
# Ensure output directory exists
|
236
239
|
os.makedirs(output_dir, exist_ok=True)
|
@@ -242,17 +245,36 @@ def generate_all_configs(output_dir: str, certs_dir: str = "./certs", keys_dir:
|
|
242
245
|
print(f"Generated: {filename}")
|
243
246
|
# Generate roles configuration
|
244
247
|
roles_config = generate_roles_config()
|
248
|
+
|
249
|
+
# Create roles.json in the root directory (test environment root) for compatibility
|
250
|
+
# When running as module, we need to create roles.json in the current working directory
|
251
|
+
# This is the directory where the user is running the command from
|
252
|
+
try:
|
253
|
+
# Get the current working directory where the user is running the command
|
254
|
+
current_dir = os.getcwd()
|
255
|
+
root_roles_filename = os.path.join(current_dir, "roles.json")
|
256
|
+
|
257
|
+
# Create roles.json in the current working directory
|
258
|
+
with open(root_roles_filename, 'w', encoding='utf-8') as f:
|
259
|
+
json.dump(roles_config, f, indent=2, ensure_ascii=False)
|
260
|
+
print(f"Generated: {root_roles_filename}")
|
261
|
+
|
262
|
+
# Also create a copy in the output directory for reference
|
263
|
+
backup_roles_filename = os.path.join(output_dir, "roles_backup.json")
|
264
|
+
with open(backup_roles_filename, 'w', encoding='utf-8') as f:
|
265
|
+
json.dump(roles_config, f, indent=2, ensure_ascii=False)
|
266
|
+
print(f"Generated backup: {backup_roles_filename}")
|
267
|
+
|
268
|
+
except Exception as e:
|
269
|
+
print(f"Warning: Could not create roles.json in current directory: {e}")
|
270
|
+
print(f"Current working directory: {os.getcwd()}")
|
271
|
+
print(f"Script directory: {os.path.dirname(os.path.abspath(__file__))}")
|
272
|
+
|
273
|
+
# Also create roles.json in configs directory for reference
|
245
274
|
roles_filename = os.path.join(output_dir, "roles.json")
|
246
275
|
with open(roles_filename, 'w', encoding='utf-8') as f:
|
247
276
|
json.dump(roles_config, f, indent=2, ensure_ascii=False)
|
248
277
|
print(f"Generated: {roles_filename}")
|
249
|
-
# Also create roles.json in certs directory for compatibility
|
250
|
-
certs_dir = os.path.join(os.path.dirname(output_dir), "certs")
|
251
|
-
if os.path.exists(certs_dir):
|
252
|
-
certs_roles_filename = os.path.join(certs_dir, "roles.json")
|
253
|
-
with open(certs_roles_filename, 'w', encoding='utf-8') as f:
|
254
|
-
json.dump(roles_config, f, indent=2, ensure_ascii=False)
|
255
|
-
print(f"Generated: {certs_roles_filename}")
|
256
278
|
print(f"\nGenerated {len(configs)} configuration files and roles.json in {output_dir}")
|
257
279
|
|
258
280
|
print("\n" + "=" * 60)
|
@@ -273,12 +295,27 @@ def main():
|
|
273
295
|
)
|
274
296
|
parser.add_argument(
|
275
297
|
"--output-dir",
|
276
|
-
default="
|
277
|
-
help="Output directory for configuration files (default:
|
298
|
+
default="configs",
|
299
|
+
help="Output directory for configuration files (default: configs)"
|
300
|
+
)
|
301
|
+
parser.add_argument(
|
302
|
+
"--certs-dir",
|
303
|
+
default="certs",
|
304
|
+
help="Certificates directory (default: certs)"
|
305
|
+
)
|
306
|
+
parser.add_argument(
|
307
|
+
"--keys-dir",
|
308
|
+
default="keys",
|
309
|
+
help="Keys directory (default: keys)"
|
310
|
+
)
|
311
|
+
parser.add_argument(
|
312
|
+
"--roles-file",
|
313
|
+
default="configs/roles.json",
|
314
|
+
help="Roles file path (default: configs/roles.json)"
|
278
315
|
)
|
279
316
|
args = parser.parse_args()
|
280
317
|
try:
|
281
|
-
generate_all_configs(args.output_dir)
|
318
|
+
generate_all_configs(args.output_dir, args.certs_dir, args.keys_dir, args.roles_file)
|
282
319
|
print("Configuration generation completed successfully!")
|
283
320
|
except Exception as e:
|
284
321
|
print(f"\n❌ CONFIGURATION GENERATION FAILED: {e}")
|
@@ -1,125 +1,318 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
"""
|
3
|
-
Full Test Suite Runner for MCP Proxy Adapter
|
4
|
-
This script automatically runs the complete test suite:
|
5
|
-
1. Setup test environment
|
6
|
-
2. Generate configurations
|
7
|
-
3. Create certificates
|
8
|
-
4. Run security tests
|
9
|
-
|
10
3
|
Author: Vasiliy Zdanovskiy
|
11
4
|
email: vasilyvz@gmail.com
|
5
|
+
Full test suite runner for MCP Proxy Adapter.
|
6
|
+
Automates the complete testing workflow.
|
12
7
|
"""
|
8
|
+
import os
|
13
9
|
import sys
|
14
10
|
import subprocess
|
15
|
-
import
|
11
|
+
import time
|
16
12
|
from pathlib import Path
|
13
|
+
from typing import List, Dict, Optional
|
17
14
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
print(f"✅ {
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
print(f"
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
print(f"
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
success = False
|
75
|
-
|
76
|
-
# 3. Create certificates
|
77
|
-
if success and not run_command([
|
78
|
-
sys.executable, "-m", "mcp_proxy_adapter.examples.create_certificates_simple"
|
79
|
-
], "Creating certificates"):
|
80
|
-
success = False
|
81
|
-
|
82
|
-
# 4. Copy roles.json to root directory
|
83
|
-
if success:
|
84
|
-
import shutil
|
85
|
-
from pathlib import Path
|
86
|
-
roles_file = Path("configs/roles.json")
|
87
|
-
if roles_file.exists():
|
88
|
-
shutil.copy2(roles_file, "roles.json")
|
89
|
-
print("✅ Copied roles.json to root directory")
|
15
|
+
class FullTestSuiteRunner:
|
16
|
+
"""Comprehensive test suite runner that automates the entire testing process."""
|
17
|
+
|
18
|
+
def __init__(self):
|
19
|
+
"""Initialize the test suite runner."""
|
20
|
+
self.working_dir = Path.cwd()
|
21
|
+
self.configs_dir = self.working_dir / "configs"
|
22
|
+
self.certs_dir = self.working_dir / "certs"
|
23
|
+
self.keys_dir = self.working_dir / "keys"
|
24
|
+
self.roles_file = self.working_dir / "configs" / "roles.json"
|
25
|
+
|
26
|
+
def print_step(self, step: str, description: str):
|
27
|
+
"""Print a formatted step header."""
|
28
|
+
print(f"\n{'='*60}")
|
29
|
+
print(f"🔧 STEP {step}: {description}")
|
30
|
+
print(f"{'='*60}")
|
31
|
+
|
32
|
+
def print_success(self, message: str):
|
33
|
+
"""Print a success message."""
|
34
|
+
print(f"✅ {message}")
|
35
|
+
|
36
|
+
def print_error(self, message: str):
|
37
|
+
"""Print an error message."""
|
38
|
+
print(f"❌ {message}")
|
39
|
+
|
40
|
+
def print_info(self, message: str):
|
41
|
+
"""Print an info message."""
|
42
|
+
print(f"ℹ️ {message}")
|
43
|
+
|
44
|
+
def check_environment(self) -> bool:
|
45
|
+
"""Check if the environment is properly set up."""
|
46
|
+
self.print_step("1", "Environment Validation")
|
47
|
+
|
48
|
+
# Check if we're in a virtual environment
|
49
|
+
if not hasattr(sys, 'real_prefix') and not (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix):
|
50
|
+
self.print_error("Not running in a virtual environment!")
|
51
|
+
self.print_info("Please activate your virtual environment first:")
|
52
|
+
self.print_info(" source venv/bin/activate # or .venv/bin/activate")
|
53
|
+
return False
|
54
|
+
|
55
|
+
self.print_success("Virtual environment is active")
|
56
|
+
|
57
|
+
# Check if mcp_proxy_adapter is installed
|
58
|
+
try:
|
59
|
+
import mcp_proxy_adapter
|
60
|
+
self.print_success(f"mcp_proxy_adapter is installed (version: {mcp_proxy_adapter.__version__})")
|
61
|
+
except ImportError:
|
62
|
+
self.print_error("mcp_proxy_adapter is not installed!")
|
63
|
+
self.print_info("Please install it first:")
|
64
|
+
self.print_info(" pip install mcp_proxy_adapter")
|
65
|
+
return False
|
66
|
+
|
67
|
+
# Check Python version
|
68
|
+
python_version = sys.version_info
|
69
|
+
if python_version.major >= 3 and python_version.minor >= 8:
|
70
|
+
self.print_success(f"Python version: {python_version.major}.{python_version.minor}.{python_version.micro}")
|
90
71
|
else:
|
91
|
-
|
92
|
-
|
72
|
+
self.print_error(f"Python {python_version.major}.{python_version.minor} is not supported. Need Python 3.8+")
|
73
|
+
return False
|
74
|
+
|
75
|
+
return True
|
76
|
+
|
77
|
+
def create_directories(self) -> bool:
|
78
|
+
"""Create necessary directories for testing."""
|
79
|
+
self.print_step("2", "Directory Creation")
|
80
|
+
|
81
|
+
try:
|
82
|
+
# Create configs directory
|
83
|
+
self.configs_dir.mkdir(exist_ok=True)
|
84
|
+
self.print_success(f"Created/verified configs directory: {self.configs_dir}")
|
85
|
+
|
86
|
+
# Create certs directory
|
87
|
+
self.certs_dir.mkdir(exist_ok=True)
|
88
|
+
self.print_success(f"Created/verified certs directory: {self.certs_dir}")
|
89
|
+
|
90
|
+
# Create keys directory
|
91
|
+
self.keys_dir.mkdir(exist_ok=True)
|
92
|
+
self.print_success(f"Created/verified keys directory: {self.keys_dir}")
|
93
|
+
|
94
|
+
return True
|
95
|
+
|
96
|
+
except Exception as e:
|
97
|
+
self.print_error(f"Failed to create directories: {e}")
|
98
|
+
return False
|
99
|
+
|
100
|
+
def generate_certificates(self) -> bool:
|
101
|
+
"""Generate SSL certificates for testing."""
|
102
|
+
self.print_step("3", "Certificate Generation")
|
103
|
+
|
104
|
+
try:
|
105
|
+
# Run certificate generation script
|
106
|
+
cmd = [sys.executable, "-m", "mcp_proxy_adapter.examples.create_certificates_simple"]
|
107
|
+
self.print_info("Running certificate generation script...")
|
108
|
+
|
109
|
+
result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.working_dir)
|
110
|
+
|
111
|
+
if result.returncode == 0:
|
112
|
+
self.print_success("Certificates generated successfully")
|
113
|
+
if result.stdout:
|
114
|
+
print(result.stdout)
|
115
|
+
return True
|
116
|
+
else:
|
117
|
+
self.print_error("Certificate generation failed!")
|
118
|
+
if result.stderr:
|
119
|
+
print("Error output:")
|
120
|
+
print(result.stderr)
|
121
|
+
return False
|
122
|
+
|
123
|
+
except Exception as e:
|
124
|
+
self.print_error(f"Failed to generate certificates: {e}")
|
125
|
+
return False
|
126
|
+
|
127
|
+
def generate_configurations(self) -> bool:
|
128
|
+
"""Generate test configurations."""
|
129
|
+
self.print_step("4", "Configuration Generation")
|
130
|
+
|
131
|
+
try:
|
132
|
+
# Run configuration generation script
|
133
|
+
cmd = [sys.executable, "-m", "mcp_proxy_adapter.examples.generate_test_configs"]
|
134
|
+
self.print_info("Running configuration generation script...")
|
135
|
+
|
136
|
+
result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.working_dir)
|
137
|
+
|
138
|
+
if result.returncode == 0:
|
139
|
+
self.print_success("Configurations generated successfully")
|
140
|
+
if result.stdout:
|
141
|
+
print(result.stdout)
|
142
|
+
return True
|
143
|
+
else:
|
144
|
+
self.print_error("Configuration generation failed!")
|
145
|
+
if result.stderr:
|
146
|
+
print("Error output:")
|
147
|
+
print(result.stderr)
|
148
|
+
return False
|
149
|
+
|
150
|
+
except Exception as e:
|
151
|
+
self.print_error(f"Failed to generate configurations: {e}")
|
152
|
+
return False
|
153
|
+
|
154
|
+
def run_security_tests(self) -> bool:
|
155
|
+
"""Run the security test suite."""
|
156
|
+
self.print_step("5", "Security Testing")
|
157
|
+
|
158
|
+
try:
|
159
|
+
# Run security tests
|
160
|
+
cmd = [sys.executable, "-m", "mcp_proxy_adapter.examples.run_security_tests", "--verbose"]
|
161
|
+
self.print_info("Running security tests...")
|
162
|
+
|
163
|
+
# Debug: show current working directory and check files
|
164
|
+
self.print_info(f"DEBUG: Current working directory: {os.getcwd()}")
|
165
|
+
self.print_info(f"DEBUG: Working directory from class: {self.working_dir}")
|
166
|
+
|
167
|
+
# Check if certificates exist before running tests
|
168
|
+
localhost_cert = self.certs_dir / "localhost_server.crt"
|
169
|
+
self.print_info(f"DEBUG: localhost_server.crt exists: {localhost_cert.exists()}")
|
170
|
+
if localhost_cert.exists():
|
171
|
+
self.print_info(f"DEBUG: localhost_server.crt is symlink: {localhost_cert.is_symlink()}")
|
172
|
+
if localhost_cert.is_symlink():
|
173
|
+
self.print_info(f"DEBUG: localhost_server.crt symlink target: {localhost_cert.readlink()}")
|
174
|
+
|
175
|
+
# List all files in certs directory
|
176
|
+
self.print_info("DEBUG: Files in certs directory:")
|
177
|
+
for file in self.certs_dir.iterdir():
|
178
|
+
self.print_info(f"DEBUG: {file.name} -> {file}")
|
179
|
+
|
180
|
+
result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.working_dir)
|
181
|
+
|
182
|
+
if result.returncode == 0:
|
183
|
+
self.print_success("Security tests completed successfully!")
|
184
|
+
if result.stdout:
|
185
|
+
print(result.stdout)
|
186
|
+
return True
|
187
|
+
else:
|
188
|
+
self.print_error("Security tests failed!")
|
189
|
+
if result.stdout:
|
190
|
+
print("Test output:")
|
191
|
+
print(result.stdout)
|
192
|
+
if result.stderr:
|
193
|
+
print("Error output:")
|
194
|
+
print(result.stderr)
|
195
|
+
return False
|
196
|
+
|
197
|
+
except Exception as e:
|
198
|
+
self.print_error(f"Failed to run security tests: {e}")
|
199
|
+
return False
|
200
|
+
|
201
|
+
def cleanup(self):
|
202
|
+
"""Clean up temporary files and processes."""
|
203
|
+
self.print_info("Cleaning up...")
|
204
|
+
|
205
|
+
# Simple cleanup - just print success message
|
206
|
+
# Process cleanup is handled by the test scripts themselves
|
207
|
+
print("✅ Cleanup completed")
|
208
|
+
|
93
209
|
|
94
|
-
# 5. Run security tests
|
95
|
-
if success and not run_command([
|
96
|
-
sys.executable, "-m", "mcp_proxy_adapter.examples.run_security_tests"
|
97
|
-
], "Running security tests"):
|
98
|
-
success = False
|
99
210
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
211
|
+
def cleanup_directories(self) -> bool:
|
212
|
+
"""Clean up existing test directories before starting."""
|
213
|
+
self.print_info("Cleaning up existing test directories...")
|
214
|
+
|
215
|
+
try:
|
216
|
+
import shutil
|
217
|
+
|
218
|
+
# Directories to clean
|
219
|
+
dirs_to_clean = [self.configs_dir, self.certs_dir, self.keys_dir]
|
220
|
+
files_to_clean = [self.working_dir / "roles.json"]
|
221
|
+
|
222
|
+
# Remove directories
|
223
|
+
for dir_path in dirs_to_clean:
|
224
|
+
if dir_path.exists():
|
225
|
+
shutil.rmtree(dir_path)
|
226
|
+
print(f"🗑️ Removed directory: {dir_path}")
|
227
|
+
|
228
|
+
# Remove files
|
229
|
+
for file_path in files_to_clean:
|
230
|
+
if file_path.exists():
|
231
|
+
file_path.unlink()
|
232
|
+
print(f"🗑️ Removed file: {file_path}")
|
233
|
+
|
234
|
+
self.print_success("Directory cleanup completed")
|
235
|
+
return True
|
236
|
+
|
237
|
+
except Exception as e:
|
238
|
+
self.print_error(f"Failed to cleanup directories: {e}")
|
239
|
+
return False
|
240
|
+
|
241
|
+
def run_full_suite(self) -> bool:
|
242
|
+
"""Run the complete test suite."""
|
243
|
+
print("🚀 MCP Proxy Adapter - Full Test Suite")
|
115
244
|
print("=" * 60)
|
116
|
-
print("
|
117
|
-
print("
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
245
|
+
print(f"Working directory: {self.working_dir}")
|
246
|
+
print(f"Python executable: {sys.executable}")
|
247
|
+
|
248
|
+
try:
|
249
|
+
# Step 0: Clean up existing directories
|
250
|
+
if not self.cleanup_directories():
|
251
|
+
return False
|
252
|
+
|
253
|
+
# Step 1: Environment validation
|
254
|
+
if not self.check_environment():
|
255
|
+
return False
|
256
|
+
|
257
|
+
# Step 2: Directory creation
|
258
|
+
if not self.create_directories():
|
259
|
+
return False
|
260
|
+
|
261
|
+
# Step 3: Certificate generation
|
262
|
+
if not self.generate_certificates():
|
263
|
+
return False
|
264
|
+
|
265
|
+
# Step 4: Configuration generation
|
266
|
+
if not self.generate_configurations():
|
267
|
+
return False
|
268
|
+
|
269
|
+
# Step 5: Security testing
|
270
|
+
if not self.run_security_tests():
|
271
|
+
return False
|
272
|
+
|
273
|
+
# All steps completed successfully
|
274
|
+
print(f"\n{'='*60}")
|
275
|
+
print("🎉 FULL TEST SUITE COMPLETED SUCCESSFULLY!")
|
276
|
+
print("="*60)
|
277
|
+
print("✅ Environment validated")
|
278
|
+
print("✅ Directories cleaned")
|
279
|
+
print("✅ Directories created")
|
280
|
+
print("✅ Certificates generated")
|
281
|
+
print("✅ Configurations generated")
|
282
|
+
print("✅ Security tests passed")
|
283
|
+
print(f"\n📁 Test artifacts created in: {self.working_dir}")
|
284
|
+
print(f"📁 Configurations: {self.configs_dir}")
|
285
|
+
print(f"📁 Certificates: {self.certs_dir}")
|
286
|
+
print(f"📁 Keys: {self.keys_dir}")
|
287
|
+
|
288
|
+
return True
|
289
|
+
|
290
|
+
except KeyboardInterrupt:
|
291
|
+
print("\n\n⚠️ Test suite interrupted by user")
|
292
|
+
return False
|
293
|
+
except Exception as e:
|
294
|
+
self.print_error(f"Unexpected error during test suite execution: {e}")
|
295
|
+
return False
|
296
|
+
finally:
|
297
|
+
try:
|
298
|
+
self.print_info("Starting cleanup in finally block...")
|
299
|
+
self.cleanup()
|
300
|
+
self.print_info("Cleanup in finally block completed")
|
301
|
+
except Exception as e:
|
302
|
+
self.print_error(f"Cleanup failed in finally block: {e}")
|
303
|
+
import traceback
|
304
|
+
traceback.print_exc()
|
122
305
|
|
306
|
+
def main():
|
307
|
+
"""Main entry point."""
|
308
|
+
runner = FullTestSuiteRunner()
|
309
|
+
|
310
|
+
try:
|
311
|
+
success = runner.run_full_suite()
|
312
|
+
sys.exit(0 if success else 1)
|
313
|
+
except Exception as e:
|
314
|
+
print(f"❌ Fatal error: {e}")
|
315
|
+
sys.exit(1)
|
123
316
|
|
124
317
|
if __name__ == "__main__":
|
125
|
-
|
318
|
+
main()
|