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.
- mcp_security_framework/__init__.py +26 -15
- mcp_security_framework/cli/__init__.py +1 -1
- mcp_security_framework/cli/cert_cli.py +233 -197
- mcp_security_framework/cli/security_cli.py +324 -234
- mcp_security_framework/constants.py +21 -27
- mcp_security_framework/core/auth_manager.py +41 -22
- mcp_security_framework/core/cert_manager.py +210 -147
- mcp_security_framework/core/permission_manager.py +9 -9
- mcp_security_framework/core/rate_limiter.py +2 -2
- mcp_security_framework/core/security_manager.py +284 -229
- mcp_security_framework/examples/__init__.py +6 -0
- mcp_security_framework/examples/comprehensive_example.py +349 -279
- mcp_security_framework/examples/django_example.py +247 -206
- mcp_security_framework/examples/fastapi_example.py +315 -283
- mcp_security_framework/examples/flask_example.py +274 -203
- mcp_security_framework/examples/gateway_example.py +304 -237
- mcp_security_framework/examples/microservice_example.py +258 -189
- mcp_security_framework/examples/standalone_example.py +255 -230
- mcp_security_framework/examples/test_all_examples.py +151 -135
- mcp_security_framework/middleware/__init__.py +46 -55
- mcp_security_framework/middleware/auth_middleware.py +62 -63
- mcp_security_framework/middleware/fastapi_auth_middleware.py +119 -118
- mcp_security_framework/middleware/fastapi_middleware.py +156 -148
- mcp_security_framework/middleware/flask_auth_middleware.py +160 -147
- mcp_security_framework/middleware/flask_middleware.py +183 -157
- mcp_security_framework/middleware/mtls_middleware.py +106 -117
- mcp_security_framework/middleware/rate_limit_middleware.py +105 -101
- mcp_security_framework/middleware/security_middleware.py +109 -124
- mcp_security_framework/schemas/config.py +2 -1
- mcp_security_framework/schemas/models.py +18 -6
- mcp_security_framework/utils/cert_utils.py +14 -8
- mcp_security_framework/utils/datetime_compat.py +116 -0
- {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/METADATA +2 -1
- mcp_security_framework-1.1.1.dist-info/RECORD +84 -0
- tests/conftest.py +63 -66
- tests/test_cli/test_cert_cli.py +184 -146
- tests/test_cli/test_security_cli.py +274 -247
- tests/test_core/test_cert_manager.py +24 -10
- tests/test_core/test_security_manager.py +2 -2
- tests/test_examples/test_comprehensive_example.py +190 -137
- tests/test_examples/test_fastapi_example.py +124 -101
- tests/test_examples/test_flask_example.py +124 -101
- tests/test_examples/test_standalone_example.py +73 -80
- tests/test_integration/test_auth_flow.py +213 -197
- tests/test_integration/test_certificate_flow.py +180 -149
- tests/test_integration/test_fastapi_integration.py +108 -111
- tests/test_integration/test_flask_integration.py +141 -140
- tests/test_integration/test_standalone_integration.py +290 -259
- tests/test_middleware/test_fastapi_auth_middleware.py +195 -174
- tests/test_middleware/test_fastapi_middleware.py +147 -132
- tests/test_middleware/test_flask_auth_middleware.py +260 -202
- tests/test_middleware/test_flask_middleware.py +201 -179
- tests/test_middleware/test_security_middleware.py +145 -130
- tests/test_utils/test_datetime_compat.py +147 -0
- mcp_security_framework-1.1.0.dist-info/RECORD +0 -82
- {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/WHEEL +0 -0
- {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/entry_points.txt +0 -0
- {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
|
-
|
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
|
15
|
-
|
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(
|
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(
|
41
|
-
|
42
|
-
|
43
|
-
|
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(
|
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(
|
61
|
-
|
62
|
-
|
63
|
-
|
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(
|
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(
|
80
|
-
|
81
|
-
|
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(
|
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 =
|
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(
|
106
|
-
|
107
|
-
|
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(
|
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 =
|
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(
|
131
|
-
|
132
|
-
|
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(
|
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 =
|
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(
|
157
|
-
|
158
|
-
|
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(
|
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 = [
|
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 =
|
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(
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
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(
|
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 =
|
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(
|
214
|
-
|
215
|
-
|
216
|
-
|
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(
|
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 = [
|
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(
|
234
|
-
|
235
|
-
|
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(
|
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(
|
255
|
-
|
256
|
-
|
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(
|
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(
|
274
|
-
|
275
|
-
|
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(
|
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(
|
291
|
-
|
292
|
-
|
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(
|
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 =
|
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(
|
318
|
-
|
319
|
-
|
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(
|
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
|
-
|
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(
|
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(
|
356
|
-
|
357
|
-
|
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(
|
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
|
-
|
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, [
|
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(
|
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, [
|
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(
|
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, [
|
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(
|
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, [
|
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(
|
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, [
|
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(
|
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, [
|
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(
|
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
|
-
|
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(
|
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
|
-
|
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(
|
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(
|
535
|
-
|
536
|
-
|
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(
|
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
|
-
|
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(
|
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(
|
597
|
-
|
598
|
-
|
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(
|
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(
|
632
|
-
|
633
|
-
|
634
|
-
|
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(
|
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
|
-
|
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
|