mcp-security-framework 1.1.0__py3-none-any.whl → 1.1.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 (58) hide show
  1. mcp_security_framework/__init__.py +26 -15
  2. mcp_security_framework/cli/__init__.py +1 -1
  3. mcp_security_framework/cli/cert_cli.py +233 -197
  4. mcp_security_framework/cli/security_cli.py +324 -234
  5. mcp_security_framework/constants.py +21 -27
  6. mcp_security_framework/core/auth_manager.py +41 -22
  7. mcp_security_framework/core/cert_manager.py +210 -147
  8. mcp_security_framework/core/permission_manager.py +9 -9
  9. mcp_security_framework/core/rate_limiter.py +2 -2
  10. mcp_security_framework/core/security_manager.py +284 -229
  11. mcp_security_framework/examples/__init__.py +6 -0
  12. mcp_security_framework/examples/comprehensive_example.py +349 -279
  13. mcp_security_framework/examples/django_example.py +247 -206
  14. mcp_security_framework/examples/fastapi_example.py +315 -283
  15. mcp_security_framework/examples/flask_example.py +274 -203
  16. mcp_security_framework/examples/gateway_example.py +304 -237
  17. mcp_security_framework/examples/microservice_example.py +258 -189
  18. mcp_security_framework/examples/standalone_example.py +255 -230
  19. mcp_security_framework/examples/test_all_examples.py +151 -135
  20. mcp_security_framework/middleware/__init__.py +46 -55
  21. mcp_security_framework/middleware/auth_middleware.py +62 -63
  22. mcp_security_framework/middleware/fastapi_auth_middleware.py +119 -118
  23. mcp_security_framework/middleware/fastapi_middleware.py +156 -148
  24. mcp_security_framework/middleware/flask_auth_middleware.py +160 -147
  25. mcp_security_framework/middleware/flask_middleware.py +183 -157
  26. mcp_security_framework/middleware/mtls_middleware.py +106 -117
  27. mcp_security_framework/middleware/rate_limit_middleware.py +105 -101
  28. mcp_security_framework/middleware/security_middleware.py +109 -124
  29. mcp_security_framework/schemas/config.py +2 -1
  30. mcp_security_framework/schemas/models.py +18 -6
  31. mcp_security_framework/utils/cert_utils.py +14 -8
  32. mcp_security_framework/utils/datetime_compat.py +116 -0
  33. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/METADATA +2 -1
  34. mcp_security_framework-1.1.1.dist-info/RECORD +84 -0
  35. tests/conftest.py +63 -66
  36. tests/test_cli/test_cert_cli.py +184 -146
  37. tests/test_cli/test_security_cli.py +274 -247
  38. tests/test_core/test_cert_manager.py +24 -10
  39. tests/test_core/test_security_manager.py +2 -2
  40. tests/test_examples/test_comprehensive_example.py +190 -137
  41. tests/test_examples/test_fastapi_example.py +124 -101
  42. tests/test_examples/test_flask_example.py +124 -101
  43. tests/test_examples/test_standalone_example.py +73 -80
  44. tests/test_integration/test_auth_flow.py +213 -197
  45. tests/test_integration/test_certificate_flow.py +180 -149
  46. tests/test_integration/test_fastapi_integration.py +108 -111
  47. tests/test_integration/test_flask_integration.py +141 -140
  48. tests/test_integration/test_standalone_integration.py +290 -259
  49. tests/test_middleware/test_fastapi_auth_middleware.py +195 -174
  50. tests/test_middleware/test_fastapi_middleware.py +147 -132
  51. tests/test_middleware/test_flask_auth_middleware.py +260 -202
  52. tests/test_middleware/test_flask_middleware.py +201 -179
  53. tests/test_middleware/test_security_middleware.py +145 -130
  54. tests/test_utils/test_datetime_compat.py +147 -0
  55. mcp_security_framework-1.1.0.dist-info/RECORD +0 -82
  56. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/WHEEL +0 -0
  57. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/entry_points.txt +0 -0
  58. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/top_level.txt +0 -0
@@ -4,306 +4,353 @@ Security CLI Tests
4
4
  This module contains tests for the security management CLI commands.
5
5
  """
6
6
 
7
- import pytest
8
- import tempfile
9
7
  import os
10
- from unittest.mock import Mock, patch, MagicMock
8
+ import tempfile
9
+ from unittest.mock import MagicMock, Mock, patch
10
+
11
+ import pytest
11
12
  from click.testing import CliRunner
12
13
 
13
14
  from mcp_security_framework.cli.security_cli import security_cli
14
- from mcp_security_framework.schemas.config import SecurityConfig, AuthConfig, RateLimitConfig, SSLConfig, PermissionConfig
15
- from mcp_security_framework.schemas.models import AuthResult, AuthStatus, AuthMethod, ValidationResult
15
+ from mcp_security_framework.schemas.config import (
16
+ AuthConfig,
17
+ PermissionConfig,
18
+ RateLimitConfig,
19
+ SecurityConfig,
20
+ SSLConfig,
21
+ )
22
+ from mcp_security_framework.schemas.models import (
23
+ AuthMethod,
24
+ AuthResult,
25
+ AuthStatus,
26
+ ValidationResult,
27
+ )
16
28
 
17
29
 
18
30
  class TestSecurityCLI:
19
31
  """Test suite for security CLI commands."""
20
-
32
+
21
33
  def setup_method(self):
22
34
  """Set up test fixtures."""
23
35
  self.runner = CliRunner()
24
36
  self.temp_dir = tempfile.mkdtemp()
25
-
37
+
26
38
  def teardown_method(self):
27
39
  """Clean up test fixtures."""
28
40
  import shutil
41
+
29
42
  shutil.rmtree(self.temp_dir, ignore_errors=True)
30
-
31
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
43
+
44
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
32
45
  def test_add_api_key_success(self, mock_security_manager_class):
33
46
  """Test successful API key addition."""
34
47
  # Mock security manager
35
48
  mock_security_manager = Mock()
36
49
  mock_security_manager_class.return_value = mock_security_manager
37
50
  mock_security_manager.auth_manager.add_api_key.return_value = True
38
-
51
+
39
52
  # Run command
40
- result = self.runner.invoke(security_cli, [
41
- 'auth', 'add-api-key',
42
- '--username', 'testuser',
43
- '--api-key', 'test_key_123'
44
- ])
45
-
53
+ result = self.runner.invoke(
54
+ security_cli,
55
+ [
56
+ "auth",
57
+ "add-api-key",
58
+ "--username",
59
+ "testuser",
60
+ "--api-key",
61
+ "test_key_123",
62
+ ],
63
+ )
64
+
46
65
  # Assertions
47
66
  assert result.exit_code == 0
48
67
  assert "✅ API key added successfully" in result.output
49
68
  assert "testuser" in result.output
50
-
51
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
69
+
70
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
52
71
  def test_add_api_key_failure(self, mock_security_manager_class):
53
72
  """Test API key addition failure."""
54
73
  # Mock security manager
55
74
  mock_security_manager = Mock()
56
75
  mock_security_manager_class.return_value = mock_security_manager
57
76
  mock_security_manager.auth_manager.add_api_key.return_value = False
58
-
77
+
59
78
  # Run command
60
- result = self.runner.invoke(security_cli, [
61
- 'auth', 'add-api-key',
62
- '--username', 'testuser',
63
- '--api-key', 'test_key_123'
64
- ])
65
-
79
+ result = self.runner.invoke(
80
+ security_cli,
81
+ [
82
+ "auth",
83
+ "add-api-key",
84
+ "--username",
85
+ "testuser",
86
+ "--api-key",
87
+ "test_key_123",
88
+ ],
89
+ )
90
+
66
91
  # Assertions
67
92
  assert result.exit_code != 0
68
93
  assert "❌ Failed to add API key" in result.output
69
-
70
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
94
+
95
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
71
96
  def test_remove_api_key_success(self, mock_security_manager_class):
72
97
  """Test successful API key removal."""
73
98
  # Mock security manager
74
99
  mock_security_manager = Mock()
75
100
  mock_security_manager_class.return_value = mock_security_manager
76
101
  mock_security_manager.auth_manager.remove_api_key.return_value = True
77
-
102
+
78
103
  # Run command
79
- result = self.runner.invoke(security_cli, [
80
- 'auth', 'remove-api-key',
81
- '--username', 'testuser'
82
- ])
83
-
104
+ result = self.runner.invoke(
105
+ security_cli, ["auth", "remove-api-key", "--username", "testuser"]
106
+ )
107
+
84
108
  # Assertions
85
109
  assert result.exit_code == 0
86
110
  assert "✅ API key removed successfully" in result.output
87
111
  assert "testuser" in result.output
88
-
89
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
112
+
113
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
90
114
  def test_test_api_key_success(self, mock_security_manager_class):
91
115
  """Test successful API key authentication."""
92
116
  # Mock security manager
93
117
  mock_security_manager = Mock()
94
118
  mock_security_manager_class.return_value = mock_security_manager
95
-
119
+
96
120
  # Mock auth result
97
121
  mock_auth_result = Mock(spec=AuthResult)
98
122
  mock_auth_result.is_valid = True
99
123
  mock_auth_result.username = "testuser"
100
124
  mock_auth_result.roles = ["user", "admin"]
101
125
  mock_auth_result.auth_method = AuthMethod.API_KEY
102
- mock_security_manager.auth_manager.authenticate_api_key.return_value = mock_auth_result
103
-
126
+ mock_security_manager.auth_manager.authenticate_api_key.return_value = (
127
+ mock_auth_result
128
+ )
129
+
104
130
  # Run command
105
- result = self.runner.invoke(security_cli, [
106
- 'auth', 'test-api-key',
107
- '--api-key', 'test_key_123'
108
- ])
109
-
131
+ result = self.runner.invoke(
132
+ security_cli, ["auth", "test-api-key", "--api-key", "test_key_123"]
133
+ )
134
+
110
135
  # Assertions
111
136
  assert result.exit_code == 0
112
137
  assert "✅ API key authentication successful!" in result.output
113
138
  assert "testuser" in result.output
114
139
  assert "user, admin" in result.output
115
-
116
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
140
+
141
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
117
142
  def test_test_api_key_failure(self, mock_security_manager_class):
118
143
  """Test API key authentication failure."""
119
144
  # Mock security manager
120
145
  mock_security_manager = Mock()
121
146
  mock_security_manager_class.return_value = mock_security_manager
122
-
147
+
123
148
  # Mock auth result
124
149
  mock_auth_result = Mock(spec=AuthResult)
125
150
  mock_auth_result.is_valid = False
126
151
  mock_auth_result.error_message = "Invalid API key"
127
- mock_security_manager.auth_manager.authenticate_api_key.return_value = mock_auth_result
128
-
152
+ mock_security_manager.auth_manager.authenticate_api_key.return_value = (
153
+ mock_auth_result
154
+ )
155
+
129
156
  # Run command
130
- result = self.runner.invoke(security_cli, [
131
- 'auth', 'test-api-key',
132
- '--api-key', 'invalid_key'
133
- ])
134
-
157
+ result = self.runner.invoke(
158
+ security_cli, ["auth", "test-api-key", "--api-key", "invalid_key"]
159
+ )
160
+
135
161
  # Assertions
136
162
  assert result.exit_code != 0
137
163
  assert "❌ API key authentication failed!" in result.output
138
164
  assert "Invalid API key" in result.output
139
-
140
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
165
+
166
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
141
167
  def test_test_jwt_success(self, mock_security_manager_class):
142
168
  """Test successful JWT authentication."""
143
169
  # Mock security manager
144
170
  mock_security_manager = Mock()
145
171
  mock_security_manager_class.return_value = mock_security_manager
146
-
172
+
147
173
  # Mock auth result
148
174
  mock_auth_result = Mock(spec=AuthResult)
149
175
  mock_auth_result.is_valid = True
150
176
  mock_auth_result.username = "testuser"
151
177
  mock_auth_result.roles = ["user"]
152
178
  mock_auth_result.auth_method = AuthMethod.JWT
153
- mock_security_manager.auth_manager.authenticate_jwt_token.return_value = mock_auth_result
154
-
179
+ mock_security_manager.auth_manager.authenticate_jwt_token.return_value = (
180
+ mock_auth_result
181
+ )
182
+
155
183
  # Run command
156
- result = self.runner.invoke(security_cli, [
157
- 'auth', 'test-jwt',
158
- '--token', 'test_jwt_token'
159
- ])
160
-
184
+ result = self.runner.invoke(
185
+ security_cli, ["auth", "test-jwt", "--token", "test_jwt_token"]
186
+ )
187
+
161
188
  # Assertions
162
189
  assert result.exit_code == 0
163
190
  assert "✅ JWT token authentication successful!" in result.output
164
191
  assert "testuser" in result.output
165
-
166
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
192
+
193
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
167
194
  def test_check_permissions_success(self, mock_security_manager_class):
168
195
  """Test successful permission check."""
169
196
  # Mock security manager
170
197
  mock_security_manager = Mock()
171
198
  mock_security_manager_class.return_value = mock_security_manager
172
-
199
+
173
200
  # Mock user roles
174
- mock_security_manager.auth_manager._get_user_roles.return_value = ["user", "admin"]
175
-
201
+ mock_security_manager.auth_manager._get_user_roles.return_value = [
202
+ "user",
203
+ "admin",
204
+ ]
205
+
176
206
  # Mock validation result
177
207
  mock_validation_result = Mock(spec=ValidationResult)
178
208
  mock_validation_result.is_valid = True
179
209
  mock_validation_result.missing_permissions = []
180
- mock_security_manager.permission_manager.validate_access.return_value = mock_validation_result
181
-
210
+ mock_security_manager.permission_manager.validate_access.return_value = (
211
+ mock_validation_result
212
+ )
213
+
182
214
  # Run command
183
- result = self.runner.invoke(security_cli, [
184
- 'permissions', 'check',
185
- '--username', 'testuser',
186
- '--permissions', 'read',
187
- '--permissions', 'write'
188
- ])
189
-
215
+ result = self.runner.invoke(
216
+ security_cli,
217
+ [
218
+ "permissions",
219
+ "check",
220
+ "--username",
221
+ "testuser",
222
+ "--permissions",
223
+ "read",
224
+ "--permissions",
225
+ "write",
226
+ ],
227
+ )
228
+
190
229
  # Assertions
191
230
  assert result.exit_code == 0
192
231
  assert "✅ User has all required permissions!" in result.output
193
232
  assert "testuser" in result.output
194
233
  assert "user, admin" in result.output
195
-
196
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
234
+
235
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
197
236
  def test_check_permissions_failure(self, mock_security_manager_class):
198
237
  """Test permission check failure."""
199
238
  # Mock security manager
200
239
  mock_security_manager = Mock()
201
240
  mock_security_manager_class.return_value = mock_security_manager
202
-
241
+
203
242
  # Mock user roles
204
243
  mock_security_manager.auth_manager._get_user_roles.return_value = ["user"]
205
-
244
+
206
245
  # Mock validation result
207
246
  mock_validation_result = Mock(spec=ValidationResult)
208
247
  mock_validation_result.is_valid = False
209
248
  mock_validation_result.missing_permissions = ["admin"]
210
- mock_security_manager.permission_manager.validate_access.return_value = mock_validation_result
211
-
249
+ mock_security_manager.permission_manager.validate_access.return_value = (
250
+ mock_validation_result
251
+ )
252
+
212
253
  # Run command
213
- result = self.runner.invoke(security_cli, [
214
- 'permissions', 'check',
215
- '--username', 'testuser',
216
- '--permissions', 'admin'
217
- ])
218
-
254
+ result = self.runner.invoke(
255
+ security_cli,
256
+ [
257
+ "permissions",
258
+ "check",
259
+ "--username",
260
+ "testuser",
261
+ "--permissions",
262
+ "admin",
263
+ ],
264
+ )
265
+
219
266
  # Assertions
220
267
  assert result.exit_code != 0
221
268
  assert "❌ User does not have required permissions!" in result.output
222
269
  assert "admin" in result.output
223
-
224
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
270
+
271
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
225
272
  def test_list_role_permissions_success(self, mock_security_manager_class):
226
273
  """Test successful role permissions listing."""
227
274
  # Mock security manager
228
275
  mock_security_manager = Mock()
229
276
  mock_security_manager_class.return_value = mock_security_manager
230
- mock_security_manager.permission_manager.get_role_permissions.return_value = ["read", "write", "delete"]
231
-
277
+ mock_security_manager.permission_manager.get_role_permissions.return_value = [
278
+ "read",
279
+ "write",
280
+ "delete",
281
+ ]
282
+
232
283
  # Run command
233
- result = self.runner.invoke(security_cli, [
234
- 'permissions', 'list-role-permissions',
235
- '--role', 'admin'
236
- ])
237
-
284
+ result = self.runner.invoke(
285
+ security_cli, ["permissions", "list-role-permissions", "--role", "admin"]
286
+ )
287
+
238
288
  # Assertions
239
289
  assert result.exit_code == 0
240
290
  assert "Permissions for role 'admin':" in result.output
241
291
  assert "read" in result.output
242
292
  assert "write" in result.output
243
293
  assert "delete" in result.output
244
-
245
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
294
+
295
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
246
296
  def test_rate_limit_check_success(self, mock_security_manager_class):
247
297
  """Test successful rate limit check."""
248
298
  # Mock security manager
249
299
  mock_security_manager = Mock()
250
300
  mock_security_manager_class.return_value = mock_security_manager
251
301
  mock_security_manager.rate_limiter.check_rate_limit.return_value = True
252
-
302
+
253
303
  # Run command
254
- result = self.runner.invoke(security_cli, [
255
- 'rate-limit', 'check',
256
- '--identifier', '192.168.1.1'
257
- ])
258
-
304
+ result = self.runner.invoke(
305
+ security_cli, ["rate-limit", "check", "--identifier", "192.168.1.1"]
306
+ )
307
+
259
308
  # Assertions
260
309
  assert result.exit_code == 0
261
310
  assert "✅ Rate limit check passed" in result.output
262
311
  assert "192.168.1.1" in result.output
263
-
264
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
312
+
313
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
265
314
  def test_rate_limit_check_failure(self, mock_security_manager_class):
266
315
  """Test rate limit check failure."""
267
316
  # Mock security manager
268
317
  mock_security_manager = Mock()
269
318
  mock_security_manager_class.return_value = mock_security_manager
270
319
  mock_security_manager.rate_limiter.check_rate_limit.return_value = False
271
-
320
+
272
321
  # Run command
273
- result = self.runner.invoke(security_cli, [
274
- 'rate-limit', 'check',
275
- '--identifier', '192.168.1.1'
276
- ])
277
-
322
+ result = self.runner.invoke(
323
+ security_cli, ["rate-limit", "check", "--identifier", "192.168.1.1"]
324
+ )
325
+
278
326
  # Assertions
279
327
  assert result.exit_code != 0
280
328
  assert "❌ Rate limit exceeded" in result.output
281
-
282
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
329
+
330
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
283
331
  def test_rate_limit_reset_success(self, mock_security_manager_class):
284
332
  """Test successful rate limit reset."""
285
333
  # Mock security manager
286
334
  mock_security_manager = Mock()
287
335
  mock_security_manager_class.return_value = mock_security_manager
288
-
336
+
289
337
  # Run command
290
- result = self.runner.invoke(security_cli, [
291
- 'rate-limit', 'reset',
292
- '--identifier', '192.168.1.1'
293
- ])
294
-
338
+ result = self.runner.invoke(
339
+ security_cli, ["rate-limit", "reset", "--identifier", "192.168.1.1"]
340
+ )
341
+
295
342
  # Assertions
296
343
  assert result.exit_code == 0
297
344
  assert "✅ Rate limit reset successfully" in result.output
298
345
  assert "192.168.1.1" in result.output
299
-
300
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
346
+
347
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
301
348
  def test_rate_limit_status_success(self, mock_security_manager_class):
302
349
  """Test successful rate limit status."""
303
350
  # Mock security manager
304
351
  mock_security_manager = Mock()
305
352
  mock_security_manager_class.return_value = mock_security_manager
306
-
353
+
307
354
  # Mock rate limit status
308
355
  mock_status = Mock()
309
356
  mock_status.current_count = 5
@@ -311,58 +358,56 @@ class TestSecurityCLI:
311
358
  mock_status.window_start = "2024-01-01 10:00:00"
312
359
  mock_status.window_end = "2024-01-01 10:01:00"
313
360
  mock_status.is_allowed = True
314
- mock_security_manager.rate_limiter.get_rate_limit_status.return_value = mock_status
315
-
361
+ mock_security_manager.rate_limiter.get_rate_limit_status.return_value = (
362
+ mock_status
363
+ )
364
+
316
365
  # Run command
317
- result = self.runner.invoke(security_cli, [
318
- 'rate-limit', 'status',
319
- '--identifier', '192.168.1.1'
320
- ])
321
-
366
+ result = self.runner.invoke(
367
+ security_cli, ["rate-limit", "status", "--identifier", "192.168.1.1"]
368
+ )
369
+
322
370
  # Assertions
323
371
  assert result.exit_code == 0
324
372
  assert "Rate Limit Status for '192.168.1.1':" in result.output
325
373
  assert "Current Count: 5" in result.output
326
374
  assert "Limit: 100" in result.output
327
-
328
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
375
+
376
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
329
377
  def test_config_validate_success(self, mock_security_manager_class):
330
378
  """Test successful configuration validation."""
331
379
  # Mock security manager
332
380
  mock_security_manager = Mock()
333
381
  mock_security_manager_class.return_value = mock_security_manager
334
-
382
+
335
383
  # Run command
336
- result = self.runner.invoke(security_cli, [
337
- 'config', 'validate'
338
- ])
339
-
384
+ result = self.runner.invoke(security_cli, ["config", "validate"])
385
+
340
386
  # Assertions
341
387
  assert result.exit_code == 0
342
388
  assert "✅ Configuration validation passed!" in result.output
343
-
344
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
389
+
390
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
345
391
  def test_config_export_success(self, mock_security_manager_class):
346
392
  """Test successful configuration export."""
347
393
  # Mock security manager
348
394
  mock_security_manager = Mock()
349
395
  mock_security_manager_class.return_value = mock_security_manager
350
-
396
+
351
397
  # Create temporary output file
352
398
  output_file = os.path.join(self.temp_dir, "config.json")
353
-
399
+
354
400
  # Run command
355
- result = self.runner.invoke(security_cli, [
356
- 'config', 'export',
357
- '--output', output_file
358
- ])
359
-
401
+ result = self.runner.invoke(
402
+ security_cli, ["config", "export", "--output", output_file]
403
+ )
404
+
360
405
  # Assertions
361
406
  assert result.exit_code == 0
362
407
  assert "✅ Configuration exported to:" in result.output
363
408
  assert os.path.exists(output_file)
364
-
365
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
409
+
410
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
366
411
  def test_status_success(self, mock_security_manager_class):
367
412
  """Test successful security status display."""
368
413
  # Mock security manager
@@ -373,91 +418,86 @@ class TestSecurityCLI:
373
418
  mock_security_manager.rate_limiter = Mock()
374
419
  mock_security_manager.ssl_manager = Mock()
375
420
  mock_security_manager.cert_manager = Mock()
376
-
421
+
377
422
  # Run command
378
- result = self.runner.invoke(security_cli, [
379
- 'status'
380
- ])
381
-
423
+ result = self.runner.invoke(security_cli, ["status"])
424
+
382
425
  # Assertions
383
426
  assert result.exit_code == 0
384
427
  assert "Security Status:" in result.output
385
428
  assert "Component Status:" in result.output
386
-
429
+
387
430
  def test_help(self):
388
431
  """Test CLI help output."""
389
- result = self.runner.invoke(security_cli, ['--help'])
432
+ result = self.runner.invoke(security_cli, ["--help"])
390
433
  assert result.exit_code == 0
391
434
  assert "Security Management CLI" in result.output
392
-
393
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
435
+
436
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
394
437
  def test_auth_help(self, mock_security_manager_class):
395
438
  """Test auth help output."""
396
439
  # Mock security manager
397
440
  mock_security_manager = Mock()
398
441
  mock_security_manager_class.return_value = mock_security_manager
399
-
400
- result = self.runner.invoke(security_cli, ['auth', '--help'])
442
+
443
+ result = self.runner.invoke(security_cli, ["auth", "--help"])
401
444
  assert result.exit_code == 0
402
445
  assert "Authentication operations" in result.output
403
-
404
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
446
+
447
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
405
448
  def test_permissions_help(self, mock_security_manager_class):
406
449
  """Test permissions help output."""
407
450
  # Mock security manager
408
451
  mock_security_manager = Mock()
409
452
  mock_security_manager_class.return_value = mock_security_manager
410
-
411
- result = self.runner.invoke(security_cli, ['permissions', '--help'])
453
+
454
+ result = self.runner.invoke(security_cli, ["permissions", "--help"])
412
455
  assert result.exit_code == 0
413
456
  assert "Permission management operations" in result.output
414
-
415
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
457
+
458
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
416
459
  def test_rate_limit_help(self, mock_security_manager_class):
417
460
  """Test rate-limit help output."""
418
461
  # Mock security manager
419
462
  mock_security_manager = Mock()
420
463
  mock_security_manager_class.return_value = mock_security_manager
421
-
422
- result = self.runner.invoke(security_cli, ['rate-limit', '--help'])
464
+
465
+ result = self.runner.invoke(security_cli, ["rate-limit", "--help"])
423
466
  assert result.exit_code == 0
424
467
  assert "Rate limiting operations" in result.output
425
-
426
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
468
+
469
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
427
470
  def test_config_help(self, mock_security_manager_class):
428
471
  """Test config help output."""
429
472
  # Mock security manager
430
473
  mock_security_manager = Mock()
431
474
  mock_security_manager_class.return_value = mock_security_manager
432
-
433
- result = self.runner.invoke(security_cli, ['config', '--help'])
475
+
476
+ result = self.runner.invoke(security_cli, ["config", "--help"])
434
477
  assert result.exit_code == 0
435
478
  assert "Configuration management operations" in result.output
436
-
437
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
479
+
480
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
438
481
  def test_missing_required_options(self, mock_security_manager_class):
439
482
  """Test missing required options."""
440
483
  # Mock security manager
441
484
  mock_security_manager = Mock()
442
485
  mock_security_manager_class.return_value = mock_security_manager
443
-
444
- result = self.runner.invoke(security_cli, ['auth', 'add-api-key'])
486
+
487
+ result = self.runner.invoke(security_cli, ["auth", "add-api-key"])
445
488
  assert result.exit_code != 0
446
489
  assert "Missing option" in result.output
447
490
 
448
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
491
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
449
492
  def test_generate_roles_template(self, mock_security_manager_class):
450
493
  """Test generating template roles configuration."""
451
494
  # Mock security manager
452
495
  mock_security_manager = Mock()
453
496
  mock_security_manager_class.return_value = mock_security_manager
454
-
497
+
455
498
  # Run command
456
- result = self.runner.invoke(security_cli, [
457
- 'generate-roles',
458
- '--template'
459
- ])
460
-
499
+ result = self.runner.invoke(security_cli, ["generate-roles", "--template"])
500
+
461
501
  # Assertions
462
502
  assert result.exit_code == 0
463
503
  assert "admin" in result.output
@@ -465,193 +505,180 @@ class TestSecurityCLI:
465
505
  assert "guest" in result.output
466
506
  assert "permissions" in result.output
467
507
 
468
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
508
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
469
509
  def test_generate_roles_current(self, mock_security_manager_class):
470
510
  """Test generating current roles configuration."""
471
511
  # Mock security manager
472
512
  mock_security_manager = Mock()
473
513
  mock_security_manager_class.return_value = mock_security_manager
474
-
514
+
475
515
  # Mock permission manager
476
516
  mock_permission_manager = Mock()
477
517
  mock_security_manager.permission_manager = mock_permission_manager
478
-
518
+
479
519
  # Mock export method
480
520
  mock_roles_config = {
481
521
  "roles": {
482
522
  "admin": {
483
523
  "description": "Administrator role",
484
524
  "permissions": ["*"],
485
- "parent_roles": []
525
+ "parent_roles": [],
486
526
  }
487
527
  },
488
- "permissions": {
489
- "*": "All permissions"
490
- }
528
+ "permissions": {"*": "All permissions"},
491
529
  }
492
530
  mock_permission_manager.export_roles_config.return_value = mock_roles_config
493
-
531
+
494
532
  # Run command
495
- result = self.runner.invoke(security_cli, [
496
- 'generate-roles'
497
- ])
498
-
533
+ result = self.runner.invoke(security_cli, ["generate-roles"])
534
+
499
535
  # Assertions
500
536
  assert result.exit_code == 0
501
537
  assert "admin" in result.output
502
538
  assert "Administrator role" in result.output
503
539
 
504
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
540
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
505
541
  def test_generate_roles_with_output(self, mock_security_manager_class):
506
542
  """Test generating roles configuration with output file."""
507
543
  # Mock security manager
508
544
  mock_security_manager = Mock()
509
545
  mock_security_manager_class.return_value = mock_security_manager
510
-
546
+
511
547
  # Mock permission manager
512
548
  mock_permission_manager = Mock()
513
549
  mock_security_manager.permission_manager = mock_permission_manager
514
-
550
+
515
551
  # Mock export method
516
552
  mock_roles_config = {
517
553
  "roles": {
518
554
  "user": {
519
555
  "description": "User role",
520
556
  "permissions": ["read:own"],
521
- "parent_roles": []
557
+ "parent_roles": [],
522
558
  }
523
559
  },
524
- "permissions": {
525
- "read:own": "Read own resources"
526
- }
560
+ "permissions": {"read:own": "Read own resources"},
527
561
  }
528
562
  mock_permission_manager.export_roles_config.return_value = mock_roles_config
529
-
563
+
530
564
  # Create temporary output file
531
565
  output_file = os.path.join(self.temp_dir, "roles.json")
532
-
566
+
533
567
  # Run command
534
- result = self.runner.invoke(security_cli, [
535
- 'generate-roles',
536
- '--output', output_file
537
- ])
538
-
568
+ result = self.runner.invoke(
569
+ security_cli, ["generate-roles", "--output", output_file]
570
+ )
571
+
539
572
  # Assertions
540
573
  assert result.exit_code == 0
541
574
  assert "✅ Current roles configuration exported" in result.output
542
575
  assert os.path.exists(output_file)
543
576
 
544
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
577
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
545
578
  def test_security_audit_text_format(self, mock_security_manager_class):
546
579
  """Test security audit in text format."""
547
580
  # Mock security manager
548
581
  mock_security_manager = Mock()
549
582
  mock_security_manager_class.return_value = mock_security_manager
550
-
583
+
551
584
  # Mock components
552
585
  mock_auth_manager = Mock()
553
586
  mock_auth_manager.api_keys = {"key1": "user1", "key2": "user2"}
554
587
  mock_security_manager.auth_manager = mock_auth_manager
555
-
588
+
556
589
  mock_permission_manager = Mock()
557
590
  mock_permission_manager.roles = {"admin": {}, "user": {}}
558
591
  mock_security_manager.permission_manager = mock_permission_manager
559
-
592
+
560
593
  mock_security_manager.rate_limiter = Mock()
561
594
  mock_security_manager.ssl_manager = Mock()
562
595
  mock_security_manager.cert_manager = Mock()
563
-
596
+
564
597
  # Run command
565
- result = self.runner.invoke(security_cli, [
566
- 'security-audit'
567
- ])
568
-
598
+ result = self.runner.invoke(security_cli, ["security-audit"])
599
+
569
600
  # Assertions
570
601
  assert result.exit_code == 0
571
602
  assert "Security Audit Report" in result.output
572
603
  assert "Configuration:" in result.output
573
604
  assert "Components:" in result.output
574
605
 
575
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
606
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
576
607
  def test_security_audit_json_format(self, mock_security_manager_class):
577
608
  """Test security audit in JSON format."""
578
609
  # Mock security manager
579
610
  mock_security_manager = Mock()
580
611
  mock_security_manager_class.return_value = mock_security_manager
581
-
612
+
582
613
  # Mock components
583
614
  mock_auth_manager = Mock()
584
615
  mock_auth_manager.api_keys = {"key1": "user1"}
585
616
  mock_security_manager.auth_manager = mock_auth_manager
586
-
617
+
587
618
  mock_permission_manager = Mock()
588
619
  mock_permission_manager.roles = {"admin": {}}
589
620
  mock_security_manager.permission_manager = mock_permission_manager
590
-
621
+
591
622
  mock_security_manager.rate_limiter = Mock()
592
623
  mock_security_manager.ssl_manager = Mock()
593
624
  mock_security_manager.cert_manager = Mock()
594
-
625
+
595
626
  # Run command
596
- result = self.runner.invoke(security_cli, [
597
- 'security-audit',
598
- '--format', 'json'
599
- ])
600
-
627
+ result = self.runner.invoke(
628
+ security_cli, ["security-audit", "--format", "json"]
629
+ )
630
+
601
631
  # Assertions
602
632
  assert result.exit_code == 0
603
633
  assert "timestamp" in result.output
604
634
  assert "configuration" in result.output
605
635
  assert "components" in result.output
606
636
 
607
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
637
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
608
638
  def test_security_audit_with_output(self, mock_security_manager_class):
609
639
  """Test security audit with output file."""
610
640
  # Mock security manager
611
641
  mock_security_manager = Mock()
612
642
  mock_security_manager_class.return_value = mock_security_manager
613
-
643
+
614
644
  # Mock components
615
645
  mock_auth_manager = Mock()
616
646
  mock_auth_manager.api_keys = {"key1": "user1"}
617
647
  mock_security_manager.auth_manager = mock_auth_manager
618
-
648
+
619
649
  mock_permission_manager = Mock()
620
650
  mock_permission_manager.roles = {"admin": {}}
621
651
  mock_security_manager.permission_manager = mock_permission_manager
622
-
652
+
623
653
  mock_security_manager.rate_limiter = Mock()
624
654
  mock_security_manager.ssl_manager = Mock()
625
655
  mock_security_manager.cert_manager = Mock()
626
-
656
+
627
657
  # Create temporary output file
628
658
  output_file = os.path.join(self.temp_dir, "audit.json")
629
-
659
+
630
660
  # Run command
631
- result = self.runner.invoke(security_cli, [
632
- 'security-audit',
633
- '--output', output_file,
634
- '--format', 'json'
635
- ])
636
-
661
+ result = self.runner.invoke(
662
+ security_cli,
663
+ ["security-audit", "--output", output_file, "--format", "json"],
664
+ )
665
+
637
666
  # Assertions
638
667
  assert result.exit_code == 0
639
668
  assert "✅ Security audit report saved" in result.output
640
669
  assert os.path.exists(output_file)
641
670
 
642
- @patch('mcp_security_framework.cli.security_cli.SecurityManager')
671
+ @patch("mcp_security_framework.cli.security_cli.SecurityManager")
643
672
  def test_security_audit_failure(self, mock_security_manager_class):
644
673
  """Test security audit failure."""
645
674
  # Mock security manager
646
675
  mock_security_manager = Mock()
647
676
  mock_security_manager_class.return_value = mock_security_manager
648
677
  mock_security_manager.auth_manager = None # This will cause an error
649
-
678
+
650
679
  # Run command
651
- result = self.runner.invoke(security_cli, [
652
- 'security-audit'
653
- ])
654
-
680
+ result = self.runner.invoke(security_cli, ["security-audit"])
681
+
655
682
  # Assertions
656
683
  assert result.exit_code != 0
657
684
  assert "❌ Failed to perform security audit" in result.output