mcp-proxy-adapter 6.6.0__py3-none-any.whl → 6.6.3__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 +28 -26
- mcp_proxy_adapter/config.py +2 -9
- mcp_proxy_adapter/core/server_adapter.py +1 -1
- mcp_proxy_adapter/examples/check_config.py +415 -0
- mcp_proxy_adapter/examples/config_builder.py +11 -17
- mcp_proxy_adapter/examples/{generate_certificates_bugfix.py → generate_certificates.py} +11 -0
- mcp_proxy_adapter/examples/generate_config.py +343 -0
- mcp_proxy_adapter/examples/run_full_test_suite.py +3 -3
- mcp_proxy_adapter/examples/security_test_client.py +6 -5
- mcp_proxy_adapter/examples/test_chk_hostname_automated.py +211 -0
- mcp_proxy_adapter/examples/test_framework_complete.py +269 -0
- mcp_proxy_adapter/examples/test_mcp_server.py +188 -0
- mcp_proxy_adapter/main.py +11 -18
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.6.0.dist-info → mcp_proxy_adapter-6.6.3.dist-info}/METADATA +1 -1
- {mcp_proxy_adapter-6.6.0.dist-info → mcp_proxy_adapter-6.6.3.dist-info}/RECORD +19 -20
- mcp_proxy_adapter/examples/config_builder_simple.py +0 -271
- mcp_proxy_adapter/examples/generate_all_certificates.py +0 -487
- mcp_proxy_adapter/examples/generate_certificates_cli.py +0 -406
- mcp_proxy_adapter/examples/generate_certificates_fixed.py +0 -313
- mcp_proxy_adapter/examples/generate_certificates_framework.py +0 -366
- mcp_proxy_adapter/examples/generate_certificates_openssl.py +0 -391
- {mcp_proxy_adapter-6.6.0.dist-info → mcp_proxy_adapter-6.6.3.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.6.0.dist-info → mcp_proxy_adapter-6.6.3.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.6.0.dist-info → mcp_proxy_adapter-6.6.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,343 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Configuration Generator CLI for MCP Proxy Adapter
|
4
|
+
Generates configurations based on command line flags.
|
5
|
+
|
6
|
+
Author: Vasiliy Zdanovskiy
|
7
|
+
email: vasilyvz@gmail.com
|
8
|
+
"""
|
9
|
+
import argparse
|
10
|
+
import json
|
11
|
+
import sys
|
12
|
+
from pathlib import Path
|
13
|
+
from typing import Dict, Any, Optional
|
14
|
+
|
15
|
+
# Add the project root to the path to import config_builder
|
16
|
+
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
17
|
+
|
18
|
+
from mcp_proxy_adapter.examples.config_builder import ConfigBuilder, ConfigFactory, Protocol, AuthMethod
|
19
|
+
|
20
|
+
|
21
|
+
def create_config_from_flags(
|
22
|
+
protocol: str,
|
23
|
+
token: bool = False,
|
24
|
+
roles: bool = False,
|
25
|
+
host: str = "127.0.0.1",
|
26
|
+
port: int = 8000,
|
27
|
+
cert_dir: str = "./certs",
|
28
|
+
key_dir: str = "./keys",
|
29
|
+
output_dir: str = "./configs"
|
30
|
+
) -> Dict[str, Any]:
|
31
|
+
"""
|
32
|
+
Create configuration based on command line flags.
|
33
|
+
|
34
|
+
Args:
|
35
|
+
protocol: Protocol type (http, https, mtls)
|
36
|
+
token: Enable token authentication
|
37
|
+
roles: Enable role-based access control
|
38
|
+
host: Server host
|
39
|
+
port: Server port
|
40
|
+
cert_dir: Certificate directory
|
41
|
+
key_dir: Key directory
|
42
|
+
output_dir: Output directory for configs
|
43
|
+
|
44
|
+
Returns:
|
45
|
+
Configuration dictionary
|
46
|
+
"""
|
47
|
+
# Use the simplified config builder
|
48
|
+
from config_builder import create_config_from_flags as simple_create_config
|
49
|
+
|
50
|
+
return simple_create_config(protocol, token, roles, port)
|
51
|
+
|
52
|
+
|
53
|
+
def save_config(config: Dict[str, Any], filename: str, output_dir: str) -> Path:
|
54
|
+
"""Save configuration to file."""
|
55
|
+
output_path = Path(output_dir)
|
56
|
+
output_path.mkdir(parents=True, exist_ok=True)
|
57
|
+
|
58
|
+
config_file = output_path / f"{filename}.json"
|
59
|
+
with open(config_file, 'w', encoding='utf-8') as f:
|
60
|
+
json.dump(config, f, indent=2, ensure_ascii=False)
|
61
|
+
|
62
|
+
return config_file
|
63
|
+
|
64
|
+
|
65
|
+
def create_full_config_with_all_options(host: str = "127.0.0.1", port: int = 20000) -> Dict[str, Any]:
|
66
|
+
"""
|
67
|
+
Create a full configuration with all options enabled but set to HTTP base.
|
68
|
+
This allows testing all features by enabling different sections.
|
69
|
+
|
70
|
+
Args:
|
71
|
+
host: Server host
|
72
|
+
port: Server port
|
73
|
+
|
74
|
+
Returns:
|
75
|
+
Full configuration dictionary with all options
|
76
|
+
"""
|
77
|
+
builder = ConfigBuilder()
|
78
|
+
|
79
|
+
# Set server configuration
|
80
|
+
builder.set_server(host=host, port=port)
|
81
|
+
|
82
|
+
# Set to HTTP base (no SSL by default)
|
83
|
+
builder.set_protocol(Protocol.HTTP)
|
84
|
+
|
85
|
+
# Enable all authentication options but keep them disabled by default
|
86
|
+
api_keys = {
|
87
|
+
"admin": "admin-secret-key",
|
88
|
+
"user": "user-secret-key",
|
89
|
+
"readonly": "readonly-secret-key"
|
90
|
+
}
|
91
|
+
roles = {
|
92
|
+
"admin": ["read", "write", "delete", "admin"],
|
93
|
+
"user": ["read", "write"],
|
94
|
+
"readonly": ["read"]
|
95
|
+
}
|
96
|
+
|
97
|
+
# Set up all authentication methods but keep security disabled
|
98
|
+
builder.set_auth(AuthMethod.TOKEN_ROLES, api_keys=api_keys, roles=roles)
|
99
|
+
|
100
|
+
# Disable security by default (will be enabled in tests)
|
101
|
+
config = builder.build()
|
102
|
+
config["security"]["enabled"] = False
|
103
|
+
|
104
|
+
# Add protocol variants for easy switching
|
105
|
+
config["protocol_variants"] = {
|
106
|
+
"http": {"server": {"protocol": "http"}},
|
107
|
+
"https": {"server": {"protocol": "https"}},
|
108
|
+
"mtls": {"server": {"protocol": "mtls"}}
|
109
|
+
}
|
110
|
+
|
111
|
+
# Add authentication configurations for easy switching
|
112
|
+
config["auth_variants"] = {
|
113
|
+
"none": {"security": {"enabled": False}},
|
114
|
+
"token": {
|
115
|
+
"security": {
|
116
|
+
"enabled": True,
|
117
|
+
"tokens": api_keys,
|
118
|
+
"roles": roles,
|
119
|
+
"roles_file": None
|
120
|
+
}
|
121
|
+
},
|
122
|
+
"token_roles": {
|
123
|
+
"security": {
|
124
|
+
"enabled": True,
|
125
|
+
"tokens": api_keys,
|
126
|
+
"roles": roles,
|
127
|
+
"roles_file": "configs/roles.json"
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
return config
|
133
|
+
|
134
|
+
|
135
|
+
def generate_all_configs(output_dir: str = "./configs", host: str = "127.0.0.1") -> None:
|
136
|
+
"""Generate all standard configurations."""
|
137
|
+
configs = [
|
138
|
+
# HTTP configurations
|
139
|
+
("http", False, False, 20000),
|
140
|
+
("http", True, True, 20001), # token=True always includes roles
|
141
|
+
("http", True, True, 20002), # token_roles is same as token now
|
142
|
+
|
143
|
+
# HTTPS configurations
|
144
|
+
("https", False, False, 20003),
|
145
|
+
("https", True, True, 20004), # token=True always includes roles
|
146
|
+
("https", True, True, 20005), # token_roles is same as token now
|
147
|
+
|
148
|
+
# mTLS configurations
|
149
|
+
("mtls", False, False, 20006),
|
150
|
+
("mtls", True, True, 20007), # token=True always includes roles
|
151
|
+
("mtls", True, True, 20008), # token_roles is same as token now
|
152
|
+
]
|
153
|
+
|
154
|
+
print("🔧 Generating MCP Proxy Adapter configurations...")
|
155
|
+
print("=" * 60)
|
156
|
+
|
157
|
+
generated_files = []
|
158
|
+
|
159
|
+
for protocol, token, roles, port in configs:
|
160
|
+
# Create configuration name
|
161
|
+
name_parts = [protocol]
|
162
|
+
if token:
|
163
|
+
name_parts.append("token")
|
164
|
+
if roles:
|
165
|
+
name_parts.append("roles")
|
166
|
+
|
167
|
+
config_name = "_".join(name_parts)
|
168
|
+
|
169
|
+
# Generate configuration
|
170
|
+
config = create_config_from_flags(
|
171
|
+
protocol=protocol,
|
172
|
+
token=token,
|
173
|
+
roles=roles,
|
174
|
+
host=host,
|
175
|
+
port=port,
|
176
|
+
output_dir=output_dir
|
177
|
+
)
|
178
|
+
|
179
|
+
# Save configuration
|
180
|
+
config_file = save_config(config, config_name, output_dir)
|
181
|
+
generated_files.append(config_file)
|
182
|
+
|
183
|
+
print(f"✅ Created {config_name}.json (port {port})")
|
184
|
+
|
185
|
+
# Create roles.json file if any role-based configs were generated
|
186
|
+
roles_config = {
|
187
|
+
"enabled": True,
|
188
|
+
"default_policy": {
|
189
|
+
"deny_by_default": False,
|
190
|
+
"require_role_match": False,
|
191
|
+
"case_sensitive": False,
|
192
|
+
"allow_wildcard": False
|
193
|
+
},
|
194
|
+
"roles": {
|
195
|
+
"admin": ["read", "write", "delete", "admin"],
|
196
|
+
"user": ["read", "write"],
|
197
|
+
"readonly": ["read"],
|
198
|
+
"guest": ["read"],
|
199
|
+
"proxy": ["read", "write"]
|
200
|
+
},
|
201
|
+
"permissions": {
|
202
|
+
"read": ["GET"],
|
203
|
+
"write": ["POST", "PUT", "PATCH"],
|
204
|
+
"delete": ["DELETE"],
|
205
|
+
"admin": ["*"]
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
roles_file = Path(output_dir) / "roles.json"
|
210
|
+
with open(roles_file, 'w', encoding='utf-8') as f:
|
211
|
+
json.dump(roles_config, f, indent=2, ensure_ascii=False)
|
212
|
+
print(f"✅ Created roles.json")
|
213
|
+
|
214
|
+
print(f"\n🎉 Generated {len(generated_files)} configurations in {output_dir}/")
|
215
|
+
print("\n📋 Generated configurations:")
|
216
|
+
for config_file in generated_files:
|
217
|
+
print(f" - {config_file.name}")
|
218
|
+
|
219
|
+
|
220
|
+
def main():
|
221
|
+
"""Main CLI function."""
|
222
|
+
parser = argparse.ArgumentParser(
|
223
|
+
description="MCP Proxy Adapter Configuration Generator",
|
224
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
225
|
+
epilog="""
|
226
|
+
Examples:
|
227
|
+
# Generate all standard configurations
|
228
|
+
python generate_config.py --all
|
229
|
+
|
230
|
+
# Generate full config with all options (HTTP base)
|
231
|
+
python generate_config.py --full-config
|
232
|
+
|
233
|
+
# Generate specific configuration
|
234
|
+
python generate_config.py --protocol https --token --roles --port 8080
|
235
|
+
|
236
|
+
# Generate HTTP configuration with token auth
|
237
|
+
python generate_config.py --protocol http --token
|
238
|
+
|
239
|
+
# Generate mTLS configuration with roles
|
240
|
+
python generate_config.py --protocol mtls --roles
|
241
|
+
"""
|
242
|
+
)
|
243
|
+
|
244
|
+
# Configuration options
|
245
|
+
parser.add_argument("--protocol", choices=["http", "https", "mtls"],
|
246
|
+
help="Protocol type (http, https, mtls)")
|
247
|
+
parser.add_argument("--token", action="store_true",
|
248
|
+
help="Enable token authentication")
|
249
|
+
parser.add_argument("--roles", action="store_true",
|
250
|
+
help="Enable role-based access control")
|
251
|
+
parser.add_argument("--all", action="store_true",
|
252
|
+
help="Generate all standard configurations")
|
253
|
+
parser.add_argument("--full-config", action="store_true",
|
254
|
+
help="Generate full config with all options (HTTP base)")
|
255
|
+
|
256
|
+
# Server configuration
|
257
|
+
parser.add_argument("--host", default="127.0.0.1",
|
258
|
+
help="Server host (default: 127.0.0.1)")
|
259
|
+
parser.add_argument("--port", type=int, default=8000,
|
260
|
+
help="Server port (default: 8000)")
|
261
|
+
|
262
|
+
# Paths
|
263
|
+
parser.add_argument("--cert-dir", default="./certs",
|
264
|
+
help="Certificate directory (default: ./certs)")
|
265
|
+
parser.add_argument("--key-dir", default="./keys",
|
266
|
+
help="Key directory (default: ./keys)")
|
267
|
+
parser.add_argument("--output-dir", default="./configs",
|
268
|
+
help="Output directory (default: ./configs)")
|
269
|
+
|
270
|
+
# Output options
|
271
|
+
parser.add_argument("--output", "-o",
|
272
|
+
help="Output filename (without extension)")
|
273
|
+
parser.add_argument("--stdout", action="store_true",
|
274
|
+
help="Output to stdout instead of file")
|
275
|
+
|
276
|
+
args = parser.parse_args()
|
277
|
+
|
278
|
+
try:
|
279
|
+
if args.all:
|
280
|
+
# Generate all configurations
|
281
|
+
generate_all_configs(
|
282
|
+
output_dir=args.output_dir,
|
283
|
+
host=args.host
|
284
|
+
)
|
285
|
+
elif args.full_config:
|
286
|
+
# Generate full config with all options
|
287
|
+
config = create_full_config_with_all_options(
|
288
|
+
host=args.host,
|
289
|
+
port=args.port
|
290
|
+
)
|
291
|
+
|
292
|
+
if args.stdout:
|
293
|
+
# Output to stdout
|
294
|
+
print(json.dumps(config, indent=2, ensure_ascii=False))
|
295
|
+
else:
|
296
|
+
# Save to file
|
297
|
+
filename = args.output or "full_config"
|
298
|
+
config_file = save_config(config, filename, args.output_dir)
|
299
|
+
print(f"✅ Full configuration saved to: {config_file}")
|
300
|
+
elif args.protocol:
|
301
|
+
# Generate specific configuration
|
302
|
+
config = create_config_from_flags(
|
303
|
+
protocol=args.protocol,
|
304
|
+
token=args.token,
|
305
|
+
roles=args.roles,
|
306
|
+
host=args.host,
|
307
|
+
port=args.port,
|
308
|
+
cert_dir=args.cert_dir,
|
309
|
+
key_dir=args.key_dir,
|
310
|
+
output_dir=args.output_dir
|
311
|
+
)
|
312
|
+
|
313
|
+
if args.stdout:
|
314
|
+
# Output to stdout
|
315
|
+
print(json.dumps(config, indent=2, ensure_ascii=False))
|
316
|
+
else:
|
317
|
+
# Save to file
|
318
|
+
if args.output:
|
319
|
+
filename = args.output
|
320
|
+
else:
|
321
|
+
# Generate filename from flags
|
322
|
+
name_parts = [args.protocol]
|
323
|
+
if args.token:
|
324
|
+
name_parts.append("token")
|
325
|
+
if args.roles:
|
326
|
+
name_parts.append("roles")
|
327
|
+
filename = "_".join(name_parts)
|
328
|
+
|
329
|
+
config_file = save_config(config, filename, args.output_dir)
|
330
|
+
print(f"✅ Configuration saved to: {config_file}")
|
331
|
+
else:
|
332
|
+
parser.print_help()
|
333
|
+
return 1
|
334
|
+
|
335
|
+
return 0
|
336
|
+
|
337
|
+
except Exception as e:
|
338
|
+
print(f"❌ Error: {e}", file=sys.stderr)
|
339
|
+
return 1
|
340
|
+
|
341
|
+
|
342
|
+
if __name__ == "__main__":
|
343
|
+
sys.exit(main())
|
@@ -113,7 +113,7 @@ class FullTestSuiteRunner:
|
|
113
113
|
|
114
114
|
try:
|
115
115
|
# Check if certificate generation script exists
|
116
|
-
cert_script = self.working_dir / "
|
116
|
+
cert_script = self.working_dir / "mcp_proxy_adapter" / "examples" / "generate_certificates.py"
|
117
117
|
if not cert_script.exists():
|
118
118
|
self.print_error(
|
119
119
|
f"Certificate generation script not found: {cert_script}"
|
@@ -167,7 +167,7 @@ class FullTestSuiteRunner:
|
|
167
167
|
|
168
168
|
try:
|
169
169
|
# Check if create_test_configs.py exists
|
170
|
-
config_script = self.working_dir / "create_test_configs.py"
|
170
|
+
config_script = self.working_dir / "mcp_proxy_adapter" / "examples" / "create_test_configs.py"
|
171
171
|
if not config_script.exists():
|
172
172
|
self.print_error(f"Configuration generator not found: {config_script}")
|
173
173
|
return False
|
@@ -194,7 +194,7 @@ class FullTestSuiteRunner:
|
|
194
194
|
# Run the configuration generator
|
195
195
|
cmd = [
|
196
196
|
sys.executable,
|
197
|
-
"create_test_configs.py",
|
197
|
+
"mcp_proxy_adapter/examples/create_test_configs.py",
|
198
198
|
"--comprehensive-config",
|
199
199
|
"comprehensive_config.json",
|
200
200
|
]
|
@@ -124,11 +124,12 @@ class SecurityTestClient:
|
|
124
124
|
def create_ssl_context_for_mtls(self) -> ssl.SSLContext:
|
125
125
|
"""Create SSL context for mTLS connections."""
|
126
126
|
# For mTLS, we need client certificates - check if they exist
|
127
|
-
#
|
128
|
-
# Use
|
129
|
-
|
130
|
-
|
131
|
-
|
127
|
+
# Use absolute paths to avoid issues with working directory
|
128
|
+
# Use newly generated admin_client_client.crt which is signed by the same CA as server
|
129
|
+
project_root = Path(__file__).parent.parent.parent
|
130
|
+
cert_file = str(project_root / "certs" / "admin_client_client.crt")
|
131
|
+
key_file = str(project_root / "keys" / "admin-client_client.key")
|
132
|
+
ca_cert_file = str(project_root / "certs" / "localhost_server.crt")
|
132
133
|
|
133
134
|
# CRITICAL: For mTLS, certificates are REQUIRED
|
134
135
|
if not os.path.exists(cert_file):
|
@@ -0,0 +1,211 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Automated tests for chk_hostname functionality in all SSL modes.
|
4
|
+
|
5
|
+
Author: Vasiliy Zdanovskiy
|
6
|
+
email: vasilyvz@gmail.com
|
7
|
+
"""
|
8
|
+
|
9
|
+
import json
|
10
|
+
import tempfile
|
11
|
+
import os
|
12
|
+
from pathlib import Path
|
13
|
+
import sys
|
14
|
+
|
15
|
+
# Add the project root to the path
|
16
|
+
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
17
|
+
|
18
|
+
from mcp_proxy_adapter.config import Config
|
19
|
+
from mcp_proxy_adapter.examples.config_builder import ConfigBuilder, Protocol, AuthMethod
|
20
|
+
|
21
|
+
|
22
|
+
def test_chk_hostname_default_config():
|
23
|
+
"""Test that default config has chk_hostname=False for HTTP."""
|
24
|
+
print("🧪 Testing default config chk_hostname...")
|
25
|
+
|
26
|
+
config = Config()
|
27
|
+
|
28
|
+
# Default should be HTTP with chk_hostname=False
|
29
|
+
assert config.get("server.protocol") == "http"
|
30
|
+
assert config.get("transport.chk_hostname") is False
|
31
|
+
|
32
|
+
print("✅ Default config: chk_hostname=False for HTTP")
|
33
|
+
|
34
|
+
|
35
|
+
def test_chk_hostname_http_config():
|
36
|
+
"""Test that HTTP config has chk_hostname=False."""
|
37
|
+
print("🧪 Testing HTTP config chk_hostname...")
|
38
|
+
|
39
|
+
# Create HTTP config
|
40
|
+
http_config = ConfigBuilder().set_protocol(Protocol.HTTP).build()
|
41
|
+
|
42
|
+
# Save to temporary file and load with Config
|
43
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
|
44
|
+
json.dump(http_config, f)
|
45
|
+
temp_config_path = f.name
|
46
|
+
|
47
|
+
try:
|
48
|
+
config = Config(temp_config_path)
|
49
|
+
|
50
|
+
# HTTP should have chk_hostname=False
|
51
|
+
assert config.get("server.protocol") == "http"
|
52
|
+
assert config.get("transport.chk_hostname") is False
|
53
|
+
|
54
|
+
print("✅ HTTP config: chk_hostname=False")
|
55
|
+
finally:
|
56
|
+
os.unlink(temp_config_path)
|
57
|
+
|
58
|
+
|
59
|
+
def test_chk_hostname_https_config():
|
60
|
+
"""Test that HTTPS config has chk_hostname=True."""
|
61
|
+
print("🧪 Testing HTTPS config chk_hostname...")
|
62
|
+
|
63
|
+
# Create HTTPS config
|
64
|
+
https_config = ConfigBuilder().set_protocol(Protocol.HTTPS).build()
|
65
|
+
|
66
|
+
# Save to temporary file and load with Config
|
67
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
|
68
|
+
json.dump(https_config, f)
|
69
|
+
temp_config_path = f.name
|
70
|
+
|
71
|
+
try:
|
72
|
+
config = Config(temp_config_path)
|
73
|
+
|
74
|
+
|
75
|
+
# HTTPS should have chk_hostname=True
|
76
|
+
assert config.get("server.protocol") == "https"
|
77
|
+
assert config.get("transport.chk_hostname") is True
|
78
|
+
|
79
|
+
print("✅ HTTPS config: chk_hostname=True")
|
80
|
+
finally:
|
81
|
+
os.unlink(temp_config_path)
|
82
|
+
|
83
|
+
|
84
|
+
def test_chk_hostname_mtls_config():
|
85
|
+
"""Test that mTLS config has chk_hostname=True."""
|
86
|
+
print("🧪 Testing mTLS config chk_hostname...")
|
87
|
+
|
88
|
+
# Create mTLS config
|
89
|
+
mtls_config = ConfigBuilder().set_protocol(Protocol.MTLS).build()
|
90
|
+
|
91
|
+
# Save to temporary file and load with Config
|
92
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
|
93
|
+
json.dump(mtls_config, f)
|
94
|
+
temp_config_path = f.name
|
95
|
+
|
96
|
+
try:
|
97
|
+
config = Config(temp_config_path)
|
98
|
+
|
99
|
+
# mTLS should have chk_hostname=True
|
100
|
+
assert config.get("server.protocol") == "mtls"
|
101
|
+
assert config.get("transport.chk_hostname") is True
|
102
|
+
|
103
|
+
print("✅ mTLS config: chk_hostname=True")
|
104
|
+
finally:
|
105
|
+
os.unlink(temp_config_path)
|
106
|
+
|
107
|
+
|
108
|
+
def test_chk_hostname_override():
|
109
|
+
"""Test that chk_hostname can be overridden in config."""
|
110
|
+
print("🧪 Testing chk_hostname override...")
|
111
|
+
|
112
|
+
# Create HTTPS config with chk_hostname=False override
|
113
|
+
https_config = ConfigBuilder().set_protocol(Protocol.HTTPS).build()
|
114
|
+
# Add transport section if it doesn't exist
|
115
|
+
if "transport" not in https_config:
|
116
|
+
https_config["transport"] = {}
|
117
|
+
https_config["transport"]["chk_hostname"] = False
|
118
|
+
|
119
|
+
# Save to temporary file and load with Config
|
120
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
|
121
|
+
json.dump(https_config, f)
|
122
|
+
temp_config_path = f.name
|
123
|
+
|
124
|
+
try:
|
125
|
+
config = Config(temp_config_path)
|
126
|
+
|
127
|
+
|
128
|
+
# Should respect the override
|
129
|
+
assert config.get("server.protocol") == "https"
|
130
|
+
assert config.get("transport.chk_hostname") is False
|
131
|
+
|
132
|
+
print("✅ HTTPS config with chk_hostname=False override works")
|
133
|
+
finally:
|
134
|
+
os.unlink(temp_config_path)
|
135
|
+
|
136
|
+
|
137
|
+
def test_chk_hostname_all_combinations():
|
138
|
+
"""Test chk_hostname for all protocol and auth combinations."""
|
139
|
+
print("🧪 Testing chk_hostname for all combinations...")
|
140
|
+
|
141
|
+
protocols = [Protocol.HTTP, Protocol.HTTPS, Protocol.MTLS]
|
142
|
+
auth_methods = [AuthMethod.NONE, AuthMethod.TOKEN, AuthMethod.TOKEN_ROLES]
|
143
|
+
|
144
|
+
for protocol in protocols:
|
145
|
+
for auth_method in auth_methods:
|
146
|
+
# Create config
|
147
|
+
config_data = (ConfigBuilder()
|
148
|
+
.set_protocol(protocol)
|
149
|
+
.set_auth(auth_method)
|
150
|
+
.build())
|
151
|
+
|
152
|
+
# Save to temporary file and load with Config
|
153
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
|
154
|
+
json.dump(config_data, f)
|
155
|
+
temp_config_path = f.name
|
156
|
+
|
157
|
+
try:
|
158
|
+
config = Config(temp_config_path)
|
159
|
+
|
160
|
+
protocol_name = protocol.value
|
161
|
+
auth_name = auth_method.value
|
162
|
+
|
163
|
+
# Check chk_hostname based on protocol
|
164
|
+
if protocol_name == "http":
|
165
|
+
expected_chk_hostname = False
|
166
|
+
else: # https or mtls
|
167
|
+
expected_chk_hostname = True
|
168
|
+
|
169
|
+
actual_chk_hostname = config.get("transport.ssl.chk_hostname")
|
170
|
+
|
171
|
+
assert actual_chk_hostname == expected_chk_hostname, (
|
172
|
+
f"Protocol {protocol_name} with auth {auth_name}: "
|
173
|
+
f"expected chk_hostname={expected_chk_hostname}, "
|
174
|
+
f"got {actual_chk_hostname}"
|
175
|
+
)
|
176
|
+
|
177
|
+
print(f"✅ {protocol_name}+{auth_name}: chk_hostname={actual_chk_hostname}")
|
178
|
+
|
179
|
+
finally:
|
180
|
+
os.unlink(temp_config_path)
|
181
|
+
|
182
|
+
print("✅ All protocol+auth combinations have correct chk_hostname values")
|
183
|
+
|
184
|
+
|
185
|
+
def main():
|
186
|
+
"""Run all chk_hostname tests."""
|
187
|
+
print("🧪 Running Automated chk_hostname Tests")
|
188
|
+
print("=" * 50)
|
189
|
+
|
190
|
+
try:
|
191
|
+
test_chk_hostname_default_config()
|
192
|
+
test_chk_hostname_http_config()
|
193
|
+
test_chk_hostname_https_config()
|
194
|
+
test_chk_hostname_mtls_config()
|
195
|
+
test_chk_hostname_override()
|
196
|
+
test_chk_hostname_all_combinations()
|
197
|
+
|
198
|
+
print("=" * 50)
|
199
|
+
print("🎉 All chk_hostname tests passed!")
|
200
|
+
return True
|
201
|
+
|
202
|
+
except Exception as e:
|
203
|
+
print(f"❌ Test failed: {e}")
|
204
|
+
import traceback
|
205
|
+
traceback.print_exc()
|
206
|
+
return False
|
207
|
+
|
208
|
+
|
209
|
+
if __name__ == "__main__":
|
210
|
+
success = main()
|
211
|
+
sys.exit(0 if success else 1)
|